diff --git a/src/components/wired/views/extras/WiredExtraVariableTextConnectorView.tsx b/src/components/wired/views/extras/WiredExtraVariableTextConnectorView.tsx
index 6468bd4..f84035a 100644
--- a/src/components/wired/views/extras/WiredExtraVariableTextConnectorView.tsx
+++ b/src/components/wired/views/extras/WiredExtraVariableTextConnectorView.tsx
@@ -5,6 +5,26 @@ import { useWired } from '../../../../hooks';
import { WiredExtraBaseView } from './WiredExtraBaseView';
const DEFAULT_CONNECTOR_PLACEHOLDER = '0=text 1\n1=text 2\n2 = text 3';
+const MAX_CONNECTOR_LINES = 30;
+const MAX_CONNECTOR_CHARACTERS = 1000;
+
+const truncateMappingsText = (value: string) =>
+{
+ const normalizedValue = (value ?? '').replace(/\r/g, '');
+ const lines = normalizedValue.split('\n');
+ const limitedByLines = lines.slice(0, MAX_CONNECTOR_LINES).join('\n');
+
+ return (limitedByLines.length > MAX_CONNECTOR_CHARACTERS)
+ ? limitedByLines.slice(0, MAX_CONNECTOR_CHARACTERS)
+ : limitedByLines;
+};
+
+const getLineCount = (value: string) =>
+{
+ if(!value.length) return 0;
+
+ return value.split('\n').length;
+};
export const WiredExtraVariableTextConnectorView: FC<{}> = () =>
{
@@ -15,7 +35,7 @@ export const WiredExtraVariableTextConnectorView: FC<{}> = () =>
{
if(!trigger) return;
- setMappingsText(trigger.stringData || '');
+ setMappingsText(truncateMappingsText(trigger.stringData || ''));
}, [ trigger ]);
const save = () =>
@@ -24,6 +44,8 @@ export const WiredExtraVariableTextConnectorView: FC<{}> = () =>
setStringParam(mappingsText ?? '');
};
+ const handleTextChange = (value: string) => setMappingsText(truncateMappingsText(value));
+
const placeholderText = (() =>
{
const localizedText = LocalizeText('wiredfurni.params.variables.connect_text.caption');
@@ -34,15 +56,20 @@ export const WiredExtraVariableTextConnectorView: FC<{}> = () =>
return localizedText;
})();
+ const lineCount = getLineCount(mappingsText);
+ const characterCount = mappingsText.length;
+
return (
{ LocalizeText('wiredfurni.params.variables.connect_text.title') }
);
diff --git a/src/components/wired/views/selectors/WiredNeighborhoodSelectorView.tsx b/src/components/wired/views/selectors/WiredNeighborhoodSelectorView.tsx
new file mode 100644
index 0000000..c042da7
--- /dev/null
+++ b/src/components/wired/views/selectors/WiredNeighborhoodSelectorView.tsx
@@ -0,0 +1,456 @@
+import { GetRoomEngine } from '@nitrots/nitro-renderer';
+import { CSSProperties, FC, MouseEvent as ReactMouseEvent, useCallback, useEffect, useMemo, useState } from 'react';
+import { FaMinus, FaPlus, FaTimes } from 'react-icons/fa';
+import { MdGridOn } from 'react-icons/md';
+import { LocalizeText, WiredFurniType } from '../../../../api';
+import sourceFurniIcon from '../../../../assets/images/wired/source_furni.png';
+import sourceUserIcon from '../../../../assets/images/wired/source_user.png';
+import { Button, Text } from '../../../../common';
+import { useWired } from '../../../../hooks';
+import { WiredFurniSelectionSourceRow } from '../WiredFurniSelectionSourceRow';
+import { sortWiredSourceOptions, useAvailableUserSources } from '../WiredSourcesSelector';
+import { WiredSelectorBaseView } from './WiredSelectorBaseView';
+
+const SOURCE_USER_TRIGGER = 0;
+const SOURCE_USER_SIGNAL = 1;
+const SOURCE_USER_CLICKED = 2;
+const SOURCE_FURNI_TRIGGER = 3;
+const SOURCE_FURNI_PICKED = 4;
+const SOURCE_FURNI_SIGNAL = 5;
+
+const USER_SOURCES = sortWiredSourceOptions([
+ { value: SOURCE_USER_TRIGGER, label: 'wiredfurni.params.sources.users.0' },
+ { value: SOURCE_USER_SIGNAL, label: 'wiredfurni.params.sources.users.201' },
+ { value: SOURCE_USER_CLICKED, label: 'wiredfurni.params.sources.users.11' }
+], 'users');
+
+const FURNI_SOURCES = sortWiredSourceOptions([
+ { value: SOURCE_FURNI_TRIGGER, label: 'wiredfurni.params.sources.furni.0' },
+ { value: SOURCE_FURNI_PICKED, label: 'wiredfurni.params.sources.furni.100' },
+ { value: SOURCE_FURNI_SIGNAL, label: 'wiredfurni.params.sources.furni.201' }
+], 'furni');
+
+const SOURCE_GROUP_BUTTONS = [
+ { key: 'user', icon: sourceUserIcon, isUserGroup: true },
+ { key: 'furni', icon: sourceFurniIcon, isUserGroup: false }
+] as const;
+
+const TILE_W = 22;
+const TILE_H = 11;
+const GRID_RANGE = 4;
+const CX = GRID_RANGE * TILE_W + TILE_W / 2;
+const CY = GRID_RANGE * TILE_H + TILE_H / 2;
+const GRID_PX_W = (GRID_RANGE * 2 + 1) * TILE_W;
+const GRID_PX_H = (GRID_RANGE * 2 + 1) * TILE_H;
+
+type Tile = { x: number; y: number };
+
+const tileIncluded = (tiles: Tile[], x: number, y: number) => tiles.some(tile => (tile.x === x && tile.y === y));
+const tileLeft = (rx: number, ry: number) => CX + (rx - ry) * (TILE_W / 2) - TILE_W / 2;
+const tileTop = (rx: number, ry: number) => CY + (rx + ry) * (TILE_H / 2) - TILE_H / 2;
+
+interface NeighborhoodGridProps
+{
+ selectedTiles: Tile[];
+ targetTile: Tile;
+ invert: boolean;
+ onSetTile: (x: number, y: number, selected: boolean) => void;
+ onMoveTarget: (x: number, y: number) => void;
+ targetPlacementMode: boolean;
+}
+
+const NeighborhoodGrid: FC
= props =>
+{
+ const { selectedTiles = [], targetTile, invert = false, onSetTile = null, onMoveTarget = null, targetPlacementMode = false } = props;
+ const [ dragMode, setDragMode ] = useState<'add' | 'remove' | 'target' | null>(null);
+ const tiles: JSX.Element[] = [];
+
+ useEffect(() =>
+ {
+ const stopDragging = () => setDragMode(null);
+
+ window.addEventListener('mouseup', stopDragging);
+
+ return () => window.removeEventListener('mouseup', stopDragging);
+ }, []);
+
+ const beginTileDrag = (event: ReactMouseEvent, rx: number, ry: number, isSelected: boolean) =>
+ {
+ event.preventDefault();
+
+ if(targetPlacementMode)
+ {
+ setDragMode('target');
+ onMoveTarget && onMoveTarget(rx, ry);
+ return;
+ }
+
+ const nextDragMode = isSelected ? 'remove' : 'add';
+
+ setDragMode(nextDragMode);
+ onSetTile && onSetTile(rx, ry, nextDragMode === 'add');
+ };
+
+ const continueTileDrag = (event: ReactMouseEvent, rx: number, ry: number) =>
+ {
+ if(!(event.buttons & 1) || !dragMode) return;
+
+ if(dragMode === 'target')
+ {
+ onMoveTarget && onMoveTarget(rx, ry);
+ return;
+ }
+
+ onSetTile && onSetTile(rx, ry, dragMode === 'add');
+ };
+
+ for(let ry = -GRID_RANGE; ry <= GRID_RANGE; ry++)
+ {
+ for(let rx = -GRID_RANGE; rx <= GRID_RANGE; rx++)
+ {
+ const isTarget = (rx === targetTile.x && ry === targetTile.y);
+ const isSelected = tileIncluded(selectedTiles, rx, ry);
+ const isActive = invert ? !isSelected : isSelected;
+ const left = tileLeft(rx, ry);
+ const top = tileTop(rx, ry);
+ const zIndex = rx + ry + GRID_RANGE * 2 + 10;
+
+ const diamondStyle: CSSProperties = {
+ position: 'absolute',
+ width: TILE_W,
+ height: TILE_H,
+ left,
+ top,
+ clipPath: 'polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)',
+ backgroundColor: isActive ? '#3399ff' : '#2a3042',
+ cursor: 'pointer',
+ zIndex,
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ color: isTarget ? '#ffffff' : 'transparent',
+ fontSize: 10
+ };
+
+ const borderStyle: CSSProperties = {
+ position: 'absolute',
+ width: TILE_W + (isTarget ? 6 : 2),
+ height: TILE_H + (isTarget ? 6 : 2),
+ left: left - (isTarget ? 3 : 1),
+ top: top - (isTarget ? 3 : 1),
+ clipPath: 'polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)',
+ backgroundColor: isTarget ? '#ffffff' : (isActive ? '#1166cc' : '#1a2032'),
+ zIndex: zIndex - 1,
+ pointerEvents: 'none'
+ };
+
+ const outlineStyle: CSSProperties = {
+ position: 'absolute',
+ width: TILE_W + 4,
+ height: TILE_H + 4,
+ left: left - 2,
+ top: top - 2,
+ zIndex: zIndex + 1,
+ pointerEvents: 'none',
+ overflow: 'visible'
+ };
+
+ tiles.push(
+ ,
+ isTarget && (
+
+ ),
+ beginTileDrag(event, rx, ry, isSelected) }
+ onMouseEnter={ event => continueTileDrag(event, rx, ry) } />
+ );
+ }
+ }
+
+ return (
+
event.preventDefault() }>
+ { tiles }
+
+ );
+};
+
+export const WiredNeighborhoodSelectorView: FC<{}> = () =>
+{
+ const [ selectedTiles, setSelectedTiles ] = useState
([]);
+ const [ filterExisting, setFilterExisting ] = useState(false);
+ const [ invert, setInvert ] = useState(false);
+ const [ sourceType, setSourceType ] = useState(SOURCE_USER_TRIGGER);
+ const [ targetTile, setTargetTile ] = useState({ x: 0, y: 0 });
+ const [ targetPlacementMode, setTargetPlacementMode ] = useState(false);
+ const [ curX, setCurX ] = useState(0);
+ const [ curY, setCurY ] = useState(0);
+
+ const { trigger = null, furniIds = [], setIntParams } = useWired();
+ const availableUserSources = useAvailableUserSources(trigger, USER_SOURCES);
+
+ useEffect(() =>
+ {
+ GetRoomEngine().areaSelectionManager.clearHighlight();
+ GetRoomEngine().areaSelectionManager.deactivate();
+ }, []);
+
+ useEffect(() =>
+ {
+ if(!trigger) return;
+
+ const params = trigger.intData;
+
+ if(params.length >= 1) setSourceType(params[0]);
+ if(params.length >= 2) setFilterExisting(params[1] === 1);
+ if(params.length >= 3) setInvert(params[2] === 1);
+ if(params.length >= 5) setTargetTile({ x: params[3], y: params[4] });
+ else setTargetTile({ x: 0, y: 0 });
+
+ if(params.length < 6)
+ {
+ setSelectedTiles([]);
+ return;
+ }
+
+ const tileCount = params[5];
+ const nextTiles: Tile[] = [];
+
+ for(let index = 0; index < tileCount; index++)
+ {
+ const tileIndex = 6 + index * 2;
+
+ if((tileIndex + 1) >= params.length) break;
+
+ nextTiles.push({ x: params[tileIndex], y: params[tileIndex + 1] });
+ }
+
+ setSelectedTiles(nextTiles);
+ }, [ trigger ]);
+
+ useEffect(() =>
+ {
+ if(sourceType !== SOURCE_USER_CLICKED) return;
+ if(availableUserSources.some(option => option.value === SOURCE_USER_CLICKED)) return;
+
+ setSourceType(SOURCE_USER_TRIGGER);
+ }, [ availableUserSources, sourceType ]);
+
+ const save = useCallback(() =>
+ {
+ setIntParams([
+ sourceType,
+ filterExisting ? 1 : 0,
+ invert ? 1 : 0,
+ targetTile.x,
+ targetTile.y,
+ selectedTiles.length,
+ ...selectedTiles.flatMap(tile => [ tile.x, tile.y ])
+ ]);
+ }, [ filterExisting, invert, selectedTiles, setIntParams, sourceType, targetTile.x, targetTile.y ]);
+
+ const setTileSelection = useCallback((x: number, y: number, selected: boolean) =>
+ {
+ setSelectedTiles(previous =>
+ {
+ const alreadySelected = tileIncluded(previous, x, y);
+
+ if(selected)
+ {
+ if(alreadySelected) return previous;
+
+ return [ ...previous, { x, y } ];
+ }
+
+ if(!alreadySelected) return previous;
+
+ return previous.filter(tile => !(tile.x === x && tile.y === y));
+ });
+ }, []);
+
+ const activeSources = useMemo(() => ((sourceType <= SOURCE_USER_CLICKED) ? availableUserSources : FURNI_SOURCES), [ availableUserSources, sourceType ]);
+ const isUserGroup = sourceType <= SOURCE_USER_CLICKED;
+ const currentIndex = Math.max(0, activeSources.findIndex(option => (option.value === sourceType)));
+ const currentSourceType = activeSources[currentIndex]?.value ?? sourceType;
+
+ useEffect(() =>
+ {
+ if(currentSourceType === sourceType) return;
+
+ setSourceType(currentSourceType);
+ }, [ currentSourceType, sourceType ]);
+
+ const changeGroup = useCallback((nextIsUserGroup: boolean) =>
+ {
+ if(nextIsUserGroup === isUserGroup) return;
+
+ const nextOptions = nextIsUserGroup ? availableUserSources : FURNI_SOURCES;
+ const nextIndex = Math.min(currentIndex, Math.max(0, nextOptions.length - 1));
+ const nextOption = nextOptions[nextIndex] ?? nextOptions[0];
+
+ if(nextOption) setSourceType(nextOption.value);
+ }, [ availableUserSources, currentIndex, isUserGroup ]);
+
+ const addTile = useCallback(() =>
+ {
+ setSelectedTiles(previous =>
+ {
+ if(tileIncluded(previous, curX, curY)) return previous;
+
+ return [ ...previous, { x: curX, y: curY } ];
+ });
+ }, [ curX, curY ]);
+
+ const removeTile = useCallback(() =>
+ {
+ setSelectedTiles(previous => previous.filter(tile => !(tile.x === curX && tile.y === curY)));
+ }, [ curX, curY ]);
+
+ const loadDefaultPattern = useCallback(() =>
+ {
+ const nextTiles: Tile[] = [];
+
+ for(let y = -2; y <= 2; y++)
+ {
+ for(let x = -2; x <= 2; x++)
+ {
+ if(x === 0 && y === 0) continue;
+
+ nextTiles.push({ x, y });
+ }
+ }
+
+ setSelectedTiles(nextTiles);
+ }, []);
+
+ const requiresFurni = (sourceType === SOURCE_FURNI_PICKED)
+ ? WiredFurniType.STUFF_SELECTION_OPTION_BY_ID
+ : WiredFurniType.STUFF_SELECTION_OPTION_NONE;
+
+ return (
+
+
+
{ LocalizeText('wiredfurni.params.neighborhood_selection') }
+
+
+
+
+
+
+
+
+
+
+ setTargetTile({ x, y }) }
+ targetPlacementMode={ targetPlacementMode } />
+
+
+
+ X:
+ setCurX(parseInt(event.target.value) || 0) } />
+ Y:
+ setCurY(parseInt(event.target.value) || 0) } />
+
+
+
+
+
{ LocalizeText('wiredfurni.params.selector_options_selector') }
+
+
+
+
+
+
+
+
+ { SOURCE_GROUP_BUTTONS.map(button => (
+
+ )) }
+
+ }
+ onChange={ value => setSourceType(value) } />
+
+ { sourceType === SOURCE_FURNI_PICKED &&
+
+ { LocalizeText('wiredfurni.pickfurnis.caption', [ 'count', 'limit' ], [ furniIds.length.toString(), (trigger?.maximumItemSelectionCount ?? 20).toString() ]) }
+ }
+
+
+ );
+};
diff --git a/src/components/wired/views/selectors/WiredSelectorFurniNeighborhoodView.tsx b/src/components/wired/views/selectors/WiredSelectorFurniNeighborhoodView.tsx
index 60829a7..1b8edbc 100644
--- a/src/components/wired/views/selectors/WiredSelectorFurniNeighborhoodView.tsx
+++ b/src/components/wired/views/selectors/WiredSelectorFurniNeighborhoodView.tsx
@@ -1,453 +1,4 @@
-import { GetRoomEngine } from '@nitrots/nitro-renderer';
-import { CSSProperties, FC, MouseEvent as ReactMouseEvent, useCallback, useEffect, useState } from 'react';
-import { FaMinus, FaPlus, FaTimes } from 'react-icons/fa';
-import { MdGridOn } from 'react-icons/md';
-import { LocalizeText, WiredFurniType } from '../../../../api';
-import { Button, Text } from '../../../../common';
-import { useWired } from '../../../../hooks';
-import { sortWiredSourceOptions } from '../WiredSourcesSelector';
-import { WiredSelectorBaseView } from './WiredSelectorBaseView';
+import { FC } from 'react';
+import { WiredNeighborhoodSelectorView } from './WiredNeighborhoodSelectorView';
-const SOURCE_USER_TRIGGER = 0;
-const SOURCE_USER_SIGNAL = 1;
-const SOURCE_USER_CLICKED = 2;
-const SOURCE_FURNI_TRIGGER = 3;
-const SOURCE_FURNI_PICKED = 4;
-const SOURCE_FURNI_SIGNAL = 5;
-
-const USER_SOURCES = sortWiredSourceOptions([
- { value: SOURCE_USER_TRIGGER, label: 'wiredfurni.params.sources.users.0' },
- { value: SOURCE_USER_SIGNAL, label: 'wiredfurni.params.sources.users.201' },
- { value: SOURCE_USER_CLICKED, label: 'wiredfurni.params.sources.users.11' },
-], 'users');
-
-const FURNI_SOURCES = sortWiredSourceOptions([
- { value: SOURCE_FURNI_TRIGGER, label: 'wiredfurni.params.sources.furni.0' },
- { value: SOURCE_FURNI_PICKED, label: 'wiredfurni.params.sources.furni.100' },
- { value: SOURCE_FURNI_SIGNAL, label: 'wiredfurni.params.sources.furni.201' },
-], 'furni');
-
-const TILE_W = 22;
-const TILE_H = 11;
-const GRID_RANGE = 4; // -4 … +4
-const CX = GRID_RANGE * TILE_W + TILE_W / 2;
-const CY = GRID_RANGE * TILE_H + TILE_H / 2;
-const GRID_PX_W = (GRID_RANGE * 2 + 1) * TILE_W;
-const GRID_PX_H = (GRID_RANGE * 2 + 1) * TILE_H;
-
-type Tile = { x: number; y: number };
-
-const tileIncluded = (tiles: Tile[], x: number, y: number) =>
- tiles.some(t => t.x === x && t.y === y);
-
-const tileLeft = (rx: number, ry: number) =>
- CX + (rx - ry) * (TILE_W / 2) - TILE_W / 2;
-
-const tileTop = (rx: number, ry: number) =>
- CY + (rx + ry) * (TILE_H / 2) - TILE_H / 2;
-
-interface GridProps {
- selectedTiles: Tile[];
- targetTile: Tile;
- invert: boolean;
- onSetTile: (x: number, y: number, selected: boolean) => void;
- onMoveTarget: (x: number, y: number) => void;
- targetPlacementMode: boolean;
-}
-
-const NeighborhoodGrid: FC = ({ selectedTiles, targetTile, invert, onSetTile, onMoveTarget, targetPlacementMode }) =>
-{
- const [ dragMode, setDragMode ] = useState<'add' | 'remove' | 'target' | null>(null);
- const tiles: JSX.Element[] = [];
-
- useEffect(() =>
- {
- const stopDragging = () => setDragMode(null);
-
- window.addEventListener('mouseup', stopDragging);
-
- return () => window.removeEventListener('mouseup', stopDragging);
- }, []);
-
- const beginTileDrag = (event: ReactMouseEvent, rx: number, ry: number, isTarget: boolean, isSelected: boolean) =>
- {
- event.preventDefault();
-
- if(targetPlacementMode)
- {
- setDragMode('target');
- onMoveTarget(rx, ry);
- return;
- }
-
- const nextMode = isSelected ? 'remove' : 'add';
-
- setDragMode(nextMode);
- onSetTile(rx, ry, nextMode === 'add');
- };
-
- const continueTileDrag = (event: ReactMouseEvent, rx: number, ry: number, isTarget: boolean) =>
- {
- if(!(event.buttons & 1) || !dragMode) return;
-
- if(dragMode === 'target')
- {
- onMoveTarget(rx, ry);
- return;
- }
-
- onSetTile(rx, ry, dragMode === 'add');
- };
-
- for (let ry = -GRID_RANGE; ry <= GRID_RANGE; ry++)
- {
- for (let rx = -GRID_RANGE; rx <= GRID_RANGE; rx++)
- {
- const isTarget = rx === targetTile.x && ry === targetTile.y;
- const isSelected = tileIncluded(selectedTiles, rx, ry);
- const isActive = invert ? !isSelected : isSelected;
- const left = tileLeft(rx, ry);
- const top_ = tileTop(rx, ry);
- const zIdx = rx + ry + GRID_RANGE * 2 + 10;
-
- const bgColor = isActive
- ? '#3399ff'
- : '#2a3042';
-
- const borderColor = isTarget
- ? '#ffffff'
- : isActive
- ? '#1166cc'
- : '#1a2032';
-
- const diamond: CSSProperties = {
- position: 'absolute',
- width: TILE_W,
- height: TILE_H,
- left,
- top: top_,
- clipPath: 'polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)',
- backgroundColor: bgColor,
- cursor: 'pointer',
- zIndex: zIdx,
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- color: isTarget ? '#ffffff' : 'transparent',
- fontSize: 10
- };
-
- const border: CSSProperties = {
- position: 'absolute',
- width: TILE_W + (isTarget ? 6 : 2),
- height: TILE_H + (isTarget ? 6 : 2),
- left: left - (isTarget ? 3 : 1),
- top: top_ - (isTarget ? 3 : 1),
- clipPath: 'polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)',
- backgroundColor: borderColor,
- zIndex: zIdx - 1,
- pointerEvents: 'none',
- };
-
- const targetOutline: CSSProperties = {
- position: 'absolute',
- width: TILE_W + 4,
- height: TILE_H + 4,
- left: left - 2,
- top: top_ - 2,
- zIndex: zIdx + 1,
- pointerEvents: 'none',
- overflow: 'visible'
- };
-
- tiles.push(
- ,
- isTarget && (
-
- ),
- beginTileDrag(event, rx, ry, isTarget, isSelected) }
- onMouseEnter={ event => continueTileDrag(event, rx, ry, isTarget) } />,
- );
- }
- }
-
- return (
-
event.preventDefault() }>
- { tiles }
-
- );
-};
-
-export const WiredSelectorFurniNeighborhoodView: FC<{}> = () =>
-{
- const [ selectedTiles, setSelectedTiles ] = useState
([]);
- const [ filterExisting, setFilterExisting ] = useState(false);
- const [ invert, setInvert ] = useState(false);
- const [ sourceType, setSourceType ] = useState(SOURCE_USER_TRIGGER);
- const [ targetTile, setTargetTile ] = useState({ x: 0, y: 0 });
- const [ targetPlacementMode, setTargetPlacementMode ] = useState(false);
- const [ curX, setCurX ] = useState(0);
- const [ curY, setCurY ] = useState(0);
-
- const { trigger = null, furniIds = [], setIntParams } = useWired();
-
- useEffect(() =>
- {
- GetRoomEngine().areaSelectionManager.clearHighlight();
- GetRoomEngine().areaSelectionManager.deactivate();
- }, []);
-
- useEffect(() =>
- {
- if(!trigger) return;
-
- const p = trigger.intData;
- if(p.length >= 1) setSourceType(p[0]);
- if(p.length >= 2) setFilterExisting(p[1] === 1);
- if(p.length >= 3) setInvert(p[2] === 1);
- if(p.length >= 5) setTargetTile({ x: p[3], y: p[4] });
- else setTargetTile({ x: 0, y: 0 });
-
- if(p.length >= 6)
- {
- const n = p[5];
- const tiles: Tile[] = [];
-
- for(let i = 0; i < n; i++)
- {
- const xi = 6 + i * 2;
- if(xi + 1 < p.length) tiles.push({ x: p[xi], y: p[xi + 1] });
- }
-
- setSelectedTiles(tiles);
- }
- else
- {
- setSelectedTiles([]);
- }
- }, [ trigger ]);
-
- const save = useCallback(() =>
- {
- const params: number[] = [
- sourceType,
- filterExisting ? 1 : 0,
- invert ? 1 : 0,
- targetTile.x,
- targetTile.y,
- selectedTiles.length,
- ...selectedTiles.flatMap(t => [ t.x, t.y ]),
- ];
-
- setIntParams(params);
- }, [ sourceType, filterExisting, invert, selectedTiles, targetTile.x, targetTile.y, setIntParams ]);
-
- const setTileSelection = useCallback((x: number, y: number, selected: boolean) =>
- {
- setSelectedTiles(prev =>
- {
- const alreadySelected = tileIncluded(prev, x, y);
-
- if(selected)
- {
- if(alreadySelected) return prev;
-
- return [ ...prev, { x, y } ];
- }
-
- if(!alreadySelected) return prev;
-
- return prev.filter(t => !(t.x === x && t.y === y));
- });
- }, []);
-
- const moveTargetTile = useCallback((x: number, y: number) =>
- {
- setTargetTile({ x, y });
- }, []);
-
- const addTile = useCallback(() =>
- {
- if(!tileIncluded(selectedTiles, curX, curY))
- setSelectedTiles(prev => [ ...prev, { x: curX, y: curY } ]);
- }, [ curX, curY, selectedTiles ]);
-
- const removeTile = useCallback(() =>
- {
- setSelectedTiles(prev => prev.filter(t => !(t.x === curX && t.y === curY)));
- }, [ curX, curY ]);
-
- const clearTiles = useCallback(() => setSelectedTiles([]), []);
-
- const loadDefaultPattern = useCallback(() =>
- {
- const tiles: Tile[] = [];
-
- for(let y = -2; y <= 2; y++)
- {
- for(let x = -2; x <= 2; x++)
- {
- if(x === 0 && y === 0) continue;
- tiles.push({ x, y });
- }
- }
-
- setSelectedTiles(tiles);
- }, []);
-
- const isUserGroup = sourceType <= SOURCE_USER_CLICKED;
- const activeSources = isUserGroup ? USER_SOURCES : FURNI_SOURCES;
- const groupOffset = isUserGroup ? 0 : SOURCE_FURNI_TRIGGER;
- const groupIndex = sourceType - groupOffset;
-
- const prevInGroup = () =>
- setSourceType(groupOffset + (groupIndex - 1 + activeSources.length) % activeSources.length);
-
- const nextInGroup = () =>
- setSourceType(groupOffset + (groupIndex + 1) % activeSources.length);
-
- const switchGroup = (toUser: boolean) =>
- {
- if(toUser === isUserGroup) return;
- const newOffset = toUser ? 0 : SOURCE_FURNI_TRIGGER;
- setSourceType(newOffset + groupIndex);
- };
-
- const requiresFurni = sourceType === SOURCE_FURNI_PICKED
- ? WiredFurniType.STUFF_SELECTION_OPTION_BY_ID
- : WiredFurniType.STUFF_SELECTION_OPTION_NONE;
-
- const pickedCount = furniIds.length;
- const pickedLimit = trigger?.maximumItemSelectionCount ?? 20;
-
- return (
-
-
-
-
{ LocalizeText('wiredfurni.params.neighborhood_selection') }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- X:
- setCurX(parseInt(e.target.value) || 0) } />
- Y:
- setCurY(parseInt(e.target.value) || 0) } />
-
-
-
-
-
{ LocalizeText('wiredfurni.params.selector_options_selector') }
-
-
-
-
-
-
-
-
{ LocalizeText('wiredfurni.params.sources.merged.title.neighborhood') }
-
-
-
-
-
-
-
-
-
- { LocalizeText(activeSources[groupIndex].label) }
-
-
-
-
- { sourceType === SOURCE_FURNI_PICKED &&
-
- { LocalizeText('wiredfurni.pickfurnis.caption', [ 'count', 'limit' ], [ pickedCount.toString(), pickedLimit.toString() ]) }
- }
-
-
-
- );
-};
+export const WiredSelectorFurniNeighborhoodView: FC<{}> = () => ;
diff --git a/src/components/wired/views/selectors/WiredSelectorUsersNeighborhoodView.tsx b/src/components/wired/views/selectors/WiredSelectorUsersNeighborhoodView.tsx
index 7362df7..38a6a0b 100644
--- a/src/components/wired/views/selectors/WiredSelectorUsersNeighborhoodView.tsx
+++ b/src/components/wired/views/selectors/WiredSelectorUsersNeighborhoodView.tsx
@@ -1,454 +1,4 @@
-import { GetRoomEngine } from '@nitrots/nitro-renderer';
-import { CSSProperties, FC, MouseEvent as ReactMouseEvent, useCallback, useEffect, useState } from 'react';
-import { FaMinus, FaPlus, FaTimes } from 'react-icons/fa';
-import { MdGridOn } from 'react-icons/md';
-import { LocalizeText, WiredFurniType } from '../../../../api';
-import { Button, Text } from '../../../../common';
-import { useWired } from '../../../../hooks';
-import { sortWiredSourceOptions } from '../WiredSourcesSelector';
-import { WiredSelectorBaseView } from './WiredSelectorBaseView';
+import { FC } from 'react';
+import { WiredNeighborhoodSelectorView } from './WiredNeighborhoodSelectorView';
-const SOURCE_USER_TRIGGER = 0;
-const SOURCE_USER_SIGNAL = 1;
-const SOURCE_USER_CLICKED = 2;
-const SOURCE_FURNI_TRIGGER = 3;
-const SOURCE_FURNI_PICKED = 4;
-const SOURCE_FURNI_SIGNAL = 5;
-
-const USER_SOURCES = sortWiredSourceOptions([
- { value: SOURCE_USER_TRIGGER, label: 'wiredfurni.params.sources.users.0' },
- { value: SOURCE_USER_SIGNAL, label: 'wiredfurni.params.sources.users.201' },
- { value: SOURCE_USER_CLICKED, label: 'wiredfurni.params.sources.users.11' },
-], 'users');
-
-const FURNI_SOURCES = sortWiredSourceOptions([
- { value: SOURCE_FURNI_TRIGGER, label: 'wiredfurni.params.sources.furni.0' },
- { value: SOURCE_FURNI_PICKED, label: 'wiredfurni.params.sources.furni.100' },
- { value: SOURCE_FURNI_SIGNAL, label: 'wiredfurni.params.sources.furni.201' },
-], 'furni');
-
-const TILE_W = 22;
-const TILE_H = 11;
-const GRID_RANGE = 4;
-const CX = GRID_RANGE * TILE_W + TILE_W / 2;
-const CY = GRID_RANGE * TILE_H + TILE_H / 2;
-const GRID_PX_W = (GRID_RANGE * 2 + 1) * TILE_W;
-const GRID_PX_H = (GRID_RANGE * 2 + 1) * TILE_H;
-
-type Tile = { x: number; y: number };
-
-const tileIncluded = (tiles: Tile[], x: number, y: number) =>
- tiles.some(t => t.x === x && t.y === y);
-
-const tileLeft = (rx: number, ry: number) =>
- CX + (rx - ry) * (TILE_W / 2) - TILE_W / 2;
-
-const tileTop = (rx: number, ry: number) =>
- CY + (rx + ry) * (TILE_H / 2) - TILE_H / 2;
-
-interface GridProps {
- selectedTiles: Tile[];
- targetTile: Tile;
- invert: boolean;
- onSetTile: (x: number, y: number, selected: boolean) => void;
- onMoveTarget: (x: number, y: number) => void;
- targetPlacementMode: boolean;
-}
-
-const NeighborhoodGrid: FC = ({ selectedTiles, targetTile, invert, onSetTile, onMoveTarget, targetPlacementMode }) =>
-{
- const [ dragMode, setDragMode ] = useState<'add' | 'remove' | 'target' | null>(null);
- const tiles: JSX.Element[] = [];
-
- useEffect(() =>
- {
- const stopDragging = () => setDragMode(null);
-
- window.addEventListener('mouseup', stopDragging);
-
- return () => window.removeEventListener('mouseup', stopDragging);
- }, []);
-
- const beginTileDrag = (event: ReactMouseEvent, rx: number, ry: number, isTarget: boolean, isSelected: boolean) =>
- {
- event.preventDefault();
-
- if(targetPlacementMode)
- {
- setDragMode('target');
- onMoveTarget(rx, ry);
- return;
- }
-
- const nextMode = isSelected ? 'remove' : 'add';
-
- setDragMode(nextMode);
- onSetTile(rx, ry, nextMode === 'add');
- };
-
- const continueTileDrag = (event: ReactMouseEvent, rx: number, ry: number, isTarget: boolean) =>
- {
- if(!(event.buttons & 1) || !dragMode) return;
-
- if(dragMode === 'target')
- {
- onMoveTarget(rx, ry);
- return;
- }
-
- onSetTile(rx, ry, dragMode === 'add');
- };
-
- for (let ry = -GRID_RANGE; ry <= GRID_RANGE; ry++)
- {
- for (let rx = -GRID_RANGE; rx <= GRID_RANGE; rx++)
- {
- const isTarget = rx === targetTile.x && ry === targetTile.y;
- const isSelected = tileIncluded(selectedTiles, rx, ry);
- const isActive = invert ? !isSelected : isSelected;
- const left = tileLeft(rx, ry);
- const top_ = tileTop(rx, ry);
- const zIdx = rx + ry + GRID_RANGE * 2 + 10;
-
- const bgColor = isActive
- ? '#3399ff'
- : '#2a3042';
-
- const borderColor = isTarget
- ? '#ffffff'
- : isActive
- ? '#1166cc'
- : '#1a2032';
-
- const diamond: CSSProperties = {
- position: 'absolute',
- width: TILE_W,
- height: TILE_H,
- left,
- top: top_,
- clipPath: 'polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)',
- backgroundColor: bgColor,
- cursor: 'pointer',
- zIndex: zIdx,
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- color: isTarget ? '#ffffff' : 'transparent',
- fontSize: 10
- };
-
- const border: CSSProperties = {
- position: 'absolute',
- width: TILE_W + (isTarget ? 6 : 2),
- height: TILE_H + (isTarget ? 6 : 2),
- left: left - (isTarget ? 3 : 1),
- top: top_ - (isTarget ? 3 : 1),
- clipPath: 'polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)',
- backgroundColor: borderColor,
- zIndex: zIdx - 1,
- pointerEvents: 'none',
- };
-
- const targetOutline: CSSProperties = {
- position: 'absolute',
- width: TILE_W + 4,
- height: TILE_H + 4,
- left: left - 2,
- top: top_ - 2,
- zIndex: zIdx + 1,
- pointerEvents: 'none',
- overflow: 'visible'
- };
-
- tiles.push(
- ,
- isTarget && (
-
- ),
- beginTileDrag(event, rx, ry, isTarget, isSelected) }
- onMouseEnter={ event => continueTileDrag(event, rx, ry, isTarget) } />,
- );
- }
- }
-
- return (
-
event.preventDefault() }>
- { tiles }
-
- );
-};
-
-export const WiredSelectorUsersNeighborhoodView: FC<{}> = () =>
-{
- const [ selectedTiles, setSelectedTiles ] = useState
([]);
- const [ filterExisting, setFilterExisting ] = useState(false);
- const [ invert, setInvert ] = useState(false);
- const [ sourceType, setSourceType ] = useState(SOURCE_USER_TRIGGER);
- const [ targetTile, setTargetTile ] = useState({ x: 0, y: 0 });
- const [ targetPlacementMode, setTargetPlacementMode ] = useState(false);
- const [ curX, setCurX ] = useState(0);
- const [ curY, setCurY ] = useState(0);
-
- const { trigger = null, furniIds = [], setIntParams } = useWired();
-
- useEffect(() =>
- {
- GetRoomEngine().areaSelectionManager.clearHighlight();
- GetRoomEngine().areaSelectionManager.deactivate();
- }, []);
-
- useEffect(() =>
- {
- if(!trigger) return;
-
- const p = trigger.intData;
- if(p.length >= 1) setSourceType(p[0]);
- if(p.length >= 2) setFilterExisting(p[1] === 1);
- if(p.length >= 3) setInvert(p[2] === 1);
- if(p.length >= 5) setTargetTile({ x: p[3], y: p[4] });
- else setTargetTile({ x: 0, y: 0 });
-
- if(p.length >= 6)
- {
- const n = p[5];
- const tiles: Tile[] = [];
-
- for(let i = 0; i < n; i++)
- {
- const xi = 6 + i * 2;
- if(xi + 1 < p.length) tiles.push({ x: p[xi], y: p[xi + 1] });
- }
-
- setSelectedTiles(tiles);
- }
- else
- {
- setSelectedTiles([]);
- }
- }, [ trigger ]);
-
- const save = useCallback(() =>
- {
- const params: number[] = [
- sourceType,
- filterExisting ? 1 : 0,
- invert ? 1 : 0,
- targetTile.x,
- targetTile.y,
- selectedTiles.length,
- ...selectedTiles.flatMap(t => [ t.x, t.y ]),
- ];
-
- setIntParams(params);
- }, [ sourceType, filterExisting, invert, selectedTiles, targetTile.x, targetTile.y, setIntParams ]);
-
- const setTileSelection = useCallback((x: number, y: number, selected: boolean) =>
- {
- setSelectedTiles(prev =>
- {
- const alreadySelected = tileIncluded(prev, x, y);
-
- if(selected)
- {
- if(alreadySelected) return prev;
-
- return [ ...prev, { x, y } ];
- }
-
- if(!alreadySelected) return prev;
-
- return prev.filter(t => !(t.x === x && t.y === y));
- });
- }, []);
-
- const moveTargetTile = useCallback((x: number, y: number) =>
- {
- setTargetTile({ x, y });
- }, []);
-
- const addTile = useCallback(() =>
- {
- if(!tileIncluded(selectedTiles, curX, curY))
- setSelectedTiles(prev => [ ...prev, { x: curX, y: curY } ]);
- }, [ curX, curY, selectedTiles ]);
-
- const removeTile = useCallback(() =>
- {
- setSelectedTiles(prev => prev.filter(t => !(t.x === curX && t.y === curY)));
- }, [ curX, curY ]);
-
- const clearTiles = useCallback(() => setSelectedTiles([]), []);
-
- const loadDefaultPattern = useCallback(() =>
- {
- const tiles: Tile[] = [];
-
- for(let y = -2; y <= 2; y++)
- {
- for(let x = -2; x <= 2; x++)
- {
- if(x === 0 && y === 0) continue;
- tiles.push({ x, y });
- }
- }
-
- setSelectedTiles(tiles);
- }, []);
-
- const isUserGroup = sourceType <= SOURCE_USER_CLICKED;
- const activeSources = isUserGroup ? USER_SOURCES : FURNI_SOURCES;
- const groupOffset = isUserGroup ? 0 : SOURCE_FURNI_TRIGGER;
- const groupIndex = sourceType - groupOffset;
-
- const prevSource = () =>
- setSourceType(groupOffset + ((groupIndex - 1 + activeSources.length) % activeSources.length));
-
- const nextSource = () =>
- setSourceType(groupOffset + ((groupIndex + 1) % activeSources.length));
-
- const switchGroup = (toUser: boolean) =>
- {
- if(toUser === isUserGroup) return;
-
- const newOffset = toUser ? 0 : SOURCE_FURNI_TRIGGER;
- setSourceType(newOffset + groupIndex);
- };
-
- const requiresFurni = sourceType === SOURCE_FURNI_PICKED
- ? WiredFurniType.STUFF_SELECTION_OPTION_BY_ID
- : WiredFurniType.STUFF_SELECTION_OPTION_NONE;
-
- const pickedCount = furniIds.length;
- const pickedLimit = trigger?.maximumItemSelectionCount ?? 20;
-
- return (
-
-
-
-
{ LocalizeText('wiredfurni.params.neighborhood_selection') }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- X:
- setCurX(parseInt(e.target.value) || 0) } />
- Y:
- setCurY(parseInt(e.target.value) || 0) } />
-
-
-
-
-
{ LocalizeText('wiredfurni.params.selector_options_selector') }
-
-
-
-
-
-
-
-
{ LocalizeText('wiredfurni.params.sources.merged.title.neighborhood') }
-
-
-
-
-
-
-
-
-
- { LocalizeText(activeSources[groupIndex].label) }
-
-
-
-
- { sourceType === SOURCE_FURNI_PICKED &&
-
- { LocalizeText('wiredfurni.pickfurnis.caption', [ 'count', 'limit' ], [ pickedCount.toString(), pickedLimit.toString() ]) }
- }
-
-
-
- );
-};
+export const WiredSelectorUsersNeighborhoodView: FC<{}> = () => ;
diff --git a/src/css/index.css b/src/css/index.css
index 329ae1d..dc2e809 100644
--- a/src/css/index.css
+++ b/src/css/index.css
@@ -182,7 +182,7 @@ body {
@apply pointer-events-none relative h-[130px] w-[90px] bg-position-[center_-8px] bg-no-repeat;
}
- .nitro-card-shell {
+ .nitro-card-shell:not(.nitro-wired) {
border: 2px solid #000 !important;
border-radius: 10px;
background: #f2f2eb;
@@ -192,7 +192,7 @@ body {
max-height: calc(100vh - 16px);
}
- .nitro-card-header-shell {
+ .nitro-card-shell:not(.nitro-wired) .nitro-card-header-shell {
border: 2px solid #3c88a6;
border-bottom-color: #000;
border-radius: 8px 8px 0 0;
@@ -200,7 +200,7 @@ body {
padding: 5px;
}
- .nitro-card-header-shell.builders-club-card-header {
+ .nitro-card-shell:not(.nitro-wired) .nitro-card-header-shell.builders-club-card-header {
border-color: #d79d2e;
border-bottom-color: #000;
background: linear-gradient(180deg, #d89f2d 0%, #c68515 100%);
@@ -274,7 +274,7 @@ body {
filter: brightness(0.96);
}
- .nitro-card-content-shell {
+ .nitro-card-shell:not(.nitro-wired) .nitro-card-content-shell {
border: 0;
border-top: 0;
border-radius: 0 0 8px 8px;
@@ -283,8 +283,8 @@ body {
color: #000;
}
- .nitro-card-shell,
- .nitro-card-content-shell {
+ .nitro-card-shell:not(.nitro-wired),
+ .nitro-card-shell:not(.nitro-wired) .nitro-card-content-shell {
h1,
h2,
h3,
@@ -385,13 +385,13 @@ body {
}
@media (max-width: 991.98px) {
- .nitro-card-shell {
+ .nitro-card-shell:not(.nitro-wired) {
width: min(calc(100vw - 16px), 100%) !important;
max-width: calc(100vw - 16px) !important;
max-height: calc(100vh - 16px) !important;
}
- .nitro-card-header-shell {
+ .nitro-card-shell:not(.nitro-wired) .nitro-card-header-shell {
padding: 4px;
}
@@ -403,7 +403,7 @@ body {
font-size: 17px;
}
- .nitro-card-content-shell {
+ .nitro-card-shell:not(.nitro-wired) .nitro-card-content-shell {
padding: 8px !important;
}
@@ -417,8 +417,8 @@ body {
padding: 4px 9px;
}
- .nitro-card-shell,
- .nitro-card-content-shell {
+ .nitro-card-shell:not(.nitro-wired),
+ .nitro-card-shell:not(.nitro-wired) .nitro-card-content-shell {
p,
label,
li,
@@ -814,70 +814,190 @@ body {
}
.nitro-wired {
- background: #d5d5d5;
- border: 1px solid #8f8f8f !important;
+ background: #efefef;
+ border: 1px solid #8d8d8d !important;
border-radius: 6px !important;
- box-shadow: inset 0 1px 0 #ffffff, 0 2px 0 rgba(0, 0, 0, 0.18) !important;
+ box-shadow: inset 0 0 0 1px #fff !important;
color: #000;
+ outline: none !important;
overflow: hidden;
.nitro-wired__header {
- min-height: 22px !important;
- max-height: 22px !important;
- background: linear-gradient(180deg, #f1f1f1 0%, #dfdfdf 45%, #c8c8c8 46%, #d7d7d7 100%) !important;
- border-bottom: 1px solid #9b9b9b;
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.95) !important;
- padding-top: 0 !important;
+ min-height: 21px !important;
+ max-height: 21px !important;
+ position: absolute !important;
+ inset: 0 0 auto 0;
+ z-index: 3;
+ border: 0 !important;
+ border-radius: 0 !important;
+ background: transparent !important;
+ box-shadow: none !important;
+ padding: 0 !important;
+ pointer-events: auto;
- span {
+ .nitro-card-title {
+ display: block;
color: #000 !important;
- font-size: 12px !important;
- font-weight: 700;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.85) !important;
- letter-spacing: 0.01em;
+ font-size: 11px !important;
+ font-weight: 700 !important;
+ line-height: 21px;
+ text-align: center;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.75);
+ pointer-events: none;
+ }
+
+ > .flex::before {
+ content: none;
+ }
+
+ > .flex::after {
+ content: none;
+ }
+
+ .nitro-card-close-button {
+ right: 6px !important;
+ width: 18px;
+ height: 18px;
+ min-width: 18px;
+ border: 1px solid #777;
+ border-radius: 5px;
+ background: linear-gradient(180deg, #f9f9f9 0%, #cacaca 100%);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9);
+ }
+
+ .nitro-card-close-button::before,
+ .nitro-card-close-button::after {
+ left: 50%;
+ top: 50%;
+ width: 10px;
+ height: 2px;
+ background: #6a6a6a;
+ margin: 0;
}
}
- .ubuntu-close-button {
- transform: scale(0.82);
- transform-origin: center;
+ .nitro-wired__content {
+ position: relative;
+ background: #efefef !important;
+ border: 0 !important;
+ box-shadow: none !important;
+ padding: 0 !important;
+ gap: 0 !important;
+ overflow: visible !important;
}
- .nitro-wired__content {
- background: #d9d9d9 !important;
- padding: 4px !important;
- gap: 4px !important;
- overflow: visible !important;
+ .nitro-wired__body {
+ display: flex;
+ flex-direction: column;
+ padding: 8px 10px 10px;
+ gap: 6px;
+ font-size: 12px;
+ line-height: 1.2;
}
.nitro-wired__section {
display: flex;
flex-direction: column;
- gap: 3px;
+ gap: 5px;
+ }
+
+ .nitro-wired__summary {
+ position: relative;
+ min-height: 56px;
+ flex-direction: row;
+ align-items: center;
+ gap: 10px;
+ padding: 22px 10px 7px 12px;
+ background: linear-gradient(180deg, #e5e5e5 0%, #d7d7d7 100%);
+ overflow: hidden;
+ color: #000;
+ }
+
+ .nitro-wired__summary-bg {
+ position: absolute;
+ width: auto;
+ height: auto;
+ top: 50%;
+ z-index: 0;
+ pointer-events: none;
+ user-select: none;
+ -webkit-user-drag: none;
+ }
+
+ .nitro-wired__summary-bg--left {
+ left: 50%;
+ transform: translate(-150%, -50%);
+ opacity: 0.45;
+ }
+
+ .nitro-wired__summary-bg--right {
+ left: 50%;
+ top: 72%;
+ transform: translate(-46%, -50%);
+ opacity: 0.24;
+ }
+
+ .nitro-wired__summary-copy {
+ position: relative;
+ z-index: 1;
+ }
+
+ .nitro-wired__summary-copy {
+ display: flex;
+ flex-direction: column;
+ min-width: 0;
+ gap: 1px;
+ }
+
+ .nitro-wired__summary-kind {
+ color: #000;
+ font-size: 10px;
+ font-weight: 700;
+ letter-spacing: 0.08em;
+ line-height: 1;
+ text-transform: uppercase;
+ }
+
+ .nitro-wired__summary-title {
+ color: #4a4a4a !important;
+ font-size: 15px !important;
+ font-weight: 700 !important;
+ line-height: 1.02;
+ text-align: left !important;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.75);
+ word-break: break-word;
}
.nitro-wired__section--body {
overflow: visible !important;
}
- .nitro-wired__section .font-bold {
+ .nitro-wired__section .font-bold:not(.nitro-wired__summary-title) {
width: 100%;
- font-weight: 400 !important;
- text-align: center;
+ font-size: 13px !important;
+ font-weight: 700 !important;
+ text-align: left;
}
.nitro-wired__summary-description,
.nitro-wired__furni-selector-description,
.nitro-wired__picker-label {
+ font-size: 12px;
line-height: 1.15;
}
+ .nitro-wired__source-row,
+ .nitro-wired__give-var-section-title,
+ .nitro-wired__advanced-toggle {
+ font-size: 12px;
+ }
+
.nitro-wired__divider,
hr {
height: 1px;
border: 0;
- background: #a6a6a6;
- box-shadow: 0 1px 0 #f8f8f8;
+ background: #bababa;
+ box-shadow: 0 1px 0 #fff;
margin: 0 !important;
}
@@ -918,14 +1038,47 @@ body {
.form-check-input[type='checkbox']:checked,
input[type='checkbox']:checked {
- background:
- linear-gradient(135deg, transparent 0 46%, #ffffff 46% 54%, transparent 54% 100%),
- linear-gradient(45deg, transparent 0 30%, #4a4a4a 30% 42%, transparent 42% 100%),
- linear-gradient(180deg, #d9d9d9 0%, #c8c8c8 100%);
+ background: linear-gradient(180deg, #d9d9d9 0%, #c8c8c8 100%);
border-color: #767676;
}
+ .form-check-input[type='checkbox']:checked::before,
+ .form-check-input[type='checkbox']:checked::after,
+ input[type='checkbox']:checked::before,
+ input[type='checkbox']:checked::after {
+ content: '';
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ width: 12px;
+ height: 2px;
+ border-radius: 2px;
+ background: #111111;
+ transform-origin: center;
+ }
+
+ .form-check-input[type='checkbox']:checked::before,
+ input[type='checkbox']:checked::before {
+ transform: translate(-50%, -50%) rotate(45deg);
+ }
+
+ .form-check-input[type='checkbox']:checked::after,
+ input[type='checkbox']:checked::after {
+ transform: translate(-50%, -50%) rotate(-45deg);
+ }
+
+ .form-check {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ }
+
+ .form-check-label {
+ margin-left: 1px;
+ }
+
.form-control,
+ .form-select,
input[type='text'],
input[type='number'],
textarea {
@@ -935,7 +1088,7 @@ body {
background: #f6f6f6 !important;
color: #000 !important;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.95);
- font-size: 11px;
+ font-size: 12px;
padding: 3px 6px;
}
@@ -945,10 +1098,10 @@ body {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
- min-height: 20px !important;
+ min-height: 22px !important;
border: 1px solid #8e8e8e !important;
- border-radius: 5px !important;
- background: linear-gradient(180deg, #f6f6f6 0%, #e4e4e4 49%, #d0d0d0 50%, #ececec 100%) !important;
+ border-radius: 6px !important;
+ background: linear-gradient(180deg, #fcfcfc 0%, #e8e8e8 46%, #d5d5d5 47%, #efefef 100%) !important;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.92) !important;
color: #000 !important;
padding-top: 0 !important;
@@ -966,9 +1119,17 @@ body {
font-weight: 700;
}
+ &.nitro-card-shell {
+ resize: none !important;
+ }
+
+ .nitro-wired__actions {
+ padding-top: 2px;
+ }
+
.nitro-slider-wrapper {
align-items: center;
- gap: 2px;
+ gap: 4px;
}
.nitro-wired__advanced-toggle {
@@ -1591,6 +1752,19 @@ body {
}
}
+.nitro-card-shell.nitro-wired {
+ border: 1px solid #8d8d8d !important;
+ border-color: #8d8d8d !important;
+ box-shadow: inset 0 0 0 1px #fff !important;
+ outline: none !important;
+}
+
+.nitro-card-shell.nitro-wired .nitro-card-header-shell,
+.nitro-card-shell.nitro-wired .nitro-card-content-shell {
+ border: 0 !important;
+ box-shadow: none !important;
+}
+
/* ── Avatar Editor ─────────────────────────────────────────────────────── */
.color-picker-frame {
diff --git a/src/hooks/wired/useWired.ts b/src/hooks/wired/useWired.ts
index e35e211..6bdb4c3 100644
--- a/src/hooks/wired/useWired.ts
+++ b/src/hooks/wired/useWired.ts
@@ -4,6 +4,7 @@ import { useBetween } from 'use-between';
import { GetRoomSession, IsOwnerOfFloorFurniture, LocalizeText, SendMessageComposer, WiredFurniType, WiredSelectionVisualizer } from '../../api';
import { useMessageEvent } from '../events';
import { useNotification } from '../notification';
+import { useWiredTools } from '../wired-tools/useWiredTools';
const useWiredState = () =>
{
@@ -19,6 +20,7 @@ const useWiredState = () =>
const [ allowedInteractionTypes, setAllowedInteractionTypes ] = useState(null);
const [ allowedInteractionErrorKey, setAllowedInteractionErrorKey ] = useState(null);
const { showConfirm = null, simpleAlert = null } = useNotification();
+ const { requestUserVariables = null, roomSettings = null } = useWiredTools();
const saveWired = () =>
{
@@ -273,6 +275,7 @@ const useWiredState = () =>
const parser = event.getParser();
WiredSelectionVisualizer.clearAllSelectionShaders();
+ if(roomSettings?.canInspect && requestUserVariables) requestUserVariables();
setTrigger(null);
});