5180 fichiers 38.5 Mo 0 téléchargements 362 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / wired / views / actions / WiredActionSetHighlightView.tsx
WiredActionSetHighlightView.tsx 12.4 Ko Télécharger le fichier
import { FC, useEffect, useMemo, useRef, useState } from 'react';
import { GetConfigurationValue, LocalizeText, localizeWithFallback, WiredFurniType } from '../../../../api';
import { Text } from '../../../../common';
import { useNotification, useWired } from '../../../../hooks';
import { WiredSourcesSelector } from '../WiredSourcesSelector';
import { WiredActionBaseView } from './WiredActionBaseView';
import {
    normalizeWiredActionSetHighlight,
    serializeWiredActionSetHighlight,
    snapWiredHighlightStrength,
    WIRED_HIGHLIGHT_AUDIENCE_EVERYONE,
    WIRED_HIGHLIGHT_AUDIENCE_SOURCE_USERS,
    WIRED_HIGHLIGHT_COLOR_TINT,
    WIRED_HIGHLIGHT_COLORS,
    WIRED_HIGHLIGHT_SELECTED_FURNI_SOURCE,
    WIRED_HIGHLIGHT_TYPES,
    WIRED_HIGHLIGHT_ANIMATION_STEADY,
    wiredHighlightAnimations,
    wiredHighlightDarkenLevels,
    wiredHighlightHasColor,
    wiredHighlightStrengthOptions,
    WiredActionSetHighlightState
} from './WiredActionSetHighlightState';
import { ToggleButton } from '../../../../common/ToggleButton';
import { Radio } from '../../../../common/Radio';
import { Select } from '../../../../common/Select';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';

const TYPE_FALLBACKS = ['Outline', 'Soft glow', 'Darken', 'Colour tint', 'Brighten', 'Neon aura'];
const EASING_FALLBACKS = ['Instant', 'Linear', 'Ease in', 'Ease out', 'Ease in and out'];

const hexColor = (color: number) => `#${(color & 0xFFFFFF).toString(16).padStart(6, '0')}`;

/** Official set furni highlight (62): audience, type, strength, colour, animation and easing, on furni or users. */
export const WiredActionSetHighlightView: FC<{}> = () => {
    const { trigger = null, setFurniIds = null, setIntParams = null, setSourceTypes = null } = useWired();
    const { simpleAlert = null } = useNotification();
    const darkenLevels = useMemo(() => wiredHighlightDarkenLevels(GetConfigurationValue<string>('wired.furni_highlight.darken_levels', '')), []);
    const read = () => normalizeWiredActionSetHighlight(trigger?.intData, trigger?.furniSourceTypes, trigger?.userSourceTypes, darkenLevels);
    const [state, setState] = useState<WiredActionSetHighlightState>(read);
    const everyoneInfoShown = useRef(false);

    useEffect(() => {
        const next = read();

        // Official: a box already showing to everyone does not explain it again.
        if (next.audience === WIRED_HIGHLIGHT_AUDIENCE_EVERYONE) everyoneInfoShown.current = true;
        setState(next);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [trigger]);

    const update = (patch: Partial<WiredActionSetHighlightState>) => setState((current) => ({ ...current, ...patch }));

    const changeAudience = (audience: number) => {
        if (audience === WIRED_HIGHLIGHT_AUDIENCE_EVERYONE && !everyoneInfoShown.current && simpleAlert) {
            everyoneInfoShown.current = true;
            simpleAlert(
                localizeWithFallback('wiredfurni.params.furni_visualization.audience.everyone_info.body', 'Stack this effect with "When a user enters the room" to keep it after re-entering.'),
                null,
                null,
                null,
                localizeWithFallback('wiredfurni.params.furni_visualization.audience.everyone_info.title', 'Keeping this effect visible after re-entering')
            );
        }

        update({ audience });
    };

    const changeType = (highlightType: number) =>
        setState((current) => {
            const animations = wiredHighlightAnimations(highlightType);

            return {
                ...current,
                highlightType,
                strength: snapWiredHighlightStrength(highlightType, current.strength, darkenLevels),
                animation: animations.includes(current.animation) ? current.animation : animations[0],
                // Colour tint has no white.
                color: highlightType === WIRED_HIGHLIGHT_COLOR_TINT && current.color === WIRED_HIGHLIGHT_COLORS[0] ? WIRED_HIGHLIGHT_COLORS[1] : current.color
            };
        });

    const save = () => {
        const wire = serializeWiredActionSetHighlight(state);

        setIntParams(wire.intParams);
        setSourceTypes({ furni: wire.furniSources, users: wire.userSources });
        if (state.targetUsers || state.furniSource !== WIRED_HIGHLIGHT_SELECTED_FURNI_SOURCE) setFurniIds?.([]);
    };

    const strengthOptions = wiredHighlightStrengthOptions(state.highlightType, darkenLevels);
    const strengthLabel = (level: number) =>
        level === 0
            ? localizeWithFallback('wiredfurni.params.set_furni_highlight.off', 'Off')
            : level < 0
              ? localizeWithFallback('wiredfurni.params.set_furni_highlight.on', 'On')
              : LocalizeText('wiredfurni.params.set_furni_highlight.level', ['level'], [String(level)]);
    const palette = state.highlightType === WIRED_HIGHLIGHT_COLOR_TINT ? WIRED_HIGHLIGHT_COLORS.slice(1) : WIRED_HIGHLIGHT_COLORS;
    const hasColor = wiredHighlightHasColor(state.highlightType);
    const showWarning = !state.targetUsers && state.highlightType === WIRED_HIGHLIGHT_COLOR_TINT;

    return (
        <NativeTextTree>
            <WiredActionBaseView
                hasSpecialInput={true}
                requiresFurni={state.targetUsers ? WiredFurniType.STUFF_SELECTION_OPTION_NONE : WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT}
                save={save}
                footerCollapsible={false}
                footer={
                    <div className="flex flex-col gap-2">
                        <Text bold>{localizeWithFallback('wiredfurni.params.sources.merged.title.target', 'Select target:')}</Text>
                        <div className="flex gap-3">
                            <label className="flex items-center gap-1">
                                <Radio checked={!state.targetUsers} name="wiredHighlightTarget" onCheckedChange={() => update({ targetUsers: false })} />
                                <Text>{localizeWithFallback('wiredfurni.params.sources.furni.title', 'Furni')}</Text>
                            </label>
                            <label className="flex items-center gap-1">
                                <Radio checked={state.targetUsers} name="wiredHighlightTarget" onCheckedChange={() => update({ targetUsers: true })} />
                                <Text>{localizeWithFallback('wiredfurni.params.sources.users.title', 'Users')}</Text>
                            </label>
                        </div>
                        {state.targetUsers ? (
                            <WiredSourcesSelector showUsers={true} userSlot={1} userSource={state.targetUserSource} onChangeUsers={(targetUserSource) => update({ targetUserSource })} />
                        ) : (
                            <WiredSourcesSelector showFurni={true} furniSource={state.furniSource} onChangeFurni={(furniSource) => update({ furniSource })} />
                        )}
                        {state.audience === WIRED_HIGHLIGHT_AUDIENCE_SOURCE_USERS && (
                            <WiredSourcesSelector
                                showUsers={true}
                                usersTitle="wiredfurni.params.visualization.visibility_audience"
                                userSource={state.userSource}
                                onChangeUsers={(userSource) => update({ userSource })}
                            />
                        )}
                    </div>
                }
            >
                <div className="flex flex-col gap-1">
                    <Text bold>{localizeWithFallback('wiredfurni.params.furni_visualization.audience', 'Who should see the effect?')}</Text>
                    <Select className="form-select form-select-sm" value={state.audience} onChange={(event) => changeAudience(Number(event.target.value))}>
                        <option value={WIRED_HIGHLIGHT_AUDIENCE_SOURCE_USERS}>{localizeWithFallback('wiredfurni.params.furni_visualization.audience.selected_users', 'Selected users')}</option>
                        <option value={WIRED_HIGHLIGHT_AUDIENCE_EVERYONE}>{localizeWithFallback('wiredfurni.params.furni_visualization.audience.everyone', 'Everyone, also users who enter later')}</option>
                    </Select>
                </div>

                <div className="flex flex-col gap-1">
                    <Text bold>{localizeWithFallback('wiredfurni.params.set_furni_highlight.type', 'Highlight type:')}</Text>
                    <Select aria-label="highlight type" className="form-select form-select-sm" value={state.highlightType} onChange={(event) => changeType(Number(event.target.value))}>
                        {WIRED_HIGHLIGHT_TYPES.map((type) => (
                            <option key={type} value={type}>
                                {localizeWithFallback(`wiredfurni.params.set_furni_highlight.type.${type}`, TYPE_FALLBACKS[type])}
                            </option>
                        ))}
                    </Select>
                    {showWarning && <Text small variant="danger">{localizeWithFallback('wiredfurni.params.set_furni_highlight.normal_furni_warning', 'This highlight type does not work on items outside Builders Club.')}</Text>}
                </div>

                <div className="flex flex-col gap-1">
                    <Text bold>{localizeWithFallback('wiredfurni.params.set_furni_highlight.strength', 'Strength:')}</Text>
                    <Select aria-label="highlight strength" className="form-select form-select-sm" value={state.strength} onChange={(event) => update({ strength: Number(event.target.value) })}>
                        {strengthOptions.map((option) => (
                            <option key={option.value} value={option.value}>
                                {strengthLabel(option.level)}
                            </option>
                        ))}
                    </Select>
                </div>

                <div className={`flex flex-col gap-1 ${hasColor ? '' : 'opacity-50 pointer-events-none'}`}>
                    <Text bold>{localizeWithFallback('wiredfurni.params.set_furni_highlight.color', 'Highlight colour:')}</Text>
                    <div className="flex flex-wrap gap-1">
                        {palette.map((color) => (
                            <ToggleButton
                                key={color}
                                aria-label={hexColor(color)}
                                pressed={state.color === color}
                                className={`h-[14px] w-[14px] border ${state.color === color ? 'border-black' : 'border-[#9a9a9a]'}`}
                                style={{ background: hexColor(color) }}
                                type="button"
                                onClick={() => update({ color })}
                            />
                        ))}
                    </div>
                </div>

                <div className="flex flex-col gap-1">
                    <Text bold>{localizeWithFallback('wiredfurni.params.set_furni_highlight.animation', 'Animation:')}</Text>
                    <Select aria-label="highlight animation" className="form-select form-select-sm" value={state.animation} onChange={(event) => update({ animation: Number(event.target.value) })}>
                        {wiredHighlightAnimations(state.highlightType).map((animation) => (
                            <option key={animation} value={animation}>
                                {localizeWithFallback(`wiredfurni.params.set_furni_highlight.animation.${animation}`, animation === 0 ? 'Steady' : 'Pulse')}
                            </option>
                        ))}
                    </Select>
                </div>

                <div className={`flex flex-col gap-1 ${state.animation === WIRED_HIGHLIGHT_ANIMATION_STEADY ? '' : 'opacity-50 pointer-events-none'}`}>
                    <Text bold>{localizeWithFallback('wiredfurni.params.set_furni_highlight.easing', 'Transition:')}</Text>
                    <Select aria-label="highlight easing" className="form-select form-select-sm" value={state.easing} onChange={(event) => update({ easing: Number(event.target.value) })}>
                        {EASING_FALLBACKS.map((fallback, value) => (
                            <option key={value} value={value}>
                                {localizeWithFallback(`wiredfurni.params.set_furni_highlight.easing.${value}`, fallback)}
                            </option>
                        ))}
                    </Select>
                </div>
            </WiredActionBaseView>
        </NativeTextTree>
    );
};
15Sujets
1Dépôts
20Membres
3En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser