import { Tab, Tabs } from './tabs.js' import Md from 'react-markdown' import { pluginBundle } from '@freesewing/plugin-bundle' import { pluginFlip } from '@freesewing/plugin-flip' import { pluginGore } from '@freesewing/plugin-gore' import { Design } from '@freesewing/core' import Svg from '../workbench/draft/svg' import Defs from '../workbench/draft/defs' import Stack from '../workbench/draft/stack' import { useGist } from 'shared/hooks/useGist' import yaml from 'js-yaml' // Get code from children export const asText = (reactEl) => { if (typeof reactEl.props.children === 'string') return reactEl.props.children if (Array.isArray(reactEl.props.children)) { return reactEl.props.children.map((el) => (typeof el === 'string' ? el : asText(el))).join('') } if (typeof reactEl.props.children === 'object') return asText(reactEl.props.children) return '' } // The actual example const Example = ({ app, draft, settings, xray = false }) => { // State for gist const { gist, unsetGist, updateGist } = useGist('example-mdx', app) if (xray) { gist._state.xray = { enabled: true } gist.margin = 20 } if (!draft.sample) return null const patternProps = settings.sample ? draft.sample().getRenderProps() : draft.draft().getRenderProps() if (draft.store.logs.error.length > 0 || draft.setStores[0].logs.error.length > 0) return ( <div className="max-w-full p-4"> <pre>{draft.store.logs.error.join('\n')}</pre> <pre>{draft.setStores[0].logs.error.join('\n')}</pre> </div> ) return ( <Svg {...patternProps} embed={true}> <Defs {...patternProps} /> <style>{`:root { --pattern-scale: 1} ${patternProps.svg.style}`}</style> <g> {Object.keys(patternProps.stacks).map((stackName) => ( <Stack {...{ app, gist, updateGist, unsetGist, patternProps }} showInfo={app.setPopup} key={stackName} stackName={stackName} stack={patternProps.stacks[stackName]} /> ))} </g> </Svg> ) } // Returns a FreeSewing draft based on code in children const buildExample = (children, settings = { margin: 5 }, tutorial = false, paperless = false) => { let code = asText(children) // FIXME: Refactor to not use eval let draft if (code.split('\n')[0].includes('function')) { code = '(' + code.split('(').slice(1).join('(') code = code.split(')') code = code[0] + ') => ' + code.slice(1).join(')') } try { draft = eval(code) } catch (err) { console.log(err, code) } const part = { draft: draft, measurements: tutorial ? [] : ['head'], options: tutorial ? { neckRatio: { pct: 80, min: 70, max: 90, menu: 'fit' }, widthRatio: { pct: 45, min: 35, max: 55, menu: 'style' }, lengthRatio: { pct: 75, min: 55, max: 85, menu: 'style' }, } : {}, plugins: [pluginBundle, pluginFlip, pluginGore], } const design = new Design({ parts: [part], data: tutorial ? { name: 'Tutorial', version: '0.0.1' } : {}, }) if (tutorial) settings.measurements = { head: 380 } if (paperless) settings.paperless = true return new design(settings) } // Wrapper component dealing with the tabs and code view const TabbedExample = ({ app, children, caption, tutorial, previewFirst, withHead, paperless, settings, }) => { if (settings) settings = { margin: 5, ...yaml.load(settings), } else settings = { margin: 5 } if (withHead) settings.measurements = { head: 300 } const draft = buildExample(children, settings, tutorial, paperless) if (tutorial && !previewFirst) return ( <div className="my-8"> <Tabs tabs="Code, Preview, X-Ray"> <Tab>{children}</Tab> <Tab> <Example {...{ draft, tutorial, paperless, settings, app }} /> </Tab> <Tab> <Example {...{ draft, tutorial, paperless, settings, app }} xray={true} /> </Tab> </Tabs> {caption && ( <div className="text-center italic -mt-4"> <Md>{caption}</Md> </div> )} </div> ) return ( <div className="my-8"> <Tabs tabs="Preview, Code, X-Ray"> <Tab> <Example {...{ draft, tutorial, paperless, settings, app }} /> </Tab> <Tab>{children}</Tab> <Tab> <Example {...{ draft, tutorial, paperless, settings, app }} xray={true} /> </Tab> </Tabs> {caption && ( <div className="text-center italic -mt-4"> <Md>{caption}</Md> </div> )} </div> ) } export default TabbedExample