wip: Working on development environment
This commit is contained in:
parent
6dbc108d29
commit
e4756087d8
10 changed files with 533 additions and 535 deletions
|
@ -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
|
||||
const renderAttributes = attr => {
|
||||
let list = [];
|
||||
const renderAttributes = (attr) => {
|
||||
let list = []
|
||||
for (let a in attr.list)
|
||||
list.push(
|
||||
<li key={a}>
|
||||
<b>{a}</b>: {renderAttributeValue(attr.list[a])}
|
||||
</li>
|
||||
);
|
||||
)
|
||||
|
||||
return <ul className="links">{list}</ul>;
|
||||
};
|
||||
return <ul>{list}</ul>
|
||||
}
|
||||
|
||||
const renderAttributeValue = val => {
|
||||
const renderAttributeValue = (val) => {
|
||||
if (Array.isArray(val)) {
|
||||
if (val.length === 1) return val.pop();
|
||||
let list = [];
|
||||
for (let v of val) list.push(<li key={v}>{v}</li>);
|
||||
return <ul>{list}</ul>;
|
||||
if (val.length === 1) return val.pop()
|
||||
let list = []
|
||||
for (let v of val) list.push(<li key={v}>{v}</li>)
|
||||
return <ul>{list}</ul>
|
||||
}
|
||||
|
||||
return val;
|
||||
};
|
||||
return val
|
||||
}
|
||||
|
||||
const idPathPoint = (part, a) => {
|
||||
for (let p in props.parts[part].points) {
|
||||
let b = props.parts[part].points[p];
|
||||
if (a.x === b.x && a.y === b.y) return p;
|
||||
let b = props.parts[part].points[p]
|
||||
if (a.x === b.x && a.y === b.y) return p
|
||||
}
|
||||
return false;
|
||||
};
|
||||
return false
|
||||
}
|
||||
|
||||
const renderPathOps = (path, part) => {
|
||||
let list = [];
|
||||
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>
|
||||
»
|
||||
<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> » </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 = [];
|
||||
if (!props.design || props.focus === null || Object.keys(props.focus).length < 1) return null
|
||||
let info = []
|
||||
for (let part of Object.keys(props.focus)) {
|
||||
info.push(
|
||||
<h5 key={"part-" + part} style={styles.h5}>
|
||||
parts.<b>{part}</b>(
|
||||
<a href="#logo" onClick={() => props.raiseEvent("part", part)}>
|
||||
Isolate
|
||||
</a>
|
||||
)
|
||||
</h5>
|
||||
);
|
||||
let points = []
|
||||
let paths = []
|
||||
for (let i in props.focus[part].paths) {
|
||||
let name = props.focus[part].paths[i];
|
||||
let path = props.parts[part].paths[name];
|
||||
info.push(
|
||||
<h6
|
||||
key={"patitle-" + name}
|
||||
style={styles.h6}
|
||||
className={"path c" + (i % 4)}
|
||||
>
|
||||
let name = props.focus[part].paths[i]
|
||||
let path = props.parts[part].paths[name]
|
||||
paths.push(
|
||||
<li key={'patitle-' + name} className={'path c' + (i % 4)}>
|
||||
path.<b>{name}</b>
|
||||
</h6>
|
||||
);
|
||||
info.push(
|
||||
<ul className="links" key={"ops-" + name} style={styles.ul}>
|
||||
<li>
|
||||
<b>attributes</b>: {renderAttributes(path.attributes)}
|
||||
</li>
|
||||
<li>
|
||||
<b>ops</b>: {renderPathOps(path, part)}
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => console.log(`parts.${part}.paths.${name}:`, path)}
|
||||
>
|
||||
<CameraIcon />
|
||||
</IconButton>
|
||||
{path.attributes.length > 0 && (
|
||||
<ul key={'ops-' + name}>
|
||||
<li>
|
||||
<b>attributes</b>: {renderAttributes(path.attributes)}
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
for (let i in props.focus[part].points) {
|
||||
let name = props.focus[part].points[i];
|
||||
let point = props.parts[part].points[name];
|
||||
info.push(
|
||||
<h6
|
||||
key={"potitle-" + name}
|
||||
style={styles.h6}
|
||||
className={"point c" + (i % 4)}
|
||||
>
|
||||
let name = props.focus[part].points[i]
|
||||
let point = props.parts[part].points[name]
|
||||
points.push(
|
||||
<li key={'potitle-' + name} className={'point c' + (i % 4)}>
|
||||
point.<b>{name}</b>
|
||||
</h6>
|
||||
);
|
||||
info.push(
|
||||
<ul className="links" key={"pdata-" + name} style={styles.ul}>
|
||||
<li>
|
||||
<b>x</b>: {point.x}
|
||||
</li>
|
||||
<li>
|
||||
<b>y</b>: {point.y}
|
||||
</li>
|
||||
<li>
|
||||
<b>attributes</b>: {renderAttributes(point.attributes)}
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => console.log(`parts.${part}.points.${name}:`, point)}
|
||||
>
|
||||
<CameraIcon />
|
||||
</IconButton>
|
||||
<ul key={'pdata-' + name}>
|
||||
<li>
|
||||
<b>x</b>: {point.x}
|
||||
</li>
|
||||
<li>
|
||||
<b>y</b>: {point.y}
|
||||
</li>
|
||||
{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 (
|
||||
<div style={styles.container} className="design">
|
||||
{info}
|
||||
<div className="design">
|
||||
<ul>{info}</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Design;
|
||||
export default Design
|
||||
|
|
|
@ -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
|
|
@ -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
|
134
packages/components/src/Workbench/DraftConfig/index.js
Normal file
134
packages/components/src/Workbench/DraftConfig/index.js
Normal 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
|
|
@ -2,45 +2,11 @@ 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 UnhideIcon from '@material-ui/icons/ChevronLeft'
|
||||
import HideIcon from '@material-ui/icons/ChevronRight'
|
||||
import Events from './Events'
|
||||
|
||||
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 blob = new Blob([svg], {
|
||||
type: 'image/svg+xml;charset=utf-8'
|
||||
|
@ -61,35 +27,6 @@ const DraftPattern = (props) => {
|
|||
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
|
||||
if (focus !== null) {
|
||||
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 (
|
||||
<div className="fs-sa">
|
||||
<section>
|
||||
<Draft
|
||||
{...patternProps}
|
||||
design={design}
|
||||
focus={focus}
|
||||
raiseEvent={raiseEvent}
|
||||
viewBox={viewBox}
|
||||
className="freesewing draft shadow"
|
||||
/>
|
||||
<Events events={patternProps.events} />
|
||||
{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>
|
||||
<section>
|
||||
<Draft
|
||||
{...props.patternProps}
|
||||
design={props.design}
|
||||
focus={props.focus}
|
||||
raiseEvent={props.raiseEvent}
|
||||
viewBox={props.viewBox}
|
||||
className="freesewing draft shadow"
|
||||
/>
|
||||
<Events events={props.patternProps.events} />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -8,12 +8,27 @@ import { dark, light } from '@freesewing/mui-theme'
|
|||
import withLanguage from '../withLanguage'
|
||||
import LanguageIcon from '@material-ui/icons/Translate'
|
||||
import DarkModeIcon from '@material-ui/icons/Brightness3'
|
||||
import LanguageChooser from './LanguageChooser'
|
||||
import DraftPattern from './DraftPattern'
|
||||
import DraftConfig from './DraftConfig'
|
||||
import Json from './Json'
|
||||
import SamplePattern from './SamplePattern'
|
||||
import Welcome from './Welcome'
|
||||
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 = ({
|
||||
updateGist,
|
||||
|
@ -22,7 +37,6 @@ const Workbench = ({
|
|||
language = 'en',
|
||||
gist,
|
||||
importGist,
|
||||
config,
|
||||
freesewing,
|
||||
Pattern,
|
||||
units = 'metric',
|
||||
|
@ -34,6 +48,38 @@ const Workbench = ({
|
|||
const [theme, setTheme] = useState('light')
|
||||
const [measurements, setMeasurements] = useState(null)
|
||||
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
|
||||
defaultGist.settings.debug = true
|
||||
|
@ -42,19 +88,15 @@ const Workbench = ({
|
|||
let m = getMeasurements()
|
||||
setMeasurements(m)
|
||||
updateGist(m, 'settings', 'measurements')
|
||||
setDisplay(getDisplay())
|
||||
setLanguage(userLanguage)
|
||||
if (translations) addTranslations(translations)
|
||||
console.log('useEffect 1')
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
if (language !== gist.settings.locale) updateGist(language, 'settings', 'locale')
|
||||
console.log('useEffect 2')
|
||||
}, [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 saveMeasurements = (data) => {
|
||||
storage.set(config.name + '-measurements', data)
|
||||
|
@ -88,33 +130,33 @@ const Workbench = ({
|
|||
if (theme === 'light') setTheme('dark')
|
||||
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 = {
|
||||
left: {
|
||||
draft: {
|
||||
type: 'button',
|
||||
onClick: () => saveDisplay('draft'),
|
||||
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
|
||||
discord: {
|
||||
type: 'link',
|
||||
href: 'https://chat.freesewing.org/',
|
||||
text: 'cfp.draftYourPattern'
|
||||
}
|
||||
},
|
||||
right: {
|
||||
|
@ -125,7 +167,7 @@ const Workbench = ({
|
|||
},
|
||||
language: {
|
||||
type: 'button',
|
||||
onClick: () => saveDisplay('languages'),
|
||||
onClick: () => setDisplay('languages'),
|
||||
text: <LanguageIcon className="nav-icon" />,
|
||||
title: 'Languages',
|
||||
active: display === 'languages' ? true : false
|
||||
|
@ -138,27 +180,71 @@ const Workbench = ({
|
|||
}
|
||||
}
|
||||
}
|
||||
if (display === 'draft' && !measurementsMissing())
|
||||
navs.left.svgExport = {
|
||||
type: 'button',
|
||||
onClick: () => setSvgExport(true),
|
||||
text: 'app.export',
|
||||
active: false
|
||||
|
||||
const languageButtons = () => (
|
||||
<p>
|
||||
{Object.keys(languages).map((lang) => {
|
||||
return (
|
||||
<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 context = null
|
||||
switch (display) {
|
||||
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
|
||||
case 'draft':
|
||||
if (measurementsMissing()) saveDisplay('measurements')
|
||||
if (measurementsMissing()) setDisplay('measurements')
|
||||
let pattern = new Pattern(gist.settings)
|
||||
pattern.draft()
|
||||
let patternProps = pattern.getRenderProps()
|
||||
main = (
|
||||
<DraftPattern
|
||||
freesewing={freesewing}
|
||||
Pattern={Pattern}
|
||||
patternProps={patternProps}
|
||||
config={config}
|
||||
gist={gist}
|
||||
updateGist={updateGist}
|
||||
|
@ -167,11 +253,37 @@ const Workbench = ({
|
|||
svgExport={svgExport}
|
||||
setSvgExport={setSvgExport}
|
||||
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
|
||||
case 'sample':
|
||||
if (measurementsMissing()) saveDisplay('measurements')
|
||||
if (measurementsMissing()) setDisplay('measurements')
|
||||
main = (
|
||||
<SamplePattern
|
||||
freesewing={freesewing}
|
||||
|
@ -199,23 +311,13 @@ const Workbench = ({
|
|||
case 'json':
|
||||
main = <Json gist={gist} />
|
||||
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:
|
||||
main = <Welcome language={language} setDisplay={saveDisplay} />
|
||||
main = (
|
||||
<>
|
||||
<Welcome language={language} setDisplay={setDisplay} />
|
||||
<div style={{ margin: 'auto', textAlign: 'center' }}>{languageButtons()}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const themes = { dark, light }
|
||||
|
@ -227,8 +329,22 @@ const Workbench = ({
|
|||
theme === 'light' ? 'workbench theme-wrapper light' : 'workbench theme-wrapper dark'
|
||||
}
|
||||
>
|
||||
{display !== 'welcome' ? <Navbar navs={navs} home={() => saveDisplay('welcome')} /> : null}
|
||||
{main}
|
||||
<Navbar navs={navs} home={() => setDisplay('welcome')} />
|
||||
<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>
|
||||
</MuiThemeProvider>
|
||||
)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
ul.config {
|
||||
@include title-font;
|
||||
@include button-font;
|
||||
padding: 0;
|
||||
}
|
||||
ul.config.l1 { overflow-x: hidden;}
|
||||
ul.config.l1 {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
ul.config.l2,
|
||||
ul.config.l3,
|
||||
ul.config.l4 {
|
||||
|
@ -10,7 +12,9 @@ ul.config.l4 {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
ul.config li { list-style-type: none; }
|
||||
ul.config li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
/* level 1 */
|
||||
ul.config.l1 > li > span {
|
||||
|
@ -65,15 +69,18 @@ div.expanded div.MuiSlider-container {
|
|||
margin: 0;
|
||||
overflow: initial;
|
||||
}
|
||||
ul.config p { @include body-font;}
|
||||
ul.config p {
|
||||
@include body-font;
|
||||
}
|
||||
|
||||
/* level 4 */
|
||||
ul.config.l3 li span.subheading {
|
||||
padding-left: 2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
ul.config.l4 > li > div { padding-left: 2.5rem; }
|
||||
|
||||
ul.config.l4 > li > div {
|
||||
padding-left: 2.5rem;
|
||||
}
|
||||
|
||||
span.dflt,
|
||||
span.p-dflt,
|
||||
|
@ -126,4 +133,3 @@ button.mini-icon-btn {
|
|||
.theme-wrapper.dark button.mini-icon-btn.pattern:enabled {
|
||||
color: $oc-green-6;
|
||||
}
|
||||
|
||||
|
|
|
@ -101,17 +101,31 @@ div.design {
|
|||
font-size: 115%;
|
||||
margin: 1rem 0;
|
||||
text-align: left;
|
||||
h6.point.c0 {
|
||||
border-bottom: 1px solid $oc-red-6;
|
||||
.path,
|
||||
.point {
|
||||
border-left: 3px solid transparent;
|
||||
padding-left: 5px;
|
||||
margin-bottom: 3px;
|
||||
font-size: 80%;
|
||||
}
|
||||
h6.point.c1 {
|
||||
border-bottom: 1px solid $oc-green-6;
|
||||
.path {
|
||||
border-left: 3px dashed transparent;
|
||||
}
|
||||
h6.point.c2 {
|
||||
border-bottom: 1px solid $oc-blue-6;
|
||||
.path.c0,
|
||||
.point.c0 {
|
||||
border-color: $oc-red-6;
|
||||
}
|
||||
h6.point.c3 {
|
||||
border-bottom: 1px solid $oc-grape-6;
|
||||
.path.c1,
|
||||
.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 {
|
||||
g.design.point {
|
||||
circle {
|
||||
|
@ -166,18 +165,3 @@ div.design {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ devDocsAvailableAt: Developer documentation is available at
|
|||
talkToUs: For questions, feedback or suggestions, come talk to us in our chat room
|
||||
draftYourPattern: Draft your pattern
|
||||
testYourPattern: Test your pattern
|
||||
draftThing: 'Draft {thing}'
|
||||
testThing: 'Test {thing}'
|
||||
renderInBrowser: Click below to render your pattern in the browser.
|
||||
weWillReRender: When you make changes, we will re-render for you.
|
||||
youCan: You can
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue