import { CssProps, VNode, RefProps } from 'lupine.components'; import { DemoContainer } from './demo-container'; import { DemoStory } from './demo-types'; export type DemoPageProps = { story: DemoStory; }; export const DemoPage = (props: DemoPageProps) => { const { story } = props; let currentArgs = { ...story.args }; let currentMode: 'preview' | 'code' = 'preview'; let iframeWindow: any = null; const ref: RefProps = {}; const updatePreview = () => { if (iframeWindow && iframeWindow._lj_demo_hook) { iframeWindow._lj_demo_hook.updateArgs(currentArgs, currentMode === 'code'); } }; const onIframeLoad = (win: Window) => { iframeWindow = win; updatePreview(); }; const updateArg = (key: keyof T, value: any) => { currentArgs[key] = value; updatePreview(); }; const renderControl = (key: string, argType: any) => { const val = (currentArgs as any)[key]; const { control, options, description } = argType; let inputNode: VNode = Unknown control: {control}; if (control === 'text') { inputNode = ( updateArg(key as keyof T, (e.target as HTMLInputElement).value)} /> ); } else if (control === 'boolean') { inputNode = ( ); } else if (control === 'select' && options) { inputNode = ( ); } else if (control === 'number') { inputNode = ( updateArg(key as keyof T, Number((e.target as HTMLInputElement).value))} /> ); } else if (control === 'color') { inputNode = ( ); } else if (control === 'file') { inputNode = ( ); } return (
{key}
{inputNode} {description &&
{description}
}
); }; const renderControlBox = () => { if (!story.argTypes) { return
No argTypes defined for this story.
; } const controlCss: CssProps = { padding: '8px', '.&-header': { display: 'flex', alignItems: 'center', // justifyContent: 'space-between', margin: '0 0 16px 0', }, '.&-title': { margin: 0, fontSize: '16px', }, '.&-modes': { display: 'flex', gap: '4px', backgroundColor: '#f5f5f5', padding: '2px', borderRadius: '4px', marginLeft: '16px', }, '.&-mode-btn': { border: 'none', background: 'transparent', padding: '4px 12px', fontSize: '12px', fontWeight: 'bold', cursor: 'pointer', borderRadius: '2px', color: '#666', '&.active': { background: 'white', color: '#000', boxShadow: '0 1px 2px rgba(0,0,0,0.1)', }, }, '.&-ctl-check': { display: 'flex', alignItems: 'center', }, '.&-ctl-item': { display: 'flex', alignItems: 'center', marginBottom: '8px', }, '.&-ctl-label': { width: '120px', fontWeight: 'bold', fontSize: '14px', }, '.&-ctl-input': { flex: 1, maxWidth: '300px', padding: '4px 8px', border: '1px solid #ccc', borderRadius: '4px', }, '.&-ctl-desc': { marginLeft: '8px', fontSize: '12px', color: '#666', }, }; return (

Controls

{story.argTypes && Object.keys(story.argTypes).map((key) => { const argType = (story.argTypes as any)[key]; return renderControl(key, argType); })}
); }; const url = typeof location !== 'undefined' ? location.pathname + `/render?id=${story.id}` : `/demo/render?id=${story.id}`; return ; };