Fixed barrels and input
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
padding: 0.3em;
|
padding: 0.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.select :global(.factory-select__multi-value) {
|
||||||
|
--fixed-item-bg: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
.select :global(.factory-select__control) {
|
.select :global(.factory-select__control) {
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
@@ -10,6 +14,8 @@
|
|||||||
.select :global(.factory-select__multi-value),
|
.select :global(.factory-select__multi-value),
|
||||||
.select :global(.factory-select__menu) {
|
.select :global(.factory-select__menu) {
|
||||||
background-color: #444;
|
background-color: #444;
|
||||||
|
|
||||||
|
--fixed-item-bg: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.option:is(:hover, :focus-visible) {
|
.option:is(:hover, :focus-visible) {
|
||||||
|
|||||||
@@ -1,33 +1,93 @@
|
|||||||
import { FC, memo, useMemo } from 'react'
|
import { FC, memo, useCallback, useEffect, useMemo } from 'react'
|
||||||
import Select from 'react-select'
|
import Select, { ActionMeta, CSSObjectWithLabel } from 'react-select'
|
||||||
import { isNonNullable } from '../../../src/utils'
|
import { isNonNullable } from '../../../src/utils'
|
||||||
import details from '../../../res/details.json'
|
|
||||||
import styles from './FactorySelect.module.css'
|
import styles from './FactorySelect.module.css'
|
||||||
|
import { useFactories } from '../../../src/hooks/useFactories'
|
||||||
import { EntitySpan } from '../EntitySpan/EntitySpan'
|
import { EntitySpan } from '../EntitySpan/EntitySpan'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
id: string
|
id: string
|
||||||
factories: string[]
|
factories: string[]
|
||||||
onSetFactories: (factories: string[]) => void
|
onSetFactories: (factories: string[]) => void
|
||||||
|
fixInputs?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = details.map(detail => ({
|
interface Option {
|
||||||
label: detail.name,
|
label: string
|
||||||
value: detail.href
|
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<Props> = ({ id, factories, onSetFactories, fixInputs }) => {
|
||||||
|
const { factories: details } = useFactories()
|
||||||
|
const options = useMemo<Option[]>(
|
||||||
|
() =>
|
||||||
|
details.map(detail => ({
|
||||||
|
label: detail.name,
|
||||||
|
value: detail.href,
|
||||||
|
isFixed: !!fixInputs && !detail.recipe
|
||||||
|
})),
|
||||||
|
[details, fixInputs]
|
||||||
|
)
|
||||||
|
|
||||||
const FactorySelectBase: FC<Props> = ({ id, factories, onSetFactories }) => {
|
|
||||||
const state = useMemo<typeof options>(() => {
|
const state = useMemo<typeof options>(() => {
|
||||||
return factories
|
return factories
|
||||||
.map(factory => options.find(option => option.value === factory))
|
.map(factory => options.find(option => option.value === factory))
|
||||||
.filter(isNonNullable)
|
.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<Option>) => {
|
||||||
|
if ((action === 'remove-value' || action === 'pop-value') && removedValue.isFixed) {
|
||||||
|
return
|
||||||
|
} else if (action === 'clear') {
|
||||||
|
const clearedValues = orderOptions(options.filter(v => v.isFixed))
|
||||||
|
onSetFactories(clearedValues.map(s => s?.value))
|
||||||
|
} else {
|
||||||
|
onSetFactories(values.map(s => s?.value))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onSetFactories, options]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
id={id}
|
id={id}
|
||||||
instanceId={id}
|
instanceId={id}
|
||||||
value={state}
|
value={orderOptions(state)}
|
||||||
|
isClearable={state.some(option => !option.isFixed)}
|
||||||
components={{
|
components={{
|
||||||
MultiValueLabel: ({ data, innerProps }) => (
|
MultiValueLabel: ({ data, innerProps }) => (
|
||||||
<EntitySpan {...innerProps} value={data.value} simpleStyle={true} />
|
<EntitySpan {...innerProps} value={data.value} simpleStyle={true} />
|
||||||
@@ -39,12 +99,11 @@ const FactorySelectBase: FC<Props> = ({ id, factories, onSetFactories }) => {
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
isMulti
|
isMulti
|
||||||
options={options as never}
|
options={orderOptions(options)}
|
||||||
onChange={e => {
|
onChange={onChange}
|
||||||
onSetFactories(e.map(s => s?.value))
|
|
||||||
}}
|
|
||||||
className={styles.select}
|
className={styles.select}
|
||||||
classNamePrefix={'factory-select'}
|
classNamePrefix={'factory-select'}
|
||||||
|
styles={selectStyles}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export const Preferences: FC = () => {
|
|||||||
id={'baseFactoriesSelect'}
|
id={'baseFactoriesSelect'}
|
||||||
factories={baseFactories}
|
factories={baseFactories}
|
||||||
onSetFactories={setBaseFactories}
|
onSetFactories={setBaseFactories}
|
||||||
|
fixInputs={true}
|
||||||
/>
|
/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
|||||||
7
res/exclude.json
Normal file
7
res/exclude.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[
|
||||||
|
"/Blueprint",
|
||||||
|
"/Deconstruction_planner",
|
||||||
|
"/Upgrade_planner",
|
||||||
|
"/Blueprint_book",
|
||||||
|
"/Space_science_pack"
|
||||||
|
]
|
||||||
119
res/manual.json
119
res/manual.json
@@ -71,5 +71,124 @@
|
|||||||
"/Solid_fuel": 1
|
"/Solid_fuel": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Crude oil barrel",
|
||||||
|
"href": "/Crude_oil_barrel",
|
||||||
|
"image": "/images/thumb/Crude_oil_barrel.png/32px-Crude_oil_barrel.png",
|
||||||
|
"recipe": {
|
||||||
|
"prerequisites": {
|
||||||
|
"/Empty_barrel": 1,
|
||||||
|
"/Crude_oil": 50
|
||||||
|
},
|
||||||
|
"time": 0.2,
|
||||||
|
"output": {
|
||||||
|
"/Crude_oil_barrel": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Heavy oil barrel",
|
||||||
|
"href": "/Heavy_oil_barrel",
|
||||||
|
"image": "/images/thumb/Heavy_oil_barrel.png/32px-Heavy_oil_barrel.png",
|
||||||
|
"recipe": {
|
||||||
|
"prerequisites": {
|
||||||
|
"/Empty_barrel": 1,
|
||||||
|
"/Heavy_oil": 50
|
||||||
|
},
|
||||||
|
"time": 0.2,
|
||||||
|
"output": {
|
||||||
|
"/Heavy_oil_barrel": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Light oil barrel",
|
||||||
|
"href": "/Light_oil_barrel",
|
||||||
|
"image": "/images/thumb/Light_oil_barrel.png/32px-Light_oil_barrel.png",
|
||||||
|
"recipe": {
|
||||||
|
"prerequisites": {
|
||||||
|
"/Empty_barrel": 1,
|
||||||
|
"/Light_oil": 50
|
||||||
|
},
|
||||||
|
"time": 0.2,
|
||||||
|
"output": {
|
||||||
|
"/Light_oil_barrel": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lubricant barrel",
|
||||||
|
"href": "/Lubricant_barrel",
|
||||||
|
"image": "/images/thumb/Lubricant_barrel.png/32px-Lubricant_barrel.png",
|
||||||
|
"recipe": {
|
||||||
|
"prerequisites": {
|
||||||
|
"/Empty_barrel": 1,
|
||||||
|
"/Lubricant": 50
|
||||||
|
},
|
||||||
|
"time": 0.2,
|
||||||
|
"output": {
|
||||||
|
"/Lubricant_barrel": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Petroleum gas barrel",
|
||||||
|
"href": "/Petroleum_gas_barrel",
|
||||||
|
"image": "/images/thumb/Petroleum_gas_barrel.png/32px-Petroleum_gas_barrel.png",
|
||||||
|
"recipe": {
|
||||||
|
"prerequisites": {
|
||||||
|
"/Empty_barrel": 1,
|
||||||
|
"/Petroleum_gas": 50
|
||||||
|
},
|
||||||
|
"time": 0.2,
|
||||||
|
"output": {
|
||||||
|
"/Petroleum_gas_barrel": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sulfuric acid barrel",
|
||||||
|
"href": "/Sulfuric_acid_barrel",
|
||||||
|
"image": "/images/thumb/Sulfuric_acid_barrel.png/32px-Sulfuric_acid_barrel.png",
|
||||||
|
"recipe": {
|
||||||
|
"prerequisites": {
|
||||||
|
"/Empty_barrel": 1,
|
||||||
|
"/Sulfuric_acid": 50
|
||||||
|
},
|
||||||
|
"time": 0.2,
|
||||||
|
"output": {
|
||||||
|
"/Sulfuric_acid_barrel": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Water barrel",
|
||||||
|
"href": "/Water_barrel",
|
||||||
|
"image": "/images/thumb/Water_barrel.png/32px-Water_barrel.png",
|
||||||
|
"recipe": {
|
||||||
|
"prerequisites": {
|
||||||
|
"/Empty_barrel": 1,
|
||||||
|
"/Water": 50
|
||||||
|
},
|
||||||
|
"time": 0.2,
|
||||||
|
"output": {
|
||||||
|
"/Water_barrel": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Steam",
|
||||||
|
"href": "/Steam",
|
||||||
|
"image": "/images/thumb/Steam.png/32px-Steam.png",
|
||||||
|
"recipe": {
|
||||||
|
"prerequisites": {
|
||||||
|
"/Water": 1
|
||||||
|
},
|
||||||
|
"time": 0,
|
||||||
|
"output": {
|
||||||
|
"/Steam": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
import { EnrichedEntity, Entity } from '../types'
|
import { EnrichedEntity, Entity } from '../types'
|
||||||
import details from '../../res/details.json'
|
import details from '../../res/details.json'
|
||||||
import manual from '../../res/manual.json'
|
import manual from '../../res/manual.json'
|
||||||
|
import exclude from '../../res/exclude.json'
|
||||||
|
|
||||||
const joined = [...details, ...manual] as Entity[]
|
const manualEntities = manual as Entity[]
|
||||||
|
const manualKeys = new Set(manualEntities.map(entity => entity.href))
|
||||||
|
const detailEntities = (details as Entity[]).filter(detail => !manualKeys.has(detail.href))
|
||||||
|
|
||||||
const factories = joined.map((detail: EnrichedEntity) => {
|
const joined = [...detailEntities, ...manualEntities]
|
||||||
detail.usedBy = joined.filter(f =>
|
|
||||||
Object.keys(f.recipe?.prerequisites ?? {}).includes(detail.href)
|
const factories = joined
|
||||||
)
|
.map((detail: EnrichedEntity) => {
|
||||||
return detail
|
detail.usedBy = joined.filter(f =>
|
||||||
})
|
Object.keys(f.recipe?.prerequisites ?? {}).includes(detail.href)
|
||||||
|
)
|
||||||
|
return detail
|
||||||
|
})
|
||||||
|
.filter(detail => !(exclude as string[]).includes(detail.href))
|
||||||
|
|
||||||
const detailsMap = Object.fromEntries(
|
const detailsMap = Object.fromEntries(
|
||||||
factories.map((detail: EnrichedEntity) => [detail.href, detail])
|
factories.map((detail: EnrichedEntity) => [detail.href, detail])
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export interface Recipe {
|
export interface Recipe {
|
||||||
prerequisites: Dict<number>
|
prerequisites: Dict<number | undefined>
|
||||||
time: number
|
time: number
|
||||||
output: Dict<number>
|
output: Dict<number | undefined>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UnfetchedEntity {
|
export interface UnfetchedEntity {
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
"jest.config.js",
|
"jest.config.js",
|
||||||
"next.config.js",
|
"next.config.js",
|
||||||
"src/backend-custom-server/index",
|
"src/backend-custom-server/index",
|
||||||
"scripts/*"
|
"scripts/*",
|
||||||
|
"res/*.json"
|
||||||
],
|
],
|
||||||
"exclude": ["dist", ".next", "out", "node_modules", "cypress"]
|
"exclude": ["dist", ".next", "out", "node_modules", "cypress"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user