1
0
Fork 0

wip: Fix all design option inputs

This commit is contained in:
joostdecock 2025-01-26 17:22:24 +01:00
parent 899b323563
commit e78864f274
4 changed files with 76 additions and 25 deletions

View file

@ -35,8 +35,13 @@ import { OptionsIcon } from '@freesewing/react/components/Icon'
*/ */
export const DesignOptionsMenu = ({ Design, isFirst = true, state, i18n, update }) => { export const DesignOptionsMenu = ({ Design, isFirst = true, state, i18n, update }) => {
const structure = useMemo( const structure = useMemo(
() => menuDesignOptionsStructure(Design.patternConfig.options, state.settings), () =>
[Design.patternConfig, state.settings] menuDesignOptionsStructure(
Design.designConfig.data.id,
Design.patternConfig.options,
state.settings
),
[Design.designConfig.data.id, Design.patternConfig, state.settings]
) )
const updateHandler = useCallback( const updateHandler = useCallback(
(name, value = '__UNSET__') => update.settings(['options', ...name], value), (name, value = '__UNSET__') => update.settings(['options', ...name], value),

View file

@ -10,9 +10,9 @@ import { capitalize } from '@freesewing/core'
/** A boolean version of {@see MenuListInput} that sets up the necessary configuration */ /** A boolean version of {@see MenuListInput} that sets up the necessary configuration */
export const MenuBoolInput = (props) => { export const MenuBoolInput = (props) => {
const { name, config } = props const { name, config } = props
const boolConfig = useBoolConfig(name, config) //const boolConfig = useBoolConfig(name, config)
return <MenuListInput {...props} config={boolConfig} /> return <MenuListInput {...props} />
} }
/** A placeholder for an input to handle constant values */ /** A placeholder for an input to handle constant values */
@ -136,13 +136,19 @@ export const MenuListInput = ({
onClick={() => handleChange(entry)} onClick={() => handleChange(entry)}
> >
<div <div
className={`tw-w-full tw-flex tw-items-start ${ className={`tw-w-full tw-flex ${
sideBySide ? 'tw-flex-row tw-justify-between tw-gap-2' : 'tw-flex-col' sideBySide
? 'tw-flex-row tw-justify-between tw-gap-2 tw-items-center'
: 'tw-flex-col tw-items-start'
}`} }`}
> >
<div className="tw-font-semibold tw-shrink-0">{config.choiceTitles[entry]}</div> <div className="tw-font-semibold">{config.choiceTitles[entry]}</div>
{compact || !config.choiceDescriptions ? null : ( {compact || !config.choiceDescriptions ? null : (
<div className="tw-text-base tw-font-normal">{config.choiceDescriptions[entry]}</div> <div
className={`${config.dense ? 'tw-text-sm tw-leading-5 tw-py-1' : 'tw-text-base'} tw-font-normal`}
>
{config.choiceDescriptions[entry]}
</div>
)} )}
</div> </div>
</ButtonFrame> </ButtonFrame>
@ -390,19 +396,6 @@ const useBoolConfig = (name, config) => {
/** an input for the 'only' setting. toggles individual parts*/ /** an input for the 'only' setting. toggles individual parts*/
export const MenuOnlySettingInput = (props) => { export const MenuOnlySettingInput = (props) => {
const { config } = props const { config } = props
//config.sideBySide = true
//config.titleMethod = (entry, t) => {
// const chunks = entry.split('.')
// return <span className="tw-font-medium tw-text-base">{entry}</span> //t(`${chunks[0]}:${chunks[1]}`)}</span>
//}
//config.valueMethod = (entry) => (
// <span className="tw-text-sm">{capitalize(entry.split('.')[0])}</span>
//)
//config.dense = true
// Sort alphabetically
//const order = []
//order.sort()
console.log(i18n)
config.list = config.list.sort() config.list = config.list.sort()
config.choiceTitles = {} config.choiceTitles = {}
for (const part of config.list) { for (const part of config.list) {

View file

@ -1,20 +1,73 @@
import React from 'react'
import { mergeOptions } from '@freesewing/core' import { mergeOptions } from '@freesewing/core'
import { designOptionType, set, orderBy } from '@freesewing/utils' import { designOptionType, set, orderBy } from '@freesewing/utils'
import { i18n } from '@freesewing/collection'
import { linkClasses } from '@freesewing/utils'
export function menuDesignOptionsStructure(options, settings, asFullList = false) { const DesignDocsLink = ({ design, item }) => (
<a
href={`/docs/designs/${design}/options/#${item.toLowerCase()}`}
className={`${linkClasses} tw-px-2`}
target="_BLANK"
>
Learn more
</a>
)
export function menuDesignOptionsStructure(design, options, settings, asFullList = false) {
if (!options) return options if (!options) return options
const sorted = {} const sorted = {}
for (const [name, option] of Object.entries(options)) { for (const [name, option] of Object.entries(options)) {
if (typeof option === 'object') sorted[name] = { ...option, name } if (typeof option === 'object') {
sorted[name] = {
...option,
name,
title: i18n[design].en.o[name].t,
about: (
<span>
{i18n[design].en.o[name].d}
<DesignDocsLink item={name} design={design} />
</span>
),
dense: true,
sideBySide: true,
}
}
} }
const menu = {} const menu = {}
// Fixme: One day we should sort this based on the translation
for (const option of orderBy(sorted, ['order', 'menu', 'name'], ['asc', 'asc', 'asc'])) { for (const option of orderBy(sorted, ['order', 'menu', 'name'], ['asc', 'asc', 'asc'])) {
if (typeof option === 'object') { if (typeof option === 'object') {
const oType = designOptionType(option) const oType = designOptionType(option)
option.dflt = option.dflt || option[oType] option.dflt = option.dflt || option[oType]
// Percentage option tweaks
if (oType === 'pct') option.dflt /= 100 if (oType === 'pct') option.dflt /= 100
// List option tweaks
else if (oType === 'list') {
option.valueTitles = {}
option.choiceTitles = {}
option.choiceDescriptions = {}
for (const entry of option.list) {
option.choiceTitles[entry] = i18n[design].en.o[`${option.name}.${entry}`].t
option.choiceDescriptions[entry] = i18n[design].en.o[`${option.name}.${entry}`].d
option.valueTitles[entry] = i18n[design].en.o[`${option.name}.${entry}`].t
}
}
// Bool option tweaks
else if (oType === 'bool') {
option.list = [false, true]
option.valueTitles = {}
option.choiceTitles = {}
option.choiceDescriptions = {}
for (const entry of option.list) {
option.choiceTitles.false = i18n[design].en.o[`${option.name}No`].t
option.choiceDescriptions.false = i18n[design].en.o[`${option.name}No`].d
option.valueTitles.false = 'No'
option.choiceTitles.true = i18n[design].en.o[`${option.name}Yes`].t
option.choiceDescriptions.true = i18n[design].en.o[`${option.name}Yes`].d
option.valueTitles.true = 'Yes'
}
}
if (typeof option.menu === 'function') if (typeof option.menu === 'function')
option.menu = asFullList option.menu = asFullList
? 'conditional' ? 'conditional'

View file

@ -98,7 +98,7 @@ export const ButtonFrame = ({
}) => ( }) => (
<button <button
className={` className={`
tw-daisy-btn tw-daisy-btn-ghost tw-daisy-btn-secondary tw-daisy-btn tw-daisy-btn-ghost tw-daisy-btn-secondary tw-h-fit
tw-w-full ${dense ? 'tw-mt-1 tw-daisy-btn-sm tw-font-light' : 'tw-mt-2 tw-py-4 tw-h-auto tw-content-start'} tw-w-full ${dense ? 'tw-mt-1 tw-daisy-btn-sm tw-font-light' : 'tw-mt-2 tw-py-4 tw-h-auto tw-content-start'}
tw-border-2 tw-border-secondary tw-text-left tw-bg-opacity-20 tw-border-2 tw-border-secondary tw-text-left tw-bg-opacity-20
${accordion ? 'hover:tw-bg-transparent' : 'hover:tw-bg-secondary hover:tw-bg-opacity-10'} ${accordion ? 'hover:tw-bg-transparent' : 'hover:tw-bg-secondary hover:tw-bg-opacity-10'}