wip(lab): Work on workbench
- Moved the various tabs on the draft view to their own views. - Renames modes to views - Started to group various aspects of the workbench state under `_state` in the gist to prevent it from getting all mixed up with the core settings. - Updated events title to make it more clear not all events might be present - Removed valid state in measurements input since it was only getting updated on keyboard input but now when preloading measurements (which it does now)
This commit is contained in:
parent
bbb2b2c23f
commit
3653700572
12 changed files with 155 additions and 156 deletions
|
@ -121,7 +121,7 @@ const DefaultLayout = ({
|
||||||
sm:flex-row-reverse
|
sm:flex-row-reverse
|
||||||
${workbench && collapsePrimaryNav
|
${workbench && collapsePrimaryNav
|
||||||
? 'sm:px-0 sm:w-16'
|
? 'sm:px-0 sm:w-16'
|
||||||
: 'sm:px-1 md:px-4 lg:px-8 xl:px-16 2xl:px-32 sm:w-[38.2%]'
|
: 'sm:px-1 md:px-4 lg:px-8 sm:w-[38.2%]'
|
||||||
}
|
}
|
||||||
`}>
|
`}>
|
||||||
{workbench && (
|
{workbench && (
|
||||||
|
@ -144,7 +144,7 @@ const DefaultLayout = ({
|
||||||
sm:px-1 md:px-4 lg:px-8
|
sm:px-1 md:px-4 lg:px-8
|
||||||
${workbench && collapsePrimaryNav
|
${workbench && collapsePrimaryNav
|
||||||
? ''
|
? ''
|
||||||
: 'max-w-61.8% xl:px-16 2xl:px-32'
|
: 'max-w-61.8%'
|
||||||
}
|
}
|
||||||
`}>
|
`}>
|
||||||
<div className={workbench ? '' : "max-w-5xl"}>
|
<div className={workbench ? '' : "max-w-5xl"}>
|
||||||
|
@ -164,7 +164,7 @@ const DefaultLayout = ({
|
||||||
sm:flex-row
|
sm:flex-row
|
||||||
${workbench && collapseAltMenu
|
${workbench && collapseAltMenu
|
||||||
? 'sm:px-0 sm:w-16'
|
? 'sm:px-0 sm:w-16'
|
||||||
: 'sm:px-1 md:px-4 lg:px-8 xl:px-16 2xl:px-32 sm:w-[38.2%]'
|
: 'sm:px-1 md:px-4 lg:px-8 sm:w-[38.2%]'
|
||||||
}
|
}
|
||||||
`}>
|
`}>
|
||||||
<div className={`hidden sm:flex`}>
|
<div className={`hidden sm:flex`}>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import Robot from 'shared/components/robot/index.js'
|
import Robot from 'shared/components/robot/index.js'
|
||||||
import Events from './events.js'
|
import Events from '../events.js'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
|
||||||
const Error = props => {
|
const Error = props => {
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
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
|
|
|
@ -1,25 +1,12 @@
|
||||||
import React, { useState } from 'react'
|
|
||||||
import SvgWrapper from './svg-wrapper'
|
import SvgWrapper from './svg-wrapper'
|
||||||
import Error from './error.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'
|
import { capitalize } from 'shared/utils.js'
|
||||||
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch"
|
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch"
|
||||||
|
|
||||||
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 LabDraft = props => {
|
||||||
const { app, draft, pattern, gist, updateGist, unsetGist } = props
|
const { app, draft, pattern, gist, updateGist, unsetGist } = props
|
||||||
if (!draft) return null
|
if (!draft) return null
|
||||||
|
|
||||||
const [tab, setTab] = useState(props.pattern.config.name)
|
|
||||||
|
|
||||||
if (gist?.renderer === 'svg') {
|
if (gist?.renderer === 'svg') {
|
||||||
// Render as SVG
|
// Render as SVG
|
||||||
let svg
|
let svg
|
||||||
|
@ -41,24 +28,14 @@ const LabDraft = props => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="tabs my-8 mx-auto justify-center">
|
<SvgWrapper
|
||||||
{[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={draft.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 && <SvgWrapper
|
|
||||||
draft={draft}
|
draft={draft}
|
||||||
patternProps={patternProps}
|
patternProps={patternProps}
|
||||||
gist={gist}
|
gist={gist}
|
||||||
updateGist={updateGist}
|
updateGist={updateGist}
|
||||||
unsetGist={unsetGist}
|
unsetGist={unsetGist}
|
||||||
app={app}
|
app={app}
|
||||||
/>}
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
44
packages/freesewing.shared/components/workbench/events.js
Normal file
44
packages/freesewing.shared/components/workbench/events.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
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 ml-2">
|
||||||
|
<Markdown>{eventBlock(events)}</Markdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
|
||||||
|
const order = [
|
||||||
|
'error',
|
||||||
|
'warning',
|
||||||
|
'info',
|
||||||
|
'debug'
|
||||||
|
]
|
||||||
|
const Events = props => (
|
||||||
|
<div className="max-w-screen-xl m-auto">
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<ul className="flex flex-row row-wrap">
|
||||||
|
{order.map(type => (props.draft.events[type].length > 0)
|
||||||
|
? (
|
||||||
|
<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>
|
||||||
|
) : (
|
||||||
|
<li key={type} className="text-base-content font-bold capitalize text-xl">
|
||||||
|
<span className="opacity-50">{type}</span>
|
||||||
|
{type === 'debug' ? '' : <span className="px-2 font-bold">|</span>}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
{order.map(type => <EventGroup type={type} events={props.draft.events[type]} />)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Events
|
|
@ -13,15 +13,17 @@ const MeasurementInput = ({ m, gist, app, updateMeasurements }) => {
|
||||||
const { t } = useTranslation(['app', 'measurements'])
|
const { t } = useTranslation(['app', 'measurements'])
|
||||||
const prefix = (app.site === 'org') ? '' : 'https://freesewing.org'
|
const prefix = (app.site === 'org') ? '' : 'https://freesewing.org'
|
||||||
const title = t(`measurements:${m}`)
|
const title = t(`measurements:${m}`)
|
||||||
const isValid = input => {
|
|
||||||
if (input === '') return ''
|
const isValValid = val => (typeof val === 'undefined' || val === '')
|
||||||
return !isNaN(input)
|
? null
|
||||||
}
|
: !isNaN(val)
|
||||||
|
const isValid = (newVal) => (typeof newVal === 'undefined')
|
||||||
|
? isValValid(gist?.measurements?.[m])
|
||||||
|
: isValValid(newVal)
|
||||||
|
|
||||||
const update = evt => {
|
const update = evt => {
|
||||||
setVal(evt.target.value)
|
setVal(evt.target.value)
|
||||||
const ok = isValid(evt.target.value)
|
const ok = isValid(evt.target.value)
|
||||||
console.log({ok})
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
setValid(true)
|
setValid(true)
|
||||||
updateMeasurements(evt.target.value*10, m)
|
updateMeasurements(evt.target.value*10, m)
|
||||||
|
@ -29,10 +31,6 @@ const MeasurementInput = ({ m, gist, app, updateMeasurements }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const [val, setVal] = useState(gist?.measurements?.[m] || '')
|
const [val, setVal] = useState(gist?.measurements?.[m] || '')
|
||||||
const [valid, setValid] = useState(typeof gist?.measurements?.[m] === 'undefined'
|
|
||||||
? '' :
|
|
||||||
isValid(gist.measurements[m])
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (gist?.measurements?.[m]) setVal(gist.measurements[m]/10)
|
if (gist?.measurements?.[m]) setVal(gist.measurements[m]/10)
|
||||||
|
@ -40,6 +38,7 @@ const MeasurementInput = ({ m, gist, app, updateMeasurements }) => {
|
||||||
|
|
||||||
if (!m) return null
|
if (!m) return null
|
||||||
|
|
||||||
|
const valid = isValid()
|
||||||
return (
|
return (
|
||||||
<div className="form-control mb-2" key={`wrap-${m}`}>
|
<div className="form-control mb-2" key={`wrap-${m}`}>
|
||||||
<label className="label">
|
<label className="label">
|
||||||
|
@ -59,20 +58,19 @@ const MeasurementInput = ({ m, gist, app, updateMeasurements }) => {
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={title}
|
placeholder={title}
|
||||||
className={`
|
className={`
|
||||||
input input-lg input-bordered grow text-base-content
|
input input-lg input-bordered grow text-base-content border-r-0
|
||||||
${valid === false && 'input-error'}
|
${isValid() === false && 'input-error'}
|
||||||
${valid === true && 'input-success'}
|
${isValid() === true && 'input-success'}
|
||||||
border-r-0
|
|
||||||
`}
|
`}
|
||||||
value={val}
|
value={val}
|
||||||
onChange={update}
|
onChange={update}
|
||||||
/>
|
/>
|
||||||
<span role="img" className={`bg-transparent border-y
|
<span role="img" className={`bg-transparent border-y
|
||||||
${valid === false && 'border-error text-neutral-content'}
|
${isValid() === false && 'border-error text-neutral-content'}
|
||||||
${valid === true && 'border-success text-neutral-content'}
|
${isValid() === true && 'border-success text-neutral-content'}
|
||||||
${valid === '' && 'border-base-200 text-base-content'}
|
${isValid() === null && 'border-base-200 text-base-content'}
|
||||||
`}>
|
`}>
|
||||||
{valid === ''
|
{isValid() === null
|
||||||
? ''
|
? ''
|
||||||
: valid
|
: valid
|
||||||
? '👍'
|
? '👍'
|
||||||
|
@ -82,7 +80,7 @@ const MeasurementInput = ({ m, gist, app, updateMeasurements }) => {
|
||||||
<span className={`
|
<span className={`
|
||||||
${valid === false && 'bg-error text-neutral-content'}
|
${valid === false && 'bg-error text-neutral-content'}
|
||||||
${valid === true && 'bg-success text-neutral-content'}
|
${valid === true && 'bg-success text-neutral-content'}
|
||||||
${valid === '' && 'bg-base-200 text-base-content'}
|
${valid === null && 'bg-base-200 text-base-content'}
|
||||||
`}>
|
`}>
|
||||||
cm
|
cm
|
||||||
</span>
|
</span>
|
||||||
|
|
9
packages/freesewing.shared/components/workbench/json.js
Normal file
9
packages/freesewing.shared/components/workbench/json.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import Json from 'shared/components/json.js'
|
||||||
|
|
||||||
|
const GistAsJson = props => (
|
||||||
|
<div className="max-w-screen-xl m-auto">
|
||||||
|
<Json>{JSON.stringify(props.gist, null, 2)}</Json>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default GistAsJson
|
|
@ -44,19 +44,19 @@ const WorkbenchMeasurements = ({ app, pattern, gist, updateGist }) => {
|
||||||
const inputProps = { app, updateMeasurements, gist }
|
const inputProps = { app, updateMeasurements, gist }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="m-auto max-w-prose">
|
<div className="m-auto max-w-2xl">
|
||||||
<h1>
|
<h1>
|
||||||
<span className='capitalize mr-4 opacity-70'>
|
<span className='capitalize mr-4 opacity-70'>
|
||||||
{pattern.config.name}:
|
{pattern.config.name}:
|
||||||
</span>
|
</span>
|
||||||
{t('measurements')}
|
{t('measurements')}
|
||||||
</h1>
|
</h1>
|
||||||
<details open>
|
<details open className="my-2">
|
||||||
<summary><h2 className="inline-block">{t('cfp:preloadMeasurements')}</h2></summary>
|
<summary><h2 className="inline pl-1">{t('cfp:preloadMeasurements')}</h2></summary>
|
||||||
<div className="ml-2 pl-4 border-l-2">
|
<div className="ml-2 pl-4 border-l-2">
|
||||||
{Object.keys(groups).map(group => (
|
{Object.keys(groups).map(group => (
|
||||||
<details key={group}>
|
<details key={group}>
|
||||||
<summary><h3 className="inline-block">{t(group)}</h3></summary>
|
<summary><h3 className="inline pl-1">{t(group)}</h3></summary>
|
||||||
<div className="ml-2 pl-4 border-l-2">
|
<div className="ml-2 pl-4 border-l-2">
|
||||||
{Object.keys(icons).map(type => (
|
{Object.keys(icons).map(type => (
|
||||||
<React.Fragment key={type}>
|
<React.Fragment key={type}>
|
||||||
|
@ -86,8 +86,8 @@ const WorkbenchMeasurements = ({ app, pattern, gist, updateGist }) => {
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details className="my-2">
|
||||||
<summary><h2 className="inline-block">{t('cfp:enterMeasurements')}</h2></summary>
|
<summary><h2 className="inline pl-2">{t('cfp:enterMeasurements')}</h2></summary>
|
||||||
<div className="ml-2 pl-4 border-l-2">
|
<div className="ml-2 pl-4 border-l-2">
|
||||||
{pattern.config.measurements && (
|
{pattern.config.measurements && (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { linkClasses, Chevron } from 'shared/components/navigation/primary.js'
|
import { linkClasses, Chevron } from 'shared/components/navigation/primary.js'
|
||||||
import ModesMenu from './modes.js'
|
import ViewMenu from './view.js'
|
||||||
import DesignOptions from './design-options'
|
import DesignOptions from './design-options'
|
||||||
import CoreSettings from './core-settings'
|
import CoreSettings from './core-settings'
|
||||||
import Xray from './xray'
|
import Xray from './xray'
|
||||||
|
@ -84,8 +84,8 @@ export const SecText = props => props.raw
|
||||||
const WorkbenchMenu = props => {
|
const WorkbenchMenu = props => {
|
||||||
return (
|
return (
|
||||||
<nav className="smmax-w-96 grow mb-12">
|
<nav className="smmax-w-96 grow mb-12">
|
||||||
<ModesMenu {...props} />
|
<ViewMenu {...props} />
|
||||||
{props.mode === 'draft' && (
|
{props.gist?._state?.view === 'draft' && (
|
||||||
<>
|
<>
|
||||||
<DesignOptions {...props} />
|
<DesignOptions {...props} />
|
||||||
<CoreSettings {...props} />
|
<CoreSettings {...props} />
|
||||||
|
|
|
@ -3,28 +3,43 @@ import OptionsIcon from 'shared/components/icons/options.js'
|
||||||
import { linkClasses, Chevron } from 'shared/components/navigation/primary.js'
|
import { linkClasses, Chevron } from 'shared/components/navigation/primary.js'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
|
||||||
const Modes = props => {
|
const View = props => {
|
||||||
const { t } = useTranslation(['app'])
|
const { t } = useTranslation(['app'])
|
||||||
const entries = [
|
const entries = [
|
||||||
{
|
{
|
||||||
name: 'measurements',
|
name: 'measurements',
|
||||||
title: t('measurements'),
|
title: t('measurements'),
|
||||||
onClick: () => props.setMode('measurements')
|
onClick: () => props.updateGist(['_state', 'view'], 'measurements')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'draft',
|
name: 'draft',
|
||||||
title: t('draftPattern', { pattern: props.pattern.config.name }),
|
title: t('draftPattern', { pattern: props.pattern.config.name }),
|
||||||
onClick: () => props.setMode('draft')
|
onClick: () => props.updateGist(['_state', 'view'], 'draft')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'test',
|
name: 'test',
|
||||||
title: t('testPattern', { pattern: props.pattern.config.name }),
|
title: t('testPattern', { pattern: props.pattern.config.name }),
|
||||||
onClick: () => props.setMode('test')
|
onClick: () => props.updateGist(['_state', 'view'], 'test')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'export',
|
name: 'export',
|
||||||
title: t('export'),
|
title: t('export'),
|
||||||
onClick: () => props.setMode('export')
|
onClick: () => props.updateGist(['_state', 'view'], 'export')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'events',
|
||||||
|
title: t('events'),
|
||||||
|
onClick: () => props.updateGist(['_state', 'view'], 'events')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'yaml',
|
||||||
|
title: t('YAML'),
|
||||||
|
onClick: () => props.updateGist(['_state', 'view'], 'yaml')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'json',
|
||||||
|
title: t('JSON'),
|
||||||
|
onClick: () => props.updateGist(['_state', 'view'], 'json')
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -40,7 +55,7 @@ const Modes = props => {
|
||||||
`}>
|
`}>
|
||||||
<span className="text-secondary-focus mr-4"><MenuIcon /></span>
|
<span className="text-secondary-focus mr-4"><MenuIcon /></span>
|
||||||
<span className={`grow ${linkClasses} hover:cursor-resize`}>
|
<span className={`grow ${linkClasses} hover:cursor-resize`}>
|
||||||
{t('modes')}
|
{t('view')}
|
||||||
</span>
|
</span>
|
||||||
<Chevron />
|
<Chevron />
|
||||||
</summary>
|
</summary>
|
||||||
|
@ -55,21 +70,21 @@ const Modes = props => {
|
||||||
sm:hover:border-secondary-focus
|
sm:hover:border-secondary-focus
|
||||||
text-left
|
text-left
|
||||||
capitalize
|
capitalize
|
||||||
${entry.name === props.mode
|
${entry.name === props.gist?._state?.view
|
||||||
? 'text-secondary border-secondary sm:text-secondary-focus sm:border-secondary-focus'
|
? 'text-secondary border-secondary sm:text-secondary-focus sm:border-secondary-focus'
|
||||||
: 'text-base-content sm:text-neutral-content'
|
: 'text-base-content sm:text-neutral-content'
|
||||||
}
|
}
|
||||||
`} onClick={entry.onClick}>
|
`} onClick={entry.onClick}>
|
||||||
<span className={`
|
<span className={`
|
||||||
text-3xl mr-2 inline-block p-0 leading-3
|
text-3xl mr-2 inline-block p-0 leading-3
|
||||||
${entry.name === props.mode
|
${entry.name === props.gist?._state?.view
|
||||||
? 'text-secondary sm:text-secondary-focus translate-y-1'
|
? 'text-secondary sm:text-secondary-focus translate-y-1'
|
||||||
: 'translate-y-3'
|
: 'translate-y-3'
|
||||||
}
|
}
|
||||||
`}>
|
`}>
|
||||||
{entry.name === props.mode ? <>•</> : <>°</>}
|
{entry.name === props.gist?._state?.view ? <>•</> : <>°</>}
|
||||||
</span>
|
</span>
|
||||||
<span className={entry.name === props.mode ? 'font-bold' : ''}>
|
<span className={entry.name === props.gist?._state?.view ? 'font-bold' : ''}>
|
||||||
{ entry.title }
|
{ entry.title }
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -80,4 +95,4 @@ const Modes = props => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Modes
|
export default View
|
9
packages/freesewing.shared/components/workbench/yaml.js
Normal file
9
packages/freesewing.shared/components/workbench/yaml.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import Yaml from 'shared/components/yaml.js'
|
||||||
|
|
||||||
|
const GistAsYaml = props => (
|
||||||
|
<div className="max-w-screen-xl m-auto">
|
||||||
|
<Yaml json={JSON.stringify(props.gist, null, 2)} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default GistAsYaml
|
|
@ -2,14 +2,29 @@ import { useState, useEffect } from 'react'
|
||||||
import useLocalStorage from 'shared/hooks/useLocalStorage.js'
|
import useLocalStorage from 'shared/hooks/useLocalStorage.js'
|
||||||
import Layout from 'shared/components/layouts/default'
|
import Layout from 'shared/components/layouts/default'
|
||||||
import Menu from 'shared/components/workbench/menu/index.js'
|
import Menu from 'shared/components/workbench/menu/index.js'
|
||||||
import Measurements, { Input } from 'shared/components/workbench/measurements/index.js'
|
|
||||||
import LabDraft from 'shared/components/workbench/draft/index.js'
|
|
||||||
import set from 'lodash.set'
|
import set from 'lodash.set'
|
||||||
import unset from 'lodash.unset'
|
import unset from 'lodash.unset'
|
||||||
import defaultSettings from 'shared/components/workbench/default-settings.js'
|
import defaultSettings from 'shared/components/workbench/default-settings.js'
|
||||||
import DraftError from 'shared/components/workbench/draft/error.js'
|
import DraftError from 'shared/components/workbench/draft/error.js'
|
||||||
import theme from 'pkgs/plugin-theme/src/index.js'
|
import theme from 'pkgs/plugin-theme/src/index.js'
|
||||||
|
|
||||||
|
// Views
|
||||||
|
import Measurements, { Input } from 'shared/components/workbench/measurements/index.js'
|
||||||
|
import LabDraft from 'shared/components/workbench/draft/index.js'
|
||||||
|
import GistAsJson from 'shared/components/workbench/json.js'
|
||||||
|
import GistAsYaml from 'shared/components/workbench/yaml.js'
|
||||||
|
import DraftEvents from 'shared/components/workbench/events.js'
|
||||||
|
|
||||||
|
const views = {
|
||||||
|
measurements: Measurements,
|
||||||
|
draft: LabDraft,
|
||||||
|
test: () => <p>TODO</p>,
|
||||||
|
export: () => <p>TODO</p>,
|
||||||
|
events: DraftEvents,
|
||||||
|
yaml: GistAsYaml,
|
||||||
|
json: GistAsJson,
|
||||||
|
welcome: () => <p>TODO</p>,
|
||||||
|
}
|
||||||
|
|
||||||
// Generates a default pattern gist to start from
|
// Generates a default pattern gist to start from
|
||||||
const defaultGist = (pattern, locale='en') => {
|
const defaultGist = (pattern, locale='en') => {
|
||||||
|
@ -33,30 +48,24 @@ const hasRequiredMeasurements = (pattern, gist) => {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This component wraps the workbench and is in charge of
|
* This component wraps the workbench and is in charge of
|
||||||
* keeping the mode & gist state, which will trickly down
|
* keeping the gist state, which will trickly down
|
||||||
* to all workbench subcomponents
|
* to all workbench subcomponents
|
||||||
*
|
|
||||||
* mode: What to display (draft, sample, measurements, ...)
|
|
||||||
* gist: The runtime pattern configuration
|
|
||||||
*/
|
*/
|
||||||
const WorkbenchWrapper = ({ app, pattern }) => {
|
const WorkbenchWrapper = ({ app, pattern }) => {
|
||||||
|
|
||||||
// State for display mode and gist
|
// State for gist
|
||||||
const [mode, setMode] = useState('measurements')
|
const [gist, setGist] = useLocalStorage(`${pattern.config.name}_gist`, defaultGist(pattern, app.locale))
|
||||||
const [gist, setGist] = useLocalStorage('gist', defaultGist(pattern, app.locale))
|
|
||||||
|
|
||||||
// If we don't have the requiremed measurements,
|
// If we don't have the required measurements,
|
||||||
// force mode to measurements
|
// force view to measurements
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
mode !== 'measurements'
|
gist?._state?.view !== 'measurements'
|
||||||
&& !hasRequiredMeasurements(pattern, gist)
|
&& !hasRequiredMeasurements(pattern, gist)
|
||||||
) setMode('measurements')
|
) updateGist(['_state', 'view'], 'measurements')
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
// Helper methods to manage the gist state
|
||||||
* Update gist method. See lodash.set
|
|
||||||
*/
|
|
||||||
const updateGist = (path, content) => {
|
const updateGist = (path, content) => {
|
||||||
const newGist = {...gist}
|
const newGist = {...gist}
|
||||||
set(newGist, path, content)
|
set(newGist, path, content)
|
||||||
|
@ -68,10 +77,9 @@ const WorkbenchWrapper = ({ app, pattern }) => {
|
||||||
setGist(newGist)
|
setGist(newGist)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the draft here so we can pass it to both Menu
|
// Generate the draft here so we can pass it down
|
||||||
// and LabDraft
|
|
||||||
let draft = false
|
let draft = false
|
||||||
if (mode === 'draft') {
|
if (['draft', 'events'].indexOf(gist?._state?.view) !== -1) {
|
||||||
draft = new pattern(gist)
|
draft = new pattern(gist)
|
||||||
if (gist?.renderer === 'svg') draft.use(theme)
|
if (gist?.renderer === 'svg') draft.use(theme)
|
||||||
try { draft.draft() }
|
try { draft.draft() }
|
||||||
|
@ -81,48 +89,23 @@ const WorkbenchWrapper = ({ app, pattern }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Props to pass down
|
||||||
|
const componentProps = { app, pattern, gist, updateGist, unsetGist, setGist, draft }
|
||||||
// Required props for layout
|
// Required props for layout
|
||||||
const layoutProps = {
|
const layoutProps = {
|
||||||
app: app,
|
app: app,
|
||||||
noSearch: true,
|
noSearch: true,
|
||||||
workbench: true,
|
workbench: true,
|
||||||
AltMenu: <Menu
|
AltMenu: <Menu {...componentProps }/>
|
||||||
app={app}
|
|
||||||
pattern={pattern}
|
|
||||||
mode={mode}
|
|
||||||
setMode={setMode}
|
|
||||||
gist={gist}
|
|
||||||
updateGist={updateGist}
|
|
||||||
unsetGist={unsetGist}
|
|
||||||
setGist={setGist}
|
|
||||||
draft={draft}
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Component = views[gist?._state?.view]
|
||||||
|
? views[gist._state.view]
|
||||||
|
: views.welcome
|
||||||
|
|
||||||
|
return <Layout {...layoutProps}>
|
||||||
return (
|
<Component {...componentProps} />
|
||||||
<Layout {...layoutProps}>
|
</Layout>
|
||||||
{mode === 'measurements' && (
|
|
||||||
<Measurements
|
|
||||||
app={app}
|
|
||||||
pattern={pattern}
|
|
||||||
gist={gist}
|
|
||||||
updateGist={updateGist}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{mode === 'draft' && (
|
|
||||||
<LabDraft
|
|
||||||
app={app}
|
|
||||||
pattern={pattern}
|
|
||||||
draft={draft}
|
|
||||||
gist={gist}
|
|
||||||
updateGist={updateGist}
|
|
||||||
unsetGist={unsetGist}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default WorkbenchWrapper
|
export default WorkbenchWrapper
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue