Skip to content

Commit d432683

Browse files
committed
feat(dev): add playground to render syntax
1 parent df8dd57 commit d432683

2 files changed

Lines changed: 92 additions & 0 deletions

File tree

dev/src/App.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Flex, Radio } from 'antd';
22
import { useState } from 'react';
33
import { Composite } from './Composite';
44
import { ItemPreview } from './ItemPreview';
5+
import { Playground } from './Playground';
56
import { Preview } from './Preview';
67
import { StreamPreview } from './StreamPreview';
78

@@ -32,6 +33,7 @@ export const App = () => {
3233
{ label: '模版预览', value: 'preview' },
3334
{ label: '数据项预览', value: 'item' },
3435
{ label: '流式渲染', value: 'stream' },
36+
{ label: '语法渲染', value: 'playground' },
3537
]}
3638
value={tab}
3739
onChange={(e) => handleTabChange(e.target.value)}
@@ -46,6 +48,8 @@ export const App = () => {
4648
<Preview />
4749
) : tab === 'stream' ? (
4850
<StreamPreview />
51+
) : tab === 'playground' ? (
52+
<Playground />
4953
) : (
5054
<ItemPreview />
5155
)}

dev/src/Playground.tsx

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import Editor from '@monaco-editor/react';
2+
import { Card } from 'antd';
3+
import { useEffect, useState } from 'react';
4+
import { Infographic } from './Infographic';
5+
import { getStoredValues, setStoredValues } from './utils/storage';
6+
7+
const STORAGE_KEY = 'playground-code';
8+
9+
const DEFAULT_CODE = `infographic list-row-horizontal-icon-arrow
10+
data
11+
title 信息图示例
12+
desc 粘贴或编辑左侧语法,右侧实时预览
13+
lists
14+
- label 项目一
15+
value 12.3
16+
desc 描述文字
17+
icon company-021_v1_lineal
18+
- label 项目二
19+
value 8.6
20+
desc 描述文字
21+
icon antenna-bars-5_v1_lineal
22+
- label 项目三
23+
value 15.1
24+
desc 描述文字
25+
icon achievment-050_v1_lineal
26+
`;
27+
28+
export const Playground = () => {
29+
const [code, setCode] = useState(DEFAULT_CODE);
30+
const [options, setOptions] = useState(DEFAULT_CODE);
31+
32+
// Hydrate from localStorage on mount
33+
useEffect(() => {
34+
const saved = getStoredValues<{ code: string }>(STORAGE_KEY);
35+
if (saved?.code) {
36+
setCode(saved.code);
37+
setOptions(saved.code);
38+
}
39+
}, []);
40+
41+
// Debounce: update preview 500ms after last edit, also persist
42+
useEffect(() => {
43+
const timer = setTimeout(() => {
44+
setOptions(code);
45+
setStoredValues(STORAGE_KEY, { code });
46+
}, 500);
47+
return () => clearTimeout(timer);
48+
}, [code]);
49+
50+
return (
51+
<div
52+
style={{
53+
display: 'flex',
54+
gap: 16,
55+
padding: 16,
56+
flex: 1,
57+
overflow: 'hidden',
58+
}}
59+
>
60+
<div style={{ width: 420, display: 'flex', flexDirection: 'column' }}>
61+
<Card title="语法输入" size="small" style={{ flex: 1 }}>
62+
<div style={{ height: 'calc(100vh - 160px)' }}>
63+
<Editor
64+
height="100%"
65+
defaultLanguage="plaintext"
66+
value={code}
67+
theme="vs-dark"
68+
options={{
69+
minimap: { enabled: false },
70+
fontSize: 13,
71+
lineNumbers: 'on',
72+
scrollBeyondLastLine: false,
73+
wordWrap: 'on',
74+
}}
75+
onChange={(value) => setCode(value || '')}
76+
/>
77+
</div>
78+
</Card>
79+
</div>
80+
81+
<div style={{ flex: 1, overflow: 'auto' }}>
82+
<Card title="预览" size="small" style={{ height: '100%' }}>
83+
<Infographic options={options} />
84+
</Card>
85+
</div>
86+
</div>
87+
);
88+
};

0 commit comments

Comments
 (0)