import React from 'react' import { mergeOptions } from '@freesewing/core' import { designOptionType, set, orderBy } from '@freesewing/utils' import { i18n } from '@freesewing/collection' import { linkClasses } from '@freesewing/utils' const DesignDocsLink = ({ design, item }) => ( Learn more ) export function menuDesignOptionsStructure(design, options, settings, asFullList = false) { if (!options) return options const sorted = {} for (const [name, option] of Object.entries(options)) { if (typeof option === 'object') { sorted[name] = { ...option, name, title: i18n[design]?.en?.o?.[name]?.t || name, about: ( {i18n[design]?.en?.o?.[name]?.d || name} ), dense: true, sideBySide: true, } } } // Save us some typing to access English options const eno = i18n[design]?.en?.o || {} const menu = {} for (const option of orderBy(sorted, ['order', 'menu', 'name'], ['asc', 'asc', 'asc'])) { if (typeof option === 'object') { const oType = designOptionType(option) option.dflt = option.dflt || option[oType] // Percentage option tweaks 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] = eno[`${option.name}.${entry}`]?.t || option.name option.choiceDescriptions[entry] = eno[`${option.name}.${entry}`]?.d || '' option.valueTitles[entry] = eno[`${option.name}.${entry}`]?.t || option.name } } // Bool option tweaks else if (oType === 'bool') { option.list = [false, true] option.valueTitles = {} option.choiceTitles = {} option.choiceDescriptions = {} option.list.forEach(() => { option.choiceTitles.false = eno[`${option.name}No`]?.t || option.name option.choiceDescriptions.false = eno[`${option.name}No`]?.d || 'No' option.valueTitles.false = 'No' option.choiceTitles.true = eno[`${option.name}Yes`]?.t || 'Yes' option.choiceDescriptions.true = eno[`${option.name}Yes`]?.d || 'No' option.valueTitles.true = 'Yes' }) } if (typeof option.menu === 'function') option.menu = asFullList ? 'conditional' : option.menu(settings, mergeOptions(settings, options)) if (option.menu) { // Handle nested groups that don't have any direct children if (option.menu.includes('.')) { let menuPath = [] for (const chunk of option.menu.split('.')) { menuPath.push(chunk) set(menu, `${menuPath.join('.')}.isGroup`, true) } } set(menu, `${option.menu}.isGroup`, true) set(menu, `${option.menu}.${option.name}`, option) } else if (typeof option.menu === 'undefined') { console.log( `Warning: Option ${option.name} does not have a menu config. ` + 'Either configure it, or set it to false to hide this option.' ) } } } // Always put advanced at the end if (menu.advanced) { const adv = menu.advanced delete menu.advanced menu.advanced = adv } return menu } /* * Helper method to grab an option from an Design options structure * * Since these structures can be nested with option groups, this needs some extra logic */ export function getOptionStructure(option, Design, state) { const { settings = {} } = state // Guard against undefined settings const structure = menuDesignOptionsStructure(Design.patternConfig.options, settings) return findOption(structure, option) } export function findOption(structure, option) { for (const [key, val] of Object.entries(structure)) { if (key === option) return val if (val.isGroup) { const sub = findOption(val, option) if (sub) return sub } } return false }