diff --git a/packages/react/components/Account/Sets.mjs b/packages/react/components/Account/Sets.mjs index d615208cc6a..83c0eff9e88 100644 --- a/packages/react/components/Account/Sets.mjs +++ b/packages/react/components/Account/Sets.mjs @@ -1,6 +1,8 @@ // Dependencies import { measurements } from '@freesewing/config' -import { cloudflareImageUrl, capitalize } from '@freesewing/utils' +import { measurements as measurementsTranslations } from '@freesewing/i18n' +import { requiredMeasurements as designMeasurements } from '@freesewing/collection' +import { cloudflareImageUrl, capitalize, hasRequiredMeasurements } from '@freesewing/utils' // Context import { LoadingStatusContext } from '@freesewing/react/context/LoadingStatus' import { ModalContext } from '@freesewing/react/context/Modal' @@ -201,7 +203,8 @@ export const MsetCard = ({ const s = sizes[size] const wrapperProps = { - className: `tw-bg-base-300 tw-aspect-square tw-h-${s} tw-w-${s} tw-mb-2 tw-grow + className: `tw-bg-base-300 tw-aspect-square tw-h-${s} tw-w-${s} tw-mb-2 tw-grow tw-w-full + hover:tw-cursor-pointer tw-border-0 tw-opacity-80 hover:tw-opacity-100 tw-mx-auto tw-flex tw-flex-col tw-items-start tw-text-center tw-justify-between tw-rounded-none md:tw-rounded shadow`, style: { backgroundImage: `url(${cloudflareImageUrl({ type: 'w500', id: set.img })})`, @@ -230,13 +233,11 @@ export const MsetCard = ({ ) if (missing.length > 0) { - const translated = missing.map((m) => { - return t(m) - }) - let missingString = t('missing') + ': ' + translated.join(', ') + const translated = missing.map((m) => measurementsTranslations[m]) + let missingString = 'Missing:' + translated.join(', ') if (missingString.length > maxLength) { const lastSpace = missingString.lastIndexOf(', ', maxLength) - missingString = missingString.substring(0, lastSpace) + ', ' + t('andMore') + '...' + missingString = missingString.substring(0, lastSpace) + ', and more...' } const measieClasses = 'tw-font-normal tw-text-xs' missingMeasies = {missingString} diff --git a/packages/react/components/Editor/components/Accordion.mjs b/packages/react/components/Editor/components/Accordion.mjs index 72c19356815..d31b1cc3243 100644 --- a/packages/react/components/Editor/components/Accordion.mjs +++ b/packages/react/components/Editor/components/Accordion.mjs @@ -5,7 +5,7 @@ import React, { useState } from 'react' * So instead, we handle this in React state */ const getProps = (isActive) => ({ - className: `tw-p-2 tw-px-4 tw-rounded-lg tw-bg-transparent tw-shadow + className: `tw-p-2 tw-px-4 tw-rounded-lg tw-bg-transparent tw-shadow hover:tw-cursor-pointer tw-w-full tw-mt-2 tw-py-4 tw-h-auto tw-content-start tw-text-left tw-bg-opacity-20 ${isActive ? 'hover:tw-bg-transparent' : 'hover:tw-bg-secondary hover:tw-bg-opacity-10'}`, }) @@ -41,7 +41,10 @@ export const BaseAccordion = ({ .map((item, i) => active === item[2] ? (
- + {item[0]} {item[1]} diff --git a/packages/react/components/Editor/components/HeaderMenu.mjs b/packages/react/components/Editor/components/HeaderMenu.mjs index 5de6ef05f83..b3cbe371a90 100644 --- a/packages/react/components/Editor/components/HeaderMenu.mjs +++ b/packages/react/components/Editor/components/HeaderMenu.mjs @@ -8,35 +8,8 @@ import { AsideViewMenuSpacer } from './AsideViewMenu.mjs' import { ViewIcon, viewLabels } from './views/index.mjs' import { Tooltip } from './Tooltip.mjs' import { ErrorIcon } from '@freesewing/react/components/Icon' - -export const HeaderMenu = ({ config, Design, pattern, state, update }) => { - const [open, setOpen] = useState() - - /* - * Guard views that require measurements agains missing measurements - * and make sure there's a view-specific header menu - */ - const ViewMenu = - !missingMeasurements(state, config) && - Swizzled.components[`HeaderMenu${config.viewComponents[state.view]}`] - ? Swizzled.components[`HeaderMenu${config.viewComponents[state.view]}`] - : Null - - return ( -
-
- - -
-
- ) -} +import { DesignOptionsMenu } from './menus/DesignOptionsMenu.mjs' +import { CoreSettingsMenu } from './menus/CoreSettingsMenu.mjs' export const HeaderMenuAllViews = ({ config, state, update, open, setOpen }) => ( @@ -47,7 +20,7 @@ export const HeaderMenuDraftView = (props) => { return ( <> -
+
@@ -74,31 +47,31 @@ export const HeaderMenuDropdown = (props) => { disabled tabIndex={0} role="button" - className="btn btn-ghost hover:bg-secondary hover:bg-opacity-20 hover:border-solid hover:boder-2 hover:border-secondary border border-secondary border-2 border-dotted btn-sm px-2 z-20 relative" + className="tw-daisy-btn tw-daisy-btn-ghost hover:tw-bg-secondary hover:tw-bg-opacity-20 hover:tw-border-solid hover:tw-border-2 hover:tw-border-secondary tw-border tw-border-secondary tw-border-2 tw-border-dotted tw-daisy-btn-sm tw-px-2 tw-z-20 tw-relative" > {toggle} ) : ( -
+
setOpen(open === id ? false : id)} > {toggle}
{props.children}
{open === id && (
setOpen(false)} >
@@ -116,8 +89,8 @@ export const HeaderMenuDraftViewDesignOptions = (props) => { tooltip="fixme: 'pe:designOptions.d'" toggle={ <> - - fixme: pe:designOptions.t + + fixme: pe:designOptions.t } > @@ -134,8 +107,8 @@ export const HeaderMenuDraftViewCoreSettings = (props) => { id="coreSettings" toggle={ <> - - fixme: pe:coreSettings.t + + fixme: pe:coreSettings.t } > @@ -152,8 +125,8 @@ export const HeaderMenuDraftViewUiPreferences = (props) => { id="uiPreferences" toggle={ <> - - fixme: pe:uiPreferences.t + + fixme: pe:uiPreferences.t } > @@ -172,8 +145,8 @@ export const HeaderMenuDraftViewFlags = (props) => { id="flags" toggle={ <> - - + + Flags ({count}) @@ -188,8 +161,8 @@ export const HeaderMenuDraftViewFlags = (props) => { export const HeaderMenuDraftViewIcons = (props) => { const { update } = props const Button = HeaderMenuButton - const size = 'w-5 h-5' - const muted = 'text-current opacity-50' + const size = 'tw-w-5 tw-h-5' + const muted = 'tw-text-current tw-opacity-50' const ux = props.state.ui.ux const levels = { ...props.config.uxLevels.core, @@ -197,13 +170,15 @@ export const HeaderMenuDraftViewIcons = (props) => { } return ( -
+
{ux >= levels.sa ? ( ) : null} {ux >= levels.paperless ? ( @@ -212,7 +187,7 @@ export const HeaderMenuDraftViewIcons = (props) => { tooltip="Turns Paperless on or off (see Core Settings)" > ) : null} @@ -222,7 +197,7 @@ export const HeaderMenuDraftViewIcons = (props) => { tooltip="Turns Details on or off (see Core Settings)" > ) : null} @@ -232,7 +207,7 @@ export const HeaderMenuDraftViewIcons = (props) => { tooltip="Turns Expand on or off (see Core Settings)" > ) : null} @@ -248,26 +223,28 @@ export const HeaderMenuDraftViewIcons = (props) => { > ) : null} {ux >= levels.ux ? ( -
+
{[0, 1, 2, 3, 4].map((i) => ( ) : null} {ux >= levels.kiosk ? ( @@ -289,7 +266,7 @@ export const HeaderMenuDraftViewIcons = (props) => { updateHandler={() => update.ui('kiosk', props.state.ui.kiosk ? 0 : 1)} tooltip="Turns Kiosk Mode on or off (see UI Preferences)" > - + ) : null} {ux >= levels.rotate ? ( @@ -297,7 +274,9 @@ export const HeaderMenuDraftViewIcons = (props) => { updateHandler={() => update.ui('rotate', props.state.ui.rotate ? 0 : 1)} tooltip="Turns Rotate Pattern on or off (see UI Preferences)" > - + ) : null} {ux >= levels.renderer ? ( @@ -308,7 +287,7 @@ export const HeaderMenuDraftViewIcons = (props) => { tooltip="Switches the Render Engine between React and SVG (see UI Preferences)" > ) : null} @@ -323,20 +302,20 @@ export const HeaderMenuUndoIcons = (props) => { const undos = props.state._?.undos && props.state._.undos.length > 0 ? props.state._.undos : false return ( -
+
{ disabled={undos ? false : true} toggle={ <> - - Undo + + Undo } > {undos ? ( -
    +
      {undos.slice(0, 9).map((step, index) => (
    • @@ -364,9 +343,9 @@ export const HeaderMenuUndoIcons = (props) => { return null /*update.state(index, state._) */ }} > -
      -
      - +
      +
      + {viewLabels.undo.t}
      {undos.length} @@ -380,10 +359,10 @@ export const HeaderMenuUndoIcons = (props) => { updateHandler={update.clearAll} tooltip="Reset all settings, but keep the design and measurements" > - +
      ) @@ -392,23 +371,23 @@ export const HeaderMenuUndoIcons = (props) => { export const HeaderMenuSaveIcons = (props) => { const { update } = props const Button = HeaderMenuButton - const size = 'w-5 h-5' + const size = 'tw-w-5 tw-h-5' const saveable = props.state._?.undos && props.state._.undos.length > 0 return ( -
      +
      ) @@ -417,14 +396,16 @@ export const HeaderMenuSaveIcons = (props) => { export const HeaderMenuIcon = (props) => { const { name, extraClasses = '' } = props //const Icon = Swizzled.components[`${Swizzled.methods.capitalize(name)}Icon`] || Swizzled.components.Noop - return + return } -export const HeaderMenuIconSpacer = () => | +export const HeaderMenuIconSpacer = () => ( + | +) export const HeaderMenuButton = ({ updateHandler, children, tooltip, disabled = false }) => ( + {set.nameEn} +
      + ) + })} +
      +) diff --git a/packages/react/components/Editor/swizzle/components/zoomable-pattern.mjs b/packages/react/components/Editor/components/ZoomablePattern.mjs similarity index 100% rename from packages/react/components/Editor/swizzle/components/zoomable-pattern.mjs rename to packages/react/components/Editor/components/ZoomablePattern.mjs diff --git a/packages/react/components/Editor/swizzle/components/menus/containers.mjs b/packages/react/components/Editor/components/menus/Container.mjs similarity index 85% rename from packages/react/components/Editor/swizzle/components/menus/containers.mjs rename to packages/react/components/Editor/components/menus/Container.mjs index 9ee30172276..13553f83745 100644 --- a/packages/react/components/Editor/swizzle/components/menus/containers.mjs +++ b/packages/react/components/Editor/components/menus/Container.mjs @@ -1,4 +1,11 @@ -import { useState, useMemo } from 'react' +// Dependencies +import { menuValueWasChanged } from '../../lib/index.mjs' +// Hooks +import React, { useState, useMemo } from 'react' +// Components +import { SubAccordion } from '../Accordion.mjs' +import { GroupIcon, OptionsIcon } from '@freesewing/react/components/Icon' +import { CoreSettingsMenu } from './CoreSettingsMenu.mjs' /** @type {String} class to apply to buttons on open menu items */ const iconButtonClass = 'btn btn-xs btn-ghost px-0 text-accent' @@ -17,11 +24,9 @@ const iconButtonClass = 'btn btn-xs btn-ghost px-0 text-accent' * @param {React.Component} Value a value display component this menu item will use * @param {Boolean} allowOverride all a text input to be used to override the given input component * @param {Number} ux the user-defined ux level - * @param {object} props.Swizzled - An object holding swizzled code */ export const MenuItem = ({ name, - Swizzled, current, updateHandler, passProps = {}, @@ -44,7 +49,6 @@ export const MenuItem = ({ ux, current, updateHandler, - t: Swizzled.methods.t, changed, override, Design, @@ -73,7 +77,7 @@ export const MenuItem = ({ setOverride(!override) }} > - - + ) buttons.push() return ( - {Swizzled.methods.t(`${name}.d`)}} + {name}.d} id={config.name} labelBR={
      {buttons}
      } labelBL={ - {Swizzled.methods.t(`pe:youAreUsing${changed ? 'ACustom' : 'TheDefault'}Value`)} + pe:youAreUsing{changed ? 'ACustom' : 'TheDefault'}Value } docs={docs} > -
      + ) } @@ -132,8 +136,6 @@ export const MenuItem = ({ * @param {Function} updateHandler the function called by change handlers on inputs within menu items * @param {Boolean} topLevel is this group the top level group? false for nested * @param {Function} t translation function - * @param {object} props.Swizzled - An object holding swizzled code - */ export const MenuItemGroup = ({ collapsible = true, @@ -149,10 +151,9 @@ export const MenuItemGroup = ({ topLevel = false, isDesignOptionsGroup = false, Design, - Swizzled, state, }) => { - if (!Item) Item = Swizzled.components.MenuItem + if (!Item) Item = MenuItem // map the entries in the structure const content = Object.entries(structure).map(([itemName, item]) => { @@ -164,7 +165,7 @@ export const MenuItemGroup = ({ const ItemIcon = item.icon ? item.icon : item.isGroup - ? Swizzled.components.GroupIcon + ? GroupIcon : Icon ? Icon : () => fixme-icon @@ -172,11 +173,11 @@ export const MenuItemGroup = ({ ? () => (
      {Object.keys(item).filter((i) => i !== 'isGroup').length} - +
      ) : isDesignOptionsGroup - ? values[Swizzled.methods.designOptionType(item)] + ? values[designOptionType(item)] : values[itemName] ? values[itemName] : () => ¯\_(ツ)_/¯ @@ -186,15 +187,14 @@ export const MenuItemGroup = ({
      - {Swizzled.methods.t([`pe:${itemName}.t`, `pe:${itemName}`])} + pe:{itemName}.t pe:{itemName}
      @@ -218,7 +218,6 @@ export const MenuItemGroup = ({ updateHandler, isDesignOptionsGroup, Design, - Swizzled, }} /> ) : ( @@ -229,13 +228,12 @@ export const MenuItemGroup = ({ current: currentValues[itemName], config: item, state, - changed: Swizzled.methods.menuValueWasChanged(currentValues[itemName], item), + changed: menuValueWasChanged(currentValues[itemName], item), Value: values[itemName], Input: inputs[itemName], updateHandler, passProps, Design, - Swizzled, }} /> ), @@ -243,7 +241,7 @@ export const MenuItemGroup = ({ ] }) - return item !== null)} /> + return item !== null)} /> } /** @@ -254,18 +252,11 @@ export const MenuItemGroup = ({ * @param {Boolean} options.open is the menu item open? * @param {String} options.emoji the emoji icon of the menu item */ -export const MenuItemTitle = ({ - name, - current = null, - open = false, - emoji = '', - Icon = false, - Swizzled, -}) => ( +export const MenuItemTitle = ({ name, current = null, open = false, emoji = '', Icon = false }) => (
      {Icon ? : {emoji}} - {Swizzled.methods.t([`${name}.t`, name])} + fixme: {name} {current}
      diff --git a/packages/react/components/Editor/swizzle/components/menus/core-settings-menu.mjs b/packages/react/components/Editor/components/menus/CoreSettingsMenu.mjs similarity index 59% rename from packages/react/components/Editor/swizzle/components/menus/core-settings-menu.mjs rename to packages/react/components/Editor/components/menus/CoreSettingsMenu.mjs index 673ce6a76bf..890e96e8fba 100644 --- a/packages/react/components/Editor/swizzle/components/menus/core-settings-menu.mjs +++ b/packages/react/components/Editor/components/menus/CoreSettingsMenu.mjs @@ -1,3 +1,11 @@ +import React from 'react' +import { + menuCoreSettingsOnlyHandler, + menuCoreSettingsSaboolHandler, + menuCoreSettingsSammHandler, + menuCoreSettingsStructure, +} from '../../lib/index.mjs' + /** * The core settings menu * @param {Object} options.update settings and ui update functions @@ -7,8 +15,8 @@ * @param {Object} options.account the user account data * @param {object} props.Swizzled - An object holding swizzled code */ -export const CoreSettingsMenu = ({ update, state, language, Design, Swizzled }) => { - const structure = Swizzled.methods.menuCoreSettingsStructure({ +export const CoreSettingsMenu = ({ update, state, language, Design }) => { + const structure = menuCoreSettingsStructure({ language, units: state.settings?.units, sabool: state.settings?.sabool, @@ -16,42 +24,38 @@ export const CoreSettingsMenu = ({ update, state, language, Design, Swizzled }) }) const inputs = { - complete: Swizzled.components.MenuListInput, - expand: Swizzled.components.MenuListInput, - margin: Swizzled.components.MenuMmInput, - only: Swizzled.components.MenuOnlySettingInput, - paperless: Swizzled.components.MenuBoolInput, - sabool: Swizzled.components.MenuBoolInput, - samm: Swizzled.components.MenuMmInput, - scale: Swizzled.components.MenuSliderInput, - units: Swizzled.components.MenuBoolInput, + complete: MenuListInput, + expand: MenuListInput, + margin: MenuMmInput, + only: MenuOnlySettingInput, + paperless: MenuBoolInput, + sabool: MenuBoolInput, + samm: MenuMmInput, + scale: MenuSliderInput, + units: MenuBoolInput, } const values = { - complete: Swizzled.components.MenuListValue, - expand: Swizzled.components.MenuListValue, - margin: Swizzled.components.MenuMmValue, - only: Swizzled.components.MenuOnlySettingValue, - paperless: Swizzled.components.MenuListValue, - sabool: Swizzled.components.MenuListValue, - samm: Swizzled.components.MenuMmValue, - scale: Swizzled.components.MenuScaleSettingValue, - units: Swizzled.components.MenuListValue, + complete: MenuListValue, + expand: MenuListValue, + margin: MenuMmValue, + only: MenuOnlySettingValue, + paperless: MenuListValue, + sabool: MenuListValue, + samm: MenuMmValue, + scale: MenuScaleSettingValue, + units: MenuListValue, } return ( - ( - + ), isFirst: true, name: 'pe:designOptions', @@ -64,7 +68,6 @@ export const CoreSettingsMenu = ({ update, state, language, Design, Swizzled }) }, updateHandler: update.settings, isDesignOptionsGroup: false, - Swizzled, state, Design, inputs, @@ -74,17 +77,15 @@ export const CoreSettingsMenu = ({ update, state, language, Design, Swizzled }) ) } +// Facilitate custom handlers for core settings +const coreSettingsHandlerMethods = { + only: menuCoreSettingsOnlyHandler, + sabool: menuCoreSettingsSaboolHandler, + samm: menuCoreSettingsSammHandler, +} + /** A wrapper for {@see MenuItem} to handle core settings-specific business */ -export const CoreSetting = ({ - Swizzled, - name, - config, - ux, - updateHandler, - current, - passProps, - ...rest -}) => { +export const CoreSetting = ({ name, config, ux, updateHandler, current, passProps, ...rest }) => { // is toggling allowed? const allowToggle = ux > 3 && config.list?.length === 2 @@ -98,10 +99,8 @@ export const CoreSetting = ({ /* * Load a specific update handler if one is configured */ - const handler = Swizzled.config.menuCoreSettingsHandlerMethods?.[name.toLowerCase()] - ? Swizzled.methods[Swizzled.config.menuCoreSettingsHandlerMethods[name.toLowerCase()]]( - handlerArgs - ) + const handler = coreSettingsHandlerMethods[name.toLowerCase()] + ? coreSettingsHandlerMethods[name.toLowerCase()](handlerArgs) : updateHandler return ( diff --git a/packages/react/components/Editor/swizzle/components/menus/design-options-menu.mjs b/packages/react/components/Editor/components/menus/DesignOptionsMenu.mjs similarity index 52% rename from packages/react/components/Editor/swizzle/components/menus/design-options-menu.mjs rename to packages/react/components/Editor/components/menus/DesignOptionsMenu.mjs index e061c1821bc..4ff201e860a 100644 --- a/packages/react/components/Editor/swizzle/components/menus/design-options-menu.mjs +++ b/packages/react/components/Editor/components/menus/DesignOptionsMenu.mjs @@ -1,16 +1,39 @@ -import { useCallback, useMemo } from 'react' +// Dependencies +import { menuDesignOptionsStructure } from '../../lib/index.mjs' +// Hooks +import React, { useCallback, useMemo } from 'react' +// Components +import { + MenuBoolInput, + MenuConstantInput, + MenuSliderInput, + MenuDegInput, + MenuListInput, + MenuPctInput, +} from './Input.mjs' +import { + MenuBoolValue, + MenuConstantOptionValue, + MenuCountOptionValue, + MenuDegOptionValue, + MenuListOptionValue, + MenyMmOptionValue, + MenuPctOptionValue, +} from './Value.mjs' +import { MenuItemGroup } from './Container.mjs' +import { OptionsIcon } from '@freesewing/react/components/Icon' +// /** * The design options menu * @param {object} props.Design - An object holding the Design instance * @param {String} props.isFirst - Boolean indicating whether this is the first/top entry of the menu * @param {Object} props.state - Object holding state * @param {Object} props.update - Object holding state handlers - * @param {object} props.Swizzled - An object holding swizzled code */ -export const DesignOptionsMenu = ({ Design, isFirst = true, state, update, Swizzled }) => { +export const DesignOptionsMenu = ({ Design, isFirst = true, state, update }) => { const structure = useMemo( - () => Swizzled.methods.menuDesignOptionsStructure(Design.patternConfig.options, state.settings), + () => menuDesignOptionsStructure(Design.patternConfig.options, state.settings), [Design.patternConfig, state.settings] ) const updateHandler = useCallback( @@ -20,45 +43,34 @@ export const DesignOptionsMenu = ({ Design, isFirst = true, state, update, Swizz const drillProps = { Design, state, update } const inputs = { - bool: (props) => , - constant: (props) => , + bool: (props) => , + constant: (props) => , count: (props) => ( - - ), - deg: (props) => , - list: (props) => ( - + ), + deg: (props) => , + list: (props) => , mm: () => FIXME: Mm options are deprecated. Please report this , - pct: (props) => , + pct: (props) => , } const values = { - bool: (props) => , - constant: (props) => , - count: (props) => , - deg: (props) => , - list: (props) => , - mm: (props) => , - pct: (props) => , + bool: (props) => , + constant: (props) => , + count: (props) => , + deg: (props) => , + list: (props) => , + mm: (props) => , + pct: (props) => , } return ( - ( - - ), + Icon: OptionsIcon, + Item: (props) => , isFirst, name: 'pe:designOptions', language: state.locale, @@ -69,7 +81,6 @@ export const DesignOptionsMenu = ({ Design, isFirst = true, state, update, Swizz }, updateHandler, isDesignOptionsGroup: true, - Swizzled, state, Design, inputs, @@ -85,8 +96,8 @@ export const DesignOptionsMenu = ({ Design, isFirst = true, state, update, Swizz * @param {Object} options.settings core settings * @param {Object} options.rest the rest of the props */ -export const DesignOption = ({ config, settings, ux, inputs, values, Swizzled, ...rest }) => { - const type = Swizzled.methods.designOptionType(config) +export const DesignOption = ({ config, settings, ux, inputs, values, ...rest }) => { + const type = designOptionType(config) const Input = inputs[type] const Value = values[type] const allowOverride = ['pct', 'count', 'deg'].includes(type) @@ -96,12 +107,11 @@ export const DesignOption = ({ config, settings, ux, inputs, values, Swizzled, . if (config?.hide || (typeof config?.hide === 'function' && config.hide(settings))) return null return ( - { - const { name, config, Swizzled } = props + const { name, config } = props const boolConfig = useBoolConfig(name, config) - return + return } /** A placeholder for an input to handle constant values */ @@ -33,8 +35,6 @@ export const MenuConstantInput = ({ /** A {@see MenuSliderInput} to handle degree values */ export const MenuDegInput = (props) => { const { updateHandler } = props - const { MenuSliderInput } = props.Swizzled.components - const { round } = props.Swizzled.methods const degUpdateHandler = useCallback( (path, newVal) => { updateHandler(path, newVal === undefined ? undefined : Number(newVal)) @@ -67,7 +67,6 @@ export const MenuListInput = ({ changed, design, isDesignOption = false, - Swizzled, }) => { const handleChange = useSharedHandlers({ dflt: config.dflt, @@ -87,7 +86,7 @@ export const MenuListInput = ({ const sideBySide = config.sideBySide || desc.length + title.length < 42 return ( - {title}
      {compact ? null :
      {desc}
      }
- + ) }) } @@ -137,13 +136,10 @@ export const MenuListToggle = ({ config, changed, updateHandler, name }) => { export const MenuMmInput = (props) => { const { units, updateHandler, current, config } = props - const { MenuSliderInput } = props.Swizzled.components const mmUpdateHandler = useCallback( (path, newCurrent) => { const calcCurrent = - typeof newCurrent === 'undefined' - ? undefined - : props.Swizzled.methods.measurementAsMm(newCurrent, units) + typeof newCurrent === 'undefined' ? undefined : measurementAsMm(newCurrent, units) updateHandler(path, calcCurrent) }, [updateHandler, units] @@ -159,15 +155,11 @@ export const MenuMmInput = (props) => { config: { step: defaultStep, ...config, - dflt: props.Swizzled.methods.measurementAsUnits(config.dflt, units), + dflt: measurementAsUnits(config.dflt, units), }, - current: - current === undefined - ? undefined - : props.Swizzled.methods.measurementAsUnits(current, units), + current: current === undefined ? undefined : measurementAsUnits(current, units), updateHandler: mmUpdateHandler, - valFormatter: (val) => - units === 'imperial' ? props.Swizzle.methods.formatFraction128(val, null) : val, + valFormatter: (val) => (units === 'imperial' ? formatFraction128(val, null) : val), suffix: units === 'imperial' ? '"' : 'cm', }} /> @@ -243,27 +235,24 @@ export const MenuMmInput = (props) => { //} /** A {@see SliderInput} to handle percentage values */ -export const MenuPctInput = ({ current, changed, updateHandler, config, Swizzled, ...rest }) => { +export const MenuPctInput = ({ current, changed, updateHandler, config, ...rest }) => { const factor = 100 - let pctCurrent = changed ? Swizzled.methods.menuRoundPct(current, factor) : current + let pctCurrent = changed ? menuRoundPct(current, factor) : current const pctUpdateHandler = useCallback( (path, newVal) => - updateHandler( - path, - newVal === undefined ? undefined : Swizzled.methods.menuRoundPct(newVal, 1 / factor) - ), + updateHandler(path, newVal === undefined ? undefined : menuRoundPct(newVal, 1 / factor)), [updateHandler] ) return ( - @@ -293,7 +282,6 @@ export const MenuSliderInput = ({ setReset, children, changed, - Swizzled, }) => { const { max, min } = config const handleChange = useSharedHandlers({ @@ -310,10 +298,9 @@ export const MenuSliderInput = ({ return ( <>
- { const [manualEdit, setManualEdit] = useState(props.current) - const { config, handleChange, Swizzled } = props - const type = Swizzled.methods.designOptionType(config) + const { config, handleChange } = props + const type = designOptionType(config) const onUpdate = useCallback( (validVal) => { @@ -370,14 +357,12 @@ export const MenuEditOption = (props) => { return (
@@ -427,16 +412,13 @@ const useBoolConfig = (name, config) => { /** an input for the 'only' setting. toggles individual parts*/ export const MenuOnlySettingInput = (props) => { - const { Swizzled, config } = props - const { t } = Swizzled.methods + const { config } = props config.sideBySide = true config.titleMethod = (entry, t) => { const chunks = entry.split('.') return {t(`${chunks[0]}:${chunks[1]}`)} } - config.valueMethod = (entry) => ( - {Swizzled.methods.capitalize(entry.split('.')[0])} - ) + config.valueMethod = (entry) => {capitalize(entry.split('.')[0])} config.dense = true // Sort alphabetically (translated) const order = [] @@ -447,13 +429,11 @@ export const MenuOnlySettingInput = (props) => { order.sort() config.list = order.map((entry) => entry.split('|')[1]) - return + return } export const MenuUxSettingInput = (props) => { - const { state, update, Swizzled } = props + const { state, update } = props - return ( - - ) + return } diff --git a/packages/react/components/Editor/swizzle/components/menus/shared-values.mjs b/packages/react/components/Editor/components/menus/Value.mjs similarity index 60% rename from packages/react/components/Editor/swizzle/components/menus/shared-values.mjs rename to packages/react/components/Editor/components/menus/Value.mjs index c94b6da8866..f72c49f32e1 100644 --- a/packages/react/components/Editor/swizzle/components/menus/shared-values.mjs +++ b/packages/react/components/Editor/components/menus/Value.mjs @@ -1,3 +1,4 @@ +import React from 'react' import { mergeOptions } from '@freesewing/core' /** Displays that constant values are not implemented in the front end */ @@ -6,16 +7,13 @@ export const MenuConstantOptionValue = () => ( ) /** Displays a count value*/ -export const MenuCountOptionValue = ({ Swizzled, config, current, changed }) => ( - +export const MenuCountOptionValue = ({ config, current, changed }) => ( + ) /** Displays a degree value */ -export const MenuDegOptionValue = ({ config, current, changed, Swizzled }) => ( - - {' '} - {changed ? current : config.deg}° - +export const MenuDegOptionValue = ({ config, current, changed }) => ( + {changed ? current : config.deg}° ) /** @@ -29,10 +27,7 @@ export const MenuHighlightValue = ({ changed, children }) => ( /** Displays a list option value */ export const MenuListOptionValue = (props) => ( - props.Swizzled.methods.t(`${props.design}:${props.config.name}.${input}.t`)} - /> + 'fixme handle option translation'} /> ) /** @@ -41,9 +36,8 @@ export const MenuListOptionValue = (props) => ( * @param {Function} options.t a translation function * @param {Object} options.config the item config * @param {Boolean} options.changed has the value been changed? - * @param {object} props.Swizzled - An object holding swizzled code */ -export const MenuListValue = ({ current, config, changed, Swizzled }) => { +export const MenuListValue = ({ current, config, changed }) => { // get the values const val = changed ? current : config.dflt @@ -54,17 +48,12 @@ export const MenuListValue = ({ current, config, changed, Swizzled }) => { // if not, is the value a string else if (typeof val === 'string') key = val // otherwise stringify booleans - else if (val) key = - else key = + else if (val) key = + else key = - const translated = - config.doNotTranslate || typeof key !== 'string' ? key : Swizzled.methods.t(key) + const translated = config.doNotTranslate || typeof key !== 'string' ? key : t(key) - return ( - - {translated} - - ) + return {translated} } /** Displays the corrent, translated value for a boolean */ @@ -76,14 +65,14 @@ export const MenuMmOptionValue = () => ( ) /** Displays a formated mm value based on the current units */ -export const MenuMmValue = ({ current, config, units, changed, Swizzled }) => ( - +export const MenuMmValue = ({ current, config, units, changed }) => ( + - + ) /** Displays the current percentage value, and the absolute value if configured @@ -95,25 +84,18 @@ export const MenuMmValue = ({ current, config, units, changed, Swizzled }) => ( * msg PencilIcon ResetIcon * ************************************************************************** * */ -export const MenuPctOptionValue = ({ - config, - current, - settings, - changed, - patternConfig, - Swizzled, -}) => { +export const MenuPctOptionValue = ({ config, current, settings, changed, patternConfig }) => { const val = changed ? current : config.pct / 100 return ( - - {Swizzled.methods.formatPercentage(val)} + + {formatPercentage(val)} {config.toAbs && settings?.measurements - ? ` | ${Swizzled.methods.formatMm( + ? ` | ${formatMm( config.toAbs(val, settings, mergeOptions(settings, patternConfig.options)) )}` : null} - + ) } @@ -123,18 +105,16 @@ export const MenuPctOptionValue = ({ * @param {Number|String|Boolean} options.dflt - The default value * @param {Boolean} options.changed - Has the value been changed? */ -export const MenuShowValue = ({ Swizzled, current, dflt, changed }) => { - const { MenuHighlightValue } = Swizzled.components - +export const MenuShowValue = ({ current, dflt, changed }) => { return {changed ? current : dflt} } -export const MenuScaleSettingValue = ({ Swizzled, current, config, changed }) => ( - +export const MenuScaleSettingValue = ({ current, config, changed }) => ( + ) -export const MenuOnlySettingValue = ({ Swizzled, current, config }) => ( - ( + { +export const DraftView = ({ Design, state, update, config }) => { /* * Don't trust that we have all measurements * * We do not need to change the view here. That is done in the central * ViewWrapper componenet. However, checking the measurements against * the design takes a brief moment, so this component will typically - * render before that happens, and if measurments are missing it will + * render before that happens, and if measurements are missing it will * throw and error. * * So when measurements are missing, we just return here and the view * will switch on the next render loop. */ - if (Swizzled.methods.missingMeasurements(state)) return null + if (missingMeasurements(state)) return /* * First, attempt to draft */ - const { pattern } = Swizzled.methods.draft(Design, state.settings) + const { pattern } = draft(Design, state.settings) let output = null let renderProps = false @@ -36,9 +45,9 @@ export const DraftView = ({ Design, state, update, Swizzled }) => { try { const __html = pattern.render() output = ( - +
- + ) } catch (err) { console.log(err) @@ -46,7 +55,7 @@ export const DraftView = ({ Design, state, update, Swizzled }) => { } else { renderProps = pattern.getRenderProps() output = ( - { } return ( - - ) : null - } + : null} /> ) } diff --git a/packages/react/components/Editor/components/views/MeasurementsView.mjs b/packages/react/components/Editor/components/views/MeasurementsView.mjs index a04e6ec53fc..84852cfbf51 100644 --- a/packages/react/components/Editor/components/views/MeasurementsView.mjs +++ b/packages/react/components/Editor/components/views/MeasurementsView.mjs @@ -1,7 +1,7 @@ // Dependencies -import { horFlexClasses } from '../../utils.mjs' import { t, designMeasurements } from '../../lib/index.mjs' import { capitalize } from '@freesewing/utils' +import { measurements as measurementsTranslations } from '@freesewing/i18n' // Hooks import React, { Fragment, useEffect } from 'react' // Components @@ -17,7 +17,11 @@ import { MeasurementsEditor } from '../MeasurementsEditor.mjs' import { SetPicker, BookmarkedSetPicker, CuratedSetPicker, UserSetPicker } from '../Set.mjs' import { HeaderMenu } from '../HeaderMenu.mjs' -const iconClasses = { className: 'w-8 h-8 md:w-10 md:h-10 lg:w-12 lg:h-12 shrink-0', stroke: 1.5 } +const iconClasses = { + className: 'tw-w-8 tw-h-8 md:tw-w-10 md:tw-h-10 lg:tw-w-12 lg:tw-h-12 tw-shrink-0', + stroke: 1.5, +} +const horFlexClasses = 'tw-flex tw-flex-row tw-items-center tw-justify-between tw-gap-4 tw-w-full' /** * The measurements view is loaded to update/set measurements @@ -40,7 +44,13 @@ export const MeasurementsView = ({ config, Design, missingMeasurements, state, u useEffect(() => { if (!config?.views || !config.views.includes(state.view)) update.view('measurements') if (state._.missingMeasurements && state._.missingMeasurements.length > 0) - update.notify({ msg: t('pe:missingMeasurementsNotify'), icon: 'tip' }, 'missingMeasurements') + update.notify( + { + msg: 'To generate this pattern, we need some additional measurements', + icon: 'tip', + }, + 'missingMeasurements' + ) else update.notifySuccess(t('pe:measurementsAreOk')) }, [state.view, update]) @@ -48,9 +58,9 @@ export const MeasurementsView = ({ config, Design, missingMeasurements, state, u update.settings(['measurements'], designMeasurements(Design, set.measies)) update.settings(['units'], set.imperial ? 'imperial' : 'metric') // Save the measurement set name to pattern settings - if (set[`name${capitalize(locale)}`]) + if (set.nameEn) // Curated measurement set - update.settings(['metadata'], { setName: set[`name${capitalize(locale)}`] }) + update.settings(['metadata'], { setName: set.nameEn }) else if (set.name) // User measurement set update.settings(['metadata'], { setName: set.name }) @@ -63,10 +73,13 @@ export const MeasurementsView = ({ config, Design, missingMeasurements, state, u [
-
{t('pe:chooseFromOwnSets')}
+

Choose one of your own measurements sets

-

{t('pe:chooseFromOwnSetsDesc')}

+

+ Pick any of your own measurements sets that have all required measurements to generate + this pattern. +

,
-
{t('pe:chooseFromBookmarkedSets')}
+

Choose one of the measurements sets you have bookmarked

-

{t('pe:chooseFromBookmarkedSetsDesc')}

+

+ If you have bookmarked any measurements sets, you can select from those too. +

,
-
{t('pe:chooseFromCuratedSets')}
+

Choose one of FreeSewing's curated measurements sets

-

{t('pe:chooseFromCuratedSetsDesc')}

+

+ If you're just looking to try out our platform, you can select from our list of + curated measurements sets. +

, , 'csets', @@ -110,10 +128,10 @@ export const MeasurementsView = ({ config, Design, missingMeasurements, state, u items.push([
-
{t('pe:editMeasurements')}
+

Edit Measurements

-

{t('pe:editMeasurementsDesc')}

+

You can manually set or override measurements below.

, , 'edit', @@ -122,35 +140,38 @@ export const MeasurementsView = ({ config, Design, missingMeasurements, state, u return ( <> -
-

{t('pe:measurements')}

+
+

Measurements

{missingMeasurements && missingMeasurements.length > 0 ? ( -
{t('pe:missingMeasurementsInfo')}:
-
    +

    + To generate this pattern, we need {missingMeasurements.length} additional measurement + {missingMeasurements.length === 1 ? '' : 's'}: +

    +
      {missingMeasurements.map((m, i) => ( -
    1. - {i > 0 ? , : null} - {t(`measurements:${m}`)} +
    2. + {i > 0 ? , : null} + {measurementsTranslations[m]}
    3. ))}
    -

    - ({missingMeasurements.length} {t('pe:missingMeasurements')}) -

    ) : ( -
    {t('pe:measurementsAreOk')}
    -
    -
    diff --git a/packages/react/components/Editor/components/views/index.mjs b/packages/react/components/Editor/components/views/index.mjs index 99394f8e728..b8970b76fc4 100644 --- a/packages/react/components/Editor/components/views/index.mjs +++ b/packages/react/components/Editor/components/views/index.mjs @@ -2,20 +2,9 @@ import React from 'react' import { ViewPicker } from './ViewPicker.mjs' import { DesignsView } from './DesignsView.mjs' import { MeasurementsView } from './MeasurementsView.mjs' +import { DraftView } from './DraftView.mjs' import { ErrorIcon } from '@freesewing/react/components/Icon' -/* - * This allows us to load a view component from the view name - */ -export const viewComponents = { - // DraftView, - DesignsView, - // SaveView, - ViewPicker, - MeasurementsView, - // UndosView, -} - /* * This returns a view-specific component */ @@ -24,6 +13,7 @@ export const View = (props) => { if (view === 'designs') return if (view === 'measurements') return + if (view === 'draft') return /* viewComponents: { draft: 'DraftView', @@ -44,7 +34,7 @@ export const View = (props) => { }, */ - return

    No view component for view {props.view}

    + return

    No view component for view {props.view}

    } /* diff --git a/packages/react/components/Editor/config/index.mjs b/packages/react/components/Editor/config/index.mjs index 6ac0db8bbb5..4d931b961b3 100644 --- a/packages/react/components/Editor/config/index.mjs +++ b/packages/react/components/Editor/config/index.mjs @@ -5,7 +5,7 @@ export const defaultConfig = { // Enable use of a (FreeSewing) backend to load data from enableBackend: true, // Link to create a new measurements set, set to false to disable - hrefNewSet: 'https://freesewing.org/new/set', + hrefNewSet: '/new/set', // Cloud default image cloudImageDflt: 'https://imagedelivery.net/ouSuR9yY1bHt-fuAokSA5Q/365cc64e-1502-4d2b-60e0-cc8beee73f00/public', @@ -56,12 +56,6 @@ export const defaultConfig = { mm: 'MmOptionValue', pct: 'PctOptionValue', }, - // Facilitate custom handlers for core settings - menuCoreSettingsHandlerMethods: { - only: 'menuCoreSettingsOnlyHandler', - sabool: 'menuCoreSettingsSaboolHandler', - samm: 'menuCoreSettingsSammHandler', - }, menuGroupEmojis: { advanced: '🤓', fit: '👕', diff --git a/packages/react/components/Editor/hooks/useEditorState.mjs b/packages/react/components/Editor/hooks/useEditorState.mjs index 3d4c8d02878..a975b6384b8 100644 --- a/packages/react/components/Editor/hooks/useEditorState.mjs +++ b/packages/react/components/Editor/hooks/useEditorState.mjs @@ -34,7 +34,7 @@ export const useEditorState = (init = {}, setEphemeralState, config) => { if (typeof URLSearchParams !== 'undefined') { try { const data = getHashData() - if (data.s === 'object') setState(data.s) + if (typeof data.s === 'object') setState(data.s) else setState(init) } catch (err) { setState(init) diff --git a/packages/react/components/Editor/index.mjs b/packages/react/components/Editor/index.mjs index 5f1fabead29..234190c5f7a 100644 --- a/packages/react/components/Editor/index.mjs +++ b/packages/react/components/Editor/index.mjs @@ -1,6 +1,7 @@ // Dependencies import { designs } from '@freesewing/collection' -import { hasRequiredMeasurements, initialEditorState } from './lib/index.mjs' +import { hasRequiredMeasurements } from '@freesewing/utils' +import { initialEditorState } from './lib/index.mjs' import { mergeConfig } from './config/index.mjs' // Hooks import React, { useState } from 'react' diff --git a/packages/react/components/Editor/lib/core-settings.mjs b/packages/react/components/Editor/lib/core-settings.mjs index d6a736be192..36badad09fc 100644 --- a/packages/react/components/Editor/lib/core-settings.mjs +++ b/packages/react/components/Editor/lib/core-settings.mjs @@ -1,13 +1,32 @@ -export function defaultSa(Swizzled, units, inMm = true) { +// Dependencies +import { defaultConfig as config } from '../config/index.mjs' +import { measurementAsMm } from '@freesewing/utils' +/* + * Components + * Note that these are only used as returns values + * There's no JSX in here so no React import needed + */ +import { + DetailIcon, + ExpandIcon, + IncludeIcon, + MarginIcon, + PaperlessIcon, + SaIcon, + ScaleIcon, + UnitsIcon, +} from '@freesewing/react/components/Icon' + +export function defaultSa(units, inMm = true) { const dflt = units === 'imperial' ? 0.5 : 1 - return inMm ? Swizzled.methods.measurementAsMm(dflt, units) : dflt + return inMm ? measurementAsMm(dflt, units) : dflt } -export function defaultSamm(Swizzled, units, inMm = true) { +export function defaultSamm(units, inMm = true) { const dflt = units === 'imperial' ? 0.5 : 1 - return inMm ? Swizzled.methods.measurementAsMm(dflt, units) : dflt + return inMm ? measurementAsMm(dflt, units) : dflt } /** custom event handlers for inputs that need them */ -export function menuCoreSettingsOnlyHandler(Swizzled, { updateHandler, current }) { +export function menuCoreSettingsOnlyHandler({ updateHandler, current }) { return function (path, part) { // Is this a reset? if (part === undefined || part === '__UNSET__') return updateHandler(path, part) @@ -26,7 +45,7 @@ export function menuCoreSettingsOnlyHandler(Swizzled, { updateHandler, current } } } -export function menuCoreSettingsSammHandler(Swizzled, { updateHandler, config }) { +export function menuCoreSettingsSammHandler({ updateHandler, config }) { return function (_path, newCurrent) { // convert to millimeters if there's a value newCurrent = newCurrent === undefined ? config.dflt : newCurrent @@ -36,16 +55,13 @@ export function menuCoreSettingsSammHandler(Swizzled, { updateHandler, config }) } } -export function menuCoreSettingsSaboolHandler(Swizzled, { toggleSa }) { +export function menuCoreSettingsSaboolHandler({ toggleSa }) { return toggleSa } -export function menuCoreSettingsStructure( - Swizzled, - { units = 'metric', sabool = false, parts = [] } -) { +export function menuCoreSettingsStructure({ units = 'metric', sabool = false, parts = [] }) { return { sabool: { - ux: Swizzled.config.uxLevels.core.sa, + ux: config.uxLevels.core.sa, list: [0, 1], choiceTitles: { 0: 'saNo', @@ -56,19 +72,19 @@ export function menuCoreSettingsStructure( 1: 'yes', }, dflt: 0, - icon: Swizzled.components.SaIcon, + icon: SaIcon, }, samm: sabool ? { - ux: Swizzled.config.uxLevels.core.sa, + ux: config.uxLevels.core.sa, min: 0, max: units === 'imperial' ? 2 : 2.5, - dflt: Swizzled.methods.defaultSamm(units), - icon: Swizzled.components.SaIcon, + dflt: defaultSamm(units), + icon: SaIcon, } : false, paperless: { - ux: Swizzled.config.uxLevels.core.paperless, + ux: config.uxLevels.core.paperless, list: [0, 1], choiceTitles: { 0: 'paperlessNo', @@ -79,10 +95,10 @@ export function menuCoreSettingsStructure( 1: 'yes', }, dflt: 0, - icon: Swizzled.components.PaperlessIcon, + icon: PaperlessIcon, }, units: { - ux: Swizzled.config.uxLevels.core.units, + ux: config.uxLevels.core.units, list: ['metric', 'imperial'], dflt: 'metric', choiceTitles: { @@ -93,10 +109,10 @@ export function menuCoreSettingsStructure( metric: 'metric', imperial: 'imperial', }, - icon: Swizzled.components.UnitsIcon, + icon: UnitsIcon, }, complete: { - ux: Swizzled.config.uxLevels.core.complete, + ux: config.uxLevels.core.complete, list: [1, 0], dflt: 1, choiceTitles: { @@ -107,10 +123,10 @@ export function menuCoreSettingsStructure( 0: 'no', 1: 'yes', }, - icon: Swizzled.components.DetailIcon, + icon: DetailIcon, }, expand: { - ux: Swizzled.config.uxLevels.core.expand, + ux: config.uxLevels.core.expand, list: [1, 0], dflt: 1, choiceTitles: { @@ -121,29 +137,29 @@ export function menuCoreSettingsStructure( 0: 'no', 1: 'yes', }, - icon: Swizzled.components.ExpandIcon, + icon: ExpandIcon, }, only: { - ux: Swizzled.config.uxLevels.core.only, + ux: config.uxLevels.core.only, dflt: false, list: parts, parts, - icon: Swizzled.components.IncludeIcon, + icon: IncludeIcon, }, scale: { - ux: Swizzled.config.uxLevels.core.scale, + ux: config.uxLevels.core.scale, min: 0.1, max: 5, dflt: 1, step: 0.1, - icon: Swizzled.components.ScaleIcon, + icon: ScaleIcon, }, margin: { - ux: Swizzled.config.uxLevels.core.margin, + ux: config.uxLevels.core.margin, min: 0, max: 2.5, - dflt: Swizzled.methods.measurementAsMm(units === 'imperial' ? 0.125 : 0.2, units), - icon: Swizzled.components.MarginIcon, + dflt: measurementAsMm(units === 'imperial' ? 0.125 : 0.2, units), + icon: MarginIcon, }, } } diff --git a/packages/react/components/Editor/lib/design-options.mjs b/packages/react/components/Editor/lib/design-options.mjs index 43a9718d62a..59c6eeec066 100644 --- a/packages/react/components/Editor/lib/design-options.mjs +++ b/packages/react/components/Editor/lib/design-options.mjs @@ -1,4 +1,4 @@ -export function designOptionType(Swizzled, option) { +export function designOptionType(option) { if (typeof option?.pct !== 'undefined') return 'pct' if (typeof option?.bool !== 'undefined') return 'bool' if (typeof option?.count !== 'undefined') return 'count' @@ -12,7 +12,7 @@ import { mergeOptions } from '@freesewing/core' import set from 'lodash.set' import orderBy from 'lodash.orderby' -export function menuDesignOptionsStructure(Swizzled, options, settings, asFullList = false) { +export function menuDesignOptionsStructure(options, settings, asFullList = false) { if (!options) return options const sorted = {} for (const [name, option] of Object.entries(options)) { @@ -23,7 +23,7 @@ export function menuDesignOptionsStructure(Swizzled, options, settings, asFullLi // Fixme: One day we should sort this based on the translation for (const option of orderBy(sorted, ['order', 'menu', 'name'], ['asc', 'asc', 'asc'])) { if (typeof option === 'object') { - const oType = Swizzled.methods.designOptionType(option) + const oType = designOptionType(option) option.dflt = option.dflt || option[oType] if (oType === 'pct') option.dflt /= 100 if (typeof option.menu === 'function') @@ -64,17 +64,14 @@ export function menuDesignOptionsStructure(Swizzled, options, settings, asFullLi * * Since these structures can be nested with option groups, this needs some extra logic */ -export function getOptionStructure(Swizzled, option, Design, state) { - const structure = Swizzled.methods.menuDesignOptionsStructure( - Design.patternConfig.options, - state.settings - ) +export function getOptionStructure(option, Design, state) { + const structure = menuDesignOptionsStructure(Design.patternConfig.options, state.settings) console.log({ structure }) - return Swizzled.methods.findOption(structure, option) + return findOption(structure, option) } -export function findOption(Swizzled, structure, option) { +export function findOption(structure, option) { for (const [key, val] of Object.entries(structure)) { if (key === option) return val if (val.isGroup) { diff --git a/packages/react/components/Editor/lib/index.mjs b/packages/react/components/Editor/lib/index.mjs index 5422eb18be5..ec0c2d01688 100644 --- a/packages/react/components/Editor/lib/index.mjs +++ b/packages/react/components/Editor/lib/index.mjs @@ -55,13 +55,7 @@ import { shortDate, parseDistanceInput, } from './formatting.mjs' -import { - designMeasurements, - hasRequiredMeasurements, - isDegreeMeasurement, - missingMeasurements, - structureMeasurementsAsDesign, -} from './measurements.mjs' +import { designMeasurements, missingMeasurements } from './measurements.mjs' import { menuUiPreferencesStructure } from './ui-preferences.mjs' /* @@ -120,10 +114,7 @@ export { parseDistanceInput, // measurements.mjs designMeasurements, - hasRequiredMeasurements, - isDegreeMeasurement, missingMeasurements, - structureMeasurementsAsDesign, // ui-preferences.mjs menuUiPreferencesStructure, } diff --git a/packages/react/components/Editor/lib/measurements.mjs b/packages/react/components/Editor/lib/measurements.mjs index 0373867cf81..2e12f51c3a5 100644 --- a/packages/react/components/Editor/lib/measurements.mjs +++ b/packages/react/components/Editor/lib/measurements.mjs @@ -1,5 +1,5 @@ // Dependencies -import { defaultConfig as config } from '../config/index.mjs' +import { defaultConfig } from '../config/index.mjs' import { degreeMeasurements } from '@freesewing/config' /* @@ -16,46 +16,9 @@ export function designMeasurements(Design, measies = {}) { return measurements } -/** - * Helper method to determine whether all required measurements for a design are present - * - * @param {object} Design - The FreeSewing design (or a plain object holding measurements) - * @param {object} measurements - An object holding the user's measurements - * @return {array} result - An array where the first element is true when we - * have all measurements, and false if not. The second element is a list of - * missing measurements. - */ -export function hasRequiredMeasurements(Design, measurements = {}) { - /* - * If design is just a plain object holding measurements, we restructure it as a Design - * AS it happens, this method is smart enough to test for this, so we call it always - */ - Design = structureMeasurementsAsDesign(Design) - /* - * Walk required measuremnets, and keep track of what's missing - */ - const missing = [] - for (const m of Design.patternConfig?.measurements || []) { - if (typeof measurements[m] === 'undefined') missing.push(m) - } - - /* - * Return true or false, plus a list of missing measurements - */ - return [missing.length === 0, missing] -} -/** - * Helper method to determine whether a measurement uses degrees - * - * @param {string} name - The name of the measurement - * @return {bool} isDegree - True if the measurment is a degree measurement - */ -export function isDegreeMeasurement(name) { - return degreeMeasurements.indexOf(name) !== -1 -} /* - * Helper method to check whether measururements are missing + * Helper method to check whether measurements are missing * * Note that this does not actually check the settings against * the chosen design, but rather relies on the missing measurements @@ -63,22 +26,12 @@ export function isDegreeMeasurement(name) { * so we do it only once. * * @param {object} state - The Editor state - * @param {object} config - The Editor configuration * @return {bool} missing - True if there are missing measurments, false if not */ -export function missingMeasurements(state, config) { +export function missingMeasurements(state) { return ( - !config.measurementsFreeViews.includes(state.view) && + !defaultConfig.measurementsFreeViews.includes(state.view) && state._.missingMeasurements && state._.missingMeasurements.length > 0 ) } -/* - * This takes a POJO of measurements, and turns it into a structure that matches a design object - * - * @param {object} measurements - The POJO of measurments - * @return {object} design - The measurements structured as a design object - */ -export function structureMeasurementsAsDesign(measurements) { - return measurements.patternConfig ? measurements : { patternConfig: { measurements } } -} diff --git a/packages/react/components/Editor/swizzle/components/curated-sets.mjs b/packages/react/components/Editor/swizzle/components/curated-sets.mjs deleted file mode 100644 index bb25160bf82..00000000000 --- a/packages/react/components/Editor/swizzle/components/curated-sets.mjs +++ /dev/null @@ -1,37 +0,0 @@ -export const CuratedMeasurementsSetLineup = ({ sets = [], locale, clickHandler, Swizzled }) => ( -
    1 ? 'justify-start px-8' : 'justify-center' - } overflow-x-scroll`} - style={{ - backgroundImage: `url(/img/lineup-backdrop.svg)`, - width: 'auto', - backgroundSize: 'auto 100%', - backgroundRepeat: 'repeat-x', - }} - > - {sets.map((set) => { - const props = { - className: 'aspect-[1/3] w-auto h-96', - style: { - backgroundImage: `url(${Swizzled.methods.cloudImageUrl({ - id: `cset-${set.id}`, - type: 'lineup', - })})`, - width: 'auto', - backgroundSize: 'contain', - backgroundRepeat: 'no-repeat', - backgroundPosition: 'center', - }, - onClick: () => clickHandler(set), - } - - return ( -
    - - {set[`name${Swizzled.methods.capitalize(locale)}`]} -
    - ) - })} -
    -) diff --git a/packages/react/components/Input/index.mjs b/packages/react/components/Input/index.mjs index 6687d54fd0a..5c5b6b7c1ed 100644 --- a/packages/react/components/Input/index.mjs +++ b/packages/react/components/Input/index.mjs @@ -6,6 +6,7 @@ import { distanceAsMm, } from '@freesewing/utils' import { collection } from '@freesewing/collection' +import { measurements as measurementsTranslations } from '@freesewing/i18n' // Context import { ModalContext } from '@freesewing/react/context/Modal' import { LoadingStatusContext } from '@freesewing/react/context/LoadingStatus' @@ -527,7 +528,7 @@ export const MeasurementInput = ({ let inputClasses = 'daisy-input-secondary' let bottomLeftLabel = null if (valid === true) { - inputClasses = 'daisy-input-success' + inputClasses = 'daisy-input-success tw-outline-success' const val = `${validatedVal}${isDegree ? '°' : imperial ? '"' : 'cm'}` bottomLeftLabel = ( {val} @@ -549,17 +550,26 @@ export const MeasurementInput = ({ * See: https://github.com/facebook/react/issues/16554 */ return ( - - localUpdate(evt.target.value)} - className={`tw-daisy-input tw-w-full tw-daisy-input-bordered ${inputClasses}`} - /> + + ) } diff --git a/packages/react/components/Popout/index.mjs b/packages/react/components/Popout/index.mjs index b4c7b0c9fe4..3ce73c851f9 100644 --- a/packages/react/components/Popout/index.mjs +++ b/packages/react/components/Popout/index.mjs @@ -72,7 +72,7 @@ export const Popout = (props) => { >
    diff --git a/packages/react/components/Spinner/index.mjs b/packages/react/components/Spinner/index.mjs index 605908eaea1..bab761f3d2e 100644 --- a/packages/react/components/Spinner/index.mjs +++ b/packages/react/components/Spinner/index.mjs @@ -3,15 +3,15 @@ import React from 'react' /* * A simple spinner */ -export const Spinner = ({ className = 'h-6 w-6' }) => ( +export const Spinner = ({ className = 'tw-h-6 tw-w-6' }) => ( ( strokeWidth="4" > diff --git a/packages/utils/src/index.mjs b/packages/utils/src/index.mjs index 10f5214103d..ae6b2da76d6 100644 --- a/packages/utils/src/index.mjs +++ b/packages/utils/src/index.mjs @@ -227,6 +227,36 @@ export function getSearchParam(name = 'id') { return new URLSearchParams(window.location.search).get(name) // eslint-disable-line } +/** + * Helper method to determine whether all required measurements for a design are present + * + * @param {object} Design - The FreeSewing design (or a plain object holding measurements) + * @param {object} measurements - An object holding the user's measurements + * @return {array} result - An array where the first element is true when we + * have all measurements, and false if not. The second element is a list of + * missing measurements. + */ +export function hasRequiredMeasurements(Design, measurements = {}) { + /* + * If design is just a plain object holding measurements, we restructure it as a Design + * As it happens, this method is smart enough to test for this, so we call it always + */ + Design = structureMeasurementsAsDesign(Design) + + /* + * Walk required measurements, and keep track of what's missing + */ + const missing = [] + for (const m of Design.patternConfig?.measurements || []) { + if (typeof measurements[m] === 'undefined') missing.push(m) + } + + /* + * Return true or false, plus a list of missing measurements + */ + return [missing.length === 0, missing] +} + /* * Convert a measurement to millimeter * @@ -413,6 +443,15 @@ export function shortDate(timestamp = false, withTime = true) { */ export const shortUuid = (uuid) => uuid.slice(0, 5) +/* + * This takes a POJO of measurements, and turns it into a structure that matches a design object + * + * @param {object} measurements - The POJO of measurments + * @return {object} design - The measurements structured as a design object + */ +export function structureMeasurementsAsDesign(measurements) { + return measurements.patternConfig ? measurements : { patternConfig: { measurements } } +} /* * We used to use react-timeago but that's too much overhead * This is a drop-in replacement that does not rerender diff --git a/sites/org/static/img/lineup-backdrop.svg b/sites/org/static/img/lineup-backdrop.svg new file mode 100644 index 00000000000..c2b1f56f450 --- /dev/null +++ b/sites/org/static/img/lineup-backdrop.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + 0.60m + 0.80m + 1.00m + 1.20m + 1.40m + 1.60m + 1.80m + 2.00m + + + + + + + + + + + + + + + + + 2f + 3f + 4f + 5f + 6f + 7f + + + + \ No newline at end of file