1
0
Fork 0

both menus using same structure and components

This commit is contained in:
Enoch Riese 2023-05-29 22:34:33 -05:00
parent 75bc302dd4
commit cc14c562d2
12 changed files with 164 additions and 264 deletions

View file

@ -99,6 +99,7 @@ export const loadSettingsConfig = ({
only: { only: {
control: 4, // Show when control > 3 control: 4, // Show when control > 3
dflt: false, dflt: false,
list: parts,
parts, parts,
emoji: '🛍️', emoji: '🛍️',
}, },

View file

@ -82,28 +82,28 @@ export const CoreSettings = ({
sabool: settings.sabool, sabool: settings.sabool,
parts: patternConfig.draftOrder, parts: patternConfig.draftOrder,
}) })
// Default control level is 2 (in case people are not logged in)
const control = account.control || 5 const control = account.control
return ( return (
<WorkbenchMenu <WorkbenchMenu
{...{ {...{
updateFunc: update.settings,
ns,
Icon: SettingsIcon,
name: 'coreSettings',
config: settingsConfig, config: settingsConfig,
control, control,
inputs,
values,
currentValues: settings, currentValues: settings,
DynamicDocs,
getDocsPath: (setting) => `site/draft/core-settings${setting ? `/${setting}` : ''}`,
Icon: SettingsIcon,
inputs,
language,
name: 'coreSettings',
ns,
passProps: { passProps: {
samm: typeof settings.samm === 'undefined' ? defaultSamm(settings.units) : settings.samm, samm: typeof settings.samm === 'undefined' ? defaultSamm(settings.units) : settings.samm,
units: settings.units, units: settings.units,
}, },
language, updateFunc: update.settings,
DynamicDocs, values,
getDocsPath: (setting) => `site/draft/core-settings${setting ? `/${setting}` : ''}`,
}} }}
/> />
) )

View file

@ -12,46 +12,26 @@ export const PaperlessSettingInput = ListInput
export const MarginSettingInput = MmInput export const MarginSettingInput = MmInput
export const ScaleSettingInput = SliderInput export const ScaleSettingInput = SliderInput
export const OnlySettingInput = ({ name, config, current, updateFunc, t, draftOrder, design }) => { export const OnlySettingInput = (props) => {
const partNames = config.parts.map((part) => ({ props.config.choiceTitles = {}
id: part, props.config.list.forEach((p) => (props.config.choiceTitles[p] = p))
t: t(`${design}:${part}.t`),
d: t(`${design}:${part}.d`),
}))
const togglePart = (part) => { const onlyUpdateFunc = useCallback(
const parts = current || [] (path, part) => {
const newParts = new Set(parts) if (part === undefined) return props.updateFunc(path, part)
let newParts = new Set(props.current || [])
if (newParts.has(part)) newParts.delete(part) if (newParts.has(part)) newParts.delete(part)
else newParts.add(part) else newParts.add(part)
if (newParts.size < 1) reset() if (newParts.size < 1) newParts = undefined
else updateFunc(['only'], [...newParts]) else newParts = [...newParts]
}
const reset = () => { props.updateFunc(path, newParts)
updateFunc(['only']) },
} [props.updateFunc, props.current]
return (
<>
<p>{t(`core-settings:only.d`)}</p>
{orderBy(partNames, ['name'], ['asc']).map((part) => {
const included = Array.isArray(current) ? (current.includes(part.id) ? true : false) : true
return (
<ChoiceButton
key={part.id}
title={part.t}
color={included ? 'secondary' : 'accent'}
active={included}
onClick={() => togglePart(part.id)}
>
{part.d}
</ChoiceButton>
)
})}
</>
) )
return <ListInput {...props} updateFunc={onlyUpdateFunc} />
} }
export const SaMmSettingInput = (props) => { export const SaMmSettingInput = (props) => {

View file

@ -1,4 +1,4 @@
import { ListValue, MmValue, PlainValue, HighlightedValue } from '../shared/values' import { ListValue, MmValue, PlainValue } from '../shared/values'
export const RendererSettingValue = ListValue export const RendererSettingValue = ListValue
export const LocaleSettingValue = ListValue export const LocaleSettingValue = ListValue
@ -10,11 +10,14 @@ export const UnitsSettingValue = ListValue
export const MarginSettingValue = MmValue export const MarginSettingValue = MmValue
export const SaMmSettingValue = MmValue export const SaMmSettingValue = MmValue
export const ScaleSettingValue = PlainValue export const ScaleSettingValue = ({ current, config, changed }) => (
<PlainValue current={current} dflt={config.dflt} changed={changed} />
)
export const OnlySettingValue = ({ current, config }) => ( export const OnlySettingValue = ({ current, config }) => (
<HighlightedValue changed={current !== undefined}> <PlainValue
{' '} current={current?.length}
{current ? current.length : config.parts.length}{' '} dflt={config.parts.length}
</HighlightedValue> changed={current !== undefined}
/>
) )

View file

@ -39,7 +39,7 @@ const inputs = {
count: SliderInput, count: SliderInput,
deg: DegInput, deg: DegInput,
list: ListInput, list: ListInput,
mm: MmInput, mm: () => <span>FIXME: Mm options are deprecated. Please report this </span>,
pct: PctInput, pct: PctInput,
} }
@ -68,7 +68,7 @@ export const DesignOption = ({
current, current,
config, config,
settings, settings,
update, updateFunc,
t, t,
loadDocs, loadDocs,
changed = false, changed = false,
@ -81,30 +81,13 @@ export const DesignOption = ({
// Hide option? // Hide option?
if (config?.hide || (typeof config?.hide === 'function' && config.hide(settings))) return null if (config?.hide || (typeof config?.hide === 'function' && config.hide(settings))) return null
if (type === 'bool') {
config = {
...config,
list: [0, 1],
choiceTitles: {
0: `${name}No`,
1: `${name}Yes`,
},
valueTitles: {
0: 'no',
1: 'yes',
},
dflt: config.dflt ? 1 : 0,
}
}
return ( return (
<MenuItem <MenuItem
{...{ {...{
name, name,
config, config,
current, current,
updateFunc: update.settings, updateFunc,
updatePath: ['options'],
t, t,
changed, changed,
loadDocs, loadDocs,
@ -117,53 +100,6 @@ export const DesignOption = ({
) )
} }
export const DesignOptionGroup = ({
design,
patternConfig,
settings,
update,
group,
options,
t,
loadDocs,
}) => (
<Collapse
bottom
color="secondary"
title={
<ItemTitle
{...{
name: group,
t,
emoji: emojis[group] ? emojis[group] : emojis.groupDflt,
}}
/>
}
openTitle={t(group)}
>
{Object.entries(options).map(([option, type]) =>
typeof type === 'string' ? (
<DesignOption
{...{ t, design, update, settings, loadDocs }}
key={option}
name={option}
settings={settings}
current={settings.options?.[option]}
config={patternConfig.options[option]}
changed={wasChanged(settings.options?.[option], option, patternConfig.options)}
/>
) : (
<DesignOptionGroup
{...{ design, patternConfig, settings, update, Option, t, loadDocs }}
group={option}
options={type}
key={option}
/>
)
)}
</Collapse>
)
export const DesignOptions = ({ export const DesignOptions = ({
design, design,
patternConfig, patternConfig,
@ -183,31 +119,19 @@ export const DesignOptions = ({
return ( return (
<WorkbenchMenu <WorkbenchMenu
{...{ {...{
name: 'design-options:designOptions', config: optionsMenu,
updateFunc: update.settings,
ns: menuNs,
Icon: OptionsIcon,
inputs,
values,
currentValues: settings.options, currentValues: settings.options,
language,
DynamicDocs, DynamicDocs,
getDocsPath,
}}
>
<MenuItemGroup
{...{
collapsible: false,
groupConfig: patternConfig.options,
currents: settings.options,
items: optionsMenu,
Item: DesignOption,
loadDocs,
itemProps: { design, update, settings },
emojis, emojis,
t, getDocsPath,
Icon: OptionsIcon,
Item: DesignOption,
name: 'design-options:designOptions',
language,
ns: menuNs,
passProps: { settings },
updateFunc: (name, value) => update.settings(['options', name], value),
}} }}
/> />
</WorkbenchMenu>
) )
} }

View file

@ -1,7 +1,7 @@
import { formatMm, formatPercentage } from 'shared/utils.mjs' import { formatMm, formatPercentage } from 'shared/utils.mjs'
import { ListValue, HighlightedValue, PlainValue } from '../shared/values' import { ListValue, HighlightedValue, PlainValue } from '../shared/values'
export const PctOptionValue = ({ name, config, current, settings, changed }) => { export const PctOptionValue = ({ name, config, current, settings, changed }) => {
const val = typeof current === 'undefined' ? config.pct / 100 : current const val = changed ? current : config.pct / 100
return ( return (
<HighlightedValue changed={changed}> <HighlightedValue changed={changed}>
@ -23,7 +23,7 @@ export const BoolOptionValue = ({ name, config, current, t, changed }) => (
) )
export const CountOptionValue = ({ config, current, changed }) => ( export const CountOptionValue = ({ config, current, changed }) => (
<PlainValue {...{ current, changed, config: { ...config, dflt: config.count } }} /> <PlainValue {...{ current, changed, dflt: config.count }} />
) )
export const ListOptionValue = ({ name, config, current, t, changed }) => { export const ListOptionValue = ({ name, config, current, t, changed }) => {

View file

@ -1,6 +1,6 @@
import { useContext } from 'react' import { useContext } from 'react'
import { Collapse } from 'shared/components/collapse.mjs' import { Collapse } from 'shared/components/collapse.mjs'
import { MenuItem, wasChanged } from './menu-item.mjs' import { MenuItemGroup, wasChanged } from './menu-item.mjs'
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
import { HelpIcon } from 'shared/components/icons.mjs' import { HelpIcon } from 'shared/components/icons.mjs'
import { ModalWrapper } from 'shared/components/wrappers/modal.mjs' import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
@ -25,7 +25,6 @@ export const useDocsLoader = (DynamicDocs, getDocsPath, language) => {
export const WorkbenchMenu = ({ export const WorkbenchMenu = ({
updateFunc, updateFunc,
updatePath = [],
ns, ns,
Icon, Icon,
name, name,
@ -38,6 +37,8 @@ export const WorkbenchMenu = ({
DynamicDocs = false, DynamicDocs = false,
getDocsPath = () => {}, getDocsPath = () => {},
language, language,
emojis,
Item,
children, children,
}) => { }) => {
const { t, i18n } = useTranslation(ns) const { t, i18n } = useTranslation(ns)
@ -69,29 +70,24 @@ export const WorkbenchMenu = ({
openTitle={t(`${name}.t`)} openTitle={t(`${name}.t`)}
openButtons={openButtons} openButtons={openButtons}
> >
<p>{t('core-settings:coreSettings.d')}</p> {children || (
{children || <MenuItemGroup
Object.keys(config)
.filter((name) => config[name].control <= control)
.map((name) => (
<MenuItem
key={name}
{...{ {...{
name, collapsible: false,
config: config[name], control,
current: currentValues[name], currentValues,
updateFunc, structure: config,
updatePath, Item,
t, values,
passProps, inputs,
changed: wasChanged(currentValues[name], name, config),
loadDocs, loadDocs,
Input: inputs[name], passProps,
Value: values[name], updateFunc,
i18n: i18n, emojis,
t,
}} }}
/> />
))} )}
</Collapse> </Collapse>
) )
} }

View file

@ -29,17 +29,17 @@ const EditCount = (props) => (
</div> </div>
) )
const useSharedHandlers = ({ dflt, updateFunc, updatePath, name, setReset }) => { const useSharedHandlers = ({ dflt, updateFunc, name, setReset }) => {
const reset = useCallback(() => updateFunc([...updatePath, name]), [updatePath, updateFunc, name]) const reset = useCallback(() => updateFunc(name), [updateFunc, name])
const handleChange = useCallback( const handleChange = useCallback(
(newCurrent) => { (newCurrent) => {
if (newCurrent === dflt) reset() if (newCurrent === dflt) reset()
else { else {
updateFunc([...updatePath, name], newCurrent) updateFunc(name, newCurrent)
} }
}, },
[dflt, updateFunc, updatePath, name] [dflt, updateFunc, name]
) )
useEffect(() => setReset(() => reset), [reset, setReset]) useEffect(() => setReset(() => reset), [reset, setReset])
@ -47,20 +47,10 @@ const useSharedHandlers = ({ dflt, updateFunc, updatePath, name, setReset }) =>
return { handleChange, reset } return { handleChange, reset }
} }
export const ListInput = ({ export const ListInput = ({ name, config, current, updateFunc, compact = false, t, setReset }) => {
name,
config,
current,
updateFunc,
updatePath = [],
compact = false,
t,
setReset,
}) => {
const { handleChange, reset, set } = useSharedHandlers({ const { handleChange, reset, set } = useSharedHandlers({
dflt: config.dflt, dflt: config.dflt,
updateFunc, updateFunc,
updatePath,
name, name,
setReset, setReset,
}) })
@ -86,7 +76,23 @@ export const ListInput = ({
) )
} }
export const BoolInput = ListInput export const BoolInput = (props) => {
const boolConfig = {
list: [0, 1],
choiceTitles: {
0: `${props.name}No`,
1: `${props.name}Yes`,
},
valueTitles: {
0: 'no',
1: 'yes',
},
dflt: props.config.dflt ? 1 : 0,
...props.config,
}
return <ListInput {...props} config={boolConfig} />
}
const EditInputValue = (props) => ( const EditInputValue = (props) => (
<div className="form-control mb-2 w-full"> <div className="form-control mb-2 w-full">
@ -123,7 +129,6 @@ export const SliderInput = ({
config, config,
current, current,
updateFunc, updateFunc,
updatePath = [],
t, t,
override, override,
suffix = '', suffix = '',
@ -136,7 +141,6 @@ export const SliderInput = ({
current, current,
dflt: config.dflt, dflt: config.dflt,
updateFunc, updateFunc,
updatePath,
name, name,
setReset, setReset,
}) })
@ -192,8 +196,7 @@ export const SliderInput = ({
export const PctInput = ({ config, settings, current, updateFunc, type = 'pct', ...rest }) => { export const PctInput = ({ config, settings, current, updateFunc, type = 'pct', ...rest }) => {
const suffix = type === 'deg' ? '°' : '%' const suffix = type === 'deg' ? '°' : '%'
const factor = type === 'deg' ? 1 : 100 const factor = type === 'deg' ? 1 : 100
const dflt = config[type] let pctCurrent = typeof current === 'undefined' ? config.dflt : current * factor
let pctCurrent = typeof current === 'undefined' ? dflt : current * factor
const valFormatter = (val) => round(val) const valFormatter = (val) => round(val)
const pctUpdateFunc = useCallback( const pctUpdateFunc = useCallback(
@ -208,7 +211,6 @@ export const PctInput = ({ config, settings, current, updateFunc, type = 'pct',
config: { config: {
...config, ...config,
step: 0.1, step: 0.1,
dflt,
}, },
current: pctCurrent, current: pctCurrent,
updateFunc: pctUpdateFunc, updateFunc: pctUpdateFunc,
@ -217,7 +219,7 @@ export const PctInput = ({ config, settings, current, updateFunc, type = 'pct',
}} }}
> >
<div className="flex flex-row justify-around"> <div className="flex flex-row justify-around">
<span className={current === dflt ? 'text-secondary' : 'text-accent'}> <span className={current === config.dflt ? 'text-secondary' : 'text-accent'}>
{config.toAbs && settings.measurements {config.toAbs && settings.measurements
? formatMm(config.toAbs(current / factor, settings)) ? formatMm(config.toAbs(current / factor, settings))
: ' '} : ' '}
@ -238,6 +240,7 @@ export const MmInput = (props) => {
}, },
[props.updateFunc, props.units] [props.updateFunc, props.units]
) )
return ( return (
<SliderInput <SliderInput
{...{ {...{

View file

@ -2,9 +2,9 @@ import { ClearIcon, 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'
export const wasChanged = (current, name, settingsConfig) => { export const wasChanged = (current, config) => {
if (typeof current === 'undefined') return false if (typeof current === 'undefined') return false
if (current === settingsConfig[name].dflt) return false if (current === config.dflt) return false
return true return true
} }
@ -16,18 +16,17 @@ export const ItemTitle = ({ name, t, changed, current = null, open = false, emoj
{emoji} {emoji}
</span> </span>
{t(`${name}.t`)} {t(`${name}.t`)}
{open ? ':' : ''}
</span> </span>
<span className="font-bold">{current}</span> <span className="font-bold">{current}</span>
</div> </div>
) )
const openButtonClass = 'btn btn-xs btn-ghost px-0'
export const MenuItem = ({ export const MenuItem = ({
name, name,
config, config,
current, current,
updateFunc, updateFunc,
updatePath = [],
t, t,
passProps = {}, passProps = {},
changed, changed,
@ -35,9 +34,10 @@ export const MenuItem = ({
Input, Input,
Value, Value,
allowOverride = false, allowOverride = false,
control = Infinity,
}) => { }) => {
const [override, setOverride] = useState(false) const [override, setOverride] = useState(false)
const [reset, setReset] = useState(() => () => updateFunc([...updatePath, name])) const [reset, setReset] = useState(() => () => updateFunc(name))
const drillProps = useMemo( const drillProps = useMemo(
() => ({ () => ({
@ -47,23 +47,20 @@ export const MenuItem = ({
updateFunc, updateFunc,
t, t,
changed, changed,
updatePath,
override, override,
setReset, setReset,
...passProps, ...passProps,
}), }),
[name, config, current, updateFunc, t, changed, updatePath, override, setReset, passProps] [name, config, current, updateFunc, t, changed, override, setReset, passProps]
) )
if (config.control && config.control > control) return null
const buttons = [] const buttons = []
const openButtons = [] const openButtons = []
if (loadDocs) if (loadDocs)
openButtons.push( openButtons.push(
<button <button className={openButtonClass} key="help" onClick={(evt) => loadDocs(evt, name)}>
className="btn btn-xs btn-ghost px-0"
key="help"
onClick={(evt) => loadDocs(evt, name)}
>
<HelpIcon className="w-4 h-4" /> <HelpIcon className="w-4 h-4" />
</button> </button>
) )
@ -71,7 +68,7 @@ export const MenuItem = ({
openButtons.push( openButtons.push(
<button <button
key="edit" key="edit"
className="btn btn-xs btn-ghost px-0" className={openButtonClass}
onClick={(evt) => { onClick={(evt) => {
evt.stopPropagation() evt.stopPropagation()
setOverride(!override) setOverride(!override)
@ -81,22 +78,9 @@ export const MenuItem = ({
</button> </button>
) )
if (changed) { if (changed) {
buttons.push( const ResetButton = ({ open }) => (
<button <button
className="btn btn-accent" className={open ? openButtonClass : 'btn btn-accent'}
key="clear"
onClick={(evt) => {
evt.stopPropagation()
reset()
}}
>
<ClearIcon />
</button>
)
openButtons.push(
<button
className="btn btn-ghost btn-xs px-0"
key="clear"
onClick={(evt) => { onClick={(evt) => {
evt.stopPropagation() evt.stopPropagation()
reset() reset()
@ -105,6 +89,8 @@ export const MenuItem = ({
<ClearIcon /> <ClearIcon />
</button> </button>
) )
buttons.push(<ResetButton key="clear" />)
openButtons.push(<ResetButton open key="clear" />)
} }
const titleProps = { name, t, current: <Value {...drillProps} />, emoji: config.emoji } const titleProps = { name, t, current: <Value {...drillProps} />, emoji: config.emoji }
@ -124,29 +110,37 @@ export const MenuItem = ({
export const MenuItemGroup = ({ export const MenuItemGroup = ({
collapsible = true, collapsible = true,
control,
name, name,
groupConfig, currentValues = {},
currents = {}, structure,
items,
Item = MenuItem, Item = MenuItem,
values = {},
inputs = {},
loadDocs, loadDocs,
itemProps = {}, passProps = {},
emojis = {}, emojis = {},
updateFunc,
t, t,
}) => { }) => {
const content = Object.entries(items).map(([itemName, item]) => { const content = Object.entries(structure).map(([itemName, item]) => {
if (typeof item === 'string') if (itemName === 'isMenu' || item === false) return null
if (!item.isMenu)
return ( return (
<Item <Item
key={itemName} key={itemName}
{...{ {...{
name: itemName, name: itemName,
current: currents[itemName], current: currentValues[itemName],
config: groupConfig[itemName], config: item,
changed: wasChanged(currents[itemName], itemName, groupConfig), control,
changed: wasChanged(currentValues[itemName], item),
Value: values[itemName],
Input: inputs[itemName],
t, t,
loadDocs, loadDocs,
...itemProps, updateFunc,
passProps,
}} }}
/> />
) )
@ -156,43 +150,34 @@ export const MenuItemGroup = ({
key={itemName} key={itemName}
{...{ {...{
collapsible: true, collapsible: true,
control,
name: itemName, name: itemName,
groupConfig, currentValues,
currents, structure: item,
items: item,
Item, Item,
values,
inputs,
loadDocs, loadDocs,
itemProps, passProps,
emojis, emojis,
updateFunc,
t, t,
}} }}
/> />
) )
}) })
const titleProps = {
name,
t,
emoji: emojis[name] || emojis.dflt,
}
return collapsible ? ( return collapsible ? (
<Collapse <Collapse
bottom bottom
color="secondary" color="secondary"
title={ title={<ItemTitle {...titleProps} />}
<ItemTitle openTitle={<ItemTitle open {...titleProps} />}
{...{
name,
t,
emoji: emojis[name] || emojis.dflt,
}}
/>
}
openTitle={
<ItemTitle
open
{...{
name,
t,
emoji: emojis[name] || emojis.dflt,
}}
/>
}
> >
{content} {content}
</Collapse> </Collapse>

View file

@ -1,18 +1,23 @@
import { formatMm, formatFraction128 } from 'shared/utils.mjs' import { formatMm, formatFraction128 } from 'shared/utils.mjs'
export const HighlightedValue = ({ changed, children }) => ( export const HighlightedValue = ({ changed, children }) => (
<span className={changed ? 'text-accent' : 'text-secondary-focus'}> {children} </span> <span className={changed ? 'text-info' : ''}> {children} </span>
) )
export const PlainValue = ({ current, config, changed }) => ( export const PlainValue = ({ current, dflt, changed }) => (
<HighlightedValue changed={changed}> {changed ? current : config.dflt} </HighlightedValue> <HighlightedValue changed={changed}> {changed ? current : dflt} </HighlightedValue>
) )
export const ListValue = ({ current, t, config, changed }) => ( export const ListValue = ({ current, t, config, changed }) => {
<HighlightedValue changed={changed}> const val = changed ? current : config.dflt
{changed ? t(`${config.valueTitles[current]}`) : t(`${config.valueTitles[config.dflt]}`)} let key
</HighlightedValue> if (config.valueTitles) key = config.valueTitles[val]
) else if (typeof val === 'string') key = val
else if (val) key = 'yes'
else key = 'no'
return <HighlightedValue changed={changed}>{t(key)}</HighlightedValue>
}
export const MmValue = ({ current, t, config, units, changed }) => ( export const MmValue = ({ current, t, config, units, changed }) => (
<HighlightedValue changed={changed}> <HighlightedValue changed={changed}>

View file

@ -8,9 +8,9 @@ const usePersistedToken = createPersistedState('fs-token')
const usePersistedSeenUser = createPersistedState('fs-seen-user') const usePersistedSeenUser = createPersistedState('fs-seen-user')
/* /*
* Make it possible to always check for account.username * Make it possible to always check for account.username and account.control
*/ */
const noAccount = { username: false } const noAccount = { username: false, control: 2 }
/* /*
* The useAccount hook * The useAccount hook

View file

@ -197,8 +197,11 @@ export const optionsMenuStructure = (options) => {
// Fixme: One day we should sort this based on the translation // Fixme: One day we should sort this based on the translation
for (const option of orderBy(sorted, ['menu', 'name'], ['asc'])) { for (const option of orderBy(sorted, ['menu', 'name'], ['asc'])) {
if (typeof option === 'object') { if (typeof option === 'object') {
if (option.menu) set(menu, `${option.menu}.${option.name}`, optionType(option)) option.dflt = option.dflt || option[optionType(option)]
else if (typeof option.menu === 'undefined') { if (option.menu) {
set(menu, `${option.menu}.isMenu`, true)
set(menu, `${option.menu}.${option.name}`, option)
} else if (typeof option.menu === 'undefined') {
console.log( console.log(
`Warning: Option ${option.name} does not have a menu config. ` + `Warning: Option ${option.name} does not have a menu config. ` +
'Either configure it, or set it to false to hide this option.' 'Either configure it, or set it to false to hide this option.'