Polish wired editor UI and source selection flows

This commit is contained in:
Lorenzune
2026-03-25 03:26:27 +01:00
parent 6472b1cc27
commit 56a0be64d9
35 changed files with 4137 additions and 256 deletions
@@ -12,11 +12,13 @@ export interface WiredExtraBaseViewProps
validate?: () => boolean;
cardStyle?: CSSProperties;
footer?: ReactNode;
footerCollapsible?: boolean;
selectionPreview?: ReactNode;
}
export const WiredExtraBaseView: FC<PropsWithChildren<WiredExtraBaseViewProps>> = props =>
{
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, hasSpecialInput = false, children = null, cardStyle = undefined, footer = null } = props;
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, hasSpecialInput = false, children = null, cardStyle = undefined, footer = null, footerCollapsible = true, selectionPreview = null } = props;
const { trigger = null, setActionDelay = null } = useWired();
useEffect(() =>
@@ -25,7 +27,7 @@ export const WiredExtraBaseView: FC<PropsWithChildren<WiredExtraBaseViewProps>>
}, [ trigger, setActionDelay ]);
return (
<WiredBaseView hasSpecialInput={ hasSpecialInput } requiresFurni={ requiresFurni } save={ save } validate={ validate } wiredType="extra" cardStyle={ cardStyle } footer={ footer }>
<WiredBaseView hasSpecialInput={ hasSpecialInput } requiresFurni={ requiresFurni } save={ save } validate={ validate } wiredType="extra" cardStyle={ cardStyle } footer={ footer } footerCollapsible={ footerCollapsible } selectionPreview={ selectionPreview }>
{ children }
</WiredBaseView>
);
@@ -0,0 +1,17 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../../api';
import { useWired } from '../../../../hooks';
import { WiredExtraBaseView } from './WiredExtraBaseView';
export const WiredExtraExecuteInOrderView: FC<{}> = () =>
{
const { setIntParams = null, setStringParam = null } = useWired();
const save = () =>
{
setIntParams([]);
setStringParam('');
};
return <WiredExtraBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save } cardStyle={ { width: 320 } } />;
};
@@ -0,0 +1,84 @@
import { FC, useEffect, useState } from 'react';
import { LocalizeText, WiredFurniType } from '../../../../api';
import { Slider, Text } from '../../../../common';
import { useWired } from '../../../../hooks';
import { WiredExtraBaseView } from './WiredExtraBaseView';
const MIN_EXECUTIONS = 1;
const MAX_EXECUTIONS = 100;
const DEFAULT_EXECUTIONS = 1;
const MIN_TIME_WINDOW_MS = 1000;
const MAX_TIME_WINDOW_MS = 10000;
const DEFAULT_TIME_WINDOW_MS = 1000;
const TIME_WINDOW_STEP_MS = 500;
const normalizeExecutions = (value: number) =>
{
if(isNaN(value)) return DEFAULT_EXECUTIONS;
return Math.max(MIN_EXECUTIONS, Math.min(MAX_EXECUTIONS, Math.round(value)));
};
const normalizeTimeWindow = (value: number) =>
{
if(isNaN(value)) return DEFAULT_TIME_WINDOW_MS;
const clampedValue = Math.max(MIN_TIME_WINDOW_MS, Math.min(MAX_TIME_WINDOW_MS, value));
return Math.round(clampedValue / TIME_WINDOW_STEP_MS) * TIME_WINDOW_STEP_MS;
};
const formatTimeWindow = (value: number) =>
{
const seconds = value / 1000;
return Number.isInteger(seconds) ? seconds.toString() : seconds.toFixed(1);
};
export const WiredExtraExecutionLimitView: FC<{}> = () =>
{
const { trigger = null, setIntParams = null, setStringParam = null } = useWired();
const [ executions, setExecutions ] = useState(DEFAULT_EXECUTIONS);
const [ timeWindowMs, setTimeWindowMs ] = useState(DEFAULT_TIME_WINDOW_MS);
useEffect(() =>
{
if(!trigger) return;
setExecutions(normalizeExecutions((trigger.intData.length > 0) ? trigger.intData[0] : DEFAULT_EXECUTIONS));
setTimeWindowMs(normalizeTimeWindow((trigger.intData.length > 1) ? trigger.intData[1] : DEFAULT_TIME_WINDOW_MS));
}, [ trigger ]);
const save = () =>
{
setIntParams([ normalizeExecutions(executions), normalizeTimeWindow(timeWindowMs) ]);
setStringParam('');
};
return (
<WiredExtraBaseView hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save } cardStyle={ { width: 380 } }>
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-2">
<Text>{ LocalizeText('wiredfurni.params.setexecutions', [ 'amount' ], [ executions.toString() ]) }</Text>
<Slider
min={ MIN_EXECUTIONS }
max={ MAX_EXECUTIONS }
step={ 1 }
value={ executions }
onChange={ value => setExecutions(normalizeExecutions(Array.isArray(value) ? value[0] : Number(value))) } />
<Text small>{ executions }</Text>
</div>
<div className="flex flex-col gap-2">
<Text>{ LocalizeText('wiredfurni.params.settimewindow', [ 'timewindow' ], [ formatTimeWindow(timeWindowMs) ]) }</Text>
<Slider
min={ MIN_TIME_WINDOW_MS }
max={ MAX_TIME_WINDOW_MS }
step={ TIME_WINDOW_STEP_MS }
value={ timeWindowMs }
onChange={ value => setTimeWindowMs(normalizeTimeWindow(Array.isArray(value) ? value[0] : Number(value))) } />
<Text small>{ formatTimeWindow(timeWindowMs) }s</Text>
</div>
</div>
</WiredExtraBaseView>
);
};
@@ -45,7 +45,7 @@ export const WiredExtraMoveCarryUsersView: FC<{}> = () =>
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE }
save={ save }
cardStyle={ { width: 420 } }
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } userSources={ USER_SOURCES } usersTitle="wiredfurni.params.sources.users.title.carry" onChangeUsers={ value => setUserSource(normalizeUserSource(value)) } /> }>
footer={ <WiredSourcesSelector showUsers={ true } userSource={ userSource } userSources={ USER_SOURCES } usersTitle="wiredfurni.params.sources.users.title.carry" allowClickedUserSource={ false } onChangeUsers={ value => setUserSource(normalizeUserSource(value)) } /> }>
<div className="flex flex-col gap-2">
<Text bold>{ LocalizeText('wiredfurni.params.carry_mode') }</Text>
<label className="flex items-center gap-1 cursor-pointer">
@@ -89,6 +89,7 @@ export const WiredExtraMovePhysicsView: FC<{}> = () =>
userSource={ moveThroughUsersSource }
userSources={ USER_SOURCES }
usersTitle="wiredfurni.params.sources.users.title.physics.0"
allowClickedUserSource={ false }
onChangeUsers={ value => setMoveThroughUsersSource(normalizeSource(value, USER_SOURCES)) } /> }
</div>
);