chore(shared): Adapted (part of) workbench for UI consistency
This commit is contained in:
parent
084e6e534c
commit
5849e6d931
22 changed files with 490 additions and 230 deletions
58
sites/shared/components/accordion.mjs
Normal file
58
sites/shared/components/accordion.mjs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
/*
|
||||||
|
* DaisyUI's accordion seems rather unreliable.
|
||||||
|
* So instead, we handle this in React state
|
||||||
|
*/
|
||||||
|
export const Accordion = ({
|
||||||
|
items, // Items in the accordion
|
||||||
|
}) => {
|
||||||
|
const [active, setActive] = useState()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav>
|
||||||
|
{items.map((item, i) => (
|
||||||
|
<button
|
||||||
|
className={`
|
||||||
|
p-2 px-4 rounded-lg bg-transparent shadow
|
||||||
|
w-full mt-2 py-4 h-auto content-start text-left bg-opacity-20
|
||||||
|
${active === i ? 'hover:bg-transparent' : 'hover:bg-secondary hover:bg-opacity-10'}
|
||||||
|
`}
|
||||||
|
onClick={() => setActive(i)}
|
||||||
|
>
|
||||||
|
{item[0]}
|
||||||
|
{active === i ? item[1] : null}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SubAccordion = ({
|
||||||
|
items, // Items in the accordion
|
||||||
|
}) => {
|
||||||
|
const [active, setActive] = useState()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav>
|
||||||
|
{items.map((item, i) => (
|
||||||
|
<button
|
||||||
|
className={`
|
||||||
|
p-2 px-4 rounded
|
||||||
|
bg-transparent
|
||||||
|
w-full mt-2 py-4 h-auto content-start bg-secondary
|
||||||
|
text-left bg-opacity-20
|
||||||
|
${
|
||||||
|
active === i
|
||||||
|
? 'bg-opacity-100 hover:bg-transparent shadow'
|
||||||
|
: 'hover:bg-opacity-10 hover:bg-secondary '
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
onClick={() => setActive(i)}
|
||||||
|
>
|
||||||
|
{item[0]}
|
||||||
|
{active === i ? item[1] : null}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
|
@ -109,14 +109,17 @@ export const ButtonFrame = ({
|
||||||
children, // Children of the button
|
children, // Children of the button
|
||||||
onClick, // onClick handler
|
onClick, // onClick handler
|
||||||
active, // Whether or not to render the button as active/selected
|
active, // Whether or not to render the button as active/selected
|
||||||
|
accordion = false, // Set this to true to not set a background color when active
|
||||||
}) => (
|
}) => (
|
||||||
<button
|
<button
|
||||||
className={`
|
className={`
|
||||||
btn btn-ghost btn-secondary
|
btn btn-ghost btn-secondary
|
||||||
w-full mt-2 py-4 h-auto content-start
|
w-full mt-2 py-4 h-auto content-start
|
||||||
border-2 border-secondary text-left bg-opacity-20
|
border-2 border-secondary text-left bg-opacity-20
|
||||||
hover:bg-secondary hover:text-secondary-content hover:border-secondary hover:border-solid hover:border-2
|
${accordion ? 'hover:bg-transparent' : 'hover:bg-secondary hover:bg-opacity-10'}
|
||||||
${active ? 'bg-secondary border-solid' : 'bg-transparent border-dotted'}
|
hover:border-secondary hover:border-solid hover:border-2
|
||||||
|
${active ? 'border-solid' : 'border-dotted'}
|
||||||
|
${active && !accordion ? 'bg-secondary' : 'bg-transparent'}
|
||||||
`}
|
`}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
|
@ -398,9 +401,11 @@ export const ListInput = ({
|
||||||
<ButtonFrame key={i} active={item.val === current} onClick={() => update(item.val)}>
|
<ButtonFrame key={i} active={item.val === current} onClick={() => update(item.val)}>
|
||||||
<div className="w-full flex flex-col gap-2">
|
<div className="w-full flex flex-col gap-2">
|
||||||
<div className="w-full text-lg leading-5">{item.label}</div>
|
<div className="w-full text-lg leading-5">{item.label}</div>
|
||||||
|
{item.desc ? (
|
||||||
<div className="w-full text-normal font-normal normal-case pt-1 leading-5">
|
<div className="w-full text-normal font-normal normal-case pt-1 leading-5">
|
||||||
{item.desc}
|
{item.desc}
|
||||||
</div>
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</ButtonFrame>
|
</ButtonFrame>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -57,4 +57,11 @@ yamlEditViewTitleThing: 'Edit Pattern Configuration for {thing}'
|
||||||
yamlEditViewError: Issues with YAML
|
yamlEditViewError: Issues with YAML
|
||||||
yamlEditViewErrorDesc: We saved your input, but it might not work for the following reasons
|
yamlEditViewErrorDesc: We saved your input, but it might not work for the following reasons
|
||||||
saveSettings: Save Settings
|
saveSettings: Save Settings
|
||||||
|
youUseDefaultValue: You are using a custom value
|
||||||
|
youUseCustomValue: You are using the default value
|
||||||
|
testOptions: Test design options
|
||||||
|
testOptionsDesc: Test how the design adapts to changes in a specific desing option
|
||||||
|
testMeasurements: Test measurements
|
||||||
|
testMeasurementsDesc: Test how the design adapts to changes to a specific measurement
|
||||||
|
testSets: Test measurements sets
|
||||||
|
testSetsDesc: Test how the design adapts across different measurements sets
|
||||||
|
|
|
@ -16,6 +16,9 @@ import {
|
||||||
DocsIcon,
|
DocsIcon,
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
MeasieIcon,
|
MeasieIcon,
|
||||||
|
XrayIcon,
|
||||||
|
EditIcon,
|
||||||
|
ExportIcon,
|
||||||
} from 'shared/components/icons.mjs'
|
} from 'shared/components/icons.mjs'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { MenuWrapper } from 'shared/components/workbench/menus/shared/menu-wrapper.mjs'
|
import { MenuWrapper } from 'shared/components/workbench/menus/shared/menu-wrapper.mjs'
|
||||||
|
@ -24,14 +27,14 @@ export const ns = ['workbench', 'sections']
|
||||||
|
|
||||||
const icons = {
|
const icons = {
|
||||||
test: BeakerIcon,
|
test: BeakerIcon,
|
||||||
export: BriefcaseIcon,
|
export: ExportIcon,
|
||||||
edit: CodeIcon,
|
Edit: EditIcon,
|
||||||
cut: CutIcon,
|
cut: CutIcon,
|
||||||
draft: OptionsIcon,
|
draft: OptionsIcon,
|
||||||
print: PrintIcon,
|
print: PrintIcon,
|
||||||
save: UploadIcon,
|
save: UploadIcon,
|
||||||
logs: DocsIcon,
|
logs: CodeIcon,
|
||||||
inspect: SearchIcon,
|
inspect: XrayIcon,
|
||||||
measies: MeasieIcon,
|
measies: MeasieIcon,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,31 +131,31 @@ const NavIcons = ({ setView, setDense, dense, view }) => {
|
||||||
label={t('workbench:exportPattern')}
|
label={t('workbench:exportPattern')}
|
||||||
active={view === 'export'}
|
active={view === 'export'}
|
||||||
>
|
>
|
||||||
<BriefcaseIcon className={iconSize} />
|
<ExportIcon className={iconSize} />
|
||||||
</NavButton>
|
</NavButton>
|
||||||
<NavButton
|
<NavButton
|
||||||
onClick={() => setView('edit')}
|
onClick={() => setView('edit')}
|
||||||
label={t('workbench:editSettings')}
|
label={t('workbench:editSettings')}
|
||||||
active={view === 'edit'}
|
active={view === 'edit'}
|
||||||
>
|
>
|
||||||
<CodeIcon className={iconSize} />
|
<EditIcon className={iconSize} />
|
||||||
</NavButton>
|
</NavButton>
|
||||||
<NavButton
|
<NavButton
|
||||||
onClick={() => setView('logs')}
|
onClick={() => setView('logs')}
|
||||||
label={t('workbench:patternLogs')}
|
label={t('workbench:patternLogs')}
|
||||||
active={view === 'logs'}
|
active={view === 'logs'}
|
||||||
>
|
>
|
||||||
<DocsIcon className={iconSize} />
|
<CodeIcon className={iconSize} />
|
||||||
</NavButton>
|
</NavButton>
|
||||||
<NavButton
|
<NavButton
|
||||||
onClick={() => setView('inspect')}
|
onClick={() => setView('inspect')}
|
||||||
label={t('workbench:patternInspector')}
|
label={t('workbench:patternInspector')}
|
||||||
active={view === 'inspect'}
|
active={view === 'inspect'}
|
||||||
>
|
>
|
||||||
<SearchIcon className={iconSize} />
|
<XrayIcon className={iconSize} />
|
||||||
</NavButton>
|
</NavButton>
|
||||||
<NavButton label={t('workbench:docs')} href="/docs/site/draft">
|
<NavButton label={t('workbench:docs')} href="/docs/site/draft">
|
||||||
<HelpIcon className={iconSize} />
|
<DocsIcon className={iconSize} />
|
||||||
</NavButton>
|
</NavButton>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -49,4 +49,5 @@ saNo.t: Do not include seam allowance
|
||||||
saNo.d: This generates a pattern which does not include any seam allowance. The size of the seam allowance does not matter as no seam allowancce will be included.
|
saNo.d: This generates a pattern which does not include any seam allowance. The size of the seam allowance does not matter as no seam allowancce will be included.
|
||||||
saYes.t: Include seam allowance
|
saYes.t: Include seam allowance
|
||||||
saYes.d: This generates a pattern that will include seam allowance. The size of the seam allowance is set individually.
|
saYes.d: This generates a pattern that will include seam allowance. The size of the seam allowance is set individually.
|
||||||
|
clearSettingsNotMeasurements: Clear settings, but keep measurements
|
||||||
|
clearSettingsAndMeasurements: Clear settings & Clear measurements
|
||||||
|
|
|
@ -71,7 +71,7 @@ export const DesignOptions = ({
|
||||||
isFirst = true,
|
isFirst = true,
|
||||||
DynamicDocs = false,
|
DynamicDocs = false,
|
||||||
}) => {
|
}) => {
|
||||||
const menuNs = [`o_${design}`, ...ns]
|
const menuNs = [design, ...ns]
|
||||||
const optionsMenu = useMemo(() => optionsMenuStructure(patternConfig.options), [patternConfig])
|
const optionsMenu = useMemo(() => optionsMenuStructure(patternConfig.options), [patternConfig])
|
||||||
const updateFunc = useCallback(
|
const updateFunc = useCallback(
|
||||||
(name, value) => update.settings(['options', ...name], value),
|
(name, value) => update.settings(['options', ...name], value),
|
||||||
|
@ -101,6 +101,8 @@ export const DesignOptions = ({
|
||||||
ns: menuNs,
|
ns: menuNs,
|
||||||
passProps: { settings, patternConfig },
|
passProps: { settings, patternConfig },
|
||||||
updateFunc,
|
updateFunc,
|
||||||
|
values,
|
||||||
|
isDesignOptionsGroup: true,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -35,7 +35,7 @@ const PctOptionInput = (props) => {
|
||||||
export const inputs = {
|
export const inputs = {
|
||||||
bool: BoolInput,
|
bool: BoolInput,
|
||||||
constant: ConstantInput,
|
constant: ConstantInput,
|
||||||
count: SliderInput,
|
count: (props) => <SliderInput {...props} config={{ ...props.config, step: 1 }} />,
|
||||||
deg: DegInput,
|
deg: DegInput,
|
||||||
list: ListInput,
|
list: ListInput,
|
||||||
mm: () => <span>FIXME: Mm options are deprecated. Please report this </span>,
|
mm: () => <span>FIXME: Mm options are deprecated. Please report this </span>,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { formatMm, formatPercentage } from 'shared/utils.mjs'
|
||||||
import { ListValue, HighlightedValue, PlainValue, BoolValue } from '../shared/values'
|
import { ListValue, HighlightedValue, PlainValue, BoolValue } from '../shared/values'
|
||||||
import { mergeOptions } from '@freesewing/core'
|
import { mergeOptions } from '@freesewing/core'
|
||||||
|
|
||||||
/** Displays the current percentatge value, and the absolute value if configured */
|
/** Displays the current percentage value, and the absolute value if configured */
|
||||||
export const PctOptionValue = ({ config, current, settings, changed, patternConfig }) => {
|
export const PctOptionValue = ({ config, current, settings, changed, patternConfig }) => {
|
||||||
const val = changed ? current : config.pct / 100
|
const val = changed ? current : config.pct / 100
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useContext } from 'react'
|
//import { useContext } from 'react'
|
||||||
import { MenuItemGroup } from './menu-item.mjs'
|
import { MenuItemGroup } from './menu-item.mjs'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
|
//import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
|
||||||
import { ModalContext } from 'shared/context/modal-context.mjs'
|
//import { ModalContext } from 'shared/context/modal-context.mjs'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a loadDocs method for a menu
|
* get a loadDocs method for a menu
|
||||||
|
@ -11,6 +11,7 @@ import { ModalContext } from 'shared/context/modal-context.mjs'
|
||||||
* @param {string} language the language to get documentation in
|
* @param {string} language the language to get documentation in
|
||||||
* @return {Function | false} an event handler that loads does into a modal
|
* @return {Function | false} an event handler that loads does into a modal
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
export const useDocsLoader = (DynamicDocs, getDocsPath, language) => {
|
export const useDocsLoader = (DynamicDocs, getDocsPath, language) => {
|
||||||
const { setModal } = useContext(ModalContext)
|
const { setModal } = useContext(ModalContext)
|
||||||
return DynamicDocs
|
return DynamicDocs
|
||||||
|
@ -27,6 +28,7 @@ export const useDocsLoader = (DynamicDocs, getDocsPath, language) => {
|
||||||
}
|
}
|
||||||
: false
|
: false
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component for a collapsible sidebar menu in workbench views
|
* A component for a collapsible sidebar menu in workbench views
|
||||||
|
@ -65,33 +67,18 @@ export const WorkbenchMenu = ({
|
||||||
Item,
|
Item,
|
||||||
isFirst,
|
isFirst,
|
||||||
children,
|
children,
|
||||||
|
docsPath,
|
||||||
|
isDesignOptionsGroup,
|
||||||
}) => {
|
}) => {
|
||||||
// get translation for the menu
|
// get translation for the menu
|
||||||
const { t } = useTranslation(ns)
|
const { t } = useTranslation(ns)
|
||||||
|
|
||||||
// get a documentation loader
|
// get a documentation loader
|
||||||
const loadDocs = useDocsLoader(DynamicDocs, getDocsPath, language)
|
//const loadDocs = useDocsLoader(DynamicDocs, getDocsPath, language)
|
||||||
|
|
||||||
return (
|
return children ? (
|
||||||
<>
|
children
|
||||||
<div className="px-2" key="header">
|
|
||||||
{control > 4 ? (
|
|
||||||
isFirst ? (
|
|
||||||
''
|
|
||||||
) : (
|
) : (
|
||||||
<div className="border-t border-solid border-base-300 mx-36"></div>
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<h5 className="flex flex-row gap-2 items-center">
|
|
||||||
<Icon />
|
|
||||||
<span>{t(`${name}`)}</span>
|
|
||||||
</h5>
|
|
||||||
<p>{t(`${name}.d`)}</p>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{children || (
|
|
||||||
<MenuItemGroup
|
<MenuItemGroup
|
||||||
{...{
|
{...{
|
||||||
collapsible: false,
|
collapsible: false,
|
||||||
|
@ -103,14 +90,16 @@ export const WorkbenchMenu = ({
|
||||||
Icon,
|
Icon,
|
||||||
values,
|
values,
|
||||||
inputs,
|
inputs,
|
||||||
loadDocs,
|
//loadDocs,
|
||||||
passProps,
|
passProps,
|
||||||
updateFunc,
|
updateFunc,
|
||||||
emojis,
|
emojis,
|
||||||
t,
|
t,
|
||||||
|
DynamicDocs,
|
||||||
|
getDocsPath,
|
||||||
|
language,
|
||||||
|
isDesignOptionsGroup,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import {
|
||||||
import { ChoiceButton } from 'shared/components/choice-button.mjs'
|
import { ChoiceButton } from 'shared/components/choice-button.mjs'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
|
import { ButtonFrame } from 'shared/components/inputs.mjs'
|
||||||
|
|
||||||
/*******************************************************************************************
|
/*******************************************************************************************
|
||||||
* This file contains the base components to be used by inputs in menus in the workbench
|
* This file contains the base components to be used by inputs in menus in the workbench
|
||||||
* For the purposes of our menus, we have two main types:
|
* For the purposes of our menus, we have two main types:
|
||||||
|
@ -229,25 +231,29 @@ export const ListInput = ({ name, config, current, updateFunc, compact = false,
|
||||||
name,
|
name,
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return config.list.map((entry) => {
|
||||||
<>
|
|
||||||
<p>{t(`${name}.d`)}</p>
|
|
||||||
{config.list.map((entry) => {
|
|
||||||
const titleKey = config.choiceTitles ? config.choiceTitles[entry] : `${name}.o.${entry}`
|
const titleKey = config.choiceTitles ? config.choiceTitles[entry] : `${name}.o.${entry}`
|
||||||
|
const title = t(`${titleKey}.t`)
|
||||||
|
const desc = t(`${titleKey}.d`)
|
||||||
|
const sideBySide = desc.length + title.length < 70
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChoiceButton
|
<ButtonFrame
|
||||||
key={entry}
|
key={entry}
|
||||||
title={t(`${titleKey}.t`)}
|
|
||||||
color={entry === config.dflt ? 'primary' : 'secondary'}
|
|
||||||
active={changed ? current === entry : entry === config.dflt}
|
active={changed ? current === entry : entry === config.dflt}
|
||||||
onClick={() => handleChange(entry)}
|
onClick={() => handleChange(entry)}
|
||||||
>
|
>
|
||||||
{compact ? null : t(`${titleKey}.d`)}
|
<div
|
||||||
</ChoiceButton>
|
className={`w-full flex items-start ${
|
||||||
)
|
sideBySide ? 'flex-row justify-between gap-2' : 'flex-col'
|
||||||
})}
|
}`}
|
||||||
</>
|
>
|
||||||
|
<div className="font-bold text-lg shrink-0">{title}</div>
|
||||||
|
{compact ? null : <div className="text-base font-normal">{desc}</div>}
|
||||||
|
</div>
|
||||||
|
</ButtonFrame>
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A boolean version of {@see ListInput} that sets up the necessary configuration */
|
/** A boolean version of {@see ListInput} that sets up the necessary configuration */
|
||||||
|
@ -328,7 +334,6 @@ export const SliderInput = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<p>{t(`${name}.d`)}</p>
|
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-row justify-between">
|
||||||
{override ? (
|
{override ? (
|
||||||
<EditCount
|
<EditCount
|
||||||
|
@ -475,7 +480,6 @@ export const ConstantInput = ({
|
||||||
config,
|
config,
|
||||||
}) => (
|
}) => (
|
||||||
<>
|
<>
|
||||||
<p>{t(`${name}.d`)}</p>
|
|
||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
className={`
|
className={`
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
import { ClearIcon, HelpIcon, EditIcon } from 'shared/components/icons.mjs'
|
import { ResetIcon, HelpIcon, EditIcon } from 'shared/components/icons.mjs'
|
||||||
import { Collapse } from 'shared/components/collapse.mjs'
|
import { Collapse } from 'shared/components/collapse.mjs'
|
||||||
import { useState, useMemo } from 'react'
|
import { useState, useMemo } from 'react'
|
||||||
import { ListToggle } from './inputs.mjs'
|
import { ListToggle } from './inputs.mjs'
|
||||||
|
import { SubAccordion } from 'shared/components/accordion.mjs'
|
||||||
|
import { FormControl } from 'shared/components/inputs.mjs'
|
||||||
|
import { BoxIcon as GroupIcon, OptionsIcon } from 'shared/components/icons.mjs'
|
||||||
|
import { optionType } from 'shared/utils.mjs'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to see if a value is different from its default
|
* Check to see if a value is different from its default
|
||||||
|
@ -34,7 +38,7 @@ export const ItemTitle = ({ name, t, current = null, open = false, emoji = '', I
|
||||||
)
|
)
|
||||||
|
|
||||||
/** @type {String} class to apply to buttons on open menu items */
|
/** @type {String} class to apply to buttons on open menu items */
|
||||||
const openButtonClass = 'btn btn-xs btn-ghost px-0'
|
const iconButtonClass = 'btn btn-xs btn-ghost px-0 text-accent'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A generic component for handling a menu item.
|
* A generic component for handling a menu item.
|
||||||
|
@ -66,6 +70,9 @@ export const MenuItem = ({
|
||||||
allowOverride = false,
|
allowOverride = false,
|
||||||
allowToggle = false,
|
allowToggle = false,
|
||||||
control = Infinity,
|
control = Infinity,
|
||||||
|
DynamicDocs,
|
||||||
|
docsPath,
|
||||||
|
language,
|
||||||
}) => {
|
}) => {
|
||||||
// state for knowing whether the override input should be shown
|
// state for knowing whether the override input should be shown
|
||||||
const [override, setOverride] = useState(false)
|
const [override, setOverride] = useState(false)
|
||||||
|
@ -91,68 +98,54 @@ export const MenuItem = ({
|
||||||
|
|
||||||
// get buttons for open and closed states
|
// get buttons for open and closed states
|
||||||
const buttons = []
|
const buttons = []
|
||||||
const openButtons = []
|
|
||||||
if (loadDocs)
|
|
||||||
openButtons.push(
|
|
||||||
<button className={openButtonClass} key="help" onClick={(evt) => loadDocs(evt, name)}>
|
|
||||||
<HelpIcon className="w-6 h-6" />
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
if (allowOverride)
|
if (allowOverride)
|
||||||
openButtons.push(
|
buttons.push(
|
||||||
<button
|
<button
|
||||||
key="edit"
|
key="edit"
|
||||||
className={openButtonClass}
|
className={iconButtonClass}
|
||||||
onClick={(evt) => {
|
onClick={(evt) => {
|
||||||
evt.stopPropagation()
|
evt.stopPropagation()
|
||||||
setOverride(!override)
|
setOverride(!override)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<EditIcon className={`w-6 h-6 ${override ? 'bg-base-100 text-accent rounded' : ''}`} />
|
<EditIcon
|
||||||
|
className={`w-6 h-6 ${
|
||||||
|
override ? 'bg-secondary text-secondary-content rounded' : 'text-secondary'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
const ResetButton = ({ open, disabled = false }) => (
|
const ResetButton = ({ open, disabled = false }) => (
|
||||||
<button
|
<button
|
||||||
className={`${open ? openButtonClass : 'btn btn-accent'} disabled:bg-opacity-0`}
|
className={`${iconButtonClass} disabled:bg-opacity-0`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={(evt) => {
|
onClick={(evt) => {
|
||||||
evt.stopPropagation()
|
evt.stopPropagation()
|
||||||
updateFunc([name])
|
updateFunc([name])
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ClearIcon />
|
<ResetIcon />
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
|
|
||||||
if (changed && !allowToggle) {
|
buttons.push(<ResetButton open disabled={!changed} key="clear" />)
|
||||||
buttons.push(<ResetButton key="clear" />)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allowToggle) {
|
|
||||||
buttons.push(<ListToggle key="toggle" {...{ config, changed, updateFunc, name }} />)
|
|
||||||
} else {
|
|
||||||
openButtons.push(<ResetButton open disabled={!changed} key="clear" />)
|
|
||||||
}
|
|
||||||
|
|
||||||
// props to pass to the ItemTitle
|
|
||||||
const titleProps = {
|
|
||||||
name,
|
|
||||||
t,
|
|
||||||
current: <Value {...drillProps} />,
|
|
||||||
emoji: config.emoji,
|
|
||||||
Icon: config.icon,
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapse
|
<FormControl
|
||||||
color={changed ? 'accent' : 'secondary'}
|
label={<span className="text-base font-normal">{t([`${name}.d`, name])}</span>}
|
||||||
openTitle={<ItemTitle open {...titleProps} />}
|
docs={<DynamicDocs path={docsPath} language={language} />}
|
||||||
title={<ItemTitle {...titleProps} />}
|
id={config.name}
|
||||||
buttons={buttons}
|
labelBR={<div className="flex flex-row items-center gap-2">{buttons}</div>}
|
||||||
openButtons={openButtons}
|
labelBL={
|
||||||
|
<span
|
||||||
|
className={`text-base font-medium -mt-2 block ${changed ? 'text-accent' : 'opacity-50'}`}
|
||||||
|
>
|
||||||
|
{t(`workbench:youUse${changed ? 'Default' : 'Custom'}Value`)}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Input {...drillProps} />
|
<Input {...drillProps} />
|
||||||
</Collapse>
|
</FormControl>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +168,7 @@ export const MenuItem = ({
|
||||||
* @param {Function} updateFunc the function called by change handlers on inputs within menu items
|
* @param {Function} updateFunc 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 {Boolean} topLevel is this group the top level group? false for nested
|
||||||
* @param {Function} t translation function
|
* @param {Function} t translation function
|
||||||
|
* @param {Function} getDocsPath returns the path to the docs for the current item
|
||||||
*/
|
*/
|
||||||
export const MenuItemGroup = ({
|
export const MenuItemGroup = ({
|
||||||
collapsible = true,
|
collapsible = true,
|
||||||
|
@ -192,35 +186,53 @@ export const MenuItemGroup = ({
|
||||||
updateFunc,
|
updateFunc,
|
||||||
topLevel = false,
|
topLevel = false,
|
||||||
t,
|
t,
|
||||||
|
DynamicDocs,
|
||||||
|
language,
|
||||||
|
getDocsPath,
|
||||||
|
isDesignOptionsGroup = false,
|
||||||
}) => {
|
}) => {
|
||||||
// map the entries in the structure
|
// map the entries in the structure
|
||||||
const content = Object.entries(structure).map(([itemName, item]) => {
|
const content = Object.entries(structure).map(([itemName, item]) => {
|
||||||
// if it's the isGroup property, or it is false, it shouldn't be shown
|
// if it's the isGroup property, or it is false, it shouldn't be shown
|
||||||
if (itemName === 'isGroup' || item === false) return null
|
if (itemName === 'isGroup' || item === false) return null
|
||||||
|
if (!item) return null
|
||||||
|
|
||||||
// if the item is not a menu, it's an Item
|
const ItemIcon = item.icon
|
||||||
if (!item.isGroup)
|
? item.icon
|
||||||
return (
|
: item.isGroup
|
||||||
<Item
|
? GroupIcon
|
||||||
key={itemName}
|
: Icon
|
||||||
{...{
|
? Icon
|
||||||
name: itemName,
|
: () => <span role="img">{emoji}</span>
|
||||||
current: currentValues[itemName],
|
const Value = item.isGroup
|
||||||
config: item,
|
? () => (
|
||||||
control,
|
<div className="flex flex-row gap-2 items-center font-medium">
|
||||||
changed: wasChanged(currentValues[itemName], item),
|
{Object.keys(item).filter((i) => i !== 'isGroup').length}
|
||||||
Value: values[itemName],
|
<OptionsIcon className="w-5 h-5" />
|
||||||
Input: inputs[itemName],
|
</div>
|
||||||
t,
|
|
||||||
loadDocs,
|
|
||||||
updateFunc,
|
|
||||||
passProps,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
|
: isDesignOptionsGroup
|
||||||
|
? values[optionType(item)]
|
||||||
|
: values[itemName]
|
||||||
|
? values[itemName]
|
||||||
|
: () => <span>¯\_(ツ)_/¯</span>
|
||||||
|
|
||||||
// otherwise, it's a group
|
return [
|
||||||
return (
|
<div className="flex flex-row items-center justify-between" key="a">
|
||||||
|
<div className="flex flex-row items-center gap-4">
|
||||||
|
<ItemIcon />
|
||||||
|
<h6>{t([`${itemName}.t`, itemName])}</h6>
|
||||||
|
</div>
|
||||||
|
<div className="font-bold">
|
||||||
|
<Value
|
||||||
|
current={currentValues[itemName]}
|
||||||
|
config={item}
|
||||||
|
t={t}
|
||||||
|
changed={wasChanged(currentValues[itemName], item)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
item.isGroup ? (
|
||||||
<MenuItemGroup
|
<MenuItemGroup
|
||||||
key={itemName}
|
key={itemName}
|
||||||
{...{
|
{...{
|
||||||
|
@ -240,12 +252,38 @@ export const MenuItemGroup = ({
|
||||||
emojis,
|
emojis,
|
||||||
updateFunc,
|
updateFunc,
|
||||||
t,
|
t,
|
||||||
|
DynamicDocs,
|
||||||
|
language,
|
||||||
|
getDocsPath,
|
||||||
|
isDesignOptionsGroup,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
) : (
|
||||||
|
<Item
|
||||||
|
key={itemName}
|
||||||
|
{...{
|
||||||
|
name: itemName,
|
||||||
|
current: currentValues[itemName],
|
||||||
|
config: item,
|
||||||
|
control,
|
||||||
|
changed: wasChanged(currentValues[itemName], item),
|
||||||
|
Value: values[itemName],
|
||||||
|
Input: inputs[itemName],
|
||||||
|
t,
|
||||||
|
loadDocs,
|
||||||
|
updateFunc,
|
||||||
|
passProps,
|
||||||
|
DynamicDocs,
|
||||||
|
docsPath: getDocsPath(itemName),
|
||||||
|
language,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
// if it should be wrapped in a collapsible
|
// if it should be wrapped in a collapsible
|
||||||
|
/*
|
||||||
if (collapsible) {
|
if (collapsible) {
|
||||||
// props to give to the group title
|
// props to give to the group title
|
||||||
const titleProps = {
|
const titleProps = {
|
||||||
|
@ -269,7 +307,8 @@ export const MenuItemGroup = ({
|
||||||
</Collapse>
|
</Collapse>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
//otherwise just return the content
|
//otherwise just return the content
|
||||||
return content
|
return <SubAccordion items={content.filter((item) => item !== null)} />
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { formatMm } from 'shared/utils.mjs'
|
||||||
|
|
||||||
/** The basis of it all. Handles the changed/unchanged styling for the wrapped value */
|
/** The basis of it all. Handles the changed/unchanged styling for the wrapped value */
|
||||||
export const HighlightedValue = ({ changed, children }) => (
|
export const HighlightedValue = ({ changed, children }) => (
|
||||||
<span className={changed ? 'text-info' : ''}> {children} </span>
|
<span className={changed ? 'text-accent' : ''}> {children} </span>
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
useMaterialList,
|
useMaterialList,
|
||||||
useMaterialLength,
|
useMaterialLength,
|
||||||
} from './hooks'
|
} from './hooks'
|
||||||
|
import { V3Wip } from 'shared/components/v3-wip.mjs'
|
||||||
|
|
||||||
export const ns = [...menuNs, ...wrapperNs]
|
export const ns = [...menuNs, ...wrapperNs]
|
||||||
|
|
||||||
|
@ -110,6 +111,8 @@ export const CutView = ({
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
menu: (
|
menu: (
|
||||||
|
<>
|
||||||
|
<V3Wip />
|
||||||
<CutMenu
|
<CutMenu
|
||||||
{...{
|
{...{
|
||||||
design,
|
design,
|
||||||
|
@ -125,6 +128,7 @@ export const CutView = ({
|
||||||
setSettings,
|
setSettings,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -4,12 +4,15 @@ import {
|
||||||
} from 'shared/components/workbench/menus/design-options/index.mjs'
|
} from 'shared/components/workbench/menus/design-options/index.mjs'
|
||||||
import {
|
import {
|
||||||
CoreSettings,
|
CoreSettings,
|
||||||
ClearAllButton,
|
|
||||||
ns as coreMenuNs,
|
ns as coreMenuNs,
|
||||||
} from 'shared/components/workbench/menus/core-settings/index.mjs'
|
} from 'shared/components/workbench/menus/core-settings/index.mjs'
|
||||||
import { UiSettings, ns as uiNs } from 'shared/components/workbench/menus/ui-settings/index.mjs'
|
import { UiSettings, ns as uiNs } from 'shared/components/workbench/menus/ui-settings/index.mjs'
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import { nsMerge } from 'shared/utils.mjs'
|
||||||
|
import { SettingsIcon, OptionsIcon, DesktopIcon } from 'shared/components/icons.mjs'
|
||||||
|
import { Accordion } from 'shared/components/accordion.mjs'
|
||||||
|
|
||||||
export const ns = [...coreMenuNs, ...designMenuNs, ...uiNs]
|
export const ns = nsMerge(coreMenuNs, designMenuNs, uiNs)
|
||||||
|
|
||||||
export const DraftMenu = ({
|
export const DraftMenu = ({
|
||||||
design,
|
design,
|
||||||
|
@ -24,6 +27,7 @@ export const DraftMenu = ({
|
||||||
view,
|
view,
|
||||||
setView,
|
setView,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
const control = account.control
|
const control = account.control
|
||||||
const menuProps = {
|
const menuProps = {
|
||||||
design,
|
design,
|
||||||
|
@ -36,12 +40,39 @@ export const DraftMenu = ({
|
||||||
control,
|
control,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sections = [
|
||||||
|
{
|
||||||
|
name: 'designOptions',
|
||||||
|
ns: 'design-options',
|
||||||
|
icon: <OptionsIcon className="w-8 h-8" />,
|
||||||
|
menu: <DesignOptions {...menuProps} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'coreSettings',
|
||||||
|
ns: 'core-settings',
|
||||||
|
icon: <SettingsIcon className="w-8 h-8" />,
|
||||||
|
menu: <CoreSettings {...menuProps} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'uiSettings',
|
||||||
|
ns: 'ui-settings',
|
||||||
|
icon: <DesktopIcon className="w-8 h-8" />,
|
||||||
|
menu: <UiSettings {...menuProps} {...{ ui, view, setView }} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav>
|
<Accordion
|
||||||
<DesignOptions {...menuProps} />
|
items={sections.map((section) => [
|
||||||
<CoreSettings {...menuProps} />
|
<>
|
||||||
<UiSettings {...menuProps} {...{ ui, view, setView }} />
|
<h5 className="flex flex-row gap-2 items-center justify-between w-full">
|
||||||
<ClearAllButton setSettings={setSettings} />
|
<span>{t(`${section.ns}:${section.name}.t`)}</span>
|
||||||
</nav>
|
{section.icon}
|
||||||
|
</h5>
|
||||||
|
<p>{t(`${section.ns}:${section.name}.d`)}</p>
|
||||||
|
</>,
|
||||||
|
section.menu,
|
||||||
|
])}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { useTranslation } from 'next-i18next'
|
||||||
import { useToast } from 'shared/hooks/use-toast.mjs'
|
import { useToast } from 'shared/hooks/use-toast.mjs'
|
||||||
import { CloseIcon } from 'shared/components/icons.mjs'
|
import { CloseIcon } from 'shared/components/icons.mjs'
|
||||||
import { capitalize } from 'shared/utils.mjs'
|
import { capitalize } from 'shared/utils.mjs'
|
||||||
|
import { V3Wip } from 'shared/components/v3-wip.mjs'
|
||||||
|
|
||||||
export const ns = ['wbedit']
|
export const ns = ['wbedit']
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ export const EditView = ({ settings, setSettings, design, Design }) => {
|
||||||
return (
|
return (
|
||||||
<div className="max-w-screen-xl m-auto h-screen form-control mt-4 flex flex-col">
|
<div className="max-w-screen-xl m-auto h-screen form-control mt-4 flex flex-col">
|
||||||
<h2>{t('yamlEditViewTitleThing', { thing: capitalize(design) })}</h2>
|
<h2>{t('yamlEditViewTitleThing', { thing: capitalize(design) })}</h2>
|
||||||
|
<V3Wip />
|
||||||
<div id="editor" className="h-2/3 my-2 overflow-auto flex flex-col">
|
<div id="editor" className="h-2/3 my-2 overflow-auto flex flex-col">
|
||||||
{error && (
|
{error && (
|
||||||
<div className={`w-full shadow bg-base-100 p-0 my-4`}>
|
<div className={`w-full shadow bg-base-100 p-0 my-4`}>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
handleExport,
|
handleExport,
|
||||||
ns as exportNs,
|
ns as exportNs,
|
||||||
} from 'shared/components/workbench/exporting/export-handler.mjs'
|
} from 'shared/components/workbench/exporting/export-handler.mjs'
|
||||||
|
import { V3Wip } from 'shared/components/v3-wip.mjs'
|
||||||
|
|
||||||
export const ns = ['exporting', exportNs]
|
export const ns = ['exporting', exportNs]
|
||||||
|
|
||||||
|
@ -45,6 +46,7 @@ export const ExportView = ({ settings, ui, design, Design }) => {
|
||||||
return (
|
return (
|
||||||
<div className="max-w-screen-xl m-auto py-8">
|
<div className="max-w-screen-xl m-auto py-8">
|
||||||
<h2>{t('export')}</h2>
|
<h2>{t('export')}</h2>
|
||||||
|
<V3Wip />
|
||||||
<p className="text-lg sm:text-xl">{t('exportPattern-txt')}</p>
|
<p className="text-lg sm:text-xl">{t('exportPattern-txt')}</p>
|
||||||
{link && (
|
{link && (
|
||||||
<Popout link compact>
|
<Popout link compact>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { InspectorPattern } from './inspector/pattern.mjs'
|
||||||
import { DraftMenu, ns as menuNs } from './menu.mjs'
|
import { DraftMenu, ns as menuNs } from './menu.mjs'
|
||||||
import { objUpdate } from 'shared/utils.mjs'
|
import { objUpdate } from 'shared/utils.mjs'
|
||||||
import { PatternWithMenu, ns as wrapperNs } from '../pattern-with-menu.mjs'
|
import { PatternWithMenu, ns as wrapperNs } from '../pattern-with-menu.mjs'
|
||||||
|
import { V3Wip } from 'shared/components/v3-wip.mjs'
|
||||||
|
|
||||||
export const ns = [...menuNs, ...wrapperNs]
|
export const ns = [...menuNs, ...wrapperNs]
|
||||||
|
|
||||||
|
@ -76,6 +77,8 @@ export const InspectView = ({
|
||||||
setSettings,
|
setSettings,
|
||||||
pattern: output,
|
pattern: output,
|
||||||
menu: (
|
menu: (
|
||||||
|
<>
|
||||||
|
<V3Wip />
|
||||||
<DraftMenu
|
<DraftMenu
|
||||||
{...{
|
{...{
|
||||||
design,
|
design,
|
||||||
|
@ -94,6 +97,7 @@ export const InspectView = ({
|
||||||
setView,
|
setView,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
ClearAllButton,
|
ClearAllButton,
|
||||||
ns as coreMenuNs,
|
ns as coreMenuNs,
|
||||||
} from 'shared/components/workbench/menus/core-settings/index.mjs'
|
} from 'shared/components/workbench/menus/core-settings/index.mjs'
|
||||||
|
import { V3Wip } from 'shared/components/v3-wip.mjs'
|
||||||
|
|
||||||
export const ns = ['logs', ...coreMenuNs]
|
export const ns = ['logs', ...coreMenuNs]
|
||||||
|
|
||||||
|
@ -88,6 +89,7 @@ export const LogView = ({ pattern, settings, setSettings }) => {
|
||||||
<h1 className="grow">{t('logs')}</h1>
|
<h1 className="grow">{t('logs')}</h1>
|
||||||
<ClearAllButton setSettings={setSettings} />
|
<ClearAllButton setSettings={setSettings} />
|
||||||
</div>
|
</div>
|
||||||
|
<V3Wip />
|
||||||
{Object.entries(logs).map(([type, lines], key) => (
|
{Object.entries(logs).map(([type, lines], key) => (
|
||||||
<DraftLogs key={key} {...{ type, lines, t }} />
|
<DraftLogs key={key} {...{ type, lines, t }} />
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { PrintIcon, RightIcon } from 'shared/components/icons.mjs'
|
||||||
import { LoadingContext } from 'shared/context/loading-context.mjs'
|
import { LoadingContext } from 'shared/context/loading-context.mjs'
|
||||||
import { useToast } from 'shared/hooks/use-toast.mjs'
|
import { useToast } from 'shared/hooks/use-toast.mjs'
|
||||||
import { PatternWithMenu, ns as wrapperNs } from '../pattern-with-menu.mjs'
|
import { PatternWithMenu, ns as wrapperNs } from '../pattern-with-menu.mjs'
|
||||||
|
import { V3Wip } from 'shared/components/v3-wip.mjs'
|
||||||
|
|
||||||
const viewNs = ['print', ...exportNs]
|
const viewNs = ['print', ...exportNs]
|
||||||
export const ns = [...viewNs, ...menuNs, ...wrapperNs]
|
export const ns = [...viewNs, ...menuNs, ...wrapperNs]
|
||||||
|
@ -114,6 +115,8 @@ export const PrintView = ({
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
menu: (
|
menu: (
|
||||||
|
<>
|
||||||
|
<V3Wip />
|
||||||
<PrintMenu
|
<PrintMenu
|
||||||
{...{
|
{...{
|
||||||
design,
|
design,
|
||||||
|
@ -129,6 +132,7 @@ export const PrintView = ({
|
||||||
exportIt,
|
exportIt,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { useToast } from 'shared/hooks/use-toast.mjs'
|
||||||
import { LoadingContext } from 'shared/context/loading-context.mjs'
|
import { LoadingContext } from 'shared/context/loading-context.mjs'
|
||||||
// Components
|
// Components
|
||||||
import { Spinner } from 'shared/components/spinner.mjs'
|
import { Spinner } from 'shared/components/spinner.mjs'
|
||||||
|
import { V3Wip } from 'shared/components/v3-wip.mjs'
|
||||||
|
|
||||||
export const ns = ['wbsave']
|
export const ns = ['wbsave']
|
||||||
|
|
||||||
|
@ -245,6 +246,7 @@ export const SaveView = ({ design, settings, from = false }) => {
|
||||||
return (
|
return (
|
||||||
<div className="m-auto mt-24">
|
<div className="m-auto mt-24">
|
||||||
<h1 className="max-w-6xl m-auto text-center">{t('wbsave:title')}</h1>
|
<h1 className="max-w-6xl m-auto text-center">{t('wbsave:title')}</h1>
|
||||||
|
<V3Wip />
|
||||||
<div className="px-4 lg:px-12 flex flex-row flex-wrap gap-4 lg:gap-8 justify-around">
|
<div className="px-4 lg:px-12 flex flex-row flex-wrap gap-4 lg:gap-8 justify-around">
|
||||||
{info.new ? <SaveNewPattern {...saveProps} /> : null}
|
{info.new ? <SaveNewPattern {...saveProps} /> : null}
|
||||||
{info.edit ? <SaveExistingPattern {...saveProps} from={from} /> : null}
|
{info.edit ? <SaveExistingPattern {...saveProps} from={from} /> : null}
|
||||||
|
|
|
@ -1,6 +1,29 @@
|
||||||
import { TestOptions, ns as optionsNs } from './options.mjs'
|
import { ns as optionsNs } from './options.mjs'
|
||||||
import { TestMeasurements, ns as measieNs } from './measurements.mjs'
|
import { ns as measieNs } from './measurements.mjs'
|
||||||
export const ns = [...optionsNs, ...measieNs]
|
import { Accordion } from 'shared/components/accordion.mjs'
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import { nsMerge } from 'shared/utils.mjs'
|
||||||
|
import { OptionsIcon, MeasieIcon, CommunityIcon } from 'shared/components/icons.mjs'
|
||||||
|
import { ListInput } from 'shared/components/inputs.mjs'
|
||||||
|
import { optionsMenuStructure } from 'shared/utils.mjs'
|
||||||
|
import { V3Wip } from 'shared/components/v3-wip.mjs'
|
||||||
|
|
||||||
|
export const ns = nsMerge('workbench', optionsNs, measieNs)
|
||||||
|
|
||||||
|
const flattenOptions = (options, list = false, path = []) => {
|
||||||
|
if (list === false) return flattenOptions(optionsMenuStructure(options), new Set())
|
||||||
|
|
||||||
|
for (const [key, option] of Object.entries(options)) {
|
||||||
|
if (key !== 'isGroup') {
|
||||||
|
if (!option.isGroup) list.add({ key, option, path })
|
||||||
|
else list = flattenOptions(option, list, [...path, key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
const spacer = <span className="px-2 opacity-50">/</span>
|
||||||
|
|
||||||
export const TestMenu = ({
|
export const TestMenu = ({
|
||||||
design,
|
design,
|
||||||
|
@ -11,22 +34,72 @@ export const TestMenu = ({
|
||||||
account,
|
account,
|
||||||
DynamicDocs,
|
DynamicDocs,
|
||||||
}) => {
|
}) => {
|
||||||
const control = account.control
|
const { t } = useTranslation(ns)
|
||||||
const menuProps = {
|
|
||||||
design,
|
const allOptions = flattenOptions(patternConfig.options)
|
||||||
patternConfig,
|
|
||||||
settings,
|
|
||||||
update,
|
|
||||||
language,
|
|
||||||
account,
|
|
||||||
DynamicDocs,
|
|
||||||
control,
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav>
|
<Accordion
|
||||||
<TestOptions {...menuProps} />
|
items={[
|
||||||
<TestMeasurements {...menuProps} />
|
[
|
||||||
</nav>
|
<>
|
||||||
|
<h5 className="flex flex-row gap-2 items-center justify-between w-full">
|
||||||
|
<span>{t('workbench:testOptions')}</span>
|
||||||
|
<OptionsIcon className="w-8 h-8" />
|
||||||
|
</h5>
|
||||||
|
<p>{t('workbench:testOptionsDesc')}</p>
|
||||||
|
</>,
|
||||||
|
<ListInput
|
||||||
|
list={[...allOptions].map((option) => ({
|
||||||
|
label: [
|
||||||
|
...option.path.map((p) => (
|
||||||
|
<>
|
||||||
|
<span>{t(`${p}.t`)}</span>
|
||||||
|
{spacer}
|
||||||
|
</>
|
||||||
|
)),
|
||||||
|
<span>{t(`${design}:${option.key}.t`)}</span>,
|
||||||
|
],
|
||||||
|
val: option.key,
|
||||||
|
}))}
|
||||||
|
update={(value) => {
|
||||||
|
if (value) update.settings(['sample'], { type: 'option', option: value })
|
||||||
|
else update.settings(['sample'])
|
||||||
|
}}
|
||||||
|
current={settings.sample.option}
|
||||||
|
/>,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
<>
|
||||||
|
<h5 className="flex flex-row gap-2 items-center justify-between w-full">
|
||||||
|
<span>{t('workbench:testMeasurements')}</span>
|
||||||
|
<MeasieIcon className="w-8 h-8" />
|
||||||
|
</h5>
|
||||||
|
<p>{t('workbench:testOptionsDesc')}</p>
|
||||||
|
</>,
|
||||||
|
<ListInput
|
||||||
|
list={patternConfig.measurements.map((m) => ({
|
||||||
|
label: t(m),
|
||||||
|
val: m,
|
||||||
|
}))}
|
||||||
|
update={(value) => {
|
||||||
|
if (value) update.settings(['sample'], { type: 'measurement', measurement: value })
|
||||||
|
else update.settings(['sample'])
|
||||||
|
}}
|
||||||
|
current={settings.sample.measurement}
|
||||||
|
/>,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
<>
|
||||||
|
<h5 className="flex flex-row gap-2 items-center justify-between w-full">
|
||||||
|
<span>{t('workbench:testSets')}</span>
|
||||||
|
<CommunityIcon className="w-8 h-8" />
|
||||||
|
</h5>
|
||||||
|
<p>{t('workbench:testSetsDesc')}</p>
|
||||||
|
</>,
|
||||||
|
<V3Wip />,
|
||||||
|
],
|
||||||
|
]}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
DetailIcon,
|
DetailIcon,
|
||||||
IconWrapper,
|
IconWrapper,
|
||||||
ClearIcon,
|
ClearIcon,
|
||||||
|
ResetIcon,
|
||||||
} from 'shared/components/icons.mjs'
|
} from 'shared/components/icons.mjs'
|
||||||
import { ClearAllButton } from 'shared/components/workbench/menus/core-settings/index.mjs'
|
import { ClearAllButton } from 'shared/components/workbench/menus/core-settings/index.mjs'
|
||||||
import { shownHeaderSelector } from 'shared/components/wrappers/header.mjs'
|
import { shownHeaderSelector } from 'shared/components/wrappers/header.mjs'
|
||||||
|
@ -94,7 +95,7 @@ export const ViewHeader = ({ update, settings, ui, control, setSettings }) => {
|
||||||
'lg:top-24'
|
'lg:top-24'
|
||||||
)} transition-[top] duration-300 ease-in-out`}
|
)} transition-[top] duration-300 ease-in-out`}
|
||||||
>
|
>
|
||||||
<div className="hidden lg:flex flex-row flex-wrap gap-4 py-4 pt-4 w-full bg-neutral text-neutral-content items-center justify-center">
|
<div className="hidden lg:flex flex-row flex-wrap gap-4 py-4 pt-8 w-full bg-neutral text-neutral-content items-center justify-center">
|
||||||
{headerZoomButtons}
|
{headerZoomButtons}
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<div className="flex flex-row items-center gap-4">
|
<div className="flex flex-row items-center gap-4">
|
||||||
|
@ -156,7 +157,34 @@ export const ViewHeader = ({ update, settings, ui, control, setSettings }) => {
|
||||||
</div>
|
</div>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<div className="flex flex-row items-center gap-4">
|
<div className="flex flex-row items-center gap-4">
|
||||||
<ClearAllButton setSettings={setSettings} compact />
|
<button
|
||||||
|
onClick={() => setSettings({ measurements: settings.measurements })}
|
||||||
|
className={`tooltip tooltip-primary tooltip-bottom flex flex-row items-center`}
|
||||||
|
data-tip={t('core-settings:clearSettingsNotMeasurements')}
|
||||||
|
disabled={typeof settings.options === 'undefined'}
|
||||||
|
>
|
||||||
|
<ResetIcon
|
||||||
|
stroke={3.5}
|
||||||
|
className={`w-6 h-6 ${
|
||||||
|
typeof settings.options === 'undefined' ? 'text-base-100 opacity-30' : 'text-accent'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setSettings({})}
|
||||||
|
className="tooltip tooltip-primary tooltip-bottom flex flex-row items-center text-warning"
|
||||||
|
data-tip={t('core-settings:clearSettingsAndMeasurements')}
|
||||||
|
disabled={!(settings.measurements && Object.keys(settings.measurements).length > 0)}
|
||||||
|
>
|
||||||
|
<ResetIcon
|
||||||
|
stroke={3.5}
|
||||||
|
className={`w-6 h-6 ${
|
||||||
|
!(settings.measurements && Object.keys(settings.measurements).length > 0)
|
||||||
|
? 'text-base-100 opacity-30'
|
||||||
|
: 'text-warning'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue