diff --git a/components/home/FactorySelect/FactorySelect.module.css b/components/home/FactorySelect/FactorySelect.module.css index 3f7a073..299601f 100644 --- a/components/home/FactorySelect/FactorySelect.module.css +++ b/components/home/FactorySelect/FactorySelect.module.css @@ -2,6 +2,10 @@ padding: 0.3em; } +.select :global(.factory-select__multi-value) { + --fixed-item-bg: #ccc; +} + @media (prefers-color-scheme: dark) { .select :global(.factory-select__control) { background-color: #222; @@ -10,6 +14,8 @@ .select :global(.factory-select__multi-value), .select :global(.factory-select__menu) { background-color: #444; + + --fixed-item-bg: #666; } .option:is(:hover, :focus-visible) { diff --git a/components/home/FactorySelect/FactorySelect.tsx b/components/home/FactorySelect/FactorySelect.tsx index 7aa66a4..53361dc 100644 --- a/components/home/FactorySelect/FactorySelect.tsx +++ b/components/home/FactorySelect/FactorySelect.tsx @@ -1,33 +1,93 @@ -import { FC, memo, useMemo } from 'react' -import Select from 'react-select' +import { FC, memo, useCallback, useEffect, useMemo } from 'react' +import Select, { ActionMeta, CSSObjectWithLabel } from 'react-select' import { isNonNullable } from '../../../src/utils' -import details from '../../../res/details.json' import styles from './FactorySelect.module.css' +import { useFactories } from '../../../src/hooks/useFactories' import { EntitySpan } from '../EntitySpan/EntitySpan' interface Props { id: string factories: string[] onSetFactories: (factories: string[]) => void + fixInputs?: boolean } -const options = details.map(detail => ({ - label: detail.name, - value: detail.href -})) +interface Option { + label: string + value: string + isFixed: boolean +} + +const selectStyles: Record< + 'multiValue' | 'multiValueLabel' | 'multiValueRemove', + (base: CSSObjectWithLabel, state: { data: Option }) => CSSObjectWithLabel +> = { + multiValue: (base, state) => { + return state.data.isFixed + ? { ...base, backgroundColor: 'var(--fixed-item-bg) !important' } + : base + }, + multiValueLabel: (base, state) => { + return state.data.isFixed ? { ...base, fontWeight: 'bold', paddingRight: '6px' } : base + }, + multiValueRemove: (base, state) => { + return state.data.isFixed ? { ...base, display: 'none' } : base + } +} + +const orderOptions = (values: Option[]) => { + return values.filter(v => v.isFixed).concat(values.filter(v => !v.isFixed)) +} + +const FactorySelectBase: FC = ({ id, factories, onSetFactories, fixInputs }) => { + const { factories: details } = useFactories() + const options = useMemo( + () => + details.map(detail => ({ + label: detail.name, + value: detail.href, + isFixed: !!fixInputs && !detail.recipe + })), + [details, fixInputs] + ) -const FactorySelectBase: FC = ({ id, factories, onSetFactories }) => { const state = useMemo(() => { return factories .map(factory => options.find(option => option.value === factory)) .filter(isNonNullable) - }, [factories]) + }, [factories, options]) + + useEffect(() => { + if (!fixInputs) return + const set = new Set(factories) + const addOptions = options + .filter(option => option.isFixed && !set.has(option.value)) + .map(option => option.value) + if (addOptions.length) { + onSetFactories([...factories, ...addOptions]) + } + }, [factories, fixInputs, onSetFactories, options]) + + const onChange = useCallback( + (values: readonly Option[], { action, removedValue }: ActionMeta