diff --git a/sites/lab/components/about.js b/sites/lab/components/about.js deleted file mode 100644 index a0c8f12481c..00000000000 --- a/sites/lab/components/about.js +++ /dev/null @@ -1,28 +0,0 @@ -import Popout from 'shared/components/popout.js' - -const About = () => ( - -

What to expect at lab.freesewing.org

-

- The FreeSewing lab is an online environment to road-test our various patterns/designs. -

-

- This website runs the bleeding edge of our code base. - Some patterns here may be unreleased or at various states of being worked on. - As such, this website is intended for FreeSewing contributors or people interested - in what happens under the hood. -

-

- If you want sewing patterns to actually start making something, - please visit freesewing.org, our flagship website for makers. -

- - This lacks translation - -
-) - -export default About diff --git a/sites/lab/components/about.mjs b/sites/lab/components/about.mjs new file mode 100644 index 00000000000..14cba0f59bd --- /dev/null +++ b/sites/lab/components/about.mjs @@ -0,0 +1,24 @@ +import { Popout } from 'shared/components/popout.mjs' + +export const About = () => ( + +

What to expect at lab.freesewing.org

+

The FreeSewing lab is an online environment to road-test our various patterns/designs.

+

+ This website runs the bleeding edge of our code base. Some patterns here may be unreleased or + at various states of being worked on. As such, this website is intended for FreeSewing + contributors or people interested in what happens under the hood. +

+

+ If you want sewing patterns to actually start making something, please visit{' '} + + freesewing.org + + , our flagship website for makers. +

+ This lacks translation +
+) diff --git a/sites/lab/components/design-picker.js b/sites/lab/components/design-picker.mjs similarity index 94% rename from sites/lab/components/design-picker.js rename to sites/lab/components/design-picker.mjs index dc428ac7589..f959a153dce 100644 --- a/sites/lab/components/design-picker.js +++ b/sites/lab/components/design-picker.mjs @@ -1,11 +1,10 @@ import React, { Fragment } from 'react' -import DesignIcon from 'shared/components/icons/design' import { useTranslation } from 'next-i18next' -import { Popover, Transition } from '@headlessui/react' -import DownIcon from 'shared/components/icons/down' import Link from 'next/link' +import { Popover, Transition } from '@headlessui/react' +import { DesignIcon, DownIcon } from 'shared/components/icons.mjs' -const PatternPicker = ({ app }) => { +export const DesignPicker = ({ app }) => { const { t } = useTranslation(['common']) const sectionPatterns = (section) => @@ -68,5 +67,3 @@ const PatternPicker = ({ app }) => { ) } - -export default PatternPicker diff --git a/sites/lab/components/footer.js b/sites/lab/components/footer.mjs similarity index 85% rename from sites/lab/components/footer.js rename to sites/lab/components/footer.mjs index d0301d67dd9..de5904180a4 100644 --- a/sites/lab/components/footer.js +++ b/sites/lab/components/footer.mjs @@ -1,18 +1,21 @@ -import Logo from 'shared/components/logos/freesewing.js' -import OsiLogo from 'shared/components/logos/osi.js' -import CreativeCommonsLogo from 'shared/components/logos/cc.js' -import CcByLogo from 'shared/components/logos/cc-by.js' +// Hooks import { useTranslation } from 'next-i18next' -import Ribbon from 'shared/components/ribbon.js' +// Components import Link from 'next/link' -import { WordMark } from 'shared/components/wordmark.js' - -import DiscordIcon from 'shared/components/icons/discord.js' -import FacebookIcon from 'shared/components/icons/facebook.js' -import GithubIcon from 'shared/components/icons/github.js' -import InstagramIcon from 'shared/components/icons/instagram.js' -import RedditIcon from 'shared/components/icons/reddit.js' -import TwitterIcon from 'shared/components/icons/twitter.js' +import { FreeSewingLogo } from 'shared/components/logos/freesewing.mjs' +import { OsiLogo } from 'shared/components/logos/osi.mjs' +import { CCLogo } from 'shared/components/logos/cc.mjs' +import { CCByLogo } from 'shared/components/logos/cc-by.mjs' +import { Ribbon } from 'shared/components/ribbon.mjs' +import { WordMark } from 'shared/components/wordmark.mjs' +import { + DiscordIcon, + FacebookIcon, + GithubIcon, + InstagramIcon, + RedditIcon, + TwitterIcon, +} from 'shared/components/icons.mjs' // Classes const link = 'text-secondary font-bold hover:pointer hover:underline px-1' @@ -77,7 +80,7 @@ const social = { }, } -const Footer = ({ app }) => { +export const Footer = ({ app }) => { const { t } = useTranslation(['common', 'patrons']) return ( @@ -88,10 +91,10 @@ const Footer = ({ app }) => {
- +
- +

{translations.cc}

@@ -157,7 +160,7 @@ const Footer = ({ app }) => { {/* Col 3 - Logo & Slogan */}
- +
@@ -172,5 +175,3 @@ const Footer = ({ app }) => { ) } - -export default Footer diff --git a/sites/lab/components/header.js b/sites/lab/components/header.mjs similarity index 80% rename from sites/lab/components/header.js rename to sites/lab/components/header.mjs index e42c30aa721..006a85e1c18 100644 --- a/sites/lab/components/header.js +++ b/sites/lab/components/header.mjs @@ -1,13 +1,14 @@ +// Hooks import { useState, useEffect } from 'react' -import ThemePicker from 'shared/components/theme-picker.js' -import LocalePicker from 'shared/components/locale-picker.js' -import DesignPicker from 'site/components/design-picker.js' -import CloseIcon from 'shared/components/icons/close.js' -import MenuIcon from 'shared/components/icons/menu.js' -import Ribbon from 'shared/components/ribbon.js' -import { WordMark } from 'shared/components/wordmark.js' +// Components +import { ThemePicker } from 'shared/components/theme-picker/index.mjs' +import { LocalePicker } from 'shared/components/locale-picker/index.mjs' +import { DesignPicker } from 'site/components/design-picker.mjs' +import { CloseIcon, MenuIcon } from 'shared/components/icons.mjs' +import { Ribbon } from 'shared/components/ribbon.mjs' +import { WordMark } from 'shared/components/wordmark.mjs' -const Header = ({ app }) => { +export const Header = ({ app }) => { const [prevScrollPos, setPrevScrollPos] = useState(0) const [show, setShow] = useState(true) @@ -67,5 +68,3 @@ const Header = ({ app }) => { ) } - -export default Header diff --git a/sites/lab/components/help-us.js b/sites/lab/components/help-us.mjs similarity index 53% rename from sites/lab/components/help-us.js rename to sites/lab/components/help-us.mjs index 772a9c3c829..ec431ec9347 100644 --- a/sites/lab/components/help-us.js +++ b/sites/lab/components/help-us.mjs @@ -1,49 +1,53 @@ -import Popout from 'shared/components/popout.js' +import { Popout } from 'shared/components/popout.mjs' -const HelpUs = ({ mdx=false, slug='/' }) => ( +export const HelpUs = ({ mdx = false, slug = '/' }) => (
Click here to learn how you can help us improve this page {mdx && ( - +
Found a mistake?
- You can edit this page on Github and help us improve our documentation. + > + edit this page on Github + {' '} + and help us improve our documentation.
)} - +
Does this look ok?

- If it looks ok, great! But if not, please let me know about it. - Either by + If it looks ok, great! But if not, please let me know about it. Either by{' '} + reaching out on Discord - or feel free to {' '} + or feel free to{' '} + create - an issue on Github. + > + create an issue on Github + + .

Why do you ask?

- I recently added a backend endpoint to auto-generate pretty (I hope) Open Graph images. - They are those little preview images you see when you paste a link in Discord (for example). + I recently added a backend endpoint to auto-generate pretty (I hope) Open Graph images. They + are those little preview images you see when you paste a link in Discord (for example).

This idea is that it will auto-generate an image, but I am certain there are some edge cases - where that will not work. - There are hundreds of pages on this website and checking them all one by one is not something - I see myself doing. But since you are here on this page, perhaps you could see if the image - above looks ok. + where that will not work. There are hundreds of pages on this website and checking them all + one by one is not something I see myself doing. But since you are here on this page, perhaps + you could see if the image above looks ok.

Thank you, I really appreciate your help with this.

) - -export default HelpUs - diff --git a/sites/lab/components/layouts/bare.js b/sites/lab/components/layouts/bare.js deleted file mode 100644 index ae312cc57f8..00000000000 --- a/sites/lab/components/layouts/bare.js +++ /dev/null @@ -1,17 +0,0 @@ -import { useRouter } from 'next/router' -import Aside from 'shared/components/navigation/aside' -import { BeforeNav } from './lab' - -const DefaultLayout = ({ app, children = [] }) => { - const router = useRouter() - const slug = router.asPath.slice(1) - - return ( - <> -
) } - -export default LayoutWrapper diff --git a/sites/lab/components/wrappers/page.js b/sites/lab/components/wrappers/page.mjs similarity index 88% rename from sites/lab/components/wrappers/page.js rename to sites/lab/components/wrappers/page.mjs index 079f4571b1b..0e2913023f4 100644 --- a/sites/lab/components/wrappers/page.js +++ b/sites/lab/components/wrappers/page.mjs @@ -1,11 +1,12 @@ +// Hooks import { useEffect } from 'react' import { useSwipeable } from 'react-swipeable' import { useRouter } from 'next/router' -// Layouts components -import LayoutWrapper from 'site/components/wrappers/layout' +// Components +import { LayoutWrapper } from 'site/components/wrappers/layout.mjs' /* This component should wrap all page content */ -const PageWrapper = ({ +export const PageWrapper = ({ title = 'FIXME: No title set', app = false, layout = false, @@ -42,5 +43,3 @@ const PageWrapper = ({
) } - -export default PageWrapper diff --git a/sites/lab/hooks/useApp.js b/sites/lab/hooks/useApp.mjs similarity index 93% rename from sites/lab/hooks/useApp.js rename to sites/lab/hooks/useApp.mjs index bb2dec828e4..5f964454e95 100644 --- a/sites/lab/hooks/useApp.js +++ b/sites/lab/hooks/useApp.mjs @@ -1,13 +1,13 @@ +// Hooks import { useState } from 'react' -// Stores state in local storage -import useLocalStorage from 'shared/hooks/useLocalStorage.js' -// Designs -import { designsByType } from 'prebuild/designs-by-type.mjs' -// Locale and translation import { useRouter } from 'next/router' import { useTranslation } from 'next-i18next' +import { useLocalStorage } from 'shared/hooks/useLocalStorage.mjs' +import { useTheme } from 'shared/hooks/useTheme.mjs' +// Dependenices +import { designsByType } from 'prebuild/designs-by-type.mjs' +// Components import { capitalize } from 'shared/utils.mjs' -import useTheme from 'shared/hooks/useTheme' // Initial navigation const initialNavigation = (t) => { diff --git a/sites/lab/page-templates/design-list.js b/sites/lab/page-templates/design-list.mjs similarity index 78% rename from sites/lab/page-templates/design-list.js rename to sites/lab/page-templates/design-list.mjs index 74133c7db0b..4364a2e51c4 100644 --- a/sites/lab/page-templates/design-list.js +++ b/sites/lab/page-templates/design-list.mjs @@ -1,10 +1,12 @@ -import Page from 'site/components/wrappers/page.js' -import useApp from 'site/hooks/useApp.js' -import Link from 'next/link' +// Hooks +import { useApp } from 'site/hooks/useApp.mjs' import { useTranslation } from 'next-i18next' -import Layout from 'site/components/layouts/bare' -import { PageTitle } from 'shared/components/layouts/default' +// Components import Head from 'next/head' +import Link from 'next/link' +import { PageWrapper } from 'site/components/wrappers/page.mjs' +import { BareLayout } from 'site/components/layouts/bare.mjs' +import { PageTitle } from 'shared/components/layouts/default.mjs' const DesignLinks = ({ list, prefix = '' }) => { const { t } = useTranslation(['patterns']) @@ -29,7 +31,7 @@ const DesignLinks = ({ list, prefix = '' }) => { ) } -const PatternListPageTemplate = ({ section = false }) => { +export const PatternListPageTemplate = ({ section = false }) => { const app = useApp() const { t } = useTranslation(['app']) @@ -47,7 +49,7 @@ const PatternListPageTemplate = ({ section = false }) => { } return ( - + {fullTitle} @@ -61,8 +63,6 @@ const PatternListPageTemplate = ({ section = false }) => {
- + ) } - -export default PatternListPageTemplate diff --git a/sites/lab/page-templates/workbench.mjs b/sites/lab/page-templates/workbench.mjs index 77fbdf33c97..ba45657a2ca 100644 --- a/sites/lab/page-templates/workbench.mjs +++ b/sites/lab/page-templates/workbench.mjs @@ -1,12 +1,15 @@ -import Page from 'site/components/wrappers/page.js' -import useApp from 'site/hooks/useApp.js' -import WorkbenchWrapper from 'shared/components/wrappers/workbench.js' +// Hooks +import { useApp } from 'site/hooks/useApp.mjs' import { useRouter } from 'next/router' -import Layout from 'site/components/layouts/lab' -import Head from 'next/head' +// Dependencies import { capitalize } from 'shared/utils.mjs' +// Components +import Head from 'next/head' +import { PageWrapper } from 'site/components/wrappers/page.mjs' +import { WorkbenchWrapper } from 'shared/components/wrappers/workbench.mjs' +import { LabLayout } from 'site/components/layouts/lab.mjs' -const WorkbenchPage = ({ design }) => { +export const WorkbenchPage = ({ design }) => { const app = useApp() const router = useRouter() const { preload, from } = router.query @@ -16,13 +19,11 @@ const WorkbenchPage = ({ design }) => { const fullTitle = title + ' - FreeSewing Lab' return ( - + {fullTitle} - - + + ) } - -export default WorkbenchPage diff --git a/sites/lab/pages/index.js b/sites/lab/pages/index.js index f87d0adb506..12e8ddf1b65 100644 --- a/sites/lab/pages/index.js +++ b/sites/lab/pages/index.js @@ -1,10 +1,13 @@ -import Page from 'site/components/wrappers/page.js' -import useApp from 'site/hooks/useApp.js' -import Head from 'next/head' -import { serverSideTranslations } from 'next-i18next/serverSideTranslations' -import Layout from 'site/components/layouts/bare' +// Hooks +import useApp from 'site/hooks/useApp.mjs' import { useTranslation } from 'next-i18next' -import { Icons } from 'shared/components/navigation/primary' +// Dependencies +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' +// Components +import Head from 'next/head' +import { PageWrapper } from 'site/components/wrappers/page.mjs' +import { BareLayout } from 'site/components/layouts/bare.mjs' +import { Icons } from 'shared/components/navigation/primary.mjs' const title = 'Welcome to the FreeSewing Lab' @@ -12,7 +15,7 @@ const HomePage = () => { const app = useApp() const { t } = useTranslation(['lab']) return ( - + @@ -148,7 +151,7 @@ const HomePage = () => {
- + ) } diff --git a/sites/shared/components/icons.mjs b/sites/shared/components/icons.mjs index dc211ab842d..960910521cb 100644 --- a/sites/shared/components/icons.mjs +++ b/sites/shared/components/icons.mjs @@ -96,7 +96,7 @@ export const CopyIcon = (props) => ( ) export const DesignIcon = (props) => ( - + ) diff --git a/sites/shared/components/workbench/default-settings.js b/sites/shared/components/workbench/default-settings.js deleted file mode 100644 index 445ed2c908e..00000000000 --- a/sites/shared/components/workbench/default-settings.js +++ /dev/null @@ -1,16 +0,0 @@ -const defaultSettings = { - sa: 0, - saBool: false, - saMm: 10, - scale: 1, - complete: true, - paperless: false, - units: 'metric', - locale: 'en', - margin: 2, - renderer: 'react', - embed: true, - debug: true, -} - -export default defaultSettings diff --git a/sites/shared/components/workbench/draft/circle/index.js b/sites/shared/components/workbench/draft/circle.mjs similarity index 91% rename from sites/shared/components/workbench/draft/circle/index.js rename to sites/shared/components/workbench/draft/circle.mjs index 1b64d6e3dfa..4fbd1d94410 100644 --- a/sites/shared/components/workbench/draft/circle/index.js +++ b/sites/shared/components/workbench/draft/circle.mjs @@ -1,4 +1,4 @@ -const Circle = (props) => +export const Circle = (props) => props.point.attributes.getAsArray('data-circle').map((r, i) => { const circleProps = props.point.attributes.asPropsIfPrefixIs('data-circle-') const extraProps = {} @@ -12,5 +12,3 @@ const Circle = (props) => return }) - -export default Circle diff --git a/sites/shared/components/workbench/draft/defs/index.js b/sites/shared/components/workbench/draft/defs.mjs similarity index 98% rename from sites/shared/components/workbench/draft/defs/index.js rename to sites/shared/components/workbench/draft/defs.mjs index f7ac20f13e5..07cb9ab5173 100644 --- a/sites/shared/components/workbench/draft/defs/index.js +++ b/sites/shared/components/workbench/draft/defs.mjs @@ -48,7 +48,7 @@ const grids = { `, } -const Defs = (props) => { +export const Defs = (props) => { let defs = props.svg.defs if (props.settings[0].paperless) { defs += grids[props.settings[0].units || 'metric'] @@ -65,5 +65,3 @@ const Defs = (props) => { return } - -export default Defs diff --git a/sites/shared/components/workbench/draft/error.js b/sites/shared/components/workbench/draft/error.mjs similarity index 89% rename from sites/shared/components/workbench/draft/error.js rename to sites/shared/components/workbench/draft/error.mjs index 6934e5ce66a..395bcbbb735 100644 --- a/sites/shared/components/workbench/draft/error.js +++ b/sites/shared/components/workbench/draft/error.mjs @@ -1,6 +1,6 @@ -import DefaultErrorView from 'shared/components/error/view' +import { ErrorView } from 'shared/components/error/view.mjs' -const Error = (props) => { +export const Error = (props) => { const errors = { pattern: 0, sets: 0, @@ -58,10 +58,8 @@ const Error = (props) => { ) return ( - +

No need to be alarmed, but we ran into some trouble while drafting this pattern.

-
+ ) } - -export default Error diff --git a/sites/shared/components/workbench/draft/index.js b/sites/shared/components/workbench/draft/index.mjs similarity index 91% rename from sites/shared/components/workbench/draft/index.js rename to sites/shared/components/workbench/draft/index.mjs index b1e407b271e..a73db7ae0d3 100644 --- a/sites/shared/components/workbench/draft/index.js +++ b/sites/shared/components/workbench/draft/index.mjs @@ -1,7 +1,7 @@ -import SvgWrapper from './svg-wrapper' -import Error from './error.js' +import { SvgWrapper } from './svg.mjs' +import { Error } from './error.mjs' -const LabDraft = (props) => { +export const LabDraft = (props) => { const { app, draft, gist, updateGist, unsetGist, showInfo, feedback, hasRequiredMeasurements } = props @@ -60,5 +60,3 @@ const LabDraft = (props) => { ) } - -export default LabDraft diff --git a/sites/shared/components/workbench/draft/part/index.js b/sites/shared/components/workbench/draft/part.mjs similarity index 90% rename from sites/shared/components/workbench/draft/part/index.js rename to sites/shared/components/workbench/draft/part.mjs index 9eceb3fe57d..f5c46200af2 100644 --- a/sites/shared/components/workbench/draft/part/index.js +++ b/sites/shared/components/workbench/draft/part.mjs @@ -1,10 +1,9 @@ import { forwardRef } from 'react' -import Path from '../path' -import Point from '../point' -import Snippet from '../snippet' -import { getProps } from '../utils' -import { round } from 'shared/utils' -import { Tr, KeyTd, ValTd, Attributes, pointCoords } from '../path/index' +import { Point } from './point.mjs' +import { Snippet } from './snippet.mjs' +import { getProps } from './utils.mjs' +import { round } from 'shared/utils.mjs' +import { Path, Tr, KeyTd, ValTd, Attributes, pointCoords } from './path.mjs' const partInfo = (props) => (
@@ -142,7 +141,7 @@ export const PartInner = forwardRef((props, ref) => { PartInner.displayName = 'PartInner' -const Part = (props) => { +export const Part = (props) => { const { partName, part } = props return ( @@ -155,14 +154,3 @@ const Part = (props) => { ) } -/* - - - */ - -export default Part diff --git a/sites/shared/components/workbench/draft/path/index.js b/sites/shared/components/workbench/draft/path.mjs similarity index 98% rename from sites/shared/components/workbench/draft/path/index.js rename to sites/shared/components/workbench/draft/path.mjs index 75e0af65512..c42e7976055 100644 --- a/sites/shared/components/workbench/draft/path/index.js +++ b/sites/shared/components/workbench/draft/path.mjs @@ -1,7 +1,7 @@ -import TextOnPath from '../text-on-path' -import { getProps } from '../utils' -import { round, formatMm } from 'shared/utils' -import RawSpan from 'shared/components/raw-span' +import { TextOnPath } from './text.mjs' +import { getProps } from './utils.mjs' +import { round, formatMm } from 'shared/utils.mjs' +import { RawSpan } from 'shared/components/raw-span.mjs' export const pointCoords = (point) => point ? `[ ${round(point.x, 2)}, ${round(point.y, 2)} ]` : null @@ -620,7 +620,7 @@ const XrayPath = (props) => { ) } -const Path = (props) => { +export const Path = (props) => { const { path, partName, pathName } = props if (path.hidden) return null const output = [] @@ -641,5 +641,3 @@ const Path = (props) => { return output } - -export default Path diff --git a/sites/shared/components/workbench/draft/point/index.js b/sites/shared/components/workbench/draft/point.mjs similarity index 93% rename from sites/shared/components/workbench/draft/point/index.js rename to sites/shared/components/workbench/draft/point.mjs index 0a2c147d83f..6ce90fed534 100644 --- a/sites/shared/components/workbench/draft/point/index.js +++ b/sites/shared/components/workbench/draft/point.mjs @@ -1,7 +1,7 @@ -import Text from '../text' -import Circle from '../circle' -import { Tr, KeyTd, ValTd, Attributes, pointCoords } from '../path/index' -import { withinPartBounds } from '../utils.js' +import { Text } from './text.mjs' +import { Circle } from './circle.mjs' +import { Tr, KeyTd, ValTd, Attributes, pointCoords } from './path.mjs' +import { withinPartBounds } from './utils.mjs' const RevealPoint = (props) => { const r = 15 * props.gist.scale @@ -82,7 +82,7 @@ const XrayPoint = (props) => ( ) -const Point = (props) => { +export const Point = (props) => { const { point, pointName, partName, gist, part } = props // Don't include parts outside the part bounding box if (!withinPartBounds(point, part)) return null @@ -103,5 +103,3 @@ const Point = (props) => { return output.length < 1 ? null : output } - -export default Point diff --git a/sites/shared/components/workbench/draft/snippet/index.js b/sites/shared/components/workbench/draft/snippet.mjs similarity index 65% rename from sites/shared/components/workbench/draft/snippet/index.js rename to sites/shared/components/workbench/draft/snippet.mjs index 1c58594c97b..0bd908a2859 100644 --- a/sites/shared/components/workbench/draft/snippet/index.js +++ b/sites/shared/components/workbench/draft/snippet.mjs @@ -1,9 +1,8 @@ import React from 'react' -import { getProps } from '../utils' -import { Tr, KeyTd, ValTd, Attributes, pointCoords } from '../path/index' +import { getProps } from './utils.mjs' +import { Tr, KeyTd, ValTd, Attributes, pointCoords } from './path.mjs' const snippetInfo = (props) => { - return (
Snippet info
@@ -27,30 +26,30 @@ const snippetInfo = (props) => { Attributes - + + +
- - + +
) } -const Snippet = (props) => { +export const Snippet = (props) => { if (!props.snippet?.anchor) return null const snippetProps = { xlinkHref: '#' + props.snippet.def, x: props.snippet.anchor.x, - y: props.snippet.anchor.y + y: props.snippet.anchor.y, } let scale = props.snippet.attributes.get('data-scale') let rotate = props.snippet.attributes.get('data-rotate') @@ -66,13 +65,16 @@ const Snippet = (props) => { } } - return { evt.stopPropagation(); props.showInfo(snippetInfo(props)) }} - /> + return ( + { + evt.stopPropagation() + props.showInfo(snippetInfo(props)) + }} + /> + ) } - -export default Snippet diff --git a/sites/shared/components/workbench/draft/stack.js b/sites/shared/components/workbench/draft/stack.mjs similarity index 75% rename from sites/shared/components/workbench/draft/stack.js rename to sites/shared/components/workbench/draft/stack.mjs index 5cbea16ff24..4f25a7d6243 100644 --- a/sites/shared/components/workbench/draft/stack.js +++ b/sites/shared/components/workbench/draft/stack.mjs @@ -1,7 +1,7 @@ -import Part from './part' -import { getProps } from './utils' +import { Part } from './part.mjs' +import { getProps } from './utils.mjs' -const Stack = (props) => { +export const Stack = (props) => { const { stack, gist, updateGist, unsetGist, showInfo } = props return ( @@ -17,5 +17,3 @@ const Stack = (props) => { ) } - -export default Stack diff --git a/sites/shared/components/workbench/draft/svg-wrapper.js b/sites/shared/components/workbench/draft/svg.mjs similarity index 70% rename from sites/shared/components/workbench/draft/svg-wrapper.js rename to sites/shared/components/workbench/draft/svg.mjs index 88374691daa..a9f6d705c4b 100644 --- a/sites/shared/components/workbench/draft/svg-wrapper.js +++ b/sites/shared/components/workbench/draft/svg.mjs @@ -1,9 +1,49 @@ +import { forwardRef } from 'react' import { SizeMe } from 'react-sizeme' import { TransformWrapper, TransformComponent } from 'react-zoom-pan-pinch' -import Svg from './svg' -import Defs from './defs' -import Stack from './stack' -import { forwardRef } from 'react' +import { Defs } from './defs.mjs' +import { Stack } from './stack.mjs' + +export const Svg = forwardRef( + ( + { + embed = true, + develop = false, + locale = 'en', + className = 'freesewing pattern', + style = {}, + viewBox = false, + width, + height, + children, + }, + ref + ) => { + if (width < 1) width = 1000 + if (height < 1) height = 1000 + let attributes = { + xmlns: 'http://www.w3.org/2000/svg', + 'xmlns:svg': 'http://www.w3.org/2000/svg', + xmlnsXlink: 'http://www.w3.org/1999/xlink', + xmlLang: locale, + viewBox: viewBox || `0 0 ${width} ${height}`, + className, + style, + } + + if (!embed) { + attributes.width = width + 'mm' + attributes.height = height + 'mm' + } + if (develop) attributes.className += ' develop' + + return ( + + {children} + + ) + } +) /* What's with all the wrapping? * @@ -26,7 +66,7 @@ import { forwardRef } from 'react' * Also still to see how this will work with SSR */ -const SvgWrapper = forwardRef((props, ref) => { +export const SvgWrapper = forwardRef((props, ref) => { const { patternProps = false, gist, updateGist, unsetGist, showInfo, viewBox } = props if (!patternProps) return null @@ -65,7 +105,3 @@ const SvgWrapper = forwardRef((props, ref) => { ) }) - -SvgWrapper.displayName = 'SvgWrapper' - -export default SvgWrapper diff --git a/sites/shared/components/workbench/draft/svg/index.js b/sites/shared/components/workbench/draft/svg/index.js deleted file mode 100644 index 70a9102aebd..00000000000 --- a/sites/shared/components/workbench/draft/svg/index.js +++ /dev/null @@ -1,35 +0,0 @@ -import {forwardRef} from 'react' - -const Svg = forwardRef(({ - embed = true, - develop = false, - locale = 'en', - className = 'freesewing pattern', - style = {}, - viewBox = false, - width, - height, - children -}, ref) => { - if (width < 1) width = 1000 - if (height < 1) height = 1000 - let attributes = { - xmlns: 'http://www.w3.org/2000/svg', - 'xmlns:svg': 'http://www.w3.org/2000/svg', - xmlnsXlink: 'http://www.w3.org/1999/xlink', - xmlLang: locale, - viewBox: viewBox || `0 0 ${width} ${height}`, - className, - style - } - - if (!embed) { - attributes.width = width + 'mm' - attributes.height = height + 'mm' - } - if (develop) attributes.className += ' develop' - - return {children} -}) - -export default Svg diff --git a/sites/shared/components/workbench/draft/text-on-path/index.js b/sites/shared/components/workbench/draft/text-on-path/index.js deleted file mode 100644 index e3e4146d0de..00000000000 --- a/sites/shared/components/workbench/draft/text-on-path/index.js +++ /dev/null @@ -1,45 +0,0 @@ -import { useTranslation } from 'next-i18next' -import { pathInfo } from '../path/index' - -const XrayTextOnPath = props => ( - { evt.stopPropagation(); props.showInfo(pathInfo(props)) }} - /> -) - -const TextOnPath = (props) => { - const { t } = useTranslation(['app']) - // Handle translation (and spaces) - let translated = '' - for (let string of props.path.attributes.getAsArray('data-text')) { - translated += t(string).replace(/"/g, '"') + ' ' - } - const textPathProps = { - xlinkHref: '#' + props.pathId, - startOffset: '0%' - } - const align = props.path.attributes.get('data-text-class') - if (align && align.indexOf('center') > -1) textPathProps.startOffset = '50%' - else if (align && align.indexOf('right') > -1) textPathProps.startOffset = '100%' - - const attr = props.path.attributes.asPropsIfPrefixIs('data-text-') - - return ( - - - - - {props.gist._state?.xray?.enabled && ( - - - - )} - - ) -} - -export default TextOnPath diff --git a/sites/shared/components/workbench/draft/text.mjs b/sites/shared/components/workbench/draft/text.mjs new file mode 100644 index 00000000000..a438c8348ff --- /dev/null +++ b/sites/shared/components/workbench/draft/text.mjs @@ -0,0 +1,148 @@ +import { useTranslation } from 'next-i18next' +import { Tr, KeyTd, ValTd, Attributes, pointCoords, pathInfo } from './path.mjs' + +const textInfo = (props) => + props.point ? ( +
+
Text info
+ + + + Coordinates + {pointCoords(props.point)} + + + Name + {props.pointName} + + + Part + {props.partName} + + + Attributes + + + + + +
+
+ + +
+
+ ) : null + +const XrayText = (props) => ( + + { + evt.stopPropagation() + props.showInfo(textInfo(props)) + }} + /> + +) + +const TextSpans = ({ point, className = '', style = {}, onClick = null }) => { + const { t } = useTranslation(['app']) + let text = [] + // Handle translation + let translated = '' + for (const string of point.attributes.getAsArray('data-text')) { + if (string) translated += t(string.toString()).replace(/"/g, '"') + ' ' + } + // Handle muti-line text + if (translated.indexOf('\n') !== -1) { + let key = 0 + let lines = translated.split('\n') + text.push({lines.shift()}) + for (let line of lines) { + key++ + text.push( + + {line.toString().replace(/"/g, '"')} + + ) + } + } else + text.push( + + {translated} + + ) + + return text +} + +export const Text = (props) => { + const attr = props.point.attributes.asPropsIfPrefixIs('data-text-') + + return ( + <> + + + + {props.gist._state?.xray?.enabled && } + + ) +} + +const XrayTextOnPath = (props) => ( + { + evt.stopPropagation() + props.showInfo(pathInfo(props)) + }} + /> +) + +export const TextOnPath = (props) => { + const { t } = useTranslation(['app']) + // Handle translation (and spaces) + let translated = '' + for (let string of props.path.attributes.getAsArray('data-text')) { + translated += t(string).replace(/"/g, '"') + ' ' + } + const textPathProps = { + xlinkHref: '#' + props.pathId, + startOffset: '0%', + } + const align = props.path.attributes.get('data-text-class') + if (align && align.indexOf('center') > -1) textPathProps.startOffset = '50%' + else if (align && align.indexOf('right') > -1) textPathProps.startOffset = '100%' + + const attr = props.path.attributes.asPropsIfPrefixIs('data-text-') + + return ( + + + + + {props.gist._state?.xray?.enabled && ( + + + + )} + + ) +} diff --git a/sites/shared/components/workbench/draft/text/index.js b/sites/shared/components/workbench/draft/text/index.js deleted file mode 100644 index 6bdd4e065f1..00000000000 --- a/sites/shared/components/workbench/draft/text/index.js +++ /dev/null @@ -1,109 +0,0 @@ -import { useTranslation } from 'next-i18next' -import { Tr, KeyTd, ValTd, Attributes, pointCoords } from '../path/index' - -const textInfo = (props) => props.point - ? ( -
-
Text info
- - - - Coordinates - {pointCoords(props.point)} - - - Name - {props.pointName} - - - Part - {props.partName} - - - Attributes - - - -
-
- - -
-
- ) : null - -const XrayText = props => ( - - { evt.stopPropagation(); props.showInfo(textInfo(props)) }} - /> - -) - -const TextSpans = ({ point, className='', style={}, onClick=null }) => { - const { t } = useTranslation(['app']) - let text = [] - // Handle translation - let translated = '' - for (const string of point.attributes.getAsArray('data-text')) { - if (string) translated += t(string.toString()).replace(/"/g, '"') + ' ' - } - // Handle muti-line text - if (translated.indexOf('\n') !== -1) { - let key = 0 - let lines = translated.split('\n') - text.push({lines.shift()}) - for (let line of lines) { - key++ - text.push( - - {line.toString().replace(/"/g, '"')} - - ) - } - } else text.push({translated}) - - return text - -} - -const Text = (props) => { - const attr = props.point.attributes.asPropsIfPrefixIs('data-text-') - - return ( - <> - - - - {props.gist._state?.xray?.enabled && } - - ) -} - -export default Text diff --git a/sites/shared/components/workbench/draft/utils.js b/sites/shared/components/workbench/draft/utils.mjs similarity index 100% rename from sites/shared/components/workbench/draft/utils.js rename to sites/shared/components/workbench/draft/utils.mjs diff --git a/sites/shared/components/workbench/exporting/export-handler.js b/sites/shared/components/workbench/exporting/export-handler.mjs similarity index 97% rename from sites/shared/components/workbench/exporting/export-handler.js rename to sites/shared/components/workbench/exporting/export-handler.mjs index c92160c3601..abd27ba6c22 100644 --- a/sites/shared/components/workbench/exporting/export-handler.js +++ b/sites/shared/components/workbench/exporting/export-handler.mjs @@ -1,8 +1,8 @@ import Worker from 'web-worker' import fileSaver from 'file-saver' import { themePlugin } from '@freesewing/plugin-theme' -import { pagesPlugin } from '../layout/print/plugin' -import { capitalize } from 'shared/utils' +import { pagesPlugin } from '../layout/print/plugin.mjs' +import { capitalize } from 'shared/utils.mjs' export const exportTypes = { exportForPrinting: ['a4', 'a3', 'a2', 'a1', 'a0', 'letter', 'tabloid'], diff --git a/sites/shared/components/workbench/exporting/export-worker.js b/sites/shared/components/workbench/exporting/export-worker.mjs similarity index 55% rename from sites/shared/components/workbench/exporting/export-worker.js rename to sites/shared/components/workbench/exporting/export-worker.mjs index 3f863a54ca6..4d83a5e90bd 100644 --- a/sites/shared/components/workbench/exporting/export-worker.js +++ b/sites/shared/components/workbench/exporting/export-worker.mjs @@ -3,43 +3,43 @@ * */ import yaml from 'js-yaml' import axios from 'axios' -import PdfMaker from './pdf-maker' +import { PdfMaker } from './pdf-maker' /** when the worker receives data from the page, do the appropriate export */ -addEventListener('message', async(e) => { - const {format, gist, svg} = e.data - // handle export by type +addEventListener('message', async (e) => { + const { format, gist, svg } = e.data + // handle export by type try { if (format === 'json') return exportJson(gist) - if (format === 'yaml') return exportYaml(gist) - if (format === 'github gist') return exportGithubGist(gist) + if (format === 'yaml') return exportYaml(gist) + if (format === 'github gist') return exportGithubGist(gist) if (format === 'svg') return exportSvg(svg) await exportPdf(e.data) } catch (e) { - postMessage({success: false, error: e}) + postMessage({ success: false, error: e }) close() } }) /** post a blob from a successful export */ const postSuccess = (blob) => { - postMessage({success: true, blob}) - close() + postMessage({ success: true, blob }) + close() } /** export a blob */ const exportBlob = (blobContent, type) => { const blob = new Blob([blobContent], { - type: `${type};charset=utf-8` + type: `${type};charset=utf-8`, }) postSuccess(blob) } const exportJson = (gist) => exportBlob(JSON.stringify(gist, null, 2), 'application/json') -const exportYaml = (gist) => exportBlob(yaml.dump(gist),'application/x-yaml') +const exportYaml = (gist) => exportBlob(yaml.dump(gist), 'application/x-yaml') const exportSvg = (svg) => exportBlob(svg, 'image/svg+xml') @@ -50,14 +50,15 @@ const exportPdf = async (data) => { } const exportGithubGist = (data) => { - axios.post('https://backend.freesewing.org/github/gist', { - design: data.design, - data: yaml.dump(data) - }) - .then(res => { - postMessage({ - success: true, - link: 'https://gist.github.com/' + res.data.id - }) - }) + axios + .post('https://backend.freesewing.org/github/gist', { + design: data.design, + data: yaml.dump(data), + }) + .then((res) => { + postMessage({ + success: true, + link: 'https://gist.github.com/' + res.data.id, + }) + }) } diff --git a/sites/shared/components/workbench/exporting/index.js b/sites/shared/components/workbench/exporting/index.mjs similarity index 87% rename from sites/shared/components/workbench/exporting/index.js rename to sites/shared/components/workbench/exporting/index.mjs index 150f5c14ff3..d7210d02fe7 100644 --- a/sites/shared/components/workbench/exporting/index.js +++ b/sites/shared/components/workbench/exporting/index.mjs @@ -1,10 +1,10 @@ import { useState } from 'react' import { useTranslation } from 'next-i18next' -import Popout from 'shared/components/popout' -import WebLink from 'shared/components/web-link' -import { exportTypes, handleExport } from './export-handler' +import { Popout } from 'shared/components/popout.mjs' +import { WebLink } from 'shared/components/web-link.mjs' +import { exportTypes, handleExport } from './export-handler.mjs' -const ExportDraft = ({ gist, design, app }) => { +export const ExportDraft = ({ gist, design, app }) => { const [link, setLink] = useState(false) const [error, setError] = useState(false) const [format, setFormat] = useState(false) @@ -64,5 +64,3 @@ const ExportDraft = ({ gist, design, app }) => {
) } - -export default ExportDraft diff --git a/sites/shared/components/workbench/exporting/pdf-maker.js b/sites/shared/components/workbench/exporting/pdf-maker.mjs similarity index 98% rename from sites/shared/components/workbench/exporting/pdf-maker.js rename to sites/shared/components/workbench/exporting/pdf-maker.mjs index 2bc94447aaf..0cad1567bbc 100644 --- a/sites/shared/components/workbench/exporting/pdf-maker.js +++ b/sites/shared/components/workbench/exporting/pdf-maker.mjs @@ -1,6 +1,6 @@ import PDFDocument from 'pdfkit/js/pdfkit.standalone' import SVGtoPDF from 'svg-to-pdfkit' -import { logoPath } from 'shared/components/icons.mjs' +import { logoPath } from 'shared/logos/freesewing.mjs' /** an svg of the logo to put on the cover page */ const logoSvg = ` @@ -18,7 +18,7 @@ const mmToPoints = 2.834645669291339 * Freesewing's first explicit class? * handles pdf exporting */ -export default class PdfMaker { +export class PdfMaker { /** the svg as text to embed in the pdf */ svg /** the document configuration */ diff --git a/sites/shared/components/workbench/gist-as-json.js b/sites/shared/components/workbench/gist-as-json.js deleted file mode 100644 index c6c5c9ee194..00000000000 --- a/sites/shared/components/workbench/gist-as-json.js +++ /dev/null @@ -1,9 +0,0 @@ -import Json from 'shared/components/json-highlight.js' - -const GistAsJson = props => ( -
- {JSON.stringify(props.gist, null, 2)} -
-) - -export default GistAsJson diff --git a/sites/shared/components/workbench/gist.mjs b/sites/shared/components/workbench/gist.mjs new file mode 100644 index 00000000000..addff81557b --- /dev/null +++ b/sites/shared/components/workbench/gist.mjs @@ -0,0 +1,58 @@ +import yaml from 'js-yaml' +import axios from 'axios' +import { Json } from 'shared/components/json.mjs' +import { Yaml } from 'shared/components/yaml.mjs' + +export const GistAsJson = (props) => ( +
+ {JSON.stringify(props.gist, null, 2)} +
+) + +export const GistAsYaml = (props) => ( +
+ +
+) + +export const defaultGist = { + sa: 0, + saBool: false, + saMm: 10, + scale: 1, + complete: true, + paperless: false, + units: 'metric', + locale: 'en', + margin: 2, + renderer: 'react', + embed: true, + debug: true, +} + +export const preloadGist = { + github: async (id, design) => { + let result + try { + result = await axios.get(`https://api.github.com/gists/${id}`) + } catch (err) { + console.log(err) + return [false, 'An unexpected error occured'] + } + + if (result.data.files['pattern.yaml'].content) { + let g = yaml.load(result.data.files['pattern.yaml'].content) + + if (g.design !== undefined && g.design !== design.designConfig.data.name) + return [ + false, + `You tried loading a configuration for ${g.design} into a ${design.designConfig.data.name} development environment`, + ] + + return g + } + + // TODO notify people of these errors + else return [false, 'This gist does not seem to be a valid pattern configuration'] + }, +} diff --git a/sites/shared/components/workbench/inputs/design-option-count.js b/sites/shared/components/workbench/inputs/design-option-count.mjs similarity index 97% rename from sites/shared/components/workbench/inputs/design-option-count.js rename to sites/shared/components/workbench/inputs/design-option-count.mjs index e9d95ed213a..9e39d2840e3 100644 --- a/sites/shared/components/workbench/inputs/design-option-count.js +++ b/sites/shared/components/workbench/inputs/design-option-count.mjs @@ -23,7 +23,7 @@ const EditCount = (props) => ( ) -const DesignOptionCount = (props) => { +export const DesignOptionCount = (props) => { const { t } = useTranslation(['app']) const { count, max, min } = props.design.patternConfig.options[props.option] const val = @@ -104,5 +104,3 @@ const DesignOptionCount = (props) => { ) } - -export default DesignOptionCount diff --git a/sites/shared/components/workbench/inputs/design-option-list.js b/sites/shared/components/workbench/inputs/design-option-list.mjs similarity index 97% rename from sites/shared/components/workbench/inputs/design-option-list.js rename to sites/shared/components/workbench/inputs/design-option-list.mjs index d0c4d7df9b7..479c2d1770b 100644 --- a/sites/shared/components/workbench/inputs/design-option-list.js +++ b/sites/shared/components/workbench/inputs/design-option-list.mjs @@ -2,7 +2,7 @@ import { useState } from 'react' import { ClearIcon } from 'shared/components/icons.mjs' import { useTranslation } from 'next-i18next' -const DesignOptionList = (props) => { +export const DesignOptionList = (props) => { const { t } = useTranslation([`o_${props.design.designConfig.data.name}`]) const { dflt, list, doNotTranslate = false } = props.design.patternConfig.options[props.option] const val = diff --git a/sites/shared/components/workbench/inputs/design-option-pct-deg.js b/sites/shared/components/workbench/inputs/design-option-pct-deg.mjs similarity index 98% rename from sites/shared/components/workbench/inputs/design-option-pct-deg.js rename to sites/shared/components/workbench/inputs/design-option-pct-deg.mjs index 56567970864..dc0bd3164f9 100644 --- a/sites/shared/components/workbench/inputs/design-option-pct-deg.js +++ b/sites/shared/components/workbench/inputs/design-option-pct-deg.mjs @@ -33,7 +33,7 @@ const EditOption = (props) => ( ) -const DesignOptionPctDeg = (props) => { +export const DesignOptionPctDeg = (props) => { const { t } = useTranslation(['app']) const suffix = props.type === 'deg' ? '°' : '%' const factor = props.type === 'deg' ? 1 : 100 @@ -134,5 +134,3 @@ const DesignOptionPctDeg = (props) => { ) } - -export default DesignOptionPctDeg diff --git a/sites/shared/components/workbench/inputs/measurement.js b/sites/shared/components/workbench/inputs/measurement.mjs similarity index 57% rename from sites/shared/components/workbench/inputs/measurement.js rename to sites/shared/components/workbench/inputs/measurement.mjs index 362095eab9d..ecbb9a228f2 100644 --- a/sites/shared/components/workbench/inputs/measurement.js +++ b/sites/shared/components/workbench/inputs/measurement.mjs @@ -1,7 +1,7 @@ import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react' import { useTranslation } from 'next-i18next' import { isDegreeMeasurement } from '../../../config/measurements' -import { measurementAsMm } from 'shared/utils' +import { measurementAsMm } from 'shared/utils.mjs' /* * This is a single input for a measurements @@ -11,68 +11,73 @@ import { measurementAsMm } from 'shared/utils' * m holds the measurement name. It's just so long to type * measurement and I always have some typo in it because dyslexia. */ -const MeasurementInput = ({ m, gist, app, updateMeasurements, focus }) => { +export const MeasurementInput = ({ m, gist, app, updateMeasurements, focus }) => { 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 isDegree = isDegreeMeasurement(m); - const factor = useMemo(() => (isDegree ? 1 : (gist.units == 'imperial' ? 25.4 : 10)), [gist.units]) + const isDegree = isDegreeMeasurement(m) + const factor = useMemo(() => (isDegree ? 1 : gist.units == 'imperial' ? 25.4 : 10), [gist.units]) - const isValValid = val => (typeof val === 'undefined' || val === '') - ? null - : val != false && !isNaN(val) - const isValid = (newVal) => (typeof newVal === 'undefined') - ? isValValid(val) - : isValValid(newVal) + const isValValid = (val) => + typeof val === 'undefined' || val === '' ? null : val != false && !isNaN(val) + const isValid = (newVal) => (typeof newVal === 'undefined' ? isValValid(val) : isValValid(newVal)) const [val, setVal] = useState(gist.measurements?.[m] / factor || '') // keep a single reference to a debounce timer - const debounceTimeout = useRef(null); - const input = useRef(null); + const debounceTimeout = useRef(null) + const input = useRef(null) // onChange - const update = useCallback((evt) => { - evt.stopPropagation(); - let evtVal = evt.target.value; - // set Val immediately so that the input reflects it - setVal(evtVal) + const update = useCallback( + (evt) => { + evt.stopPropagation() + let evtVal = evt.target.value + // set Val immediately so that the input reflects it + setVal(evtVal) - let useVal = isDegree ? evtVal : measurementAsMm(evtVal, gist.units); - const ok = isValid(useVal) - // only set to the gist if it's valid - if (ok) { - // debounce in case it's still changing - if (debounceTimeout.current !== null) { clearTimeout(debounceTimeout.current); } - debounceTimeout.current = setTimeout(() => { - // clear the timeout reference - debounceTimeout.current = null; - updateMeasurements(useVal, m) - }, 500); - } - }, [gist.units]) + let useVal = isDegree ? evtVal : measurementAsMm(evtVal, gist.units) + const ok = isValid(useVal) + // only set to the gist if it's valid + if (ok) { + // debounce in case it's still changing + if (debounceTimeout.current !== null) { + clearTimeout(debounceTimeout.current) + } + debounceTimeout.current = setTimeout(() => { + // clear the timeout reference + debounceTimeout.current = null + updateMeasurements(useVal, m) + }, 500) + } + }, + [gist.units] + ) // use this for better update efficiency // FIXME: This breaks gist updates. // See: https://github.com/freesewing/freesewing/issues/2281 const memoVal = useMemo(() => gist.measurements?.[m], [gist]) // track validity against the value and the units - const valid = useMemo(() => isValid(isDegree ? val : measurementAsMm(val, gist.units)), [val, gist.units]) + const valid = useMemo( + () => isValid(isDegree ? val : measurementAsMm(val, gist.units)), + [val, gist.units] + ) // hook to update the value or format when the gist changes useEffect(() => { - // set the value to the proper value and format - if (memoVal) { - let gistVal = +(memoVal / factor).toFixed(2); - setVal(gistVal) - } + // set the value to the proper value and format + if (memoVal) { + let gistVal = +(memoVal / factor).toFixed(2) + setVal(gistVal) + } }, [memoVal, factor]) // focus when prompted by parent useEffect(() => { if (focus) { - input.current.focus(); + input.current.focus() } }, [focus]) @@ -110,25 +115,27 @@ const MeasurementInput = ({ m, gist, app, updateMeasurements, focus }) => { value={val} onChange={update} /> - - {(valid === true) && '👍'} - {(valid === false) && '🤔'} + `} + > + {valid === true && '👍'} + {valid === false && '🤔'} - - {isDegree ? '° ' : gist.units == 'metric' ? 'cm' : 'in'} + `} + > + {isDegree ? '° ' : gist.units == 'metric' ? 'cm' : 'in'} ) } - -export default MeasurementInput - diff --git a/sites/shared/components/workbench/layout/cut/index.js b/sites/shared/components/workbench/layout/cut/index.mjs similarity index 50% rename from sites/shared/components/workbench/layout/cut/index.js rename to sites/shared/components/workbench/layout/cut/index.mjs index f7c5e87fc10..ab3c7226493 100644 --- a/sites/shared/components/workbench/layout/cut/index.js +++ b/sites/shared/components/workbench/layout/cut/index.mjs @@ -1,23 +1,15 @@ import { useTranslation } from 'next-i18next' -import Settings from './settings' +import { CutLayoutSettings } from './settings.mjs' -const CutLayout = props => { +export const CutLayout = (props) => { const { t } = useTranslation(['workbench']) let name = props.design.designConfig.data.name name = name.replace('@freesewing/', '') return (
-

- { - t('layoutThing', { thing: name }) - + ': ' - + t('forCutting') - } -

+

{t('layoutThing', { thing: name }) + ': ' + t('forCutting')}

) } - -export default CutLayout diff --git a/sites/shared/components/workbench/layout/cut/settings.js b/sites/shared/components/workbench/layout/cut/settings.mjs similarity index 53% rename from sites/shared/components/workbench/layout/cut/settings.js rename to sites/shared/components/workbench/layout/cut/settings.mjs index d71f192bb34..ef88eec44f9 100644 --- a/sites/shared/components/workbench/layout/cut/settings.js +++ b/sites/shared/components/workbench/layout/cut/settings.mjs @@ -1,10 +1,7 @@ -const CutLayoutSettings = props => { - +export const CutLayoutSettings = (props) => { return (

Fixme: Cut layout settings here

) } - -export default CutLayoutSettings diff --git a/sites/shared/components/workbench/layout/default.mjs b/sites/shared/components/workbench/layout/default.mjs new file mode 100644 index 00000000000..ed781b9f351 --- /dev/null +++ b/sites/shared/components/workbench/layout/default.mjs @@ -0,0 +1,222 @@ +// Hooks +import { useState, Fragment } from 'react' +import { useRouter } from 'next/router' +// Depenencies +import get from 'lodash.get' +// Components +import Link from 'next/link' +import { FreeSewingLogo } from 'shared/components/logos/freesewing.mjs' +import { PrimaryNavigation } from 'shared/components/navigation/primary.mjs' +import { RightIcon, LeftIcon } from 'shared/components/icons.mjs' +import { Header } from 'site/components/header.mjs' +import { Footer } from 'site/components/footer.mjs' +import { Search } from 'site/components/search.mjs' + +export const PageTitle = ({ app, slug, title }) => { + if (title) return

{title}

+ if (slug) return

{get(app.navigation, slug.split('/')).__title}

+ + return

FIXME: This page has no title

+} + +const Breadcrumbs = ({ app, slug = false, title }) => { + if (!slug) return null + const crumbs = [] + const chunks = slug.split('/') + for (const i in chunks) { + const j = parseInt(i) + parseInt(1) + const page = get(app.navigation, chunks.slice(0, j)) + if (page) crumbs.push([page.__linktitle, '/' + chunks.slice(0, j).join('/'), j < chunks.length]) + } + + return ( +
    +
  • + + + +
  • + {crumbs.map((crumb) => ( + +
  • »
  • +
  • + {crumb[2] ? ( + + {crumb[0]} + + ) : ( + {crumb[0]} + )} +
  • +
    + ))} +
+ ) +} + +const asideClasses = ` + fixed top-0 right-0 + pt-28 + sm:pt-8 sm:mt-16 + pb-4 px-2 + sm:relative sm:transform-none + h-screen w-screen + bg-base-100 + sm:bg-base-50 + sm:flex + sm:sticky + overflow-y-scroll + z-20 + bg-base-100 text-base-content + transition-all + xl:w-1/4 +` + +export const DefaultLayout = ({ + app, + title = false, + children = [], + search, + setSearch, + noSearch = false, + workbench = false, + AltMenu = null, +}) => { + const startNavigation = () => { + app.startLoading() + // Force close of menu on mobile if it is open + if (app.primaryNavigation) app.setPrimaryNavigation(false) + // Force close of search modal if it is open + if (search) setSearch(false) + } + + const router = useRouter() + router.events?.on('routeChangeStart', startNavigation) + router.events?.on('routeChangeComplete', () => app.stopLoading()) + const slug = router.asPath.slice(1) + const [collapsePrimaryNav, setCollapsePrimaryNav] = useState(workbench || false) + const [collapseAltMenu, setCollapseAltMenu] = useState(false) + + return ( +
+
+
+
+ + +
+
+
+ {title && ( + <> + + + + )} + {children} +
+
+
+
+ + {workbench && AltMenu && ( + + )} +
+ {!noSearch && search && ( + <> +
+ +
+
+ + )} +
+
+ ) +} diff --git a/sites/shared/components/workbench/layout/draft/buttons.js b/sites/shared/components/workbench/layout/draft/buttons.js deleted file mode 100644 index a9e8fd7c9bb..00000000000 --- a/sites/shared/components/workbench/layout/draft/buttons.js +++ /dev/null @@ -1,66 +0,0 @@ -import {FlipIconInner} from 'shared/components/icons/flip' -import {RotateIconInner} from 'shared/components/icons/rotate' -import {ClearIconInner} from 'shared/components/icons/clear' -import { useTranslation } from 'next-i18next' - -const rectSize = 24 - -const Button = ({onClickCb, transform, Icon, children}) => { - const _onClick = (event) => { - event.stopPropagation(); - onClickCb(event); - } - - return - - - {children} - - } - -/** buttons for manipulating the part */ -const Buttons = ({ transform, flip, rotate, setRotate, resetPart, rotate90}) => { - const {t} = useTranslation('workbench') - return ( - - {rotate - ? - : - } - - - - - - - ) -} - -export default Buttons diff --git a/sites/shared/components/workbench/layout/draft/buttons.mjs b/sites/shared/components/workbench/layout/draft/buttons.mjs new file mode 100644 index 00000000000..e41f9ee57c5 --- /dev/null +++ b/sites/shared/components/workbench/layout/draft/buttons.mjs @@ -0,0 +1,98 @@ +import { useTranslation } from 'next-i18next' + +const Triangle = ({ transform = 'translate(0,0)', fill = 'currentColor' }) => ( + +) + +const FlipIconInner = ({ x = 0, y = 0, rotate = 0, ...style }) => ( + + + + + + +) + +const RotateIconInner = ({ flipX = false }) => ( + +) + +const rectSize = 24 + +const Button = ({ onClickCb, transform, Icon, children }) => { + const _onClick = (event) => { + event.stopPropagation() + onClickCb(event) + } + + return ( + + + + {children} + + + ) +} + +/** buttons for manipulating the part */ +export const Buttons = ({ transform, flip, rotate, setRotate, resetPart, rotate90 }) => { + const { t } = useTranslation('workbench') + return ( + + {rotate ? ( + + ) : ( + + )} + + + + + + + ) +} diff --git a/sites/shared/components/workbench/layout/draft/index.js b/sites/shared/components/workbench/layout/draft/index.mjs similarity index 95% rename from sites/shared/components/workbench/layout/draft/index.js rename to sites/shared/components/workbench/layout/draft/index.mjs index 50d8f20b621..3f01508dba0 100644 --- a/sites/shared/components/workbench/layout/draft/index.js +++ b/sites/shared/components/workbench/layout/draft/index.mjs @@ -1,9 +1,9 @@ import { useRef } from 'react' -import Stack from './stack' -import SvgWrapper from '../../draft/svg-wrapper' -import { PartInner } from '../../draft/part' +import { Stack } from './stack.mjs' +import { SvgWrapper } from '../../draft/svg.mjs' +import { PartInner } from '../../draft/part.mjs' -const Draft = (props) => { +export const Draft = (props) => { const { draft, patternProps, @@ -111,5 +111,3 @@ const Draft = (props) => { ) } - -export default Draft diff --git a/sites/shared/components/workbench/layout/draft/stack.js b/sites/shared/components/workbench/layout/draft/stack.mjs similarity index 98% rename from sites/shared/components/workbench/layout/draft/stack.js rename to sites/shared/components/workbench/layout/draft/stack.mjs index ed2d189f9e4..048a422e6a6 100644 --- a/sites/shared/components/workbench/layout/draft/stack.js +++ b/sites/shared/components/workbench/layout/draft/stack.mjs @@ -43,15 +43,15 @@ * I've sort of left it at this because I'm starting to wonder if we should perhaps re-think * how custom layouts are supported in the core. And I would like to discuss this with the core team. */ -import Part from '../../draft/part' +import { useRef, useState, useEffect } from 'react' import { generateStackTransform } from '@freesewing/core' -import { getProps, angle } from '../../draft/utils' +import { Part } from '../../draft/part.mjs' +import { getProps, angle } from '../../draft/utils.mjs' import { drag } from 'd3-drag' import { select } from 'd3-selection' -import { useRef, useState, useEffect } from 'react' -import Buttons from './buttons' +import { Buttons } from './buttons.mjs' -const Stack = (props) => { +export const Stack = (props) => { const { layout, stack, stackName, gist } = props const stackLayout = layout.stacks?.[stackName] @@ -265,5 +265,3 @@ const Stack = (props) => { ) } - -export default Stack diff --git a/sites/shared/components/workbench/layout/print/index.js b/sites/shared/components/workbench/layout/print/index.mjs similarity index 86% rename from sites/shared/components/workbench/layout/print/index.js rename to sites/shared/components/workbench/layout/print/index.mjs index aef51f45348..a1c106ba87d 100644 --- a/sites/shared/components/workbench/layout/print/index.js +++ b/sites/shared/components/workbench/layout/print/index.mjs @@ -1,15 +1,15 @@ import { useEffect, useState } from 'react' import { useTranslation } from 'next-i18next' -import Settings from './settings' -import Draft from '../draft/index' -import { pagesPlugin } from './plugin' +import { Settings } from './settings.mjs' +import { Draft } from '../draft/index.mjs' +import { pagesPlugin } from './plugin.mjs' import { handleExport, defaultPdfSettings, -} from 'shared/components/workbench/exporting/export-handler' -import Popout from 'shared/components/popout' +} from 'shared/components/workbench/exporting/export-handler.mjs' +import { Popout } from 'shared/components/popout.mjs' -const PrintLayout = (props) => { +export const PrintLayout = (props) => { // disable xray useEffect(() => { if (props.gist?._state?.xray?.enabled) props.updateGist(['_state', 'xray', 'enabled'], false) @@ -76,5 +76,3 @@ const PrintLayout = (props) => { ) } - -export default PrintLayout diff --git a/sites/shared/components/workbench/layout/print/orientation-picker.js b/sites/shared/components/workbench/layout/print/orientation-picker.mjs similarity index 89% rename from sites/shared/components/workbench/layout/print/orientation-picker.js rename to sites/shared/components/workbench/layout/print/orientation-picker.mjs index 84a6928a556..ba20d81a6e2 100644 --- a/sites/shared/components/workbench/layout/print/orientation-picker.js +++ b/sites/shared/components/workbench/layout/print/orientation-picker.mjs @@ -1,7 +1,7 @@ import { PageIcon } from 'shared/components/icons.mjs' import { useTranslation } from 'next-i18next' -const PageOrientationPicker = ({ gist, updateGist }) => { +export const PageOrientationPicker = ({ gist, updateGist }) => { const { t } = useTranslation(['workbench']) return ( @@ -30,5 +30,3 @@ const PageOrientationPicker = ({ gist, updateGist }) => { ) } - -export default PageOrientationPicker diff --git a/sites/shared/components/workbench/layout/print/pagesize-picker.js b/sites/shared/components/workbench/layout/print/pagesize-picker.mjs similarity index 93% rename from sites/shared/components/workbench/layout/print/pagesize-picker.js rename to sites/shared/components/workbench/layout/print/pagesize-picker.mjs index e337e8852c9..5f586e59ed9 100644 --- a/sites/shared/components/workbench/layout/print/pagesize-picker.js +++ b/sites/shared/components/workbench/layout/print/pagesize-picker.mjs @@ -1,10 +1,10 @@ import { PageSizeIcon } from 'shared/components/icons.mjs' import { useTranslation } from 'next-i18next' -import Popout from 'shared/components/popout' +import { Popout } from 'shared/components/popout.mjs' const sizes = ['a4', 'a3', 'a2', 'a1', 'a0', 'letter', 'tabloid'] -const PageSizePicker = ({ gist, updateGist }) => { +export const PageSizePicker = ({ gist, updateGist }) => { const { t } = useTranslation(['workbench']) const setSize = (size) => { updateGist(['_state', 'layout', 'forPrinting', 'page', 'size'], size) @@ -56,5 +56,3 @@ const PageSizePicker = ({ gist, updateGist }) => { ) } - -export default PageSizePicker diff --git a/sites/shared/components/workbench/layout/print/plugin.js b/sites/shared/components/workbench/layout/print/plugin.mjs similarity index 100% rename from sites/shared/components/workbench/layout/print/plugin.js rename to sites/shared/components/workbench/layout/print/plugin.mjs diff --git a/sites/shared/components/workbench/layout/print/settings.js b/sites/shared/components/workbench/layout/print/settings.mjs similarity index 94% rename from sites/shared/components/workbench/layout/print/settings.js rename to sites/shared/components/workbench/layout/print/settings.mjs index 555a1c80a1a..017ea86d845 100644 --- a/sites/shared/components/workbench/layout/print/settings.js +++ b/sites/shared/components/workbench/layout/print/settings.mjs @@ -1,9 +1,9 @@ -import PageSizePicker from './pagesize-picker' -import OrientationPicker from './orientation-picker' +import { PageSizePicker } from './pagesize-picker.mjs' +import { OrientationPicker } from './orientation-picker.mjs' import { PrintIcon, RightIcon, ClearIcon, ExportIcon } from 'shared/components/icons.mjs' import { useTranslation } from 'next-i18next' -const PrintLayoutSettings = (props) => { +export const PrintLayoutSettings = (props) => { const { t } = useTranslation(['workbench']) let pages = props.draft?.setStores[0].get('pages') if (!pages) return null @@ -106,5 +106,3 @@ const PrintLayoutSettings = (props) => { ) } - -export default PrintLayoutSettings diff --git a/sites/shared/components/workbench/logs.js b/sites/shared/components/workbench/logs.mjs similarity index 100% rename from sites/shared/components/workbench/logs.js rename to sites/shared/components/workbench/logs.mjs diff --git a/sites/shared/components/workbench/menu/core-settings/core-setting-bool.js b/sites/shared/components/workbench/menu/core-settings/core-setting-bool.mjs similarity index 69% rename from sites/shared/components/workbench/menu/core-settings/core-setting-bool.js rename to sites/shared/components/workbench/menu/core-settings/core-setting-bool.mjs index 9cdeff3bd2e..6e5e9b7614c 100644 --- a/sites/shared/components/workbench/menu/core-settings/core-setting-bool.js +++ b/sites/shared/components/workbench/menu/core-settings/core-setting-bool.mjs @@ -1,9 +1,8 @@ import { useState } from 'react' -import { SecText, SumButton, Li, SumDiv, Deg } from 'shared/components/workbench/menu/index.js' import { useTranslation } from 'next-i18next' +import { SecText, SumButton, Li, SumDiv, Deg } from 'shared/components/workbench/menu/index.mjs' -const CoreSettingBool = props => { - +export const CoreSettingBool = (props) => { const { t } = useTranslation(['app']) const [value, setValue] = useState(props.gist[props.setting]) @@ -17,12 +16,10 @@ const CoreSettingBool = props => { - { t(`settings:${props.setting}.t`) } + {t(`settings:${props.setting}.t`)} - { t(value ? 'yes' : 'no')} + {t(value ? 'yes' : 'no')} ) } - -export default CoreSettingBool diff --git a/sites/shared/components/workbench/menu/core-settings/core-setting-list.js b/sites/shared/components/workbench/menu/core-settings/core-setting-list.mjs similarity index 87% rename from sites/shared/components/workbench/menu/core-settings/core-setting-list.js rename to sites/shared/components/workbench/menu/core-settings/core-setting-list.mjs index 30c4b1797bf..b2a894929dd 100644 --- a/sites/shared/components/workbench/menu/core-settings/core-setting-list.js +++ b/sites/shared/components/workbench/menu/core-settings/core-setting-list.mjs @@ -1,8 +1,8 @@ import { useState } from 'react' -import { Deg } from 'shared/components/workbench/menu/index.js' import { useTranslation } from 'next-i18next' +import { Deg } from 'shared/components/workbench/menu/index.mjs' -const CoreSettingList = props => { +export const CoreSettingList = (props) => { const { t } = useTranslation(['settings']) const { dflt } = props const val = props.gist?.[props.setting] @@ -29,7 +29,7 @@ const CoreSettingList = props => {

- {props.list.map(entry => ( + {props.list.map((entry) => (
) } - -export default CoreSettingList diff --git a/sites/shared/components/workbench/menu/core-settings/core-setting-mm.js b/sites/shared/components/workbench/menu/core-settings/core-setting-mm.mjs similarity index 94% rename from sites/shared/components/workbench/menu/core-settings/core-setting-mm.js rename to sites/shared/components/workbench/menu/core-settings/core-setting-mm.mjs index 52a68771d01..e181aeb1397 100644 --- a/sites/shared/components/workbench/menu/core-settings/core-setting-mm.js +++ b/sites/shared/components/workbench/menu/core-settings/core-setting-mm.mjs @@ -1,9 +1,9 @@ import { useState } from 'react' -import { formatMm } from 'shared/utils' -import { ClearIcon } from 'shared/components/icons.mjs' import { useTranslation } from 'next-i18next' +import { formatMm } from 'shared/utils.mjs' +import { ClearIcon } from 'shared/components/icons.mjs' -const CoreSettingMm = (props) => { +export const CoreSettingMm = (props) => { const { t } = useTranslation(['app', 'settings']) const { dflt, min, max } = props const val = props.gist?.[props.setting] @@ -69,5 +69,3 @@ const CoreSettingMm = (props) => {
) } - -export default CoreSettingMm diff --git a/sites/shared/components/workbench/menu/core-settings/core-setting-nr.js b/sites/shared/components/workbench/menu/core-settings/core-setting-nr.mjs similarity index 96% rename from sites/shared/components/workbench/menu/core-settings/core-setting-nr.js rename to sites/shared/components/workbench/menu/core-settings/core-setting-nr.mjs index 095706b46f0..310735858d9 100644 --- a/sites/shared/components/workbench/menu/core-settings/core-setting-nr.js +++ b/sites/shared/components/workbench/menu/core-settings/core-setting-nr.mjs @@ -2,7 +2,7 @@ import { useState } from 'react' import { ClearIcon } from 'shared/components/icons.mjs' import { useTranslation } from 'next-i18next' -const CoreSettingNr = (props) => { +export const CoreSettingNr = (props) => { const { t } = useTranslation(['app', 'settings']) const { dflt, min, max } = props const val = props.gist?.[props.setting] @@ -61,5 +61,3 @@ const CoreSettingNr = (props) => { ) } - -export default CoreSettingNr diff --git a/sites/shared/components/workbench/menu/core-settings/core-setting-only.js b/sites/shared/components/workbench/menu/core-settings/core-setting-only.mjs similarity index 96% rename from sites/shared/components/workbench/menu/core-settings/core-setting-only.js rename to sites/shared/components/workbench/menu/core-settings/core-setting-only.mjs index 6223bb3473e..3e3f1f44222 100644 --- a/sites/shared/components/workbench/menu/core-settings/core-setting-only.js +++ b/sites/shared/components/workbench/menu/core-settings/core-setting-only.mjs @@ -2,7 +2,7 @@ import { ClearIcon } from 'shared/components/icons.mjs' import orderBy from 'lodash.orderby' import { useTranslation } from 'next-i18next' -const CoreSettingOnly = (props) => { +export const CoreSettingOnly = (props) => { const { t } = useTranslation(['app', 'parts', 'settings']) const list = props.draft.config.draftOrder const partNames = list.map((part) => ({ id: part, name: t(`parts:${part}`) })) @@ -66,5 +66,3 @@ const CoreSettingOnly = (props) => { ) } - -export default CoreSettingOnly diff --git a/sites/shared/components/workbench/menu/core-settings/core-setting-sa-bool.js b/sites/shared/components/workbench/menu/core-settings/core-setting-sa-bool.mjs similarity index 75% rename from sites/shared/components/workbench/menu/core-settings/core-setting-sa-bool.js rename to sites/shared/components/workbench/menu/core-settings/core-setting-sa-bool.mjs index 4aff106cec0..460aae7eef6 100644 --- a/sites/shared/components/workbench/menu/core-settings/core-setting-sa-bool.js +++ b/sites/shared/components/workbench/menu/core-settings/core-setting-sa-bool.mjs @@ -1,9 +1,8 @@ import { useState } from 'react' -import { SecText, SumButton, Li, SumDiv, Deg } from 'shared/components/workbench/menu/index.js' import { useTranslation } from 'next-i18next' +import { SecText, SumButton, Li, SumDiv, Deg } from 'shared/components/workbench/menu/index.mjs' -const CoreSettingSaBool = props => { - +export const CoreSettingSaBool = (props) => { const { t } = useTranslation(['app', 'settings']) const [value, setValue] = useState(props.gist.saBool || false) @@ -11,7 +10,7 @@ const CoreSettingSaBool = props => { props.setGist({ ...props.gist, saBool: !value, - sa: value ? 0 : props.gist.saMm + sa: value ? 0 : props.gist.saMm, }) setValue(!value) } @@ -21,12 +20,10 @@ const CoreSettingSaBool = props => { - { t('settings:sabool.t') } + {t('settings:sabool.t')} {t(value ? 'yes' : 'no')} ) } - -export default CoreSettingSaBool diff --git a/sites/shared/components/workbench/menu/core-settings/core-setting-sa-mm.js b/sites/shared/components/workbench/menu/core-settings/core-setting-sa-mm.mjs similarity index 94% rename from sites/shared/components/workbench/menu/core-settings/core-setting-sa-mm.js rename to sites/shared/components/workbench/menu/core-settings/core-setting-sa-mm.mjs index 620a7f97e19..93c662d22db 100644 --- a/sites/shared/components/workbench/menu/core-settings/core-setting-sa-mm.js +++ b/sites/shared/components/workbench/menu/core-settings/core-setting-sa-mm.mjs @@ -1,9 +1,9 @@ import { useState } from 'react' -import { formatMm } from 'shared/utils' +import { formatMm } from 'shared/utils.mjs' import { ClearIcon } from 'shared/components/icons.mjs' import { useTranslation } from 'next-i18next' -const CoreSettingMm = (props) => { +export const CoreSettingMm = (props) => { const { t } = useTranslation(['app', 'settings']) const { dflt, min, max } = props const val = props.gist?.[props.setting] @@ -70,5 +70,3 @@ const CoreSettingMm = (props) => { ) } - -export default CoreSettingMm diff --git a/sites/shared/components/workbench/menu/core-settings/index.js b/sites/shared/components/workbench/menu/core-settings/index.mjs similarity index 100% rename from sites/shared/components/workbench/menu/core-settings/index.js rename to sites/shared/components/workbench/menu/core-settings/index.mjs diff --git a/sites/shared/components/workbench/menu/core-settings/setting.js b/sites/shared/components/workbench/menu/core-settings/setting.js deleted file mode 100644 index ea75ac8b7b2..00000000000 --- a/sites/shared/components/workbench/menu/core-settings/setting.js +++ /dev/null @@ -1,116 +0,0 @@ -import { Chevron } from 'shared/components/navigation/primary' -import ListSetting from './core-setting-list' -import OnlySetting from './core-setting-only' -import MmSetting from './core-setting-mm' -import NrSetting from './core-setting-nr' -import BoolSetting from './core-setting-bool' -import SaBoolSetting from './core-setting-sa-bool' -import SaMmSetting from './core-setting-sa-mm' -import { formatMm } from 'shared/utils' -import { SecText, Li, Details, Summary, SumDiv, Deg } from 'shared/components/workbench/menu/index' -import { useTranslation } from 'next-i18next' - -const settings = { - paperless: props => ( - - {props.t(props.gist.paperless ? 'yes' : 'no')} - - ), - complete: props => ( - - {props.t(props.gist.complete ? 'yes' : 'no')} - - ), - debug: props => ( - - {props.t(props.gist.debug ? 'yes' : 'no')} - - ), - locale: props => ( - - {props.t(`i18n:${props.gist.locale}`)} - - ), - units: props => ( - - {props.t(`${props.gist.units}Units`)} - - ), - margin: props => , - scale: props => props.gist.scale === 1 - ? {props.gist.scale} - : {props.gist.scale}, - saMm: props => , - renderer: props => ( - - {props.config.titles[props.gist.renderer]} - - ), - only: props => (props.gist?.only && props.gist.only.length > 0) - ? {props.gist.only.length} - : {props.t('default')} -} - -const inputs = { - locale: props => ({ - key, - title: props.t(`i18n:${key}`) - }))} - />, - units: props => ({ - key, - title: props.t(`${key}Units`) - }))} - />, - margin: props => , - scale: props => , - saMm: props => , - renderer: props => ({ - key, - title: props.config.titles[key] - }))} - />, - only: props => -} - -const Setting = props => { - const { t } = useTranslation(['app', 'i18n', 'settings']) - if (props.setting === 'saBool') - return - if (['paperless', 'complete', 'debug', 'xray'].indexOf(props.setting) !== -1) - return - - const Input = inputs[props.setting] - const Value = settings[props.setting] - - return ( -
  • -
    - - - - {props.setting === 'saMm' - ? ( - <> - {t(`settings:sa.t`)} - - ) - : {t(`settings:${props.setting}.t`)} - } - - - - - -
    -
  • - ) -} - -export default Setting diff --git a/sites/shared/components/workbench/menu/core-settings/setting.mjs b/sites/shared/components/workbench/menu/core-settings/setting.mjs new file mode 100644 index 00000000000..491642573fa --- /dev/null +++ b/sites/shared/components/workbench/menu/core-settings/setting.mjs @@ -0,0 +1,107 @@ +import { Chevron } from 'shared/components/navigation/primary.mjs' +import { CoreSettingList as ListSetting } from './core-setting-list.mjs' +import { CoreSettingOnly as OnlySetting } from './core-setting-only.mjs' +import { CoreSettingMm as MmSetting } from './core-setting-mm.mjs' +import { CoreSettingNr as NrSetting } from './core-setting-nr.mjs' +import { CoreSettingBool as BoolSetting } from './core-setting-bool.mjs' +import { CoreSettingSaBool as SaBoolSetting } from './core-setting-sa-bool.mjs' +import { CoreSettingSaMm as SaMmSetting } from './core-setting-sa-mm.mjs' +import { formatMm } from 'shared/utils.mjs' +import { + SecText, + Li, + Details, + Summary, + SumDiv, + Deg, +} from 'shared/components/workbench/menu/index.mjs' +import { useTranslation } from 'next-i18next' + +const settings = { + paperless: (props) => {props.t(props.gist.paperless ? 'yes' : 'no')}, + complete: (props) => {props.t(props.gist.complete ? 'yes' : 'no')}, + debug: (props) => {props.t(props.gist.debug ? 'yes' : 'no')}, + locale: (props) => {props.t(`i18n:${props.gist.locale}`)}, + units: (props) => {props.t(`${props.gist.units}Units`)}, + margin: (props) => , + scale: (props) => + props.gist.scale === 1 ? ( + {props.gist.scale} + ) : ( + {props.gist.scale} + ), + saMm: (props) => , + renderer: (props) => {props.config.titles[props.gist.renderer]}, + only: (props) => + props.gist?.only && props.gist.only.length > 0 ? ( + {props.gist.only.length} + ) : ( + {props.t('default')} + ), +} + +const inputs = { + locale: (props) => ( + ({ + key, + title: props.t(`i18n:${key}`), + }))} + /> + ), + units: (props) => ( + ({ + key, + title: props.t(`${key}Units`), + }))} + /> + ), + margin: (props) => , + scale: (props) => , + saMm: (props) => , + renderer: (props) => ( + ({ + key, + title: props.config.titles[key], + }))} + /> + ), + only: (props) => , +} + +export const Setting = (props) => { + const { t } = useTranslation(['app', 'i18n', 'settings']) + if (props.setting === 'saBool') return + if (['paperless', 'complete', 'debug', 'xray'].indexOf(props.setting) !== -1) + return + + const Input = inputs[props.setting] + const Value = settings[props.setting] + + return ( +
  • +
    + + + + {props.setting === 'saMm' ? ( + <> + {t(`settings:sa.t`)} + + ) : ( + {t(`settings:${props.setting}.t`)} + )} + + + + + +
    +
  • + ) +} diff --git a/sites/shared/components/workbench/menu/design-options/index.js b/sites/shared/components/workbench/menu/design-options/index.mjs similarity index 85% rename from sites/shared/components/workbench/menu/design-options/index.js rename to sites/shared/components/workbench/menu/design-options/index.mjs index bf457068dce..47594ddc6e8 100644 --- a/sites/shared/components/workbench/menu/design-options/index.js +++ b/sites/shared/components/workbench/menu/design-options/index.mjs @@ -1,12 +1,12 @@ import { OptionsIcon } from 'shared/components/icons.mjs' import { Chevron } from 'shared/components/navigation/primary.js' -import OptionGroup from './option-group' -import OptionComponent from './option' -import { Ul, Details, TopSummary, TopSumTitle } from 'shared/components/workbench/menu' +import { OptionGroup } from './option-group.mjs' +import { OptionComponent } from './option.mjs' +import { Ul, Details, TopSummary, TopSumTitle } from 'shared/components/workbench/menu.mjs' import { useTranslation } from 'next-i18next' import { optionsMenuStructure } from 'shared/utils.mjs' -const DesignOptions = (props) => { +export const DesignOptions = (props) => { const { t } = useTranslation(['app']) const Option = props.Option ? props.Option : OptionComponent const optionsMenu = optionsMenuStructure(props.design.patternConfig.options) @@ -29,5 +29,3 @@ const DesignOptions = (props) => { ) } - -export default DesignOptions diff --git a/sites/shared/components/workbench/menu/design-options/option-group.js b/sites/shared/components/workbench/menu/design-options/option-group.mjs similarity index 51% rename from sites/shared/components/workbench/menu/design-options/option-group.js rename to sites/shared/components/workbench/menu/design-options/option-group.mjs index 742c986a559..b3d3156e9cc 100644 --- a/sites/shared/components/workbench/menu/design-options/option-group.js +++ b/sites/shared/components/workbench/menu/design-options/option-group.mjs @@ -1,8 +1,8 @@ -import { Chevron } from 'shared/components/navigation/primary.js' -import { Li, Ul, Details, Summary, SumDiv, Deg } from 'shared/components/workbench/menu' +import { Chevron } from 'shared/components/navigation/primary.mjs' +import { Li, Ul, Details, Summary, SumDiv, Deg } from 'shared/components/workbench/menu.mjs' import { useTranslation } from 'next-i18next' -const OptionGroup = props => { +export const OptionGroup = (props) => { const { t } = useTranslation(['optiongroups']) const Option = props.Option @@ -12,21 +12,20 @@ const OptionGroup = props => { - - { t(props.group) } - + {t(props.group)}
      - {Object.entries(props.options).map(([option, type]) => typeof type === "string" - ?
    ) } - -export default OptionGroup diff --git a/sites/shared/components/workbench/menu/design-options/option-input.js b/sites/shared/components/workbench/menu/design-options/option-input.js deleted file mode 100644 index 641f4a6d09f..00000000000 --- a/sites/shared/components/workbench/menu/design-options/option-input.js +++ /dev/null @@ -1,15 +0,0 @@ -import PctDegOption from 'shared/components/workbench/inputs/design-option-pct-deg' -import CountOption from 'shared/components/workbench/inputs/design-option-count' -import ListOption from 'shared/components/workbench/inputs/design-option-list' -import Popout from 'shared/components/popout' - -export const Tmp = props =>

    not yet

    - -export const inputs = { - pct: PctDegOption, - count: CountOption, - deg: props => (), - list: ListOption, - mm: () => Mm options are deprecated. Please report this, - constant: Tmp, -} diff --git a/sites/shared/components/workbench/menu/design-options/option-input.mjs b/sites/shared/components/workbench/menu/design-options/option-input.mjs new file mode 100644 index 00000000000..54de231e491 --- /dev/null +++ b/sites/shared/components/workbench/menu/design-options/option-input.mjs @@ -0,0 +1,19 @@ +import { PctDegOption } from 'shared/components/workbench/inputs/design-option-pct-deg.mjs' +import { CountOption } from 'shared/components/workbench/inputs/design-option-count.mjs' +import { ListOption } from 'shared/components/workbench/inputs/design-option-list.mjs' +import { Popout } from 'shared/components/popout.mjs' + +export const Tmp = (props) =>

    not yet

    + +export const inputs = { + pct: PctDegOption, + count: CountOption, + deg: (props) => , + list: ListOption, + mm: () => ( + + Mm options are deprecated. Please report this + + ), + constant: Tmp, +} diff --git a/sites/shared/components/workbench/menu/design-options/option-value.js b/sites/shared/components/workbench/menu/design-options/option-value.js deleted file mode 100644 index ee2e824daac..00000000000 --- a/sites/shared/components/workbench/menu/design-options/option-value.js +++ /dev/null @@ -1,72 +0,0 @@ -import { useTranslation } from 'next-i18next' -import { formatMm, formatPercentage} from 'shared/utils' - -export const values = { - pct: props => { - const val = (typeof props.gist?.options?.[props.option] === 'undefined') - ? props.design.patternConfig.options[props.option].pct/100 - : props.gist.options[props.option] - return ( - - {formatPercentage(val)} - {props.design.patternConfig.options[props.option]?.toAbs && props.gist.measurements - ? ' | ' +formatMm(props.design.patternConfig.options[props.option]?.toAbs(val, props.gist)) - : null - } - - ) - }, - bool: props => { - const { t } = useTranslation(['app']) - const dflt = props.design.patternConfig.options[props.option].bool - let current = props.gist?.options?.[props.option] - current = current === undefined ? dflt : current; - return ( - - {current - ? t('yes') - : t('no') - } - - ) - }, - count: props => { - const dflt = props.design.patternConfig.options[props.option].count - const current = props.gist?.options?.[props.option] - return (dflt==current || typeof current === 'undefined') - ? ({dflt}) - : ({current}) - }, - list: props => { - const dflt = props.design.patternConfig.options[props.option].dflt - const current = props.gist?.options?.[props.option] - const prefix = `${props.option}.o.` - const translate = props.design.patternConfig.options[props.option]?.doNotTranslate - ? (input) => input - : (input) => props.t(prefix+input) - return (dflt==current || typeof current === 'undefined') - ? ({translate(dflt)}) - : ({translate(current)}) - }, - deg: props => { - const dflt = props.design.patternConfig.options[props.option].deg - const current = props.gist?.options?.[props.option] - return (dflt==current || typeof current === 'undefined') - ? ({dflt}°) - : ({current}°) - }, - mm: props => { - return (

    No mm val yet

    ) - }, - constant: props => { - return (

    No constant val yet

    ) - } -} diff --git a/sites/shared/components/workbench/menu/design-options/option-value.mjs b/sites/shared/components/workbench/menu/design-options/option-value.mjs new file mode 100644 index 00000000000..27e1e2017cc --- /dev/null +++ b/sites/shared/components/workbench/menu/design-options/option-value.mjs @@ -0,0 +1,78 @@ +import { useTranslation } from 'next-i18next' +import { formatMm, formatPercentage } from 'shared/utils.mjs' + +export const values = { + pct: (props) => { + const val = + typeof props.gist?.options?.[props.option] === 'undefined' + ? props.design.patternConfig.options[props.option].pct / 100 + : props.gist.options[props.option] + return ( + + {formatPercentage(val)} + {props.design.patternConfig.options[props.option]?.toAbs && props.gist.measurements + ? ' | ' + + formatMm(props.design.patternConfig.options[props.option]?.toAbs(val, props.gist)) + : null} + + ) + }, + bool: (props) => { + const { t } = useTranslation(['app']) + const dflt = props.design.patternConfig.options[props.option].bool + let current = props.gist?.options?.[props.option] + current = current === undefined ? dflt : current + return ( + + {current ? t('yes') : t('no')} + + ) + }, + count: (props) => { + const dflt = props.design.patternConfig.options[props.option].count + const current = props.gist?.options?.[props.option] + return dflt == current || typeof current === 'undefined' ? ( + {dflt} + ) : ( + {current} + ) + }, + list: (props) => { + const dflt = props.design.patternConfig.options[props.option].dflt + const current = props.gist?.options?.[props.option] + const prefix = `${props.option}.o.` + const translate = props.design.patternConfig.options[props.option]?.doNotTranslate + ? (input) => input + : (input) => props.t(prefix + input) + return dflt == current || typeof current === 'undefined' ? ( + {translate(dflt)} + ) : ( + {translate(current)} + ) + }, + deg: (props) => { + const dflt = props.design.patternConfig.options[props.option].deg + const current = props.gist?.options?.[props.option] + return dflt == current || typeof current === 'undefined' ? ( + {dflt}° + ) : ( + {current}° + ) + }, + mm: (props) => { + return

    No mm val yet

    + }, + constant: (props) => { + return

    No constant val yet

    + }, +} diff --git a/sites/shared/components/workbench/menu/design-options/option.js b/sites/shared/components/workbench/menu/design-options/option.mjs similarity index 86% rename from sites/shared/components/workbench/menu/design-options/option.js rename to sites/shared/components/workbench/menu/design-options/option.mjs index 1b6bfdf02d4..b78e9444cf4 100644 --- a/sites/shared/components/workbench/menu/design-options/option.js +++ b/sites/shared/components/workbench/menu/design-options/option.mjs @@ -1,11 +1,11 @@ -import { Chevron } from 'shared/components/navigation/primary' -import { optionType } from 'shared/utils' -import { Li, Details, Summary, SumButton, SumDiv, Deg } from 'shared/components/workbench/menu' +import { Chevron } from 'shared/components/navigation/primary.mjs' +import { optionType } from 'shared/utils.mjs' +import { Li, Details, Summary, SumButton, SumDiv, Deg } from 'shared/components/workbench/menu.mjs' import { useTranslation } from 'next-i18next' -import { values } from 'shared/components/workbench/menu/design-options/option-value' -import { inputs } from 'shared/components/workbench/menu/design-options/option-input' +import { values } from 'shared/components/workbench/menu/design-options/option-value.mjs' +import { inputs } from 'shared/components/workbench/menu/design-options/option-input.mjs' -const Option = (props) => { +export const Option = (props) => { const { t } = useTranslation([`o_${props.design.designConfig.data.name}`]) const opt = props.design.patternConfig.options[props.option] const type = optionType(opt) @@ -57,5 +57,3 @@ const Option = (props) => { ) } - -export default Option diff --git a/sites/shared/components/workbench/menu/index.js b/sites/shared/components/workbench/menu/index.mjs similarity index 55% rename from sites/shared/components/workbench/menu/index.js rename to sites/shared/components/workbench/menu/index.mjs index 025fd804b05..a883bda189c 100644 --- a/sites/shared/components/workbench/menu/index.js +++ b/sites/shared/components/workbench/menu/index.mjs @@ -1,67 +1,82 @@ -import { linkClasses } from 'shared/components/navigation/primary.js' -import ViewMenu from './view.js' -import DesignOptions from './design-options' -import CoreSettings from './core-settings' -import Xray from './xray' -import TestDesignOptions from './test-design-options' +import { linkClasses } from 'shared/components/navigation/primary.mjs' +import { ViewMenu } from './view.mjs' +import { DesignOptions } from './design-options.mjs' +import { CoreSettings } from './core-settings.mjs' +import { Xray } from './xray' +import { TestDesignOptions } from './test-design-options.mjs' -export const Ul = props =>
      {props.children}
    -export const Li = props => ( -
  • - {props.children} -
  • +export const Ul = (props) =>
      {props.children}
    +export const Li = (props) => ( +
  • {props.children}
  • ) -export const Details = props => ( +export const Details = (props) => (
    {props.children}
    ) -export const Deg = props => ° -export const NoSumDiv = props => ( -
    ( + ° +) +export const NoSumDiv = (props) => ( +
    {props.children}
    + `} + > + {props.children} +
    ) -export const SumDiv = props => ( -
    ( +
    {props.children}
    + `} + > + {props.children} +
    ) -export const Summary = props => ( - ( + {props.children} + `} + > + {props.children} + ) -export const TopSummary = props => ( - ( + + `} + > {props.icon || null} {props.children} ) -export const SumButton = props => ( - + `} + onClick={props.onClick} + > + {props.children} + ) -export const TopSumTitle = props => ( +export const TopSumTitle = (props) => ( {props.children} ) -export const SecText = props => props.raw - ? - : {props.children} +export const SecText = (props) => + props.raw ? ( + + ) : ( + {props.children} + ) -const WorkbenchMenu = props => { +export const WorkbenchMenu = (props) => { return ( ) } - -export default WorkbenchMenu diff --git a/sites/shared/components/workbench/menu/view.js b/sites/shared/components/workbench/menu/view.mjs similarity index 97% rename from sites/shared/components/workbench/menu/view.js rename to sites/shared/components/workbench/menu/view.mjs index a3dbc52ca9f..3cc70272135 100644 --- a/sites/shared/components/workbench/menu/view.js +++ b/sites/shared/components/workbench/menu/view.mjs @@ -1,9 +1,9 @@ import { MenuIcon } from 'shared/components/icons.mjs' -import { linkClasses, Chevron } from 'shared/components/navigation/primary.js' +import { linkClasses, Chevron } from 'shared/components/navigation/primary.mjs' import { useTranslation } from 'next-i18next' -import { defaultGist } from 'shared/hooks/useGist' +import { defaultGist } from 'shared/hooks/useGist.mjs' -const View = (props) => { +export const View = (props) => { const { t } = useTranslation(['app']) const entries = [ { @@ -126,5 +126,3 @@ const View = (props) => { ) } - -export default View diff --git a/sites/shared/components/workbench/preload.js b/sites/shared/components/workbench/preload.js deleted file mode 100644 index e42df83c4d3..00000000000 --- a/sites/shared/components/workbench/preload.js +++ /dev/null @@ -1,31 +0,0 @@ -import yaml from 'js-yaml' -import axios from 'axios' - -const preload = { - github: async (id, design) => { - let result - try { - result = await axios.get(`https://api.github.com/gists/${id}`) - } - catch (err) { - console.log(err) - return [false, 'An unexpected error occured'] - } - - if (result.data.files['pattern.yaml'].content) { - let g = yaml.load(result.data.files['pattern.yaml'].content) - - if (g.design !== undefined && g.design !== design.designConfig.data.name) return [ - false, `You tried loading a configuration for ${g.design} into a ${design.designConfig.data.name} development environment` - ] - - return g - } - - // TODO notify people of these errors - else return [false, 'This gist does not seem to be a valid pattern configuration'] - } -} - -export default preload - diff --git a/sites/shared/components/workbench/sample.js b/sites/shared/components/workbench/sample.mjs similarity index 72% rename from sites/shared/components/workbench/sample.js rename to sites/shared/components/workbench/sample.mjs index c7e6806b8cb..cfeffd7d42f 100644 --- a/sites/shared/components/workbench/sample.js +++ b/sites/shared/components/workbench/sample.mjs @@ -1,10 +1,9 @@ -import SvgWrapper from './draft/svg-wrapper' -import Error from './draft/error.js' -import { svgattrPlugin } from '@freesewing/plugin-svgattr' import { useTranslation } from 'next-i18next' +import { svgattrPlugin } from '@freesewing/plugin-svgattr' +import { SvgWrapper } from './draft/svg-wrapper.mjs' +import { Error } from './draft/error.mjs' -const LabSample = ({ gist, draft, updateGist, unsetGist, showInfo, app, feedback }) => { - +export const LabSample = ({ gist, draft, updateGist, unsetGist, showInfo, app, feedback }) => { const { t } = useTranslation(['workbench']) let svg let title = '' @@ -13,19 +12,18 @@ const LabSample = ({ gist, draft, updateGist, unsetGist, showInfo, app, feedback if (gist.sample) { try { draft.use(svgattrPlugin, { - class: 'freesewing pattern max-h-screen' + class: 'freesewing pattern max-h-screen', }) draft = draft.sample() // Render as React patternProps = draft.getRenderProps() for (const logs of patternProps.logs) errors.push(...logs.error) - } - catch(err) { + } catch (err) { console.log(err) } if (gist.sample.type === 'option') { title = t('testThing', { - thing: ' : ' + t('option') + ' : ' + gist.sample.option + thing: ' : ' + t('option') + ' : ' + gist.sample.option, }) } } @@ -39,9 +37,7 @@ const LabSample = ({ gist, draft, updateGist, unsetGist, showInfo, app, feedback -
    +
    ) } - -export default LabSample diff --git a/sites/shared/components/workbench/yaml.js b/sites/shared/components/workbench/yaml.js deleted file mode 100644 index 2c8ed3a7a40..00000000000 --- a/sites/shared/components/workbench/yaml.js +++ /dev/null @@ -1,9 +0,0 @@ -import Yaml from 'shared/components/yaml.js' - -const GistAsYaml = props => ( -
    - -
    -) - -export default GistAsYaml diff --git a/sites/shared/components/wrappers/workbench.js b/sites/shared/components/wrappers/workbench.mjs similarity index 80% rename from sites/shared/components/wrappers/workbench.js rename to sites/shared/components/wrappers/workbench.mjs index 8c0861e5dbe..a8de62c976a 100644 --- a/sites/shared/components/wrappers/workbench.js +++ b/sites/shared/components/wrappers/workbench.mjs @@ -1,24 +1,25 @@ +// Hooks import { useEffect, useState, useMemo } from 'react' import { useGist } from 'shared/hooks/useGist' -import Layout from 'shared/components/layouts/default' -import Menu from 'shared/components/workbench/menu/index.js' -import DraftError from 'shared/components/workbench/draft/error.js' +// Dependencies import { pluginTheme } from '@freesewing/plugin-theme' import preloaders from 'shared/components/workbench/preload.js' -import Modal from 'shared/components/modal' - +// Components +import { DefaultLayout } from 'shared/components/workbench/layout/default.mjs' +import { Menu } from 'shared/components/workbench/menu/index.mjs' +import { DraftError } from 'shared/components/workbench/draft/error.mjs' +import { Modal } from 'shared/components/modal.mjs' +import { ErrorBoundary } from 'shared/components/error/error-boundary.mjs' // Views -import Measurements from 'shared/components/workbench/measurements/index.js' -import LabDraft from 'shared/components/workbench/draft/index.js' -import LabSample from 'shared/components/workbench/sample.js' -import ExportDraft from 'shared/components/workbench/exporting/index.js' -import GistAsJson from 'shared/components/workbench/gist-as-json.js' -import GistAsYaml from 'shared/components/workbench/yaml.js' -import DraftLogs from 'shared/components/workbench/logs.js' -import CutLayout from 'shared/components/workbench/layout/cut' -import PrintingLayout from 'shared/components/workbench/layout/print' - -import ErrorBoundary from 'shared/components/error/error-boundary' +import { Measurements } from 'shared/components/workbench/measurements/index.js' +import { LabDraft } from 'shared/components/workbench/draft/index.js' +import { LabSample } from 'shared/components/workbench/sample.js' +import { ExportDraft } from 'shared/components/workbench/exporting/index.js' +import { GistAsJson } from 'shared/components/workbench/gist-as-json.js' +import { GistAsYaml } from 'shared/components/workbench/yaml.js' +import { DraftLogs } from 'shared/components/workbench/logs.js' +import { CutLayout } from 'shared/components/workbench/layout/cut' +import { PrintingLayout } from 'shared/components/workbench/layout/print' const views = { measurements: Measurements, @@ -54,7 +55,13 @@ const doPreload = async (preload, from, design, gist, setGist, setPreloaded) => * keeping the gist state, which will trickle down * to all workbench subcomponents */ -const WorkbenchWrapper = ({ app, design, preload = false, from = false, layout = false }) => { +export const WorkbenchWrapper = ({ + app, + design, + preload = false, + from = false, + layout = false, +}) => { // State for gist const { gist, setGist, unsetGist, updateGist, gistReady, undoGist, resetGist } = useGist( design.designConfig?.data?.name, @@ -175,5 +182,3 @@ const WorkbenchWrapper = ({ app, design, preload = false, from = false, layout = ) } - -export default WorkbenchWrapper diff --git a/sites/shared/hooks/useGist.js b/sites/shared/hooks/useGist.js deleted file mode 100644 index df26219a0f4..00000000000 --- a/sites/shared/hooks/useGist.js +++ /dev/null @@ -1,88 +0,0 @@ -import useLocalStorage from './useLocalStorage'; -import set from 'lodash.set' -import unset from 'lodash.unset' -import cloneDeep from 'lodash.clonedeep' -import defaultSettings from 'shared/components/workbench/default-settings.js' -import {useState} from 'react' - -// Generates a default design gist to start from -export const defaultGist = (design, locale='en') => { - const gist = { - design, - ...defaultSettings, - _state: {view: 'draft'} - } - if (locale) gist.locale = locale - - return gist -} - -// generate the gist state and its handlers -export function useGist(design, app) { - // get the localstorage state and setter - const [gist, _setGist, gistReady] = useLocalStorage(`${design}_gist`, defaultGist(design, app.locale)); - const [gistHistory, setGistHistory] = useState([]); - const [gistFuture, setGistFuture] = useState([]); - - const setGist = (newGist, addToHistory=true) => { - let oldGist - _setGist((gistState) => { - // have to clone it or nested objects will be referenced instead of copied, which defeats the purpose - if (addToHistory) oldGist = cloneDeep(gistState) - - return typeof newGist === 'function' ? newGist(cloneDeep(gistState)) : newGist - }) - - if (addToHistory) { - setGistHistory((history) => { - return [...history, oldGist] - }) - setGistFuture([]) - } - } - - /** update a single gist value */ - const updateGist = (path, value, addToHistory=true) => { - setGist((gistState) => { - const newGist = {...gistState}; - set(newGist, path, value); - return newGist; - }, addToHistory) - } - - /** unset a single gist value */ - const unsetGist = (path, addToHistory=true) => { - setGist((gistState) => { - const newGist = {...gistState}; - unset(newGist, path); - return newGist; - }, addToHistory) - } - - const undoGist = () => { - _setGist((gistState) => { - let prevGist; - setGistHistory((history) => { - const newHistory = [...history] - prevGist = newHistory.pop() || defaultGist(design, app.locale); - return newHistory; - }) - setGistFuture((future) => [gistState, ...future]); - - return {...prevGist} - }) - } - - const redoGist = () => { - const newHistory = [...gistHistory, gist] - const newFuture = [...gistFuture] - const newGist = newFuture.shift() - setGistHistory(newHistory) - setGistFuture(newFuture) - _setGist(newGist) - } - - const resetGist = () => setGist(defaultGist(design, app.locale)) - - return {gist, setGist, unsetGist, gistReady, updateGist, undoGist, redoGist, resetGist}; -} diff --git a/sites/shared/hooks/useGist.mjs b/sites/shared/hooks/useGist.mjs new file mode 100644 index 00000000000..da1f1a36fb8 --- /dev/null +++ b/sites/shared/hooks/useGist.mjs @@ -0,0 +1,91 @@ +import { useState } from 'react' +import set from 'lodash.set' +import unset from 'lodash.unset' +import cloneDeep from 'lodash.clonedeep' +import { useLocalStorage } from './useLocalStorage' +import { defaultSettings } from 'shared/components/workbench/default-settings.mjs' + +// Generates a default design gist to start from +export const defaultGist = (design, locale = 'en') => { + const gist = { + design, + ...defaultSettings, + _state: { view: 'draft' }, + } + if (locale) gist.locale = locale + + return gist +} + +// generate the gist state and its handlers +export function useGist(design, app) { + // get the localstorage state and setter + const [gist, _setGist, gistReady] = useLocalStorage( + `${design}_gist`, + defaultGist(design, app.locale) + ) + const [gistHistory, setGistHistory] = useState([]) + const [gistFuture, setGistFuture] = useState([]) + + const setGist = (newGist, addToHistory = true) => { + let oldGist + _setGist((gistState) => { + // have to clone it or nested objects will be referenced instead of copied, which defeats the purpose + if (addToHistory) oldGist = cloneDeep(gistState) + + return typeof newGist === 'function' ? newGist(cloneDeep(gistState)) : newGist + }) + + if (addToHistory) { + setGistHistory((history) => { + return [...history, oldGist] + }) + setGistFuture([]) + } + } + + /** update a single gist value */ + const updateGist = (path, value, addToHistory = true) => { + setGist((gistState) => { + const newGist = { ...gistState } + set(newGist, path, value) + return newGist + }, addToHistory) + } + + /** unset a single gist value */ + const unsetGist = (path, addToHistory = true) => { + setGist((gistState) => { + const newGist = { ...gistState } + unset(newGist, path) + return newGist + }, addToHistory) + } + + const undoGist = () => { + _setGist((gistState) => { + let prevGist + setGistHistory((history) => { + const newHistory = [...history] + prevGist = newHistory.pop() || defaultGist(design, app.locale) + return newHistory + }) + setGistFuture((future) => [gistState, ...future]) + + return { ...prevGist } + }) + } + + const redoGist = () => { + const newHistory = [...gistHistory, gist] + const newFuture = [...gistFuture] + const newGist = newFuture.shift() + setGistHistory(newHistory) + setGistFuture(newFuture) + _setGist(newGist) + } + + const resetGist = () => setGist(defaultGist(design, app.locale)) + + return { gist, setGist, unsetGist, gistReady, updateGist, undoGist, redoGist, resetGist } +} diff --git a/sites/shared/hooks/useLocalStorage.js b/sites/shared/hooks/useLocalStorage.mjs similarity index 64% rename from sites/shared/hooks/useLocalStorage.js rename to sites/shared/hooks/useLocalStorage.mjs index 793df99fbb3..be19e75f368 100644 --- a/sites/shared/hooks/useLocalStorage.js +++ b/sites/shared/hooks/useLocalStorage.mjs @@ -1,12 +1,13 @@ import { useState, useEffect, useRef, useReducer } from 'react' // See: https://usehooks.com/useLocalStorage/ -function useLocalStorage(key, initialValue, reducer) { +export function useLocalStorage(key, initialValue, reducer) { const prefix = 'fs_' - const [storedValue, setStoredValue] = typeof reducer == 'function' ? useReducer(reducer, initialValue) : useState(initialValue); + const [storedValue, setStoredValue] = + typeof reducer == 'function' ? useReducer(reducer, initialValue) : useState(initialValue) // use this to track whether it's mounted. useful for doing other effects outside this hook - const [ready, setReady] = useState(false); - const readyInternal = useRef(false); + const [ready, setReady] = useState(false) + const readyInternal = useRef(false) const setValue = setStoredValue // set to localstorage every time the storedValue changes @@ -18,22 +19,20 @@ function useLocalStorage(key, initialValue, reducer) { // get the item from localstorage after the component has mounted. empty brackets mean it runs one time useEffect(() => { - readyInternal.current = true; + readyInternal.current = true const item = window.localStorage.getItem(prefix + key) - let valueToSet = storedValue; + let valueToSet = storedValue if (item) { valueToSet = JSON.parse(item) } if (reducer) { - valueToSet = {value: valueToSet, type: 'replace'} + valueToSet = { value: valueToSet, type: 'replace' } } setValue(valueToSet) - setReady(true); + setReady(true) }, []) return [storedValue, setValue, ready] } - -export default useLocalStorage diff --git a/sites/shared/hooks/useTheme.js b/sites/shared/hooks/useTheme.js deleted file mode 100644 index a515d14cd50..00000000000 --- a/sites/shared/hooks/useTheme.js +++ /dev/null @@ -1,22 +0,0 @@ -import useLocalStorage from 'shared/hooks/useLocalStorage'; -import {useEffect } from 'react' - -function useTheme() { - // make a local storage item for the theme - const [storedTheme, setStoredTheme, ready] = useLocalStorage('theme', undefined); - - useEffect(() => { - // set the default theme based on user prefence after mounting - if (ready && storedTheme === undefined) { - const prefersDarkMode = (typeof window !== 'undefined' && typeof window.matchMedia === 'function') - ? window.matchMedia(`(prefers-color-scheme: dark`).matches - : undefined - - setStoredTheme(prefersDarkMode ? 'dark' : 'light') - } - }, [ready]) - - return [storedTheme, setStoredTheme]; -} - -export default useTheme; diff --git a/sites/shared/hooks/useTheme.mjs b/sites/shared/hooks/useTheme.mjs new file mode 100644 index 00000000000..8aa6dbc08dc --- /dev/null +++ b/sites/shared/hooks/useTheme.mjs @@ -0,0 +1,21 @@ +import { useLocalStorage } from 'shared/hooks/useLocalStorage' +import { useEffect } from 'react' + +export function useTheme() { + // make a local storage item for the theme + const [storedTheme, setStoredTheme, ready] = useLocalStorage('theme', undefined) + + useEffect(() => { + // set the default theme based on user prefence after mounting + if (ready && storedTheme === undefined) { + const prefersDarkMode = + typeof window !== 'undefined' && typeof window.matchMedia === 'function' + ? window.matchMedia(`(prefers-color-scheme: dark`).matches + : undefined + + setStoredTheme(prefersDarkMode ? 'dark' : 'light') + } + }, [ready]) + + return [storedTheme, setStoredTheme] +}