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
@@ -14,11 +14,13 @@ export interface WiredActionBaseViewProps
cardStyle?: CSSProperties;
hideDelay?: boolean;
footer?: ReactNode;
footerCollapsible?: boolean;
selectionPreview?: ReactNode;
}
export const WiredActionBaseView: FC<PropsWithChildren<WiredActionBaseViewProps>> = props =>
{
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, hasSpecialInput = false, children = null, cardStyle = undefined, hideDelay = false, footer = null } = props;
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, hasSpecialInput = false, children = null, cardStyle = undefined, hideDelay = false, footer = null, footerCollapsible = true, selectionPreview = null } = props;
const { trigger = null, actionDelay = 0, setActionDelay = null } = useWired();
useEffect(() =>
@@ -27,10 +29,10 @@ export const WiredActionBaseView: FC<PropsWithChildren<WiredActionBaseViewProps>
}, [ trigger, setActionDelay ]);
return (
<WiredBaseView hasSpecialInput={ hasSpecialInput } requiresFurni={ requiresFurni } save={ save } validate={ validate } wiredType="action" cardStyle={ cardStyle } footer={ footer }>
<WiredBaseView hasSpecialInput={ hasSpecialInput } requiresFurni={ requiresFurni } save={ save } validate={ validate } wiredType="action" cardStyle={ cardStyle } footer={ footer } footerCollapsible={ footerCollapsible } selectionPreview={ selectionPreview }>
{ children }
{ !hideDelay && !!children && <hr className="m-0 bg-dark" /> }
{ !hideDelay && <div className="flex flex-col">
{ !hideDelay && !!children && <div className="nitro-wired__divider" /> }
{ !hideDelay && <div className="flex flex-col nitro-wired__section nitro-wired__section--delay">
<Text bold>{ LocalizeText('wiredfurni.params.delay', [ 'seconds' ], [ GetWiredTimeLocale(actionDelay) ]) }</Text>
<Slider
max={ 20 }
@@ -4,7 +4,7 @@ import { Text } from '../../../../common';
import { useWired } from '../../../../hooks';
import { NitroInput } from '../../../../layout';
import { WiredActionBaseView } from './WiredActionBaseView';
import { WiredSourceOption, WiredSourcesSelector } from '../WiredSourcesSelector';
import { CLICKED_USER_SOURCE_VALUE, WiredSourceOption, WiredSourcesSelector } from '../WiredSourcesSelector';
import { WiredHandItemField } from '../WiredHandItemField';
const USER_SOURCE_OPTIONS: WiredSourceOption[] = [
@@ -20,7 +20,7 @@ const BOT_SOURCE_OPTIONS: WiredSourceOption[] = [
{ value: 201, label: 'wiredfurni.params.sources.users.201' }
];
const normalizeUserSource = (value: number) => (USER_SOURCE_OPTIONS.some(option => (option.value === value)) ? value : 0);
const normalizeUserSource = (value: number) => ((value === CLICKED_USER_SOURCE_VALUE) || USER_SOURCE_OPTIONS.some(option => (option.value === value)) ? value : 0);
const normalizeBotSource = (value: number, hasBotName = false) => (BOT_SOURCE_OPTIONS.some(option => (option.value === value)) ? value : (hasBotName ? 100 : 0));
export const WiredActionBotGiveHandItemView: FC<{}> = props =>
@@ -56,7 +56,7 @@ export const WiredActionBotGiveHandItemView: FC<{}> = props =>
<div className="flex flex-col gap-2">
<WiredSourcesSelector showUsers={ true } userSource={ userSource } userSources={ USER_SOURCE_OPTIONS } onChangeUsers={ setUserSource } />
<hr className="m-0 bg-dark" />
<WiredSourcesSelector showUsers={ true } userSource={ botSource } userSources={ BOT_SOURCE_OPTIONS } usersTitle="wiredfurni.params.sources.users.title.bots" onChangeUsers={ value => setBotSource(normalizeBotSource(value, (botName.length > 0))) } />
<WiredSourcesSelector showUsers={ true } userSource={ botSource } userSources={ BOT_SOURCE_OPTIONS } usersTitle="wiredfurni.params.sources.users.title.bots" allowClickedUserSource={ false } onChangeUsers={ value => setBotSource(normalizeBotSource(value, (botName.length > 0))) } />
</div>
}>
<div className="form-check">
@@ -1,8 +1,8 @@
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { LocalizeText, WiredFurniType, WiredSelectionVisualizer } from '../../../../api';
import { Button, Text } from '../../../../common';
import { WiredFurniType, WiredSelectionVisualizer } from '../../../../api';
import { useWired } from '../../../../hooks';
import { WiredSourcesSelector, FURNI_SOURCES, WiredSourceOption } from '../WiredSourcesSelector';
import { WiredFurniSelectionSourceRow } from '../WiredFurniSelectionSourceRow';
import { FURNI_SOURCES, sortWiredSourceOptions, WiredSourceOption } from '../WiredSourcesSelector';
import { WiredActionBaseView } from './WiredActionBaseView';
const SOURCE_TRIGGER = 0;
@@ -10,12 +10,12 @@ const SOURCE_SELECTED = 100;
const SOURCE_SECONDARY_SELECTED = 101;
const FURNI_DELIMITER = ';';
const TARGET_FURNI_SOURCES: WiredSourceOption[] = [
const TARGET_FURNI_SOURCES: WiredSourceOption[] = sortWiredSourceOptions([
{ value: 0, label: 'wiredfurni.params.sources.furni.0' },
{ value: SOURCE_SECONDARY_SELECTED, label: 'wiredfurni.params.sources.furni.101' },
{ value: 200, label: 'wiredfurni.params.sources.furni.200' },
{ value: 201, label: 'wiredfurni.params.sources.furni.201' }
];
], 'furni');
type SelectionMode = 'move' | 'target';
@@ -185,49 +185,32 @@ export const WiredActionFurniToFurniView: FC<{}> = () =>
hasSpecialInput={ true }
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID }
save={ save }
footer={
selectionPreview={
<div className="flex flex-col gap-2">
<WiredSourcesSelector
showFurni={ true }
furniTitle="wiredfurni.params.sources.furni.title.mv.0"
furniSources={ FURNI_SOURCES }
furniSource={ moveSource }
onChangeFurni={ setMoveSource } />
<hr className="m-0 bg-dark" />
<WiredSourcesSelector
showFurni={ true }
furniTitle="wiredfurni.params.sources.furni.title.mv.1"
furniSources={ TARGET_FURNI_SOURCES }
furniSource={ targetSource }
onChangeFurni={ value => setTargetSource((value === SOURCE_SELECTED) ? SOURCE_SECONDARY_SELECTED : value) } />
<WiredFurniSelectionSourceRow
title="wiredfurni.params.sources.furni.title.mv.0"
options={ FURNI_SOURCES }
value={ moveSource }
selectionKind="primary"
selectionActive={ selectionMode === 'move' }
selectionCount={ moveFurniIds.length }
selectionLimit={ selectionLimit }
selectionEnabledValues={ [ SOURCE_SELECTED ] }
onChange={ setMoveSource }
onSelectionActivate={ () => switchSelection('move') } />
<WiredFurniSelectionSourceRow
title="wiredfurni.params.sources.furni.title.mv.1"
options={ TARGET_FURNI_SOURCES }
value={ targetSource }
selectionKind="secondary"
selectionActive={ selectionMode === 'target' }
selectionCount={ targetFurniIds.length }
selectionLimit={ selectionLimit }
selectionEnabledValues={ [ SOURCE_SECONDARY_SELECTED ] }
onChange={ value => setTargetSource((value === SOURCE_SELECTED) ? SOURCE_SECONDARY_SELECTED : value) }
onSelectionActivate={ () => switchSelection('target') } />
</div>
}>
<div className="flex flex-col gap-3">
<div className="flex flex-col gap-1">
<Text bold>{ LocalizeText('wiredfurni.params.sources.furni.title.mv.0') }</Text>
<div className="flex items-center gap-2">
<Button
variant={ (selectionMode === 'move') ? 'primary' : 'secondary' }
disabled={ moveSource !== SOURCE_SELECTED }
onClick={ () => switchSelection('move') }>
{ LocalizeText('wiredfurni.params.sources.furni.100') }
</Button>
<Text small>{ selectionLimit ? `${ moveFurniIds.length }/${ selectionLimit }` : moveFurniIds.length }</Text>
</div>
</div>
<div className="flex flex-col gap-1">
<Text bold>{ LocalizeText('wiredfurni.params.sources.furni.title.mv.1') }</Text>
<div className="flex items-center gap-2">
<Button
variant={ (selectionMode === 'target') ? 'primary' : 'secondary' }
disabled={ targetSource !== SOURCE_SECONDARY_SELECTED }
onClick={ () => switchSelection('target') }>
{ LocalizeText('wiredfurni.params.sources.furni.101') }
</Button>
<Text small>{ selectionLimit ? `${ targetFurniIds.length }/${ selectionLimit }` : targetFurniIds.length }</Text>
</div>
</div>
</div>
</WiredActionBaseView>
}
/>
);
};
@@ -54,6 +54,8 @@ import { WiredExtraFilterFurniView } from '../extras/WiredExtraFilterFurniView';
import { WiredExtraFilterUserView } from '../extras/WiredExtraFilterUserView';
import { WiredExtraAnimationTimeView } from '../extras/WiredExtraAnimationTimeView';
import { WiredExtraMoveCarryUsersView } from '../extras/WiredExtraMoveCarryUsersView';
import { WiredExtraExecuteInOrderView } from '../extras/WiredExtraExecuteInOrderView';
import { WiredExtraExecutionLimitView } from '../extras/WiredExtraExecutionLimitView';
import { WiredExtraMoveNoAnimationView } from '../extras/WiredExtraMoveNoAnimationView';
import { WiredExtraMovePhysicsView } from '../extras/WiredExtraMovePhysicsView';
import { WiredExtraRandomView } from '../extras/WiredExtraRandomView';
@@ -183,6 +185,10 @@ export const WiredActionLayoutView = (code: number) =>
return <WiredExtraUnseenView />;
case WiredActionLayoutCode.RANDOM_EXTRA:
return <WiredExtraRandomView />;
case WiredActionLayoutCode.EXEC_IN_ORDER_EXTRA:
return <WiredExtraExecuteInOrderView />;
case WiredActionLayoutCode.EXECUTION_LIMIT_EXTRA:
return <WiredExtraExecutionLimitView />;
case WiredActionLayoutCode.SEND_SIGNAL:
return <WiredActionSendSignalView />;
}
@@ -1,8 +1,9 @@
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { LocalizeText, WiredFurniType, WiredSelectionVisualizer } from '../../../../api';
import { Button, Text } from '../../../../common';
import { Text } from '../../../../common';
import { useWired } from '../../../../hooks';
import { WiredSourcesSelector } from '../WiredSourcesSelector';
import { WiredFurniSelectionSourceRow } from '../WiredFurniSelectionSourceRow';
import { FURNI_SOURCES, USER_SOURCES } from '../WiredSourcesSelector';
import { WiredActionBaseView } from './WiredActionBaseView';
const ANTENNA_INTERACTION_TYPES = [ 'antenna' ];
@@ -184,7 +185,6 @@ export const WiredActionSendSignalView: FC<{}> = () =>
}, []);
const selectionLimit = trigger?.maximumItemSelectionCount ?? 0;
const forwardSelectionEnabled = (furniSource === SOURCE_SELECTED);
return (
<WiredActionBaseView
@@ -192,40 +192,48 @@ export const WiredActionSendSignalView: FC<{}> = () =>
requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID }
cardStyle={ { width: '400px' } }
save={ save }
footer={ (
<WiredSourcesSelector
showFurni={ true }
showUsers={ true }
furniSource={ furniSource }
userSource={ userSource }
onChangeFurni={ onChangeFurniSource }
onChangeUsers={ setUserSource } />
) }>
selectionPreview={
<div className="flex flex-col gap-2">
<WiredFurniSelectionSourceRow
title="Antenne:"
titleIsLiteral={ true }
options={ [ { value: SOURCE_SELECTED, label: 'wiredfurni.params.sources.furni.100' } ] }
value={ SOURCE_SELECTED }
selectionKind="primary"
selectionActive={ selectionMode === 'antenna' }
selectionCount={ antennaIds.length }
selectionLimit={ selectionLimit }
selectionEnabledValues={ [ SOURCE_SELECTED ] }
onChange={ () => {} }
onSelectionActivate={ () => switchSelection('antenna') } />
<WiredFurniSelectionSourceRow
title="Furni da mandare avanti:"
titleIsLiteral={ true }
options={ FURNI_SOURCES }
value={ furniSource }
selectionKind="secondary"
selectionActive={ selectionMode === 'furni' }
selectionCount={ forwardFurniIds.length }
selectionLimit={ selectionLimit }
selectionEnabledValues={ [ SOURCE_SELECTED ] }
onChange={ onChangeFurniSource }
onSelectionActivate={ () => switchSelection('furni') } />
<WiredFurniSelectionSourceRow
title="Utenti da mandare avanti:"
titleIsLiteral={ true }
options={ USER_SOURCES }
value={ userSource }
selectionKind="secondary"
selectionActive={ false }
selectionCount={ 0 }
selectionLimit={ 0 }
selectionEnabledValues={ [] }
showSelectionToggle={ false }
onChange={ setUserSource } />
</div>
}
>
<div className="flex flex-col gap-3">
<div className="flex flex-col gap-1">
<Text bold>Antenne selezionate</Text>
<div className="flex items-center gap-2">
<Button
variant={ (selectionMode === 'antenna') ? 'primary' : 'secondary' }
onClick={ () => switchSelection('antenna') }>
Antenne
</Button>
<Text small>{ selectionLimit ? `${ antennaIds.length }/${ selectionLimit }` : antennaIds.length }</Text>
</div>
</div>
<div className="flex flex-col gap-1">
<Text bold>Furni selezionati</Text>
<div className="flex items-center gap-2">
<Button
variant={ (selectionMode === 'furni') ? 'primary' : 'secondary' }
disabled={ !forwardSelectionEnabled }
onClick={ () => switchSelection('furni') }>
Furni
</Button>
<Text small>{ selectionLimit ? `${ forwardFurniIds.length }/${ selectionLimit }` : forwardFurniIds.length }</Text>
</div>
</div>
<Text bold>{ LocalizeText('wiredfurni.params.signal.options') }</Text>
<div className="form-check">
<input