1
0
Fork 0

feat(lab): Draft view pretty ok now

This commit is contained in:
Joost De Cock 2022-01-28 16:57:07 +01:00
parent 73163f5676
commit 929822b249
15 changed files with 327 additions and 29 deletions

View file

@ -32,7 +32,7 @@
"react-copy-to-clipboard": "^5.0.4",
"react-hotkeys-hook": "^3.4.4",
"react-instantsearch-dom": "^6.18.0",
"react-markdown": "^7.1.1",
"react-markdown": "^8.0.0",
"react-swipeable": "^6.2.0",
"react-timeago": "^6.2.1",
"rehype-highlight": "^5.0.1",

View file

@ -0,0 +1,17 @@
import React from 'react'
import Highlight from 'shared/components/mdx/highlight.js'
import hljs from 'highlight.js/lib/common'
const Json = props => {
const code = props.js
? JSON.stringify(props.js, null, 2)
: props.children
return <Highlight
language='json'
raw={hljs.highlight(code, { language: 'json' }).value}
/>
}
export default Json

View file

@ -4,14 +4,23 @@ const names = {
js: 'javascript',
bash: 'bash',
sh: 'shell',
json: 'JSON',
yaml: 'YAML',
}
const Highlight = (props) => {
const language = props.children
const language = props.language
? props.language
: props.children
? props.children.props.className.split('-').pop()
: 'txt'
const preProps = {
className: `language-${language} hljs text-base lg:text-lg whitespace-pre-wrap break-words`
}
if (props.raw) preProps.dangerouslySetInnerHTML = { __html: props.raw }
return (
<div className="hljs my-4">
<div className={`
@ -24,7 +33,7 @@ const Highlight = (props) => {
<span>{names[language] ? names[language] : language}</span>
<CopyToClipboard content={props.children} />
</div>
<pre className={`language-${language} hljs text-base lg:text-lg whitespace-pre-wrap break-words`}>
<pre {...preProps}>
{props.children}
</pre>
</div>

View file

@ -0,0 +1,29 @@
import poses from './poses'
// pose is one of:
// fail,
// ohno,
// shrug,
// shrug2,
// yay
const Robot = ({
size = 124,
viewBox = '0 0 500 500',
className = '',
pose = 'yay',
color = false,
embed = false
}) => (
<svg
className={className || ''}
xmlns="http://www.w3.org/2000/svg"
width={embed ? '' : size || 124}
height={embed ? '' : size || 124}
viewBox={viewBox || '0 0 500 500'}
>
<path stroke="none" fill={color ? color : 'currentColor'} d={poses[pose]} />
</svg>
)
export default Robot

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,15 @@
import Robot from 'shared/components/robot/index.js'
import Events from './events.js'
const Error = props => (
<div className="mt-12">
<div className="flex flex-row items-center justify-around">
<h1>{props.app.t('errors.something')}</h1>
<div className="max-w-96"><Robot pose='fail' embed/></div>
</div>
<Events events={props.patternInstance.events} />
</div>
)
export default Error

View file

@ -0,0 +1,36 @@
import Markdown from 'react-markdown'
import { linkClasses } from 'shared/components/navigation/primary.js'
const eventBlock = events => events.join(" \n")
const EventGroup = ({ type='info', events=[] }) => events.length > 0 ? (
<div className="">
<h3 className="capitalize" id={`events-${type}`}>{type}</h3>
<div className="mdx">
<Markdown>{eventBlock(events)}</Markdown>
</div>
</div>
) : null
const order = [
'error',
'warning',
'info',
'debug'
]
const Events = props => (
<div className="flex flex-col">
<ul className="flex flex-row row-wrap">
{order.map(type => (
<li key={type} className="">
<a href={`#events-${type}`} className={`text-secondary font-bold capitalize text-xl`}>{type}</a>
{type === 'debug' ? '' : <span className="px-2 font-bold">|</span>}
</li>
))}
</ul>
{order.map(type => <EventGroup type={type} events={props.events[type]} />)}
</div>
)
export default Events

View file

@ -3,18 +3,67 @@ import Svg from './svg'
import Defs from './defs'
import Part from './part'
import theme from 'pkgs/plugin-theme/src/index.js'
import Robot from 'shared/components/robot/index.js'
import Error from './error.js'
import Events from './events.js'
import Json from 'shared/components/json.js'
import Yaml from 'shared/components/yaml.js'
import { capitalize } from 'shared/utils.js'
const LabDraft = ({ app, pattern, gist, updateGist }) => {
const tabClasses = active => `
tab tab-bordered font-bold text-4xl pb-12 capitalize
${active && 'text-base-content tab-active'}
`
const Wrap = props => <div className="max-w-screen-xl m-auto">{props.children}</div>
const LabDraft = props => {
const { app, pattern, gist, updateGist } = props
const [tab, setTab] = useState(props.pattern.config.name)
const patternInstance = new pattern(gist)
if (gist?.renderer === 'svg') return <div
dangerouslySetInnerHTML={{ __html: patternInstance.use(theme).draft().render()}} />
const eprops = { ...props, patternInstance }
if (gist?.renderer === 'svg') patternInstance.use(theme)
// Catch errors
try { patternInstance.draft() }
catch(error) {
console.log('Failed to draft pattern', error)
return <Error error={error} {...eprops} at={'draft'} />
}
const patternProps = patternInstance.draft().getRenderProps()
console.log(patternProps)
// Render as SVG
let svg
try { svg = patternInstance.render() }
catch(error) {
console.log('Failed to render pattern', error)
return <Error error={error} {...eprops} />
}
if (gist?.renderer === 'svg')
return <div dangerouslySetInnerHTML={{ __html: svg }} />
// Render as React
let patternProps = {}
try { patternProps = patternInstance.draft().getRenderProps() }
catch(error) {
console.log('Failed to get render props for pattern', error)
return <Error error={error} {...eprops} />
}
return (
<div>
<div className="tabs my-8 mx-auto justify-center">
{[props.pattern.config.name, 'events', 'yaml', 'json'].map(name => <button
key={name}
onClick={() => setTab(name)}
className={tabClasses(tab === name)}
>{name}</button>)}
</div>
{tab === 'events' && <Wrap><Events events={patternInstance.events} /></Wrap>}
{tab === 'json' && <Wrap><Json>{JSON.stringify(props.gist, null, 2)}</Json></Wrap>}
{tab === 'yaml' && <Wrap><Yaml json={JSON.stringify(props.gist, null, 2)} /></Wrap>}
{tab === props.pattern.config.name && (
<Svg {...patternProps}>
<Defs {...patternProps} />
<style>{`:root { --pattern-scale: ${gist.scale || 1}}`}</style>
@ -32,6 +81,8 @@ const LabDraft = ({ app, pattern, gist, updateGist }) => {
))}
</g>
</Svg>
)}
</div>
)
}

View file

@ -0,0 +1,64 @@
import ClearIcon from 'shared/components/icons/clear.js'
import orderBy from 'lodash.orderby'
const CoreSettingOnly = props => {
const list = props.pattern.config.draftOrder
const partNames = list.map(part => ({ id: part, name: props.app.t(`parts.${part}`, props.app.locale) }))
const togglePart = part => {
const parts = props.gist.only || []
const newParts = new Set(parts)
if (newParts.has(part)) newParts.delete(part)
else newParts.add(part)
if (newParts.size < 1) reset()
else props.updateGist(['only'], [...newParts])
}
const reset = () => {
props.unsetGist(['only'])
}
return (
<div className="py-4 mx-6 border-l-2 pl-2">
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
{props.app.t(`settings.only.description`)}
</p>
<div className="flex flex-row">
<div className="grow">
{orderBy(partNames, ['name'], ['asc']).map(part => (
<button
key={part.id}
onClick={() => togglePart(part.id)}
className={`
mr-1 mb-1 text-left text-lg w-full hover:text-secondary-focus px-2
${props.gist?.only && props.gist.only.indexOf(part.id) !== -1 && 'font-bold text-secondary'}
`}
>
<span className={`
text-3xl mr-2 inline-block p-0 leading-3
translate-y-3
`}>
<>&deg;</>
</span>
{part.name}
</button>
))}
</div>
</div>
<div className="flex flex-row-reverse">
<button
title={props.app.t('app.reset')}
className="btn btn-ghost btn-xs text-accent"
disabled={!props.gist.only || props.gist.only.length < 1}
onClick={reset}
>
<ClearIcon />
</button>
</div>
</div>
)
}
export default CoreSettingOnly

View file

@ -17,6 +17,7 @@ const settings = {
complete: {
dflt: false,
},
only: { },
locale: {
list: ['de', 'en', 'es', 'fr', 'nl'],
},
@ -35,6 +36,9 @@ const settings = {
svg: '@freesewing/core (SVG)'
}
},
debug: {
dflt: false,
},
}
const CoreSettings = props => {

View file

@ -2,6 +2,7 @@ import { linkClasses, Chevron } from 'shared/components/navigation/primary.js'
import PctDegOption from 'shared/components/workbench/inputs/design-option-pct-deg'
import CountOption from 'shared/components/workbench/inputs/design-option-count'
import ListSetting from './core-setting-list'
import OnlySetting from './core-setting-only'
import MmSetting from './core-setting-mm'
import BoolSetting from './core-setting-bool.js'
import SaBoolSetting from './core-setting-sa-bool.js'
@ -23,6 +24,13 @@ const settings = {
</span>
)
},
debug: props => {
return (
<span className="text-secondary">
{props.app.t(`app.${props.gist.debug ? 'yes' : 'no'}`)}
</span>
)
},
locale: props => {
return (
<span className="text-secondary">
@ -56,6 +64,9 @@ const settings = {
{props.config.titles[props.gist.renderer]}
</span>
),
only: props => (props.gist?.only && props.gist.only.lenght > 0)
? <span>{props.gist.only.length}</span>
: <span>fixme</span>
}
const inputs = {
@ -82,13 +93,14 @@ const inputs = {
title: props.config.titles[key]
}))}
/>,
only: props => <OnlySetting {...props} />
}
const Setting = props => {
if (props.setting === 'saBool')
return <SaBoolSetting {...props} {...props.config} />
if (['paperless', 'complete'].indexOf(props.setting) !== -1)
if (['paperless', 'complete', 'debug'].indexOf(props.setting) !== -1)
return <BoolSetting {...props} {...props.config} />
const Input = inputs[props.setting]

View file

@ -102,8 +102,6 @@ const WorkbenchWrapper = ({ app, pattern }) => {
updateGist={updateGist}
/>
)}
<pre>{JSON.stringify(mode, null, 2)}</pre>
<pre>{JSON.stringify(gist, null, 2)}</pre>
</Layout>
)
}

View file

@ -0,0 +1,19 @@
import React from 'react'
import Highlight from 'shared/components/mdx/highlight.js'
import hljs from 'highlight.js/lib/common'
import yaml from 'js-yaml'
const Yaml = props => {
let code
if (props.json) code = yaml.dump(JSON.parse(props.json))
else if (props.js) code = yaml.dump(props.js)
else code = props.children
return <Highlight
language='yaml'
raw={hljs.highlight(code, { language: 'yaml' }).value}
/>
}
export default Yaml

View file

@ -15,9 +15,10 @@
"dependencies": {
"@tailwindcss/typography": "^0.5.0",
"daisyui": "^1.16.2",
"highlight.js": "^11.4.0",
"lodash.orderby": "^4.6.0",
"lodash.unset": "^4.5.2",
"react-markdown": "^7.1.1",
"react-markdown": "^8.0.0",
"react-timeago": "^6.2.1",
"rehype-highlight": "^5.0.1",
"remark-extract-frontmatter": "^3.2.0",

View file

@ -14021,6 +14021,11 @@ highlight.js@^10.4.1:
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==
highlight.js@^11.4.0:
version "11.4.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.4.0.tgz#34ceadd49e1596ee5aba3d99346cdfd4845ee05a"
integrity sha512-nawlpCBCSASs7EdvZOYOYVkJpGmAOKMYZgZtUqSRqodZE0GRVcFKwo1RcpeOemqh9hyttTdd5wDBwHkuSyUfnA==
highlight.js@~11.3.0:
version "11.3.1"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.3.1.tgz#813078ef3aa519c61700f84fe9047231c5dc3291"
@ -22996,6 +23001,26 @@ react-markdown@^7.1.1:
unist-util-visit "^4.0.0"
vfile "^5.0.0"
react-markdown@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.0.tgz#3243296a59ddb0f451d262cc2e11123674b416c2"
integrity sha512-qbrWpLny6Ef2xHqnYqtot948LXP+4FtC+MWIuaN1kvSnowM+r1qEeEHpSaU0TDBOisQuj+Qe6eFY15cNL3gLAw==
dependencies:
"@types/hast" "^2.0.0"
"@types/unist" "^2.0.0"
comma-separated-tokens "^2.0.0"
hast-util-whitespace "^2.0.0"
prop-types "^15.0.0"
property-information "^6.0.0"
react-is "^17.0.0"
remark-parse "^10.0.0"
remark-rehype "^10.0.0"
space-separated-tokens "^2.0.0"
style-to-object "^0.3.0"
unified "^10.0.0"
unist-util-visit "^4.0.0"
vfile "^5.0.0"
react-moment-proptypes@^1.6.0, react-moment-proptypes@^1.7.0:
version "1.8.1"
resolved "https://registry.yarnpkg.com/react-moment-proptypes/-/react-moment-proptypes-1.8.1.tgz#7ba4076147f6b5998f0d4f51d302d6d8c62049fd"