diff --git a/packages/components/src/Workbench/Design/index.js b/packages/components/src/Workbench/Design/index.js index 2383f39f8a1..2e2e6a252c3 100644 --- a/packages/components/src/Workbench/Design/index.js +++ b/packages/components/src/Workbench/Design/index.js @@ -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(
  • {a}: {renderAttributeValue(attr.list[a])}
  • - ); + ) - return ; - }; + return + } - 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(
  • {v}
  • ); - return ; + if (val.length === 1) return val.pop() + let list = [] + for (let v of val) list.push(
  • {v}
  • ) + return } - 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 ; - }; - - 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 = (op.to.x,op.to.y); - 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 ( -
  • - {op.type} -  »  - - {text} - -
  • - ); - } 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] = ( - - ({op[t].x},{op[t].y}) - - ); - clicks[t] = () => - props.raiseEvent("coords", { - ...focus, - coords: { - x: op[t].x, - y: op[t].y - } - }); - } - } - return ( -
  • - {op.type} - {types.map(t => ( - -  »  - - {texts[t]} - - - ))} -
  • - ); - } else if (op.type === "close") - return ( -
  • - close -
  • - ); - - 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( -
    - parts.{part}( - props.raiseEvent("part", part)}> - Isolate - - ) -
    - ); + 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( -
    + let name = props.focus[part].paths[i] + let path = props.parts[part].paths[name] + paths.push( +
  • path.{name} -
  • - ); - info.push( - - ); + console.log(`parts.${part}.paths.${name}:`, path)} + > + + + {path.attributes.length > 0 && ( + + )} + + ) } for (let i in props.focus[part].points) { - let name = props.focus[part].points[i]; - let point = props.parts[part].points[name]; - info.push( -
    + let name = props.focus[part].points[i] + let point = props.parts[part].points[name] + points.push( +
  • point.{name} -
  • - ); - info.push( - - ); + console.log(`parts.${part}.points.${name}:`, point)} + > + + + + + ) } + info.push( +
  • + parts.{part} + props.raiseEvent('part', part)}> + + + {points.length > 0 && } + {paths.length > 0 && } +
  • + ) } return ( -
    - {info} +
    +
    - ); -}; + ) +} -export default Design; +export default Design diff --git a/packages/components/src/Workbench/DraftConfig/Events/event.js b/packages/components/src/Workbench/DraftConfig/Events/event.js new file mode 100644 index 00000000000..5afe220e9de --- /dev/null +++ b/packages/components/src/Workbench/DraftConfig/Events/event.js @@ -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) => ( +
    + + + + + +
    + ) + + const formatObject = (obj) => ( + + ) + + 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() + + return data + } + + return ( +
    +
    + {type === 'debug' && } + {type === 'info' && } + {type === 'warning' && } + {type === 'error' && } +
    + {formatEvent(event)} +
    + ) +} + +export default Event diff --git a/packages/components/src/Workbench/DraftConfig/Events/index.js b/packages/components/src/Workbench/DraftConfig/Events/index.js new file mode 100644 index 00000000000..6a6afe491a9 --- /dev/null +++ b/packages/components/src/Workbench/DraftConfig/Events/index.js @@ -0,0 +1,16 @@ +import React from 'react' +import Event from './event' + +const DraftEvents = ({ events }) => ( +
    + {['error', 'warning', 'debug'].map((type) => ( +
    + {events[type].map((event, index) => ( + + ))} +
    + ))} +
    +) + +export default DraftEvents diff --git a/packages/components/src/Workbench/DraftConfig/index.js b/packages/components/src/Workbench/DraftConfig/index.js new file mode 100644 index 00000000000..73713d9e879 --- /dev/null +++ b/packages/components/src/Workbench/DraftConfig/index.js @@ -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 ( +
    +
    + props.setHideAside(true)} title="Hide sidebar" {...iconProps}> + + + props.setDesign(!props.design)} + title="Toggle design mode" + {...iconProps} + > + + + + + {props.design && ( + props.raiseEvent('clearFocusAll', null)} + title="Clear design mode" + {...iconProps} + > + + + )} + console.log(props.pattern)} + title="console.log(pattern)" + {...iconProps} + > + + + | + props.updateGist(!props.gist.settings.advanced, 'settings', 'advanced')} + title="Toggle advanced settings" + {...iconProps} + > + + + + + props.updateGist(!props.gist.settings.paperless, 'settings', 'paperless')} + title="Toggle paperless" + {...iconProps} + > + + + + + props.updateGist(!props.gist.settings.complete, 'settings', 'complete')} + title="Toggle complete" + {...iconProps} + > + + + + +
    + {props.design && ( + + )} + +
    + +
    +
    + ) +} + +export default DraftPattern diff --git a/packages/components/src/Workbench/DraftPattern/index.js b/packages/components/src/Workbench/DraftPattern/index.js index 35e2441bcc4..1eea448c753 100644 --- a/packages/components/src/Workbench/DraftPattern/index.js +++ b/packages/components/src/Workbench/DraftPattern/index.js @@ -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 ( -
    -
    - - - {hideAside && ( -
    - setHideAside(false)} - title="Show sidebar" - {...iconProps} - style={{ margin: 0 }} - > - - - - -
    - )} -
    - - -
    +
    + + +
    ) } diff --git a/packages/components/src/Workbench/LanguageChooser/index.js b/packages/components/src/Workbench/LanguageChooser/index.js deleted file mode 100644 index b06aed0ff29..00000000000 --- a/packages/components/src/Workbench/LanguageChooser/index.js +++ /dev/null @@ -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 ( -
    -
    - {Object.keys(languages).map(lang => { - return ( - - ); - })} -
    -
    - ); -}; - -export default LanguageChooser; diff --git a/packages/components/src/Workbench/index.js b/packages/components/src/Workbench/index.js index c0c79363620..1af5864086c 100644 --- a/packages/components/src/Workbench/index.js +++ b/packages/components/src/Workbench/index.js @@ -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: , + test: , + measurements: , + xport: +} 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: , + test: , + measurements: , + xport: + } // 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 = () => ( + + ) 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: , 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 = () => ( +

    + {Object.keys(languages).map((lang) => { + return ( + + ) + })} +

    + ) + + 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 = + main = ( + <> +

    + +

    + {languageButtons()} + + ) + context = ( + + ) break case 'draft': - if (measurementsMissing()) saveDisplay('measurements') + if (measurementsMissing()) setDisplay('measurements') + let pattern = new Pattern(gist.settings) + pattern.draft() + let patternProps = pattern.getRenderProps() main = ( + ) + context = ( + ) break case 'sample': - if (measurementsMissing()) saveDisplay('measurements') + if (measurementsMissing()) setDisplay('measurements') main = ( break - case 'inspect': - main = ( - - ) - break default: - main = + main = ( + <> + +
    {languageButtons()}
    + + ) } const themes = { dark, light } @@ -227,8 +329,22 @@ const Workbench = ({ theme === 'light' ? 'workbench theme-wrapper light' : 'workbench theme-wrapper dark' } > - {display !== 'welcome' ? saveDisplay('welcome')} /> : null} - {main} + setDisplay('welcome')} /> +
    + {hideAside ? ( + setHideAside(false)}> + + + ) : ( + + )} +
    {main}
    +
    ) diff --git a/packages/css-theme/src/components/_draft-configurator.scss b/packages/css-theme/src/components/_draft-configurator.scss index 7b3c9296ca5..ec462731a5f 100644 --- a/packages/css-theme/src/components/_draft-configurator.scss +++ b/packages/css-theme/src/components/_draft-configurator.scss @@ -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; } - diff --git a/packages/css-theme/src/components/_draft-design.scss b/packages/css-theme/src/components/_draft-design.scss index b59867b8dd9..d2149752d6d 100644 --- a/packages/css-theme/src/components/_draft-design.scss +++ b/packages/css-theme/src/components/_draft-design.scss @@ -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); - } -} diff --git a/packages/i18n/src/locales/en/cfp.yaml b/packages/i18n/src/locales/en/cfp.yaml index 05700427fb3..f59ddb4c643 100644 --- a/packages/i18n/src/locales/en/cfp.yaml +++ b/packages/i18n/src/locales/en/cfp.yaml @@ -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