@pascal-app/editor 1.0.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +18 -15
- package/src/components/editor/action-menu-button.tsx +4 -1
- package/src/components/editor/alignment-3d-guide-layer.tsx +102 -11
- package/src/components/editor/bake-thumbnail.tsx +3 -2
- package/src/components/editor/custom-camera-controls.tsx +110 -42
- package/src/components/editor/duplicate-node.ts +2 -1
- package/src/components/editor/elevation-3d-guide-layer.tsx +1 -1
- package/src/components/editor/first-person-controls.tsx +77 -68
- package/src/components/editor/fit-scene-framing.test.ts +318 -0
- package/src/components/editor/fit-scene-framing.ts +142 -0
- package/src/components/editor/floating-action-menu.tsx +31 -11
- package/src/components/editor/floating-building-action-menu.tsx +1 -1
- package/src/components/editor/floor-openings-overlay.tsx +1 -1
- package/src/components/editor/floor-region-controls.tsx +2 -2
- package/src/components/editor/floorplan-panel.test.ts +220 -0
- package/src/components/editor/floorplan-panel.tsx +458 -140
- package/src/components/editor/floorplan-wall-typing-keys.test.tsx +152 -0
- package/src/components/editor/floorplan-wall-typing-keys.ts +79 -0
- package/src/components/editor/footprint-height-handle.tsx +2 -2
- package/src/components/editor/grid.tsx +24 -15
- package/src/components/editor/group-actions.ts +19 -1
- package/src/components/editor/group-floating-action-menu.tsx +1 -1
- package/src/components/editor/group-move-3d.ts +27 -2
- package/src/components/editor/group-selection-box-3d.tsx +4 -1
- package/src/components/editor/group-transform-shared.ts +23 -1
- package/src/components/editor/index.tsx +150 -20
- package/src/components/editor/inspector-extension-actions.tsx +36 -0
- package/src/components/editor/localized-html.tsx +22 -0
- package/src/components/editor/measurement-pill.tsx +1 -1
- package/src/components/editor/node-action-menu.tsx +46 -12
- package/src/components/editor/node-arrow-handles.tsx +2 -3
- package/src/components/editor/open-wall-ends-3d-layer.tsx +2 -3
- package/src/components/editor/open-wall-ends-hint.tsx +1 -1
- package/src/components/editor/opening-guides-3d-layer.tsx +1 -1
- package/src/components/editor/quick-measurement-card.tsx +1 -1
- package/src/components/editor/registry-action-contributions.test.tsx +67 -6
- package/src/components/editor/registry-action-contributions.tsx +115 -15
- package/src/components/editor/riser-diagram-panel.tsx +59 -9
- package/src/components/editor/room-controls.tsx +4 -3
- package/src/components/editor/room-handles-2d.tsx +158 -7
- package/src/components/editor/room-handles.tsx +244 -54
- package/src/components/editor/room-highlight.tsx +2 -0
- package/src/components/editor/room-labels.tsx +33 -17
- package/src/components/editor/selection-manager.tsx +15 -102
- package/src/components/editor/separator-end-grip.tsx +74 -0
- package/src/components/editor/site-edge-labels.tsx +7 -3
- package/src/components/editor/thumbnail-generator.test.ts +15 -6
- package/src/components/editor/thumbnail-generator.tsx +26 -1
- package/src/components/editor/use-floorplan-background-placement.ts +55 -52
- package/src/components/editor/views/view-bar.tsx +111 -26
- package/src/components/editor/wall-measurement-label.tsx +31 -15
- package/src/components/editor/wall-move-side-handles.tsx +15 -7
- package/src/components/editor/wall-pull-grip.tsx +193 -0
- package/src/components/editor/wall-region-handles.tsx +2 -2
- package/src/components/editor/wall-snap-beacon-layer.tsx +134 -33
- package/src/components/editor-2d/floorplan-adjacent-walls-layer.test.ts +76 -0
- package/src/components/editor-2d/floorplan-adjacent-walls-layer.tsx +186 -0
- package/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +63 -3
- package/src/components/editor-2d/floorplan-group-move.tsx +32 -4
- package/src/components/editor-2d/floorplan-measurement-tool-layer.test.ts +6 -0
- package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +33 -24
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +12 -5
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +2 -1
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +29 -5
- package/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +96 -4
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +52 -12
- package/src/components/editor-2d/renderers/floorplan-draft-measurement.tsx +7 -1
- package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +13 -1
- package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.test.tsx +35 -0
- package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.tsx +65 -0
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +34 -1
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +211 -39
- package/src/components/procedural-items/inspector.tsx +59 -12
- package/src/components/systems/ceiling/ceiling-bracket-batch.test.ts +2 -0
- package/src/components/systems/ceiling/ceiling-system.test.ts +141 -0
- package/src/components/systems/ceiling/ceiling-system.tsx +53 -18
- package/src/components/systems/roof/roof-edit-system.test.tsx +15 -1
- package/src/components/systems/roof/roof-edit-system.tsx +30 -19
- package/src/components/tools/distribution/distribution-run-tool.test.tsx +371 -3
- package/src/components/tools/distribution/distribution-run-tool.tsx +200 -58
- package/src/components/tools/item/move-tool.tsx +1 -6
- package/src/components/tools/item/placement-history.test.tsx +1 -1
- package/src/components/tools/item/placement-strategies.test.ts +64 -1
- package/src/components/tools/item/placement-strategies.ts +5 -9
- package/src/components/tools/item/use-placement-coordinator.tsx +31 -35
- package/src/components/tools/paint-region/wall-paint-region-tool.tsx +1 -1
- package/src/components/tools/registry/item-surface-move.test.ts +11 -0
- package/src/components/tools/registry/move-registry-node-tool.test.ts +42 -1
- package/src/components/tools/registry/move-registry-node-tool.tsx +38 -14
- package/src/components/tools/select/select-candidates.test.ts +45 -0
- package/src/components/tools/select/select-candidates.ts +13 -2
- package/src/components/tools/shared/cursor-sphere.tsx +10 -3
- package/src/components/tools/shared/draft-measurement-label.tsx +1 -1
- package/src/components/tools/shared/placement-box.tsx +2 -6
- package/src/components/tools/shared/placement-coordinate-input.tsx +94 -0
- package/src/components/tools/shared/placement-dimension-guides.tsx +1 -1
- package/src/components/tools/shared/segment-angle.ts +0 -4
- package/src/components/tools/site/terrain-brush-cursor.tsx +1 -1
- package/src/components/tools/tool-manager.tsx +1 -24
- package/src/components/tools/wall/wall-drafting.test.ts +299 -23
- package/src/components/tools/wall/wall-drafting.ts +132 -24
- package/src/components/tools/wall/wall-pull-snap.test.ts +274 -0
- package/src/components/tools/wall/wall-pull-snap.ts +563 -0
- package/src/components/tools/wall/wall-snap-geometry.test.ts +113 -1
- package/src/components/tools/wall/wall-snap-geometry.ts +137 -0
- package/src/components/tools/wall/wall-typed-entry.test.ts +99 -0
- package/src/components/tools/wall/wall-typed-entry.ts +70 -0
- package/src/components/tools/zone/zone-tool.tsx +3 -3
- package/src/components/ui/action-menu/action-button.tsx +2 -0
- package/src/components/ui/action-menu/camera-actions.tsx +8 -7
- package/src/components/ui/action-menu/control-modes.tsx +9 -5
- package/src/components/ui/action-menu/follow-pascal-pill.tsx +3 -1
- package/src/components/ui/action-menu/follow-pascal-toggle.tsx +7 -1
- package/src/components/ui/action-menu/furnish-tools.tsx +7 -6
- package/src/components/ui/action-menu/index.tsx +1 -0
- package/src/components/ui/action-menu/measurement-control.tsx +35 -29
- package/src/components/ui/action-menu/point-ask-button.tsx +4 -3
- package/src/components/ui/action-menu/structure-tools.tsx +25 -23
- package/src/components/ui/action-menu/view-toggles.test.ts +18 -0
- package/src/components/ui/action-menu/view-toggles.tsx +256 -51
- package/src/components/ui/build-panel/build-panel.tsx +163 -25
- package/src/components/ui/command-palette/editor-commands.tsx +38 -11
- package/src/components/ui/controls/finish-swatch.tsx +45 -19
- package/src/components/ui/controls/material-picker.tsx +24 -17
- package/src/components/ui/controls/metric-control.test.ts +52 -0
- package/src/components/ui/controls/metric-control.tsx +62 -24
- package/src/components/ui/controls/segmented-control.tsx +5 -2
- package/src/components/ui/controls/slider-control.test.tsx +23 -0
- package/src/components/ui/controls/slider-control.tsx +47 -19
- package/src/components/ui/controls/tool-options-panel.tsx +74 -44
- package/src/components/ui/floating-level-selector.tsx +100 -48
- package/src/components/ui/helpers/building-helper.tsx +5 -3
- package/src/components/ui/helpers/contextual-helper-panel.tsx +97 -37
- package/src/components/ui/helpers/helper-manager.test.tsx +106 -3
- package/src/components/ui/helpers/helper-manager.tsx +136 -57
- package/src/components/ui/helpers/item-helper.tsx +6 -4
- package/src/components/ui/helpers/registered-tool-helper.tsx +3 -1
- package/src/components/ui/level-duplicate-dialog.tsx +32 -23
- package/src/components/ui/level-wall-copy-prompt.tsx +124 -0
- package/src/components/ui/panels/collections/collections-popover.tsx +11 -11
- package/src/components/ui/panels/deck-boards-fields.tsx +136 -0
- package/src/components/ui/panels/floor-foundation-panel.tsx +114 -39
- package/src/components/ui/panels/floor-opening-panel.tsx +74 -26
- package/src/components/ui/panels/inspector-extensions.tsx +66 -0
- package/src/components/ui/panels/mobile-panel-sheet.tsx +3 -1
- package/src/components/ui/panels/mobile-selection-bar.tsx +34 -28
- package/src/components/ui/panels/multi-field-value.test.ts +27 -0
- package/src/components/ui/panels/multi-field-value.ts +20 -1
- package/src/components/ui/panels/multi-height-mode.tsx +11 -10
- package/src/components/ui/panels/multi-parametric-inspector.tsx +122 -34
- package/src/components/ui/panels/multi-selection-panel.tsx +76 -36
- package/src/components/ui/panels/node-display.ts +35 -24
- package/src/components/ui/panels/panel-manager.tsx +9 -5
- package/src/components/ui/panels/panel-wrapper.tsx +63 -127
- package/src/components/ui/panels/parametric-field-control.tsx +13 -10
- package/src/components/ui/panels/parametric-inspector.tsx +18 -12
- package/src/components/ui/panels/reference-panel.tsx +51 -35
- package/src/components/ui/panels/room-construction-rows.tsx +465 -66
- package/src/components/ui/panels/room-name-options.test.ts +36 -3
- package/src/components/ui/panels/room-name-options.ts +110 -11
- package/src/components/ui/panels/room-openings-field.tsx +22 -13
- package/src/components/ui/panels/room-panel.tsx +207 -100
- package/src/components/ui/panels/shape-choice.tsx +7 -5
- package/src/components/ui/panels/wall-region-list.tsx +7 -7
- package/src/components/ui/primitives/shortcut-token.tsx +10 -6
- package/src/components/ui/right-stack.test.ts +13 -6
- package/src/components/ui/right-stack.tsx +21 -10
- package/src/components/ui/sidebar/icon-rail.tsx +11 -9
- package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +10 -10
- package/src/components/ui/sidebar/panels/items-panel/index.tsx +10 -9
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +3 -0
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +102 -32
- package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +4 -3
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +5 -3
- package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +7 -5
- package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/default-names.ts +75 -0
- package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +118 -72
- package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +36 -3
- package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +7 -4
- package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +8 -2
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +8 -5
- package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +9 -4
- package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +8 -7
- package/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +7 -6
- package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +16 -1
- package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +15 -8
- package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +4 -2
- package/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx +3 -1
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +19 -9
- package/src/components/ui/sidebar/panels/zone-panel/index.tsx +25 -14
- package/src/components/ui/sidebar/tab-bar.tsx +4 -1
- package/src/components/ui/sidebar/use-plugin-panels.tsx +19 -10
- package/src/components/ui/snap-target-badge.tsx +7 -6
- package/src/components/ui/wall-type/wall-type-editor-dialog.tsx +721 -0
- package/src/components/ui/wall-type/wall-type-menu.tsx +167 -0
- package/src/components/viewer/floorplan-compass-button.tsx +12 -3
- package/src/components/viewer/floorplan-preview.tsx +27 -19
- package/src/components/viewer/render-settings-menu.tsx +294 -0
- package/src/components/viewer/sky-control.tsx +710 -0
- package/src/components/viewer/use-viewer-ui-sounds.test.ts +15 -0
- package/src/components/viewer/use-viewer-ui-sounds.ts +46 -0
- package/src/components/viewer/viewer-controls-bar.tsx +278 -260
- package/src/components/viewer/viewer-hover-label.tsx +12 -4
- package/src/components/viewer/viewer-rooms.tsx +62 -5
- package/src/components/viewer/viewer-scene-header.tsx +28 -17
- package/src/components/viewer/viewer-stage-switcher.tsx +4 -2
- package/src/components/viewer-overlay.tsx +8 -0
- package/src/components/walkthrough-hud.tsx +75 -2
- package/src/hooks/use-keyboard.test.ts +85 -4
- package/src/hooks/use-keyboard.ts +65 -7
- package/src/hooks/use-selected-room.ts +12 -1
- package/src/i18n/floor-footprint-name.ts +30 -0
- package/src/i18n/level-name.ts +39 -0
- package/src/i18n/locales/en/messages.po +15849 -0
- package/src/i18n/locales/en/messages.ts +1 -0
- package/src/i18n/locales/en-XA/messages.ts +1 -0
- package/src/i18n/locales/es/messages.po +39331 -0
- package/src/i18n/locales/es/messages.ts +1 -0
- package/src/i18n/locales/fr/messages.po +39331 -0
- package/src/i18n/locales/fr/messages.ts +1 -0
- package/src/i18n/locales/ja/messages.po +39331 -0
- package/src/i18n/locales/ja/messages.ts +1 -0
- package/src/i18n/locales/zh-CN/messages.po +39331 -0
- package/src/i18n/locales/zh-CN/messages.ts +1 -0
- package/src/i18n/locales.test.ts +63 -0
- package/src/i18n/locales.ts +32 -0
- package/src/i18n/message-slot.tsx +25 -0
- package/src/i18n/node-messages.ts +169 -0
- package/src/i18n/pseudo-locale.ts +17 -0
- package/src/i18n/published-entry.test.ts +17 -0
- package/src/i18n/scene-theme-name.ts +16 -0
- package/src/index.tsx +224 -45
- package/src/lib/add-storey.test.ts +3 -3
- package/src/lib/contextual-help.test.ts +20 -1
- package/src/lib/contextual-help.ts +101 -19
- package/src/lib/continuation.ts +38 -11
- package/src/lib/elevation-guides.ts +21 -6
- package/src/lib/elevator-support.ts +1 -72
- package/src/lib/floor-footprints.test.ts +3 -2
- package/src/lib/floor-footprints.ts +1 -9
- package/src/lib/floor-foundation-support.test.ts +15 -6
- package/src/lib/floor-opening-draft.ts +1 -1
- package/src/lib/floor-region-session.ts +1 -1
- package/src/lib/floorplan/dimension-drive.test.ts +36 -2
- package/src/lib/floorplan/dimension-drive.ts +68 -3
- package/src/lib/floorplan/floorplan-export.test.ts +16 -5
- package/src/lib/floorplan/floorplan-export.tsx +13 -16
- package/src/lib/floorplan/floorplan-extension.test.ts +11 -12
- package/src/lib/floorplan/floorplan-extension.ts +37 -18
- package/src/lib/floorplan/floorplan-mode.test.ts +13 -6
- package/src/lib/floorplan/floorplan-mode.ts +14 -12
- package/src/lib/floorplan/floorplan-plugin-install.test.tsx +1 -1
- package/src/lib/floorplan/floorplan-readonly.ts +3 -3
- package/src/lib/floorplan/open-wall-ends.ts +2 -1
- package/src/lib/floorplan/schedules.ts +10 -6
- package/src/lib/floorplan/site-plan/site-annotations.test.ts +46 -1
- package/src/lib/floorplan/site-plan/site-annotations.ts +3 -0
- package/src/lib/floorplan/site-plan/site-parts.ts +6 -3
- package/src/lib/geometry-script/author.test.ts +114 -0
- package/src/lib/geometry-script/author.ts +55 -23
- package/src/lib/geometry-script/client.ts +3 -0
- package/src/lib/geometry-script/finish-scripts.ts +7 -7
- package/src/lib/gesture-lifecycle.ts +3 -1
- package/src/lib/glb-export.test.ts +327 -0
- package/src/lib/glb-export.ts +70 -2
- package/src/lib/grid-frame.test.ts +56 -3
- package/src/lib/grid-frame.ts +28 -1
- package/src/lib/history.test.ts +2 -1
- package/src/lib/hud-title.ts +48 -24
- package/src/lib/ifc-export.test.ts +41 -1
- package/src/lib/inspector-card-mode.test.ts +3 -31
- package/src/lib/inspector-card-mode.ts +5 -10
- package/src/lib/inspector-expanded.test.ts +13 -0
- package/src/lib/inspector-expanded.ts +13 -1
- package/src/lib/interaction/scope.ts +1 -0
- package/src/lib/keyboard-pan.test.ts +7 -0
- package/src/lib/keyboard-pan.ts +9 -2
- package/src/lib/layer-thickness.test.ts +22 -0
- package/src/lib/layer-thickness.ts +79 -0
- package/src/lib/level-selection.test.ts +18 -2
- package/src/lib/level-selection.ts +31 -8
- package/src/lib/linear-display.ts +1 -1
- package/src/lib/live-gesture-round-trip.test.ts +1 -1
- package/src/lib/lot/drop-in.test.ts +59 -1
- package/src/lib/lot/drop-in.ts +42 -50
- package/src/lib/material-swatch-style.ts +24 -0
- package/src/lib/measurement-label.test.ts +1 -1
- package/src/lib/measurement-parser.ts +7 -3
- package/src/lib/measurements.test.ts +24 -6
- package/src/lib/measurements.ts +1 -203
- package/src/lib/mezzanine-selection.test.ts +3 -1
- package/src/lib/node-action-movement.test.tsx +115 -0
- package/src/lib/node-action-movement.ts +2 -0
- package/src/lib/orbit-near-plane.test.ts +12 -0
- package/src/lib/orbit-near-plane.ts +13 -0
- package/src/lib/paint-regions.test.ts +8 -5
- package/src/lib/paint-scope.test.ts +53 -0
- package/src/lib/paint-scope.ts +18 -4
- package/src/lib/panel-rows.ts +17 -8
- package/src/lib/placement-metadata.ts +4 -0
- package/src/lib/point-ask/describe-target.ts +6 -8
- package/src/lib/point-ask/region.ts +1 -1
- package/src/lib/print-shell-compiler.ts +12 -1
- package/src/lib/print-wall-solids.test.ts +11 -0
- package/src/lib/print-wall-solids.ts +9 -0
- package/src/lib/reference-scale.ts +83 -0
- package/src/lib/room-assembly-overlay.ts +1 -1
- package/src/lib/room-built-on.test.ts +28 -17
- package/src/lib/room-built-on.ts +21 -17
- package/src/lib/room-construction-commands.ts +3 -2
- package/src/lib/room-construction.test.ts +28 -1
- package/src/lib/room-construction.ts +14 -0
- package/src/lib/room-controls-phase6.test.ts +141 -1
- package/src/lib/room-handle-drag.ts +554 -58
- package/src/lib/room-name-catalog.test.ts +8 -0
- package/src/lib/room-name-catalog.ts +8 -1
- package/src/lib/room-name-messages.test.ts +132 -0
- package/src/lib/room-name-messages.ts +147 -0
- package/src/lib/room-name-storage.test.ts +334 -0
- package/src/lib/room-push-dimensions.test.ts +38 -1
- package/src/lib/room-push-dimensions.ts +226 -2
- package/src/lib/room-selection.test.ts +23 -6
- package/src/lib/scene-bounds.test.ts +144 -0
- package/src/lib/scene-bounds.ts +79 -15
- package/src/lib/scene-clipboard.test.ts +70 -49
- package/src/lib/scene-clipboard.ts +11 -5
- package/src/lib/selection-cycle.ts +63 -0
- package/src/lib/separator-edit.test.ts +431 -0
- package/src/lib/separator-edit.ts +179 -0
- package/src/lib/separator-lines.ts +38 -0
- package/src/lib/sfx-bus.ts +27 -1
- package/src/lib/sfx-player.ts +16 -0
- package/src/lib/snapping-mode.test.ts +23 -1
- package/src/lib/tool-cursor-icon.ts +5 -1
- package/src/lib/tool-shortcuts.ts +130 -0
- package/src/lib/viewer-selection.test.ts +28 -24
- package/src/lib/viewer-selection.ts +21 -6
- package/src/lib/wall-draw-variant.test.ts +7 -6
- package/src/lib/wall-draw-variant.ts +107 -6
- package/src/lib/wall-nudge.test.ts +44 -0
- package/src/lib/wall-nudge.ts +131 -0
- package/src/lib/wall-parallel-snap.test.ts +83 -0
- package/src/lib/wall-parallel-snap.ts +176 -0
- package/src/lib/wall-placement-pointer.test.ts +23 -0
- package/src/lib/wall-placement-pointer.ts +18 -0
- package/src/lib/wall-pull.test.ts +245 -0
- package/src/lib/wall-pull.ts +209 -0
- package/src/lib/wall-push-line-up.test.ts +132 -0
- package/src/lib/wall-region-list.ts +17 -6
- package/src/lib/wall-run-snap.test.ts +188 -0
- package/src/lib/wall-run-snap.ts +83 -0
- package/src/lib/wall-type.test.ts +125 -0
- package/src/lib/wall-type.ts +119 -0
- package/src/lib/window-interaction.test.ts +44 -0
- package/src/lib/world-grid-snap.test.ts +139 -2
- package/src/lib/world-grid-snap.ts +102 -105
- package/src/store/use-alignment-guides.ts +27 -1
- package/src/store/use-editor.tsx +53 -0
- package/src/store/use-floorplan-annotation-visibility.test.ts +64 -0
- package/src/store/use-floorplan-annotation-visibility.ts +47 -22
- package/src/store/use-placement-typing.test.ts +165 -0
- package/src/store/use-placement-typing.ts +186 -0
- package/src/store/use-wall-snap-indicator.ts +15 -2
- package/src/components/tools/elevator/elevator-defaults.ts +0 -8
- package/src/components/tools/elevator/elevator-tool.tsx +0 -372
- package/src/components/tools/elevator/move-elevator-tool.tsx +0 -262
- package/src/lib/door-interaction.ts +0 -102
- package/src/lib/measurement-label.ts +0 -68
- package/src/lib/window-interaction.ts +0 -100
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AnyNodeId, useScene, type WallNode } from '@pascal-app/core'
|
|
1
|
+
import { type AnyNodeId, useScene, usePascalI18n, type WallNode } from '@pascal-app/core'
|
|
2
2
|
import { useViewer } from '@pascal-app/viewer'
|
|
3
3
|
import Image from 'next/image'
|
|
4
4
|
import { memo, useCallback, useEffect, useRef, useState } from 'react'
|
|
@@ -6,6 +6,7 @@ import { useShallow } from 'zustand/react/shallow'
|
|
|
6
6
|
import { InlineRenameInput } from './inline-rename-input'
|
|
7
7
|
import { focusTreeNode, handleTreeSelection, TreeNode, TreeNodeWrapper } from './tree-node'
|
|
8
8
|
import { TreeNodeActions } from './tree-node-actions'
|
|
9
|
+
import { nodeLabelDescriptor } from '../../../../../i18n/node-messages'
|
|
9
10
|
|
|
10
11
|
interface WallTreeNodeProps {
|
|
11
12
|
nodeId: AnyNodeId
|
|
@@ -18,6 +19,7 @@ export const WallTreeNode = memo(function WallTreeNode({
|
|
|
18
19
|
depth,
|
|
19
20
|
isLast,
|
|
20
21
|
}: WallTreeNodeProps) {
|
|
22
|
+
const i18n = usePascalI18n()
|
|
21
23
|
const [expanded, setExpanded] = useState(false)
|
|
22
24
|
const [isEditing, setIsEditing] = useState(false)
|
|
23
25
|
const isVisible = useScene((s) => s.nodes[nodeId as AnyNodeId]?.visible !== false)
|
|
@@ -83,7 +85,7 @@ export const WallTreeNode = memo(function WallTreeNode({
|
|
|
83
85
|
isVisible={isVisible}
|
|
84
86
|
label={
|
|
85
87
|
<InlineRenameInput
|
|
86
|
-
defaultName=
|
|
88
|
+
defaultName={i18n._(nodeLabelDescriptor('wall', 'Wall'))}
|
|
87
89
|
isEditing={isEditing}
|
|
88
90
|
nodeId={nodeId as AnyNodeId}
|
|
89
91
|
onStartEditing={handleStartEditing}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { type AnyNodeId, type WindowNode, useScene } from '@pascal-app/core'
|
|
3
|
+
import { type AnyNodeId, type WindowNode, useScene, usePascalI18n } from '@pascal-app/core'
|
|
4
4
|
import { useViewer } from '@pascal-app/viewer'
|
|
5
5
|
import Image from 'next/image'
|
|
6
6
|
import { memo, useCallback, useState } from 'react'
|
|
@@ -8,6 +8,7 @@ import { resolveNodeSnapTarget, SnapTargetIcon } from '../../../snap-target-badg
|
|
|
8
8
|
import { InlineRenameInput } from './inline-rename-input'
|
|
9
9
|
import { focusTreeNode, handleTreeSelection, TreeNodeWrapper } from './tree-node'
|
|
10
10
|
import { TreeNodeActions } from './tree-node-actions'
|
|
11
|
+
import { nodeLabelDescriptor } from '../../../../../i18n/node-messages'
|
|
11
12
|
|
|
12
13
|
interface WindowTreeNodeProps {
|
|
13
14
|
nodeId: AnyNodeId
|
|
@@ -20,6 +21,7 @@ export const WindowTreeNode = memo(function WindowTreeNode({
|
|
|
20
21
|
depth,
|
|
21
22
|
isLast,
|
|
22
23
|
}: WindowTreeNodeProps) {
|
|
24
|
+
const i18n = usePascalI18n()
|
|
23
25
|
const [isEditing, setIsEditing] = useState(false)
|
|
24
26
|
const isVisible = useScene((s) => s.nodes[nodeId as AnyNodeId]?.visible !== false)
|
|
25
27
|
const node = useScene((s) => s.nodes[nodeId] as WindowNode | undefined)
|
|
@@ -62,7 +64,7 @@ export const WindowTreeNode = memo(function WindowTreeNode({
|
|
|
62
64
|
isVisible={isVisible}
|
|
63
65
|
label={
|
|
64
66
|
<InlineRenameInput
|
|
65
|
-
defaultName=
|
|
67
|
+
defaultName={i18n._(nodeLabelDescriptor('window', 'Window'))}
|
|
66
68
|
isEditing={isEditing}
|
|
67
69
|
nodeId={nodeId as AnyNodeId}
|
|
68
70
|
onStartEditing={handleStartEditing}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { usePascalI18n } from '@pascal-app/core'
|
|
1
2
|
import { Checkbox } from './../../../primitives/checkbox'
|
|
2
3
|
|
|
3
4
|
/** Membership toggle shown on zone rows while a unit is focused. */
|
|
@@ -10,9 +11,10 @@ export function ZoneMembershipCheckbox({
|
|
|
10
11
|
onToggle: () => void
|
|
11
12
|
unitName: string
|
|
12
13
|
}) {
|
|
14
|
+
const i18n = usePascalI18n()
|
|
13
15
|
return (
|
|
14
16
|
<Checkbox
|
|
15
|
-
aria-label={
|
|
17
|
+
aria-label={i18n._({ id: 'editor.sidebar.panels.sitePanel.zoneMembershipCheckbox.inUnitname', message: 'In {unitName}', values: { unitName } })}
|
|
16
18
|
checked={checked}
|
|
17
19
|
className="mr-2"
|
|
18
20
|
onCheckedChange={onToggle}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import { useScene, type ZoneNode } from '@pascal-app/core'
|
|
1
|
+
import { useScene, type ZoneNode, usePascalI18n} from '@pascal-app/core'
|
|
2
2
|
import { useViewer } from '@pascal-app/viewer'
|
|
3
3
|
import { memo, useCallback, useState } from 'react'
|
|
4
4
|
import { ColorDot } from './../../../../../components/ui/primitives/color-dot'
|
|
5
|
-
import { formatAreaLabel } from '
|
|
5
|
+
import { formatAreaLabel } from '@pascal-app/core'
|
|
6
6
|
import {
|
|
7
7
|
selectZoneOrRoom,
|
|
8
8
|
useZoneSelected,
|
|
9
|
-
zoneKindLabel,
|
|
10
9
|
} from './../../../../../lib/room-zone-routing'
|
|
11
10
|
import { toggleZoneMembership } from './../../../../../lib/units'
|
|
12
|
-
import {
|
|
11
|
+
import { RoomRenameInput } from './inline-rename-input'
|
|
13
12
|
import { focusTreeNode, TreeNodeWrapper } from './tree-node'
|
|
14
13
|
import { TreeNodeActions } from './tree-node-actions'
|
|
15
14
|
import { ZoneMembershipCheckbox } from './zone-membership-checkbox'
|
|
15
|
+
import { zoneDefaultName } from './default-names'
|
|
16
|
+
import { nodeLabelDescriptor } from '../../../../../i18n/node-messages'
|
|
16
17
|
|
|
17
18
|
interface ZoneTreeNodeProps {
|
|
18
19
|
nodeId: ZoneNode['id']
|
|
@@ -25,13 +26,14 @@ export const ZoneTreeNode = memo(function ZoneTreeNode({
|
|
|
25
26
|
depth,
|
|
26
27
|
isLast,
|
|
27
28
|
}: ZoneTreeNodeProps) {
|
|
29
|
+
const i18n = usePascalI18n()
|
|
28
30
|
const [isEditing, setIsEditing] = useState(false)
|
|
29
31
|
const updateNode = useScene((state) => state.updateNode)
|
|
30
32
|
const isVisible = useScene((s) => s.nodes[nodeId]?.visible !== false)
|
|
31
33
|
const color = useScene((s) => (s.nodes[nodeId] as ZoneNode | undefined)?.color)
|
|
32
34
|
const polygon = useScene((s) => (s.nodes[nodeId] as ZoneNode | undefined)?.polygon ?? [])
|
|
33
35
|
const isSelected = useZoneSelected(nodeId)
|
|
34
|
-
const
|
|
36
|
+
const spaceRole = useScene((s) => (s.nodes[nodeId] as ZoneNode | undefined)?.spaceRole)
|
|
35
37
|
const isHovered = useViewer((state) => state.hoveredId === nodeId)
|
|
36
38
|
const setHoveredId = useViewer((state) => state.setHoveredId)
|
|
37
39
|
const unit = useViewer((state) => state.unit)
|
|
@@ -48,7 +50,7 @@ export const ZoneTreeNode = memo(function ZoneTreeNode({
|
|
|
48
50
|
const handleStartEditing = useCallback(() => setIsEditing(true), [])
|
|
49
51
|
const handleStopEditing = useCallback(() => setIsEditing(false), [])
|
|
50
52
|
|
|
51
|
-
const defaultName =
|
|
53
|
+
const defaultName = zoneDefaultName(i18n, { spaceRole }, formatAreaLabel(calculatePolygonArea(polygon), unit))
|
|
52
54
|
|
|
53
55
|
return (
|
|
54
56
|
<TreeNodeWrapper
|
|
@@ -57,7 +59,15 @@ export const ZoneTreeNode = memo(function ZoneTreeNode({
|
|
|
57
59
|
expanded={false}
|
|
58
60
|
hasChildren={false}
|
|
59
61
|
icon={
|
|
60
|
-
<ColorDot
|
|
62
|
+
<ColorDot
|
|
63
|
+
color={color ?? '#3b82f6'}
|
|
64
|
+
label={i18n._({
|
|
65
|
+
id: 'editor.layers.spaceColour',
|
|
66
|
+
message: '{role, select, room {Room colour} other {Zone colour}}',
|
|
67
|
+
values: { role: spaceRole ?? 'generic' },
|
|
68
|
+
})}
|
|
69
|
+
onChange={(c) => updateNode(nodeId, { color: c })}
|
|
70
|
+
/>
|
|
61
71
|
}
|
|
62
72
|
isHovered={isHovered}
|
|
63
73
|
isLast={isLast}
|
|
@@ -70,10 +80,10 @@ export const ZoneTreeNode = memo(function ZoneTreeNode({
|
|
|
70
80
|
<ZoneMembershipCheckbox
|
|
71
81
|
checked={focusedUnit.members.includes(nodeId)}
|
|
72
82
|
onToggle={() => toggleZoneMembership(focusedUnit.id, nodeId)}
|
|
73
|
-
unitName={focusedUnit.name || 'Unit'}
|
|
83
|
+
unitName={focusedUnit.name || i18n._(nodeLabelDescriptor('unit', 'Unit'))}
|
|
74
84
|
/>
|
|
75
85
|
)}
|
|
76
|
-
<
|
|
86
|
+
<RoomRenameInput
|
|
77
87
|
defaultName={defaultName}
|
|
78
88
|
isEditing={isEditing}
|
|
79
89
|
nodeId={nodeId}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
type AnyNodeId,
|
|
3
3
|
emitter,
|
|
4
4
|
useScene,
|
|
5
|
-
type ZoneNode,
|
|
5
|
+
type ZoneNode, usePascalI18n,
|
|
6
6
|
} from '@pascal-app/core'
|
|
7
7
|
import { useViewer } from '@pascal-app/viewer'
|
|
8
8
|
import { Camera, Hexagon, Save, Trash2 } from 'lucide-react'
|
|
@@ -19,8 +19,10 @@ import { cn } from './../../../../../lib/utils'
|
|
|
19
19
|
import useEditor from './../../../../../store/use-editor'
|
|
20
20
|
import { ActionButton } from '../../../controls/action-button'
|
|
21
21
|
import { PanelSection } from '../../../controls/panel-section'
|
|
22
|
+
import { displayRoomName } from '../../../../../lib/room-name-messages'
|
|
22
23
|
|
|
23
24
|
function ZoneItem({ zone }: { zone: ZoneNode }) {
|
|
25
|
+
const i18n = usePascalI18n()
|
|
24
26
|
const [cameraPopoverOpen, setCameraPopoverOpen] = useState(false)
|
|
25
27
|
const deleteNode = useScene((state) => state.deleteNode)
|
|
26
28
|
const updateNode = useScene((state) => state.updateNode)
|
|
@@ -57,17 +59,25 @@ function ZoneItem({ zone }: { zone: ZoneNode }) {
|
|
|
57
59
|
onClick={handleClick}
|
|
58
60
|
>
|
|
59
61
|
<span className="mr-2">
|
|
60
|
-
<ColorDot
|
|
62
|
+
<ColorDot
|
|
63
|
+
color={zone.color}
|
|
64
|
+
label={i18n._({
|
|
65
|
+
id: 'editor.layers.spaceColour',
|
|
66
|
+
message: '{role, select, room {Room colour} other {Zone colour}}',
|
|
67
|
+
values: { role: zone.spaceRole ?? 'generic' },
|
|
68
|
+
})}
|
|
69
|
+
onChange={handleColorChange}
|
|
70
|
+
/>
|
|
61
71
|
</span>
|
|
62
72
|
<Hexagon className="mr-1.5 h-3.5 w-3.5 shrink-0" />
|
|
63
|
-
<span className="flex-1 truncate">{zone.name}</span>
|
|
73
|
+
<span className="flex-1 truncate">{displayRoomName(zone.name ?? '', i18n)}</span>
|
|
64
74
|
{/* Camera snapshot button */}
|
|
65
75
|
<Popover onOpenChange={setCameraPopoverOpen} open={cameraPopoverOpen}>
|
|
66
76
|
<PopoverTrigger asChild>
|
|
67
77
|
<button
|
|
68
78
|
className="relative flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground opacity-0 transition-colors hover:bg-black/5 hover:text-foreground group-hover/row:opacity-100 dark:hover:bg-white/10"
|
|
69
79
|
onClick={(e) => e.stopPropagation()}
|
|
70
|
-
title=
|
|
80
|
+
title={i18n._({ id: 'editor.sidebar.panels.zonePanel.cameraSnapshot', message: 'Camera snapshot' })}
|
|
71
81
|
>
|
|
72
82
|
<Camera className="h-3 w-3" />
|
|
73
83
|
{zone.camera && (
|
|
@@ -92,7 +102,7 @@ function ZoneItem({ zone }: { zone: ZoneNode }) {
|
|
|
92
102
|
}}
|
|
93
103
|
>
|
|
94
104
|
<Camera className="h-3.5 w-3.5" />
|
|
95
|
-
View snapshot
|
|
105
|
+
{i18n._({ id: 'editor.sidebar.panels.zonePanel.viewSnapshot', message: 'View snapshot' })}
|
|
96
106
|
</button>
|
|
97
107
|
)}
|
|
98
108
|
<button
|
|
@@ -104,7 +114,7 @@ function ZoneItem({ zone }: { zone: ZoneNode }) {
|
|
|
104
114
|
}}
|
|
105
115
|
>
|
|
106
116
|
<Camera className="h-3.5 w-3.5" />
|
|
107
|
-
{zone.camera ? 'Update snapshot' : 'Take snapshot'}
|
|
117
|
+
{zone.camera ? i18n._({ id: 'editor.sidebar.panels.zonePanel.updateSnapshot', message: 'Update snapshot' }) : i18n._({ id: 'editor.sidebar.panels.zonePanel.takeSnapshot', message: 'Take snapshot' })}
|
|
108
118
|
</button>
|
|
109
119
|
{zone.camera && (
|
|
110
120
|
<button
|
|
@@ -116,7 +126,7 @@ function ZoneItem({ zone }: { zone: ZoneNode }) {
|
|
|
116
126
|
}}
|
|
117
127
|
>
|
|
118
128
|
<Trash2 className="h-3.5 w-3.5" />
|
|
119
|
-
Clear snapshot
|
|
129
|
+
{i18n._({ id: 'editor.sidebar.panels.zonePanel.clearSnapshot', message: 'Clear snapshot' })}
|
|
120
130
|
</button>
|
|
121
131
|
)}
|
|
122
132
|
</div>
|
|
@@ -133,6 +143,7 @@ function ZoneItem({ zone }: { zone: ZoneNode }) {
|
|
|
133
143
|
}
|
|
134
144
|
|
|
135
145
|
export function ZonePanel() {
|
|
146
|
+
const i18n = usePascalI18n()
|
|
136
147
|
const nodes = useScene((state) => state.nodes)
|
|
137
148
|
const currentLevelId = useViewer((state) => state.selection.levelId)
|
|
138
149
|
const selectedZoneId = useViewer((state) => state.selection.zoneId)
|
|
@@ -167,7 +178,7 @@ export function ZonePanel() {
|
|
|
167
178
|
if (!currentLevelId) {
|
|
168
179
|
return (
|
|
169
180
|
<div className="px-3 py-4 text-muted-foreground text-sm">
|
|
170
|
-
Select a level to view and create zones
|
|
181
|
+
{i18n._({ id: 'editor.sidebar.panels.zonePanel.selectALevelToViewAnd', message: 'Select a level to view and create zones' })}
|
|
171
182
|
</div>
|
|
172
183
|
)
|
|
173
184
|
}
|
|
@@ -176,34 +187,34 @@ export function ZonePanel() {
|
|
|
176
187
|
<div className="py-1">
|
|
177
188
|
{levelZones.length === 0 ? (
|
|
178
189
|
<div className="px-3 py-4 text-muted-foreground text-sm">
|
|
179
|
-
No zones on this level.{' '}
|
|
190
|
+
{i18n._({ id: 'editor.sidebar.panels.zonePanel.noZonesOnThisLevel', message: 'No zones on this level.' })}{' '}
|
|
180
191
|
<button className="cursor-pointer text-primary hover:underline" onClick={handleAddZone}>
|
|
181
|
-
Add one
|
|
192
|
+
{i18n._({ id: 'editor.sidebar.panels.zonePanel.addOne', message: 'Add one' })}
|
|
182
193
|
</button>
|
|
183
194
|
</div>
|
|
184
195
|
) : (
|
|
185
196
|
levelZones.map((zone) => <ZoneItem key={zone.id} zone={zone} />)
|
|
186
197
|
)}
|
|
187
198
|
{selectedZone ? (
|
|
188
|
-
<PanelSection className="mt-2 border-t" title=
|
|
199
|
+
<PanelSection className="mt-2 border-t" title={i18n._({ id: 'editor.sidebar.panels.zonePanel.actions', message: 'Actions' })}>
|
|
189
200
|
<ActionButton
|
|
190
201
|
className="w-full flex-none"
|
|
191
202
|
icon={<Save className="h-4 w-4" />}
|
|
192
|
-
label=
|
|
203
|
+
label={i18n._({ id: 'editor.sidebar.panels.zonePanel.saveToCatalog', message: 'Save to catalog' })}
|
|
193
204
|
onClick={() => emitter.emit('room-preset:create', { zoneId: selectedZone.id })}
|
|
194
205
|
type="button"
|
|
195
206
|
/>
|
|
196
207
|
<ActionButton
|
|
197
208
|
className="w-full flex-none"
|
|
198
209
|
icon={<Trash2 className="h-4 w-4 text-red-600 dark:text-red-400" />}
|
|
199
|
-
label=
|
|
210
|
+
label={i18n._({ id: 'editor.sidebar.panels.zonePanel.delete', message: 'Delete' })}
|
|
200
211
|
onClick={() => deleteSelectedZone(false)}
|
|
201
212
|
type="button"
|
|
202
213
|
/>
|
|
203
214
|
<ActionButton
|
|
204
215
|
className="w-full flex-none"
|
|
205
216
|
icon={<Trash2 className="h-4 w-4 text-red-600 dark:text-red-400" />}
|
|
206
|
-
label=
|
|
217
|
+
label={i18n._({ id: 'editor.sidebar.panels.zonePanel.deleteWithContents', message: 'Delete with contents' })}
|
|
207
218
|
onClick={() => deleteSelectedZone(true)}
|
|
208
219
|
type="button"
|
|
209
220
|
/>
|
|
@@ -121,7 +121,10 @@ export function IconRail({ tabs, activeTab, collapsed, onIconClick }: IconRailPr
|
|
|
121
121
|
|
|
122
122
|
return (
|
|
123
123
|
<TooltipProvider delayDuration={0} disableHoverableContent>
|
|
124
|
-
<div
|
|
124
|
+
<div
|
|
125
|
+
className="flex h-full w-14 shrink-0 flex-col items-center gap-1 border-border/50 border-r py-2"
|
|
126
|
+
data-surface="icon-rail"
|
|
127
|
+
>
|
|
125
128
|
{defaultTabs.map(renderTab)}
|
|
126
129
|
{pluginTabs.length > 0 && (
|
|
127
130
|
<div className="mt-1 flex w-11 flex-col items-center gap-1 border-border/70 border-t pt-2">
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { Icon } from '@iconify/react'
|
|
4
|
-
import { type IconRef, useScene } from '@pascal-app/core'
|
|
4
|
+
import { type IconRef, useScene, usePascalI18n } from '@pascal-app/core'
|
|
5
5
|
import { Plus } from 'lucide-react'
|
|
6
6
|
import {
|
|
7
7
|
type ComponentType,
|
|
@@ -28,9 +28,8 @@ import type { ExtraPanel } from './icon-rail'
|
|
|
28
28
|
// The rail's "+" puts the plugin directory on the stage, as a view in the
|
|
29
29
|
// focused pane, and stays lit while it is there instead of leaving an
|
|
30
30
|
// unrelated panel open beside it. `component` serves the v1 sidebar.
|
|
31
|
-
const pluginsManagerPanel: ExtraPanel = {
|
|
31
|
+
const pluginsManagerPanel: Omit<ExtraPanel, 'label'> = {
|
|
32
32
|
id: 'plugins',
|
|
33
|
-
label: 'Plugins',
|
|
34
33
|
icon: <img alt="" className="size-8 object-contain" src="/icons/plugins.webp" />,
|
|
35
34
|
component: PluginsView,
|
|
36
35
|
noPanel: true,
|
|
@@ -63,12 +62,12 @@ function renderIconRef(ref: IconRef): ReactNode {
|
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
function PluginPanelCrashed({ label }: { label: string }) {
|
|
65
|
+
const i18n = usePascalI18n()
|
|
66
66
|
return (
|
|
67
67
|
<div className="flex flex-col gap-2 p-4 text-sm">
|
|
68
|
-
<p className="font-medium text-sidebar-foreground">"{label}" plugin crashed</p>
|
|
68
|
+
<p className="font-medium text-sidebar-foreground">{i18n._({ id: 'editor.sidebar.usePluginPanels.labelPluginCrashed', message: '"{label}" plugin crashed', values: { label } })}</p>
|
|
69
69
|
<p className="text-sidebar-foreground/50 text-xs">
|
|
70
|
-
This panel hit an error and was unloaded for this session. The rest of the editor is
|
|
71
|
-
unaffected — reload to try again.
|
|
70
|
+
{i18n._({ id: 'editor.sidebar.usePluginPanels.thisPanelHitAnErrorAnd', message: 'This panel hit an error and was unloaded for this session. The rest of the editor is unaffected — reload to try again.' })}
|
|
72
71
|
</p>
|
|
73
72
|
</div>
|
|
74
73
|
)
|
|
@@ -83,13 +82,16 @@ function resolvePanelComponent(panel: EditorHostPanel): ComponentType {
|
|
|
83
82
|
const cached = wrappedPanelCache.get(panel.component)
|
|
84
83
|
if (cached) return cached
|
|
85
84
|
const Lazy = lazy(panel.component)
|
|
86
|
-
const Wrapped: ComponentType = () =>
|
|
85
|
+
const Wrapped: ComponentType = () => {
|
|
86
|
+
const i18n = usePascalI18n()
|
|
87
|
+
return ((
|
|
87
88
|
<ErrorBoundary fallback={<PluginPanelCrashed label={panel.label} />}>
|
|
88
|
-
<Suspense fallback={<div className="p-4 text-sidebar-foreground/50 text-sm">Loading
|
|
89
|
+
<Suspense fallback={<div className="p-4 text-sidebar-foreground/50 text-sm">{i18n._({ id: 'editor.sidebar.usePluginPanels.loading', message: 'Loading…' })}</div>}>
|
|
89
90
|
<Lazy />
|
|
90
91
|
</Suspense>
|
|
91
92
|
</ErrorBoundary>
|
|
92
|
-
)
|
|
93
|
+
))
|
|
94
|
+
}
|
|
93
95
|
Wrapped.displayName = `PluginPanel(${panel.id})`
|
|
94
96
|
wrappedPanelCache.set(panel.component, Wrapped)
|
|
95
97
|
return Wrapped
|
|
@@ -107,6 +109,7 @@ function resolvePanelComponent(panel: EditorHostPanel): ComponentType {
|
|
|
107
109
|
* authoring panel like Nature doesn't ride into the studio rail.
|
|
108
110
|
*/
|
|
109
111
|
export function useHostPanels(hostPanels?: ExtraPanel[]): ExtraPanel[] {
|
|
112
|
+
const i18n = usePascalI18n()
|
|
110
113
|
const registered = useSyncExternalStore(
|
|
111
114
|
editorHostPanelRegistry.subscribe,
|
|
112
115
|
editorHostPanelRegistry.getSnapshot,
|
|
@@ -151,7 +154,13 @@ export function useHostPanels(hostPanels?: ExtraPanel[]): ExtraPanel[] {
|
|
|
151
154
|
readOnly,
|
|
152
155
|
workspaceMode,
|
|
153
156
|
})
|
|
154
|
-
? [
|
|
157
|
+
? [
|
|
158
|
+
{
|
|
159
|
+
...pluginsManagerPanel,
|
|
160
|
+
label: i18n._({ id: 'editor.sidebar.usePluginPanels.plugins', message: 'Plugins' }),
|
|
161
|
+
stageActive: pluginsViewShown,
|
|
162
|
+
},
|
|
163
|
+
]
|
|
155
164
|
: []
|
|
156
165
|
return [...(hostPanels ?? []), ...fromRegistry, ...manager]
|
|
157
166
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AnyNode, type AssetInput, type MessageDescriptor, usePascalI18n } from '@pascal-app/core'
|
|
2
2
|
import { isProceduralItem } from '@pascal-app/core/procedural-items'
|
|
3
3
|
import type { ReactNode } from 'react'
|
|
4
4
|
import { cn } from '../../lib/utils'
|
|
@@ -12,10 +12,10 @@ const SNAP_TARGET_ICONS: Record<SnapTarget, string> = {
|
|
|
12
12
|
roof: '/icons/roof.webp',
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const SNAP_TARGET_LABELS: Record<SnapTarget,
|
|
16
|
-
wall: 'Wall attachment',
|
|
17
|
-
ceiling: 'Ceiling attachment',
|
|
18
|
-
roof: 'Roof attachment',
|
|
15
|
+
const SNAP_TARGET_LABELS: Record<SnapTarget, MessageDescriptor> = {
|
|
16
|
+
wall: /* i18n */ { id: 'editor.snapTarget.wall', message: 'Wall attachment' },
|
|
17
|
+
ceiling: /* i18n */ { id: 'editor.snapTarget.ceiling', message: 'Ceiling attachment' },
|
|
18
|
+
roof: /* i18n */ { id: 'editor.snapTarget.roof', message: 'Roof attachment' },
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const SNAP_TARGET_BADGE_SIZE_CLASSES: Record<SnapTargetBadgeSize, string> = {
|
|
@@ -53,6 +53,7 @@ export function SnapTargetBadge({
|
|
|
53
53
|
size?: SnapTargetBadgeSize
|
|
54
54
|
target: SnapTarget
|
|
55
55
|
}) {
|
|
56
|
+
const i18n = usePascalI18n()
|
|
56
57
|
return (
|
|
57
58
|
<span
|
|
58
59
|
className={cn(
|
|
@@ -62,7 +63,7 @@ export function SnapTargetBadge({
|
|
|
62
63
|
)}
|
|
63
64
|
>
|
|
64
65
|
<img
|
|
65
|
-
alt={SNAP_TARGET_LABELS[target]}
|
|
66
|
+
alt={i18n._(SNAP_TARGET_LABELS[target])}
|
|
66
67
|
className={cn('object-contain', SNAP_TARGET_ICON_SIZE_CLASSES[size])}
|
|
67
68
|
src={SNAP_TARGET_ICONS[target]}
|
|
68
69
|
/>
|