Skip to content

Commit f2a230a

Browse files
committed
feat: decouple source and preview panels
Add a mode prop to ExamplePreview to allow rendering only the source code or only the preview, decoupling the previously tightly bound architecture.
1 parent 0903822 commit f2a230a

File tree

4 files changed

+337
-333
lines changed

4 files changed

+337
-333
lines changed

example/src/main.tsx

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ interface UrlState {
151151
tab?: PreviewTab;
152152
file?: string;
153153
example?: string;
154+
mode?: 'linked' | 'preview-only' | 'source-only';
154155
}
155156

156157
function readUrlState(): UrlState {
@@ -416,6 +417,7 @@ function buildJsxString({
416417
highlight,
417418
img,
418419
schema,
420+
mode,
419421
}: {
420422
example: string;
421423
defaultFile: string;
@@ -425,13 +427,14 @@ function buildJsxString({
425427
highlight: string;
426428
img: string;
427429
schema: string;
430+
mode: 'linked' | 'preview-only' | 'source-only';
428431
}): string {
429432
const props: string[] = [`example="${example}"`];
430-
if (defaultFile) props.push(`defaultFile="${defaultFile}"`);
431-
if (defaultTab !== 'web') props.push(`defaultTab="${defaultTab}"`);
432-
if (defaultEntryFile) props.push(`defaultEntryFile="${defaultEntryFile}"`);
433-
if (highlight) props.push(`highlight="${highlight}"`);
434-
if (entryFilter) {
433+
if (defaultFile && mode !== 'preview-only') props.push(`defaultFile="${defaultFile}"`);
434+
if (defaultTab !== 'web' && mode !== 'source-only') props.push(`defaultTab="${defaultTab}"`);
435+
if (defaultEntryFile && mode !== 'source-only') props.push(`defaultEntryFile="${defaultEntryFile}"`);
436+
if (highlight && mode !== 'preview-only') props.push(`highlight="${highlight}"`);
437+
if (entryFilter && mode !== 'source-only') {
435438
if (entryFilter.includes(',')) {
436439
props.push(
437440
`entry={${JSON.stringify(entryFilter.split(',').map((s) => s.trim()))}}`,
@@ -440,8 +443,9 @@ function buildJsxString({
440443
props.push(`entry="${entryFilter}"`);
441444
}
442445
}
443-
if (schema) props.push(`schema="${schema}"`);
444-
if (img) props.push(`img="${img}"`);
446+
if (schema && mode !== 'source-only') props.push(`schema="${schema}"`);
447+
if (img && mode !== 'source-only') props.push(`img="${img}"`);
448+
if (mode !== 'linked') props.push(`mode="${mode}"`);
445449

446450
if (props.length <= 2) {
447451
return `<Go ${props.join(' ')} />`;
@@ -515,6 +519,9 @@ function App() {
515519
const [defaultFile, setDefaultFile] = useState(
516520
initial.file ?? ((initial.example ?? 'hello-world').startsWith('vue-') ? 'src/App.vue' : 'src/App.tsx'),
517521
);
522+
const [mode, setMode] = useState<'linked' | 'preview-only' | 'source-only'>(
523+
initial.mode ?? 'linked'
524+
);
518525
const [copied, setCopied] = useState(false);
519526
const [exampleSearch, setExampleSearch] = useState('');
520527
const [entrySearch, setEntrySearch] = useState('');
@@ -558,6 +565,7 @@ function App() {
558565
highlight,
559566
img,
560567
schema,
568+
mode,
561569
}),
562570
[
563571
example,
@@ -568,6 +576,7 @@ function App() {
568576
highlight,
569577
img,
570578
schema,
579+
mode,
571580
],
572581
);
573582

@@ -600,8 +609,8 @@ function App() {
600609

601610
// Persist state to URL hash
602611
useEffect(() => {
603-
writeUrlState({ dark, lang, tab: defaultTab, file: defaultFile, example });
604-
}, [dark, lang, defaultTab, defaultFile, example]);
612+
writeUrlState({ dark, lang, tab: defaultTab, file: defaultFile, example, mode: mode === 'linked' ? undefined : mode });
613+
}, [dark, lang, defaultTab, defaultFile, example, mode]);
605614

606615
// Apply Semi UI dark/light mode
607616
useEffect(() => {
@@ -802,6 +811,18 @@ function App() {
802811
/>
803812
</ControlGroup>
804813

814+
<ControlGroup label="Mode">
815+
<AdaptiveControl
816+
value={mode}
817+
options={[
818+
{ value: 'linked', label: 'Linked' },
819+
{ value: 'preview-only', label: 'Preview Only' },
820+
{ value: 'source-only', label: 'Source Only' },
821+
]}
822+
onChange={(v) => setMode(v as 'linked' | 'preview-only' | 'source-only')}
823+
/>
824+
</ControlGroup>
825+
805826
{/* JSX button */}
806827
<button
807828
className="toolbar-btn"
@@ -1193,7 +1214,7 @@ function App() {
11931214
{/* Desktop */}
11941215
<div style={{ flex: '1 1 500px', minWidth: 0 }}>
11951216
<Go
1196-
key={`desktop-${example}-${selectedEntry}-${defaultTab}`}
1217+
key={`desktop-${example}-${selectedEntry}-${defaultTab}-${mode}`}
11971218
example={example}
11981219
defaultFile={defaultFile}
11991220
defaultTab={defaultTab}
@@ -1202,6 +1223,7 @@ function App() {
12021223
highlight={highlight || undefined}
12031224
img={img || undefined}
12041225
schema={schema || undefined}
1226+
mode={mode}
12051227
/>
12061228
<div className="figure-caption">Desktop</div>
12071229
</div>
@@ -1223,7 +1245,7 @@ function App() {
12231245
}}
12241246
>
12251247
<Go
1226-
key={`mobile-${example}-${selectedEntry}-${defaultTab}`}
1248+
key={`mobile-${example}-${selectedEntry}-${defaultTab}-${mode}`}
12271249
example={example}
12281250
defaultFile={defaultFile}
12291251
defaultTab={defaultTab}
@@ -1232,6 +1254,7 @@ function App() {
12321254
highlight={highlight || undefined}
12331255
img={img || undefined}
12341256
schema={schema || undefined}
1257+
mode={mode}
12351258
/>
12361259
</div>
12371260
<div className="figure-caption">Mobile (320 × 660)</div>

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,6 @@
5757
"react-copy-to-clipboard": "^5.1.0",
5858
"swr": "^2.2.5",
5959
"vscode-icons-js": "^11.6.1"
60-
}
60+
},
61+
"packageManager": "pnpm@9.15.2+sha512.93e57b0126f0df74ce6bff29680394c0ba54ec47246b9cf321f0121d8d9bb03f750a705f24edc3c1180853afd7c2c3b94196d0a3d53d3e069d9e2793ef11f321"
6162
}

0 commit comments

Comments
 (0)