1
0
Fork 0

wip: Working on development environment

This commit is contained in:
Joost De Cock 2020-10-25 18:35:28 +01:00
parent 6dbc108d29
commit e4756087d8
10 changed files with 533 additions and 535 deletions

View file

@ -1,221 +1,113 @@
import React from "react"; import React from 'react'
import IconButton from '@material-ui/core/IconButton'
import IsolateIcon from '@material-ui/icons/Search'
import CameraIcon from '@material-ui/icons/CameraAlt'
const Design = props => { const Design = (props) => {
// Methods // Methods
const renderAttributes = attr => { const renderAttributes = (attr) => {
let list = []; let list = []
for (let a in attr.list) for (let a in attr.list)
list.push( list.push(
<li key={a}> <li key={a}>
<b>{a}</b>: {renderAttributeValue(attr.list[a])} <b>{a}</b>: {renderAttributeValue(attr.list[a])}
</li> </li>
); )
return <ul className="links">{list}</ul>; return <ul>{list}</ul>
}; }
const renderAttributeValue = val => { const renderAttributeValue = (val) => {
if (Array.isArray(val)) { if (Array.isArray(val)) {
if (val.length === 1) return val.pop(); if (val.length === 1) return val.pop()
let list = []; let list = []
for (let v of val) list.push(<li key={v}>{v}</li>); for (let v of val) list.push(<li key={v}>{v}</li>)
return <ul>{list}</ul>; return <ul>{list}</ul>
} }
return val; return val
}; }
const idPathPoint = (part, a) => { const idPathPoint = (part, a) => {
for (let p in props.parts[part].points) { for (let p in props.parts[part].points) {
let b = props.parts[part].points[p]; let b = props.parts[part].points[p]
if (a.x === b.x && a.y === b.y) return p; if (a.x === b.x && a.y === b.y) return p
} }
return false; return false
}; }
const renderPathOps = (path, part) => { if (!props.design || props.focus === null || Object.keys(props.focus).length < 1) return null
let list = []; let info = []
for (let i in path.ops) list.push(renderPathOp(path.ops[i], i, part));
return <ul className="links">{list}</ul>;
};
const renderPathOp = (op, key, part) => {
let list = [];
let focus = {
part,
coords: {
x: null,
y: null
}
};
if (op.type === "move" || op.type === "line") {
focus.coords.x = op.to.x;
focus.coords.y = op.to.y;
let text = <span>(op.to.x,op.to.y)</span>;
let click = () => props.raiseEvent("coords", focus);
let pname = idPathPoint(part, op.to);
if (pname) {
text = pname;
click = () =>
props.raiseEvent("point", {
point: props.parts[part].points[pname],
name: pname,
part: part
});
}
return (
<li key={key}>
<b>{op.type}</b>
&nbsp;&raquo;&nbsp;
<a href="#logo" role="button" onClick={click}>
{text}
</a>
</li>
);
} else if (op.type === "curve") {
let texts = {};
let clicks = {};
let types = ["to", "cp1", "cp2"];
for (let t of types) {
let pname = idPathPoint(part, op[t]);
if (pname) {
texts[t] = pname;
clicks[t] = () =>
props.raiseEvent("point", {
point: props.parts[part].points[pname],
name: pname,
part
});
} else {
texts[t] = (
<span>
({op[t].x},{op[t].y})
</span>
);
clicks[t] = () =>
props.raiseEvent("coords", {
...focus,
coords: {
x: op[t].x,
y: op[t].y
}
});
}
}
return (
<li key={key}>
<b>{op.type}</b>
{types.map(t => (
<React.Fragment key={t}>
<span>&ensp;&raquo;&ensp;</span>
<a href="#logo" role="button" onClick={clicks[t]}>
{texts[t]}
</a>
</React.Fragment>
))}
</li>
);
} else if (op.type === "close")
return (
<li key={key}>
<b>close</b>
</li>
);
return null;
};
// Variables
const styles = {
container: {
padding: "0 1rem"
},
h5: {
margin: "0.5rem 0"
},
h6: {
margin: "0.25rem 0 0 0.5rem"
},
ul: {
marginTop: "0.25rem"
}
};
if (
!props.design ||
props.focus === null ||
Object.keys(props.focus).length < 1
)
return null;
let info = [];
for (let part of Object.keys(props.focus)) { for (let part of Object.keys(props.focus)) {
info.push( let points = []
<h5 key={"part-" + part} style={styles.h5}> let paths = []
parts.<b>{part}</b>(
<a href="#logo" onClick={() => props.raiseEvent("part", part)}>
Isolate
</a>
)
</h5>
);
for (let i in props.focus[part].paths) { for (let i in props.focus[part].paths) {
let name = props.focus[part].paths[i]; let name = props.focus[part].paths[i]
let path = props.parts[part].paths[name]; let path = props.parts[part].paths[name]
info.push( paths.push(
<h6 <li key={'patitle-' + name} className={'path c' + (i % 4)}>
key={"patitle-" + name}
style={styles.h6}
className={"path c" + (i % 4)}
>
path.<b>{name}</b> path.<b>{name}</b>
</h6> <IconButton
); size="small"
info.push( onClick={() => console.log(`parts.${part}.paths.${name}:`, path)}
<ul className="links" key={"ops-" + name} style={styles.ul}> >
<li> <CameraIcon />
<b>attributes</b>: {renderAttributes(path.attributes)} </IconButton>
</li> {path.attributes.length > 0 && (
<li> <ul key={'ops-' + name}>
<b>ops</b>: {renderPathOps(path, part)} <li>
</li> <b>attributes</b>: {renderAttributes(path.attributes)}
</ul> </li>
); </ul>
)}
</li>
)
} }
for (let i in props.focus[part].points) { for (let i in props.focus[part].points) {
let name = props.focus[part].points[i]; let name = props.focus[part].points[i]
let point = props.parts[part].points[name]; let point = props.parts[part].points[name]
info.push( points.push(
<h6 <li key={'potitle-' + name} className={'point c' + (i % 4)}>
key={"potitle-" + name}
style={styles.h6}
className={"point c" + (i % 4)}
>
point.<b>{name}</b> point.<b>{name}</b>
</h6> <IconButton
); size="small"
info.push( onClick={() => console.log(`parts.${part}.points.${name}:`, point)}
<ul className="links" key={"pdata-" + name} style={styles.ul}> >
<li> <CameraIcon />
<b>x</b>: {point.x} </IconButton>
</li> <ul key={'pdata-' + name}>
<li> <li>
<b>y</b>: {point.y} <b>x</b>: {point.x}
</li> </li>
<li> <li>
<b>attributes</b>: {renderAttributes(point.attributes)} <b>y</b>: {point.y}
</li> </li>
</ul> {point.attributes.length > 0 && (
); <li>
<b>attributes</b>: {renderAttributes(point.attributes)}
</li>
)}
</ul>
</li>
)
} }
info.push(
<li key={'part-' + part}>
parts.<b>{part}</b>
<IconButton onClick={() => props.raiseEvent('part', part)}>
<IsolateIcon />
</IconButton>
{points.length > 0 && <ul>{points}</ul>}
{paths.length > 0 && <ul>{paths}</ul>}
</li>
)
} }
return ( return (
<div style={styles.container} className="design"> <div className="design">
{info} <ul>{info}</ul>
</div> </div>
); )
}; }
export default Design; export default Design

View file

@ -0,0 +1,72 @@
import React from 'react'
import DebugIcon from '@material-ui/icons/PlayCircleOutline'
import InfoIcon from '@material-ui/icons/Info'
import WarningIcon from '@material-ui/icons/ErrorOutline'
import ErrorIcon from '@material-ui/icons/HighlightOff'
import Markdown from 'react-markdown'
const Event = ({ type, event }) => {
const formatError = (err) => (
<details>
<summary>
<Markdown
source={`
\`\`\`js
${err.name}: ${err.message}
\`\`\`
`}
className="react-markdown dense"
/>
</summary>
<Markdown
source={`Error in \`${err.fileName}\` line \`${err.lineNumber}:${err.columnNumber}\``}
className="react-markdown"
/>
<Markdown
source={`
\`\`\`js
${err.stack}
\`\`\`
`}
className="react-markdown"
/>
</details>
)
const formatObject = (obj) => (
<Markdown
source={`
\`\`\`json
${JSON.stringify(obj, null, 2)}
\`\`\`
`}
className="react-markdown"
/>
)
const formatEvent = (e, data = false) => {
if (!data) data = []
if (typeof e === 'object') {
if (e instanceof Error === true) data.push(formatError(e))
else if (Array.isArray(e)) {
for (const subevent of e) data.concat(formatEvent(subevent, data))
} else data.push(formatObject(e))
} else data.push(<Markdown source={e} className="react-markdown" />)
return data
}
return (
<div className={`draft-event ${type}`}>
<div className={`icon ${type}`}>
{type === 'debug' && <DebugIcon fontSize="small" />}
{type === 'info' && <InfoIcon fontSize="small" />}
{type === 'warning' && <WarningIcon fontSize="small" />}
{type === 'error' && <ErrorIcon fontSize="small" />}
</div>
{formatEvent(event)}
</div>
)
}
export default Event

View file

@ -0,0 +1,16 @@
import React from 'react'
import Event from './event'
const DraftEvents = ({ events }) => (
<div className="draft-events">
{['error', 'warning', 'debug'].map((type) => (
<div className={`events-${type}`} key={type}>
{events[type].map((event, index) => (
<Event event={event} type={type} key={index} />
))}
</div>
))}
</div>
)
export default DraftEvents

View file

@ -0,0 +1,134 @@
import React, { useState } from 'react'
import Draft from '../../Draft'
import Zoombox from '../Zoombox'
import Design from '../Design'
import DraftConfigurator from '../../DraftConfigurator'
import fileSaver from 'file-saver'
import theme from '@freesewing/plugin-theme'
import IconButton from '@material-ui/core/IconButton'
import DesignIcon from '@material-ui/icons/Fingerprint'
import DumpIcon from '@material-ui/icons/LocalSee'
import ClearIcon from '@material-ui/icons/HighlightOff'
import AdvancedIcon from '@material-ui/icons/Policy'
import PaperlessIcon from '@material-ui/icons/Nature'
import CompleteIcon from '@material-ui/icons/Style'
import HideIcon from '@material-ui/icons/ChevronLeft'
import Events from './Events'
const DraftPattern = (props) => {
const styles = {
icon: {
margin: '0 0.25rem'
},
unhide: {
position: 'absolute',
top: '76px',
right: 0,
background: props.theme === 'dark' ? '#f8f9fa' : '#212529',
borderTopLeftRadius: '50%',
borderBottomLeftRadius: '50%',
width: '26px',
height: '30px'
}
}
let focusCount = 0
if (props.focus !== null) {
for (let p of Object.keys(props.focus)) {
for (let i in props.focus[p].points) focusCount++
for (let i in props.focus[p].paths) focusCount++
for (let i in props.focus[p].coords) focusCount++
}
}
let iconProps = {
size: 'small',
style: styles.icon,
color: 'inherit'
}
const color = (check) => (check ? '#40c057' : '#fa5252')
return (
<div>
<div style={{ margin: '1rem auto 0', textAlign: 'center' }}>
<IconButton onClick={() => props.setHideAside(true)} title="Hide sidebar" {...iconProps}>
<HideIcon />
</IconButton>
<IconButton
onClick={() => props.setDesign(!props.design)}
title="Toggle design mode"
{...iconProps}
>
<span style={{ color: color(props.design) }}>
<DesignIcon />
</span>
</IconButton>
{props.design && (
<IconButton
onClick={() => props.raiseEvent('clearFocusAll', null)}
title="Clear design mode"
{...iconProps}
>
<ClearIcon color="primary" />
</IconButton>
)}
<IconButton
onClick={() => console.log(props.pattern)}
title="console.log(pattern)"
{...iconProps}
>
<DumpIcon color="primary" />
</IconButton>
|
<IconButton
onClick={() => props.updateGist(!props.gist.settings.advanced, 'settings', 'advanced')}
title="Toggle advanced settings"
{...iconProps}
>
<span style={{ color: color(props.gist.settings.advanced) }}>
<AdvancedIcon />
</span>
</IconButton>
<IconButton
onClick={() => props.updateGist(!props.gist.settings.paperless, 'settings', 'paperless')}
title="Toggle paperless"
{...iconProps}
>
<span style={{ color: color(props.gist.settings.paperless) }}>
<PaperlessIcon />
</span>
</IconButton>
<IconButton
onClick={() => props.updateGist(!props.gist.settings.complete, 'settings', 'complete')}
title="Toggle complete"
{...iconProps}
>
<span style={{ color: color(props.gist.settings.complete) }}>
<CompleteIcon />
</span>
</IconButton>
</div>
{props.design && (
<Design
focus={props.focus}
design={props.design}
raiseEvent={props.raiseEvent}
parts={props.patternProps.parts}
/>
)}
<DraftConfigurator
noDocs
config={props.config}
data={props.gist}
updatePatternData={props.updateGist}
raiseEvent={props.raiseEvent}
freesewing={props.freesewing}
units={props.units || 'metric'}
/>
<div style={{ padding: '5px', marginTop: '1rem' }}>
<Zoombox patternProps={props.patternProps} setViewBox={props.setViewBox} />
</div>
</div>
)
}
export default DraftPattern

View file

@ -2,45 +2,11 @@ import React, { useState } from 'react'
import Draft from '../../Draft' import Draft from '../../Draft'
import Zoombox from '../Zoombox' import Zoombox from '../Zoombox'
import Design from '../Design' import Design from '../Design'
import DraftConfigurator from '../../DraftConfigurator'
import fileSaver from 'file-saver' import fileSaver from 'file-saver'
import theme from '@freesewing/plugin-theme' import theme from '@freesewing/plugin-theme'
import IconButton from '@material-ui/core/IconButton'
import DesignIcon from '@material-ui/icons/Fingerprint'
import DumpIcon from '@material-ui/icons/LocalSee'
import ClearIcon from '@material-ui/icons/HighlightOff'
import AdvancedIcon from '@material-ui/icons/Policy'
import PaperlessIcon from '@material-ui/icons/Nature'
import CompleteIcon from '@material-ui/icons/Style'
import UnhideIcon from '@material-ui/icons/ChevronLeft'
import HideIcon from '@material-ui/icons/ChevronRight'
import Events from './Events' import Events from './Events'
const DraftPattern = (props) => { const DraftPattern = (props) => {
const [design, setDesign] = useState(true)
const [focus, setFocus] = useState(null)
const [viewBox, setViewBox] = useState(false)
const [hideAside, setHideAside] = useState(false)
const raiseEvent = (type, data) => {
if (type === 'clearFocusAll') {
props.updateGist(false, 'settings', 'only')
return setFocus(null)
}
let f = {}
if (focus !== null) f = { ...focus }
if (typeof f[data.part] === 'undefined') f[data.part] = { paths: [], points: [], coords: [] }
if (type === 'point') f[data.part].points.push(data.name)
else if (type === 'path') f[data.part].paths.push(data.name)
else if (type === 'coords') f[data.part].coords.push(data.coords)
else if (type === 'clearFocus') {
let i = focus[data.part][data.type].indexOf(data.name)
f[data.part][data.type].splice(i, 1)
} else if (type === 'part') props.updateGist(data, 'settings', 'only')
setFocus(f)
}
const svgToFile = (svg) => { const svgToFile = (svg) => {
const blob = new Blob([svg], { const blob = new Blob([svg], {
type: 'image/svg+xml;charset=utf-8' type: 'image/svg+xml;charset=utf-8'
@ -61,35 +27,6 @@ const DraftPattern = (props) => {
props.setSvgExport(false) props.setSvgExport(false)
} }
const styles = {
paragraph: {
padding: '0 1rem'
},
aside: {
maxWidth: '350px',
background: 'transparent',
border: 0,
fontSize: '90%',
boxShadow: '0 0 1px #cccc',
display: hideAside ? 'none' : 'block'
},
icon: {
margin: '0 0.25rem'
},
unhide: {
position: 'absolute',
top: '76px',
right: 0,
background: props.theme === 'dark' ? '#f8f9fa' : '#212529',
borderTopLeftRadius: '50%',
borderBottomLeftRadius: '50%',
width: '26px',
height: '30px'
}
}
let pattern = new props.Pattern(props.gist.settings)
pattern.draft()
let patternProps = pattern.getRenderProps()
let focusCount = 0 let focusCount = 0
if (focus !== null) { if (focus !== null) {
for (let p of Object.keys(focus)) { for (let p of Object.keys(focus)) {
@ -99,130 +36,18 @@ const DraftPattern = (props) => {
} }
} }
let iconProps = {
size: 'small',
style: styles.icon,
color: 'inherit'
}
const color = (check) => (check ? '#40c057' : '#fa5252')
return ( return (
<div className="fs-sa"> <section>
<section> <Draft
<Draft {...props.patternProps}
{...patternProps} design={props.design}
design={design} focus={props.focus}
focus={focus} raiseEvent={props.raiseEvent}
raiseEvent={raiseEvent} viewBox={props.viewBox}
viewBox={viewBox} className="freesewing draft shadow"
className="freesewing draft shadow" />
/> <Events events={props.patternProps.events} />
<Events events={patternProps.events} /> </section>
{hideAside && (
<div style={styles.unhide}>
<IconButton
onClick={() => setHideAside(false)}
title="Show sidebar"
{...iconProps}
style={{ margin: 0 }}
>
<span style={{ color: props.theme === 'dark' ? '#212529' : '#f8f9fa' }}>
<UnhideIcon />
</span>
</IconButton>
</div>
)}
</section>
<aside style={styles.aside}>
<div className="sticky">
<div style={{ padding: '5px' }}>
<Zoombox patternProps={patternProps} setViewBox={setViewBox} />
</div>
<div style={{ margin: '1rem auto 0', textAlign: 'center' }}>
<IconButton
onClick={() => setDesign(!design)}
title="Toggle design mode"
{...iconProps}
>
<span style={{ color: color(design) }}>
<DesignIcon />
</span>
</IconButton>
{design && (
<IconButton
onClick={() => raiseEvent('clearFocusAll', null)}
title="Clear design mode"
{...iconProps}
>
<ClearIcon color="primary" />
</IconButton>
)}
<IconButton
onClick={() => console.log(pattern)}
title="console.log(pattern)"
{...iconProps}
>
<DumpIcon color="primary" />
</IconButton>
|
<IconButton
onClick={() =>
props.updateGist(!props.gist.settings.advanced, 'settings', 'advanced')
}
title="Toggle advanced settings"
{...iconProps}
>
<span style={{ color: color(props.gist.settings.advanced) }}>
<AdvancedIcon />
</span>
</IconButton>
<IconButton
onClick={() =>
props.updateGist(!props.gist.settings.paperless, 'settings', 'paperless')
}
title="Toggle paperless"
{...iconProps}
>
<span style={{ color: color(props.gist.settings.paperless) }}>
<PaperlessIcon />
</span>
</IconButton>
<IconButton
onClick={() =>
props.updateGist(!props.gist.settings.complete, 'settings', 'complete')
}
title="Toggle complete"
{...iconProps}
>
<span style={{ color: color(props.gist.settings.complete) }}>
<CompleteIcon />
</span>
</IconButton>
<IconButton onClick={() => setHideAside(true)} title="Hide sidebar" {...iconProps}>
<HideIcon />
</IconButton>
</div>
{design && (
<Design
focus={focus}
design={design}
raiseEvent={raiseEvent}
parts={patternProps.parts}
/>
)}
<DraftConfigurator
noDocs
config={props.config}
data={props.gist}
updatePatternData={props.updateGist}
raiseEvent={props.raiseEvent}
freesewing={props.freesewing}
units={props.units || 'metric'}
/>
</div>
</aside>
</div>
) )
} }

View file

@ -1,49 +0,0 @@
import React from "react";
import Button from "@material-ui/core/Button";
import { languages } from "@freesewing/i18n";
const LanguageChooser = props => {
const styles = {
container: {
display: "flex",
flexDirection: "row",
width: "100%"
},
chooser: {
width: "100%",
textAlign: "center",
alignSelf: "center"
},
button: {
margin: "1rem"
}
};
const changeLanguage = lang => {
props.setLanguage(lang);
props.setDisplay("pattern");
};
return (
<div style={styles.container}>
<div style={styles.chooser}>
{Object.keys(languages).map(lang => {
return (
<Button
style={styles.button}
key={lang}
color="primary"
size="large"
variant="contained"
onClick={() => changeLanguage(lang)}
>
{languages[lang]}
</Button>
);
})}
</div>
</div>
);
};
export default LanguageChooser;

View file

@ -8,12 +8,27 @@ import { dark, light } from '@freesewing/mui-theme'
import withLanguage from '../withLanguage' import withLanguage from '../withLanguage'
import LanguageIcon from '@material-ui/icons/Translate' import LanguageIcon from '@material-ui/icons/Translate'
import DarkModeIcon from '@material-ui/icons/Brightness3' import DarkModeIcon from '@material-ui/icons/Brightness3'
import LanguageChooser from './LanguageChooser'
import DraftPattern from './DraftPattern' import DraftPattern from './DraftPattern'
import DraftConfig from './DraftConfig'
import Json from './Json' import Json from './Json'
import SamplePattern from './SamplePattern' import SamplePattern from './SamplePattern'
import Welcome from './Welcome' import Welcome from './Welcome'
import Measurements from './Measurements' import Measurements from './Measurements'
import DraftIcon from '@material-ui/icons/Gesture'
import TestIcon from '@material-ui/icons/DoneAll'
import MeasurementsIcon from '@material-ui/icons/Height'
import ExportIcon from '@material-ui/icons/ScreenShare'
import { FormattedMessage } from 'react-intl'
import { languages } from '@freesewing/i18n'
import Button from '@material-ui/core/Button'
import UnhideIcon from '@material-ui/icons/ChevronRight'
const icons = {
draft: <DraftIcon />,
test: <TestIcon />,
measurements: <MeasurementsIcon />,
xport: <ExportIcon />
}
const Workbench = ({ const Workbench = ({
updateGist, updateGist,
@ -22,7 +37,6 @@ const Workbench = ({
language = 'en', language = 'en',
gist, gist,
importGist, importGist,
config,
freesewing, freesewing,
Pattern, Pattern,
units = 'metric', units = 'metric',
@ -34,6 +48,38 @@ const Workbench = ({
const [theme, setTheme] = useState('light') const [theme, setTheme] = useState('light')
const [measurements, setMeasurements] = useState(null) const [measurements, setMeasurements] = useState(null)
const [svgExport, setSvgExport] = useState(false) const [svgExport, setSvgExport] = useState(false)
const [viewBox, setViewBox] = useState(false)
const [hideAside, setHideAside] = useState(false)
const [design, setDesign] = useState(true)
const [focus, setFocus] = useState(null)
const raiseEvent = (type, data) => {
if (type === 'clearFocusAll') {
updateGist(false, 'settings', 'only')
return setFocus(null)
}
let f = {}
if (focus !== null) f = { ...focus }
if (typeof f[data.part] === 'undefined') f[data.part] = { paths: [], points: [], coords: [] }
if (type === 'point') f[data.part].points.push(data.name)
else if (type === 'path') f[data.part].paths.push(data.name)
else if (type === 'coords') f[data.part].coords.push(data.coords)
else if (type === 'clearFocus') {
let i = focus[data.part][data.type].indexOf(data.name)
f[data.part][data.type].splice(i, 1)
} else if (type === 'part') updateGist(data, 'settings', 'only')
setFocus(f)
}
// Get config from pattern object
const config = Pattern.config
const links = {
draft: <FormattedMessage id="cfp.draftThing" values={{ thing: config.name }} />,
test: <FormattedMessage id="cfp.testThing" values={{ thing: config.name }} />,
measurements: <FormattedMessage id="app.measurements" />,
xport: <FormattedMessage id="app.export" />
}
// Enable debug in Workbench // Enable debug in Workbench
defaultGist.settings.debug = true defaultGist.settings.debug = true
@ -42,19 +88,15 @@ const Workbench = ({
let m = getMeasurements() let m = getMeasurements()
setMeasurements(m) setMeasurements(m)
updateGist(m, 'settings', 'measurements') updateGist(m, 'settings', 'measurements')
setDisplay(getDisplay())
setLanguage(userLanguage) setLanguage(userLanguage)
if (translations) addTranslations(translations) if (translations) addTranslations(translations)
console.log('useEffect 1')
}, []) }, [])
useEffect(() => { useEffect(() => {
if (language !== gist.settings.locale) updateGist(language, 'settings', 'locale') if (language !== gist.settings.locale) updateGist(language, 'settings', 'locale')
console.log('useEffect 2')
}, [language]) }, [language])
const getDisplay = () => storage.get(config.name + '-display')
const saveDisplay = (d) => {
setDisplay(d)
storage.set(config.name + '-display', d)
}
const getMeasurements = () => storage.get(config.name + '-measurements') const getMeasurements = () => storage.get(config.name + '-measurements')
const saveMeasurements = (data) => { const saveMeasurements = (data) => {
storage.set(config.name + '-measurements', data) storage.set(config.name + '-measurements', data)
@ -88,33 +130,33 @@ const Workbench = ({
if (theme === 'light') setTheme('dark') if (theme === 'light') setTheme('dark')
else setTheme('light') else setTheme('light')
} }
const raiseEvent = (type = null, data = null) => {} //const raiseEvent = (type = null, data = null) => {}
const MainMenu = () => (
<ul className="aside-main-menu">
{Object.keys(icons).map((link) => {
return (
<li key={link}>
<a
href={`#test`}
onClick={() => setDisplay(link)}
className={link === display ? 'active' : ''}
>
{icons[link]}
<span className="text">{links[link]}</span>
</a>
</li>
)
})}
</ul>
)
const navs = { const navs = {
left: { left: {
draft: { discord: {
type: 'button', type: 'link',
onClick: () => saveDisplay('draft'), href: 'https://chat.freesewing.org/',
text: 'cfp.draftYourPattern', text: 'cfp.draftYourPattern'
active: display === 'draft' ? true : false
},
sample: {
type: 'button',
onClick: () => saveDisplay('sample'),
text: 'cfp.testYourPattern',
active: display === 'sample' ? true : false
},
measurements: {
type: 'button',
onClick: () => saveDisplay('measurements'),
text: 'app.measurements',
active: display === 'measurements' ? true : false
},
json: {
type: 'button',
onClick: () => saveDisplay('json'),
text: ['JSON'],
active: display === 'json' ? true : false
} }
}, },
right: { right: {
@ -125,7 +167,7 @@ const Workbench = ({
}, },
language: { language: {
type: 'button', type: 'button',
onClick: () => saveDisplay('languages'), onClick: () => setDisplay('languages'),
text: <LanguageIcon className="nav-icon" />, text: <LanguageIcon className="nav-icon" />,
title: 'Languages', title: 'Languages',
active: display === 'languages' ? true : false active: display === 'languages' ? true : false
@ -138,27 +180,71 @@ const Workbench = ({
} }
} }
} }
if (display === 'draft' && !measurementsMissing())
navs.left.svgExport = { const languageButtons = () => (
type: 'button', <p>
onClick: () => setSvgExport(true), {Object.keys(languages).map((lang) => {
text: 'app.export', return (
active: false <Button
key={lang}
color="primary"
size="large"
variant="outlined"
onClick={() => setLanguage(lang)}
style={{ margin: '0 0.5rem 0.5rem 0' }}
disabled={lang === language ? true : false}
>
{languages[lang]}
</Button>
)
})}
</p>
)
const styles = {
unhide: {
position: 'absolute',
left: 0,
top: 0
} }
// FIXME: }
navs.mleft = navs.left
navs.mright = navs.right
let main = null let main = null
let context = null
switch (display) { switch (display) {
case 'languages': case 'languages':
main = <LanguageChooser setLanguage={setLanguage} setDisplay={saveDisplay} /> main = (
<>
<h1>
<FormattedMessage id="account.languageTitle" />
</h1>
{languageButtons()}
</>
)
context = (
<ul>
{Object.keys(languages).map((lang) => {
return (
<li key={lang}>
<a href="#" onClick={() => setLanguage(lang)}>
{languages[lang]}
</a>
</li>
)
})}
</ul>
)
break break
case 'draft': case 'draft':
if (measurementsMissing()) saveDisplay('measurements') if (measurementsMissing()) setDisplay('measurements')
let pattern = new Pattern(gist.settings)
pattern.draft()
let patternProps = pattern.getRenderProps()
main = ( main = (
<DraftPattern <DraftPattern
freesewing={freesewing} freesewing={freesewing}
Pattern={Pattern} Pattern={Pattern}
patternProps={patternProps}
config={config} config={config}
gist={gist} gist={gist}
updateGist={updateGist} updateGist={updateGist}
@ -167,11 +253,37 @@ const Workbench = ({
svgExport={svgExport} svgExport={svgExport}
setSvgExport={setSvgExport} setSvgExport={setSvgExport}
theme={theme} theme={theme}
viewBox={viewBox}
focus={focus}
design={design}
/>
)
context = (
<DraftConfig
freesewing={freesewing}
Pattern={Pattern}
patternProps={patternProps}
config={config}
gist={gist}
updateGist={updateGist}
raiseEvent={raiseEvent}
units={units}
svgExport={svgExport}
setSvgExport={setSvgExport}
theme={theme}
viewBox={viewBox}
setViewBox={setViewBox}
setHideAside={setHideAside}
focus={focus}
setFocus={setFocus}
design={design}
setDesign={setDesign}
pattern={pattern}
/> />
) )
break break
case 'sample': case 'sample':
if (measurementsMissing()) saveDisplay('measurements') if (measurementsMissing()) setDisplay('measurements')
main = ( main = (
<SamplePattern <SamplePattern
freesewing={freesewing} freesewing={freesewing}
@ -199,23 +311,13 @@ const Workbench = ({
case 'json': case 'json':
main = <Json gist={gist} /> main = <Json gist={gist} />
break break
case 'inspect':
main = (
<InspectPattern
freesewing={freesewing}
Pattern={Pattern}
config={config}
gist={gist}
updateGist={updateGist}
raiseEvent={raiseEvent}
units={units}
svgExport={svgExport}
setSvgExport={setSvgExport}
/>
)
break
default: default:
main = <Welcome language={language} setDisplay={saveDisplay} /> main = (
<>
<Welcome language={language} setDisplay={setDisplay} />
<div style={{ margin: 'auto', textAlign: 'center' }}>{languageButtons()}</div>
</>
)
} }
const themes = { dark, light } const themes = { dark, light }
@ -227,8 +329,22 @@ const Workbench = ({
theme === 'light' ? 'workbench theme-wrapper light' : 'workbench theme-wrapper dark' theme === 'light' ? 'workbench theme-wrapper light' : 'workbench theme-wrapper dark'
} }
> >
{display !== 'welcome' ? <Navbar navs={navs} home={() => saveDisplay('welcome')} /> : null} <Navbar navs={navs} home={() => setDisplay('welcome')} />
{main} <div className="fs-sa" style={{ position: 'relative' }}>
{hideAside ? (
<a href="#" style={styles.unhide} onClick={() => setHideAside(false)}>
<UnhideIcon />
</a>
) : (
<aside>
<div className="sticky">
<MainMenu />
<div className="aside-context">{context}</div>
</div>
</aside>
)}
<section>{main}</section>
</div>
</div> </div>
</MuiThemeProvider> </MuiThemeProvider>
) )

View file

@ -1,8 +1,10 @@
ul.config { ul.config {
@include title-font; @include button-font;
padding: 0; padding: 0;
} }
ul.config.l1 { overflow-x: hidden;} ul.config.l1 {
overflow-x: hidden;
}
ul.config.l2, ul.config.l2,
ul.config.l3, ul.config.l3,
ul.config.l4 { ul.config.l4 {
@ -10,7 +12,9 @@ ul.config.l4 {
padding: 0; padding: 0;
} }
ul.config li { list-style-type: none; } ul.config li {
list-style-type: none;
}
/* level 1 */ /* level 1 */
ul.config.l1 > li > span { ul.config.l1 > li > span {
@ -65,15 +69,18 @@ div.expanded div.MuiSlider-container {
margin: 0; margin: 0;
overflow: initial; overflow: initial;
} }
ul.config p { @include body-font;} ul.config p {
@include body-font;
}
/* level 4 */ /* level 4 */
ul.config.l3 li span.subheading { ul.config.l3 li span.subheading {
padding-left: 2rem; padding-left: 2rem;
font-weight: bold; font-weight: bold;
} }
ul.config.l4 > li > div { padding-left: 2.5rem; } ul.config.l4 > li > div {
padding-left: 2.5rem;
}
span.dflt, span.dflt,
span.p-dflt, span.p-dflt,
@ -126,4 +133,3 @@ button.mini-icon-btn {
.theme-wrapper.dark button.mini-icon-btn.pattern:enabled { .theme-wrapper.dark button.mini-icon-btn.pattern:enabled {
color: $oc-green-6; color: $oc-green-6;
} }

View file

@ -101,17 +101,31 @@ div.design {
font-size: 115%; font-size: 115%;
margin: 1rem 0; margin: 1rem 0;
text-align: left; text-align: left;
h6.point.c0 { .path,
border-bottom: 1px solid $oc-red-6; .point {
border-left: 3px solid transparent;
padding-left: 5px;
margin-bottom: 3px;
font-size: 80%;
} }
h6.point.c1 { .path {
border-bottom: 1px solid $oc-green-6; border-left: 3px dashed transparent;
} }
h6.point.c2 { .path.c0,
border-bottom: 1px solid $oc-blue-6; .point.c0 {
border-color: $oc-red-6;
} }
h6.point.c3 { .path.c1,
border-bottom: 1px solid $oc-grape-6; .point.c1 {
border-color: $oc-green-6;
}
.path.c2,
.point.c2 {
border-color: $oc-blue-6;
}
.path.c3,
.point.c3 {
border-color: $oc-grape-6;
} }
} }
@ -132,21 +146,6 @@ div.design {
} }
} }
.theme-wrapper.light div.design {
h6.path.c0 {
background-color: rgba($oc-red-6, 0.3);
}
h6.path.c1 {
background-color: rgba($oc-green-6, 0.3);
}
h6.path.c2 {
background-color: rgba($oc-blue-6, 0.3);
}
h6.path.c3 {
background-color: rgba($oc-grape-6, 0.3);
}
}
.theme-wrapper.dark svg.freesewing.draft { .theme-wrapper.dark svg.freesewing.draft {
g.design.point { g.design.point {
circle { circle {
@ -166,18 +165,3 @@ div.design {
stroke-opacity: 0.5; stroke-opacity: 0.5;
} }
} }
.theme-wrapper.dark div.design {
h6.path.c0 {
background-color: rgba($oc-red-6, 0.5);
}
h6.path.c1 {
background-color: rgba($oc-green-6, 0.5);
}
h6.path.c2 {
background-color: rgba($oc-blue-6, 0.5);
}
h6.path.c3 {
background-color: rgba($oc-grape-6, 0.5);
}
}

View file

@ -11,6 +11,8 @@ devDocsAvailableAt: Developer documentation is available at
talkToUs: For questions, feedback or suggestions, come talk to us in our chat room talkToUs: For questions, feedback or suggestions, come talk to us in our chat room
draftYourPattern: Draft your pattern draftYourPattern: Draft your pattern
testYourPattern: Test your pattern testYourPattern: Test your pattern
draftThing: 'Draft {thing}'
testThing: 'Test {thing}'
renderInBrowser: Click below to render your pattern in the browser. renderInBrowser: Click below to render your pattern in the browser.
weWillReRender: When you make changes, we will re-render for you. weWillReRender: When you make changes, we will re-render for you.
youCan: You can youCan: You can