@pascal-app/editor 1.0.3 → 1.0.5
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/README.md +106 -0
- package/package.json +42 -38
- package/src/components/editor/__bench__/room-label-placement.bench.ts +108 -0
- package/src/components/editor/action-menu-button.tsx +83 -0
- package/src/components/editor/bake-thumbnail.tsx +307 -5
- package/src/components/editor/capture-level-picker.tsx +72 -0
- package/src/components/editor/construction-reveal-audio.test.tsx +150 -0
- package/src/components/editor/construction-reveal-audio.tsx +40 -0
- package/src/components/editor/custom-camera-controls.tsx +275 -57
- package/src/components/editor/delete-confirmation-dialog.tsx +297 -7
- package/src/components/editor/duplicate-node.ts +244 -0
- package/src/components/editor/editor-layout-mobile.tsx +37 -26
- package/src/components/editor/editor-layout-v2.tsx +132 -59
- package/src/components/editor/export-manager.tsx +47 -26
- package/src/components/editor/first-person/build-collider-world.test.ts +320 -0
- package/src/components/editor/first-person/build-collider-world.ts +28 -7
- package/src/components/editor/first-person/ground-holes.test.ts +128 -0
- package/src/components/editor/first-person/ground-holes.ts +130 -0
- package/src/components/editor/first-person/mechanism-targets.test.ts +162 -0
- package/src/components/editor/first-person/mechanism-targets.ts +88 -0
- package/src/components/editor/first-person-controls.tsx +220 -9
- package/src/components/editor/floating-action-menu.tsx +63 -207
- package/src/components/editor/floor-aware-camera-controls.test.ts +466 -0
- package/src/components/editor/floor-aware-camera-controls.ts +324 -0
- package/src/components/editor/floor-openings-overlay.tsx +243 -0
- package/src/components/editor/floor-region-controls.tsx +846 -0
- package/src/components/editor/floor-region-webgpu-materials.test.ts +12 -0
- package/src/components/editor/floor-surface.test.ts +165 -0
- package/src/components/editor/floor-surface.ts +182 -0
- package/src/components/editor/floorplan-background-selection.test.ts +11 -2
- package/src/components/editor/floorplan-background-selection.ts +1 -3
- package/src/components/editor/floorplan-mode-coordinator.tsx +2 -2
- package/src/components/editor/floorplan-panel.tsx +414 -363
- package/src/components/editor/follow-pascal.test.tsx +912 -0
- package/src/components/editor/follow-pascal.tsx +354 -0
- package/src/components/editor/footprint-height-handle.tsx +204 -0
- package/src/components/editor/group-actions.ts +56 -2
- package/src/components/editor/group-move-3d.ts +2 -0
- package/src/components/editor/group-rotate-handle.tsx +2 -0
- package/src/components/editor/group-transform-shared.test.ts +460 -0
- package/src/components/editor/handles/handle-hit-priority.test.tsx +63 -0
- package/src/components/editor/handles/handle-hit-priority.tsx +37 -0
- package/src/components/editor/handles/swallow-next-click.test.ts +28 -0
- package/src/components/editor/handles/use-handle-drag.ts +269 -197
- package/src/components/editor/index.tsx +409 -197
- package/src/components/editor/join-walls-pill.tsx +44 -0
- package/src/components/editor/node-action-menu.tsx +68 -70
- package/src/components/editor/node-arrow-handles.tsx +25 -6
- package/src/components/editor/open-wall-ends-3d-layer.tsx +273 -0
- package/src/components/editor/open-wall-ends-hint.tsx +89 -0
- package/src/components/editor/quick-measurement-hud.tsx +3 -2
- package/src/components/editor/registry-action-contributions.test.tsx +63 -0
- package/src/components/editor/registry-action-contributions.tsx +80 -1
- package/src/components/editor/riser-diagram-panel.tsx +14 -7
- package/src/components/editor/room-controls.tsx +847 -0
- package/src/components/editor/room-floor-highlight.tsx +128 -0
- package/src/components/editor/room-handles-2d.tsx +354 -0
- package/src/components/editor/room-handles.tsx +675 -0
- package/src/components/editor/room-highlight.tsx +233 -0
- package/src/components/editor/room-labels.test.ts +850 -0
- package/src/components/editor/room-labels.tsx +1890 -0
- package/src/components/editor/room-transform-ghost.tsx +256 -0
- package/src/components/editor/room-webgpu-materials.test.ts +27 -0
- package/src/components/editor/selection-manager.tsx +474 -419
- package/src/components/editor/slab-hole-highlights.tsx +5 -2
- package/src/components/editor/snapshot-capture-overlay.tsx +7 -2
- package/src/components/editor/snapshot-capture.test.ts +119 -60
- package/src/components/editor/snapshot-capture.ts +36 -5
- package/src/components/editor/thumbnail-generator.test.ts +654 -0
- package/src/components/editor/thumbnail-generator.tsx +1103 -223
- package/src/components/editor/use-floorplan-background-placement.ts +34 -12
- package/src/components/editor/vector-edge-extractor.tsx +121 -0
- package/src/components/editor/views/host-view.tsx +61 -0
- package/src/components/editor/views/plugins-view.tsx +663 -0
- package/src/components/editor/views/scene-region.tsx +59 -0
- package/src/components/editor/views/use-editor-views.ts +57 -0
- package/src/components/editor/views/view-bar.test.tsx +54 -0
- package/src/components/editor/views/view-bar.tsx +343 -0
- package/src/components/editor/wall-justification.test.ts +140 -0
- package/src/components/editor/wall-move-side-handles.tsx +43 -142
- package/src/components/editor/wall-push-arrow.tsx +92 -0
- package/src/components/editor/wall-region-handles.tsx +509 -0
- package/src/components/editor/wall-snap-beacon-layer.tsx +8 -4
- package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +8 -4
- package/src/components/editor-2d/floorplan-group-move.tsx +3 -0
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.test.tsx +86 -0
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +290 -0
- package/src/components/editor-2d/floorplan-registered-tool-layer.tsx +2 -2
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +11 -1
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +116 -106
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.test.ts +156 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +278 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +77 -0
- package/src/components/editor-2d/renderers/{floorplan-draft-wall-measurement.tsx → floorplan-draft-measurement.tsx} +8 -8
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +4 -1
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +38 -8
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +319 -233
- package/src/components/editor-2d/renderers/floorplan-reveal.test.tsx +254 -0
- package/src/components/editor-2d/renderers/floorplan-reveal.ts +141 -0
- package/src/components/editor-2d/svg-paths.ts +12 -15
- package/src/components/point-ask/bubble.tsx +538 -0
- package/src/components/point-ask/hover-chip.tsx +91 -0
- package/src/components/point-ask/mode-pill.tsx +92 -0
- package/src/components/point-ask/optional-motion.ts +22 -0
- package/src/components/point-ask/outline-corners.tsx +93 -0
- package/src/components/point-ask/pins.tsx +711 -0
- package/src/components/point-ask/point-ask-layer.tsx +83 -0
- package/src/components/point-ask/point-ask-styles.ts +105 -0
- package/src/components/point-ask/region-marquee-styles.ts +15 -0
- package/src/components/point-ask/region-marquee.tsx +64 -0
- package/src/components/procedural-items/inspector.tsx +40 -15
- package/src/components/systems/ceiling/ceiling-bracket-batch.test.ts +12 -2
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.test.ts +97 -14
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +18 -18
- package/src/components/systems/roof/roof-edit-system.tsx +1 -0
- package/src/components/systems/zone/zone-system.test.ts +47 -0
- package/src/components/systems/zone/zone-system.tsx +29 -68
- package/src/components/tools/distribution/connection-compatibility.test.ts +34 -0
- package/src/components/tools/distribution/connection-compatibility.ts +43 -0
- package/src/components/tools/distribution/distribution-public.ts +9 -0
- package/src/components/tools/distribution/distribution-run-contract.test.ts +26 -0
- package/src/components/tools/distribution/distribution-run-contract.ts +94 -0
- package/src/components/tools/distribution/distribution-run-tool.test.ts +241 -0
- package/src/components/tools/distribution/distribution-run-tool.test.tsx +125 -0
- package/src/components/tools/distribution/distribution-run-tool.tsx +1323 -0
- package/src/components/tools/distribution/draw-alignment.ts +35 -0
- package/src/components/tools/distribution/ports.test.ts +56 -0
- package/src/components/tools/distribution/ports.ts +378 -0
- package/src/components/tools/distribution/run-cursor.test.ts +135 -0
- package/src/components/tools/distribution/run-cursor.ts +36 -0
- package/src/components/tools/distribution/run-direction-feedback.test.ts +60 -0
- package/src/components/tools/distribution/run-direction-feedback.tsx +251 -0
- package/src/components/tools/distribution/run-port-snap.test.ts +79 -0
- package/src/components/tools/distribution/run-port-snap.ts +25 -0
- package/src/components/tools/distribution/run-screen-direction.test.ts +23 -0
- package/src/components/tools/distribution/run-screen-direction.ts +30 -0
- package/src/components/tools/elevator/elevator-tool.tsx +3 -6
- package/src/components/tools/elevator/move-elevator-tool.tsx +2 -3
- package/src/components/tools/item/item-surface-strategy-resolver.test.ts +67 -68
- package/src/components/tools/item/placement-history.test.tsx +512 -0
- package/src/components/tools/item/placement-strategies.test.ts +46 -1
- package/src/components/tools/item/placement-strategies.ts +11 -10
- package/src/components/tools/item/shelf-surface-strategy-resolver.test.ts +56 -56
- package/src/components/tools/item/use-draft-node.test.tsx +432 -1
- package/src/components/tools/item/use-draft-node.ts +166 -95
- package/src/components/tools/item/use-placement-coordinator.tsx +148 -95
- package/src/components/tools/paint-region/use-paint-tint.ts +37 -0
- package/src/components/tools/paint-region/wall-paint-region-tool.tsx +466 -0
- package/src/components/tools/registry/item-surface-move.test.ts +62 -63
- package/src/components/tools/registry/item-surface-move.ts +2 -0
- package/src/components/tools/registry/item-surface-resolver.test.ts +26 -26
- package/src/components/tools/registry/move-registry-node-tool.test.ts +268 -1
- package/src/components/tools/registry/move-registry-node-tool.tsx +66 -30
- package/src/components/tools/select/box-select-tool.tsx +2 -12
- package/src/components/tools/select/plane-box-select-tool.test.tsx +79 -0
- package/src/components/tools/select/plane-box-select-tool.tsx +35 -22
- package/src/components/tools/select/select-candidates.test.ts +37 -4
- package/src/components/tools/select/select-candidates.ts +15 -11
- package/src/components/tools/shared/cursor-sphere.tsx +36 -12
- package/src/components/tools/site/site-boundary-editor.tsx +1 -2
- package/src/components/tools/tool-manager.tsx +59 -24
- package/src/components/tools/wall/wall-drafting.test.ts +175 -47
- package/src/components/tools/zone/zone-tool.tsx +4 -12
- package/src/components/ui/action-menu/action-button.tsx +9 -1
- package/src/components/ui/action-menu/camera-actions.tsx +9 -4
- package/src/components/ui/action-menu/control-modes.tsx +15 -42
- package/src/components/ui/action-menu/follow-pascal-pill.tsx +32 -0
- package/src/components/ui/action-menu/follow-pascal-toggle.tsx +36 -0
- package/src/components/ui/action-menu/index.tsx +56 -33
- package/src/components/ui/action-menu/measurement-control.tsx +14 -19
- package/src/components/ui/action-menu/placement.ts +20 -0
- package/src/components/ui/action-menu/point-ask-button.tsx +52 -0
- package/src/components/ui/action-menu/view-toggles.tsx +47 -42
- package/src/components/ui/build-panel/build-panel.tsx +242 -0
- package/src/components/ui/command-palette/editor-commands.tsx +7 -42
- package/src/components/ui/command-palette/index.tsx +50 -39
- package/src/components/ui/command-palette/ranked-groups.test.ts +31 -0
- package/src/components/ui/controls/action-button.tsx +5 -2
- package/src/components/ui/controls/finish-swatch.tsx +110 -0
- package/src/components/ui/controls/material-paint-panel.tsx +97 -26
- package/src/components/ui/controls/material-picker.tsx +4 -1
- package/src/components/ui/controls/metric-control.tsx +1 -1
- package/src/components/ui/controls/scene-material-list.tsx +4 -32
- package/src/components/ui/controls/segmented-control.tsx +21 -8
- package/src/components/ui/controls/select-control.tsx +65 -0
- package/src/components/ui/controls/slider-control.tsx +1 -1
- package/src/components/ui/controls/toggle-control.tsx +3 -3
- package/src/components/ui/controls/tool-options-panel.tsx +1 -1
- package/src/components/ui/floating-level-selector.tsx +159 -59
- package/src/components/ui/helpers/building-helper.tsx +4 -1
- package/src/components/ui/helpers/contextual-helper-panel.tsx +181 -72
- package/src/components/ui/helpers/helper-manager.test.tsx +121 -0
- package/src/components/ui/helpers/helper-manager.tsx +331 -14
- package/src/components/ui/helpers/item-helper.tsx +17 -1
- package/src/components/ui/helpers/registered-tool-helper.tsx +8 -1
- package/src/components/ui/icon-ref.tsx +45 -1
- package/src/components/ui/level-duplicate-dialog.tsx +1 -1
- package/src/components/ui/node-icon-image.tsx +16 -0
- package/src/components/ui/panels/collections/collections-popover.tsx +28 -22
- package/src/components/ui/panels/floor-foundation-panel.tsx +551 -0
- package/src/components/ui/panels/floor-opening-panel.tsx +143 -0
- package/src/components/ui/panels/mobile-panel-sheet.tsx +4 -4
- package/src/components/ui/panels/mobile-selection-bar.tsx +8 -5
- package/src/components/ui/panels/multi-field-value.test.ts +26 -3
- package/src/components/ui/panels/multi-field-value.ts +6 -3
- package/src/components/ui/panels/multi-parametric-inspector.tsx +52 -2
- package/src/components/ui/panels/multi-selection-panel.tsx +161 -5
- package/src/components/ui/panels/node-display.ts +8 -3
- package/src/components/ui/panels/panel-manager.tsx +103 -68
- package/src/components/ui/panels/panel-wrapper.tsx +130 -62
- package/src/components/ui/panels/parametric-field-control.tsx +3 -3
- package/src/components/ui/panels/parametric-inspector.tsx +7 -7
- package/src/components/ui/panels/reference-panel.tsx +2 -3
- package/src/components/ui/panels/room-construction-rows.tsx +774 -0
- package/src/components/ui/panels/room-name-options.test.ts +55 -0
- package/src/components/ui/panels/room-name-options.ts +47 -0
- package/src/components/ui/panels/room-openings-field.tsx +110 -0
- package/src/components/ui/panels/room-panel.tsx +790 -0
- package/src/components/ui/panels/shape-choice.tsx +58 -0
- package/src/components/ui/panels/wall-region-list.tsx +109 -0
- package/src/components/ui/primitives/badge.tsx +8 -0
- package/src/components/ui/primitives/color-dot.tsx +36 -24
- package/src/components/ui/primitives/sidebar.tsx +3 -1
- package/src/components/ui/right-stack.test.ts +29 -0
- package/src/components/ui/right-stack.tsx +164 -0
- package/src/components/ui/sidebar/app-sidebar.tsx +1 -1
- package/src/components/ui/sidebar/icon-rail.tsx +8 -3
- package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +1 -1
- package/src/components/ui/sidebar/panels/items-panel/index.tsx +6 -6
- package/src/components/ui/sidebar/panels/settings-panel/animation-speed-setting.tsx +40 -0
- package/src/components/ui/sidebar/panels/settings-panel/audio-settings-dialog.tsx +7 -8
- package/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.test.tsx +170 -0
- package/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.tsx +92 -0
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +138 -27
- package/src/components/ui/sidebar/panels/settings-panel/interface-theme.test.tsx +20 -0
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +5 -5
- package/src/components/ui/sidebar/panels/settings-panel/print-export-button.tsx +4 -10
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +3 -11
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +4 -4
- package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +197 -0
- package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +24 -11
- package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +181 -223
- package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +30 -8
- package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +4 -1
- package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +1 -4
- package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +1 -3
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +21 -13
- package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +13 -37
- package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +2 -3
- package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +1 -5
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +9 -4
- package/src/components/ui/sidebar/panels/zone-panel/index.tsx +2 -4
- package/src/components/ui/sidebar/tab-bar.tsx +14 -4
- package/src/components/ui/sidebar/use-plugin-panels.tsx +15 -5
- package/src/components/viewer/floorplan-compass-button.tsx +9 -1
- package/src/components/viewer/floorplan-preview.tsx +5 -6
- package/src/components/viewer/viewer-controls-bar.tsx +18 -6
- package/src/components/viewer/viewer-hover-label.tsx +34 -0
- package/src/components/viewer/viewer-rooms.tsx +191 -0
- package/src/components/viewer/viewer-scene-header.tsx +181 -145
- package/src/components/viewer/viewer-selection-manager.tsx +124 -0
- package/src/components/viewer/viewer-stage.tsx +2 -2
- package/src/components/viewer-zone-system.tsx +3 -8
- package/src/hooks/use-auto-save.integration.test.tsx +215 -43
- package/src/hooks/use-auto-save.ts +60 -9
- package/src/hooks/use-ceiling-events.test.ts +123 -118
- package/src/hooks/use-grid-events.test.ts +105 -105
- package/src/hooks/use-keyboard.test.ts +243 -19
- package/src/hooks/use-keyboard.ts +118 -83
- package/src/hooks/use-open-wall-ends.test.ts +99 -0
- package/src/hooks/use-open-wall-ends.ts +238 -0
- package/src/hooks/use-placement-notice.test.ts +71 -0
- package/src/hooks/use-placement-notice.ts +73 -0
- package/src/hooks/use-selected-room.ts +143 -0
- package/src/index.tsx +312 -58
- package/src/lib/__fixtures__/owner-victor-seattle-parking.json +1 -0
- package/src/lib/__fixtures__/owner-villa-aurelia-basement.json +1 -0
- package/src/lib/add-storey.test.ts +177 -0
- package/src/lib/add-storey.ts +59 -0
- package/src/lib/below-grade.test.tsx +171 -0
- package/src/lib/below-grade.ts +133 -0
- package/src/lib/camera-facing.test.ts +24 -0
- package/src/lib/camera-facing.ts +24 -0
- package/src/lib/ceiling-edit-session.test.ts +321 -0
- package/src/lib/ceiling-edit-session.ts +206 -0
- package/src/lib/ceiling-region-session.test.ts +179 -0
- package/src/lib/continuation.test.ts +19 -1
- package/src/lib/continuation.ts +25 -4
- package/src/lib/direct-manipulation.ts +2 -0
- package/src/lib/door-interaction.ts +14 -0
- package/src/lib/download-project-file.ts +17 -0
- package/src/lib/editor-level-display.test.ts +96 -0
- package/src/lib/editor-level-display.ts +55 -0
- package/src/lib/editor-views.ts +178 -0
- package/src/lib/export-geometry-wait.test.ts +90 -0
- package/src/lib/export-texture-utils.ts +2 -4
- package/src/lib/floor-edit-session.ts +153 -0
- package/src/lib/floor-footprints.test.ts +563 -0
- package/src/lib/floor-footprints.ts +395 -0
- package/src/lib/floor-foundation-support.test.ts +284 -0
- package/src/lib/floor-opening-draft.ts +218 -0
- package/src/lib/floor-openings.test.ts +216 -0
- package/src/lib/floor-region-geometry.ts +191 -0
- package/src/lib/floor-region-session.test.ts +485 -0
- package/src/lib/floor-region-session.ts +589 -0
- package/src/lib/floor-region-snap.ts +101 -0
- package/src/lib/floor-step-hover.test.ts +32 -0
- package/src/lib/floorplan/annotation-visibility.ts +17 -0
- package/src/lib/floorplan/dimension-drive.test.ts +360 -0
- package/src/lib/floorplan/dimension-drive.ts +479 -0
- package/src/lib/floorplan/floorplan-export.test.ts +12 -8
- package/src/lib/floorplan/floorplan-export.tsx +32 -8
- package/src/lib/floorplan/floorplan-extension.ts +32 -0
- package/src/lib/floorplan/floorplan-mode.test.ts +4 -0
- package/src/lib/floorplan/floorplan-mode.ts +2 -0
- package/src/lib/floorplan/floorplan-pdfkit-document.ts +363 -27
- package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +177 -8
- package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +60 -25
- package/src/lib/floorplan/floorplan-plugin-install.test.tsx +138 -0
- package/src/lib/floorplan/floorplan-readonly.ts +6 -0
- package/src/lib/floorplan/geometry.ts +13 -6
- package/src/lib/floorplan/index.ts +0 -9
- package/src/lib/floorplan/items.ts +5 -2
- package/src/lib/floorplan/marks.test.ts +213 -0
- package/src/lib/floorplan/marks.ts +238 -0
- package/src/lib/floorplan/open-wall-ends.test.ts +268 -0
- package/src/lib/floorplan/open-wall-ends.ts +162 -0
- package/src/lib/floorplan/pdf-fonts/GeistMono-Bold.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/GeistMono-Regular.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/LICENSE-GeistMono.txt +92 -0
- package/src/lib/floorplan/pdf-fonts/LICENSE-LiberationSans.txt +102 -0
- package/src/lib/floorplan/pdf-fonts/LiberationSans-Bold.ttf +0 -0
- package/src/lib/floorplan/pdf-fonts/LiberationSans-Regular.ttf +0 -0
- package/src/lib/floorplan/pdfkit-standard-fonts.d.ts +5 -0
- package/src/lib/floorplan/schedules.test.ts +189 -0
- package/src/lib/floorplan/schedules.ts +339 -0
- package/src/lib/floorplan/sheet-export.test.ts +124 -0
- package/src/lib/floorplan/sheet-export.ts +318 -0
- package/src/lib/floorplan/site-plan/build-site-plan-drawing.ts +768 -0
- package/src/lib/floorplan/site-plan/contours.test.ts +43 -0
- package/src/lib/floorplan/site-plan/contributors.ts +97 -0
- package/src/lib/floorplan/site-plan/coverage.ts +230 -0
- package/src/lib/floorplan/site-plan/drawing-type-switch.test.ts +15 -0
- package/src/lib/floorplan/site-plan/drawing-type-switch.tsx +86 -0
- package/src/lib/floorplan/site-plan/front-edge.test.ts +103 -0
- package/src/lib/floorplan/site-plan/front-edge.ts +157 -0
- package/src/lib/floorplan/site-plan/geometry.test.ts +269 -0
- package/src/lib/floorplan/site-plan/geometry.ts +142 -0
- package/src/lib/floorplan/site-plan/index.ts +55 -0
- package/src/lib/floorplan/site-plan/site-annotations.test.ts +483 -0
- package/src/lib/floorplan/site-plan/site-annotations.ts +1084 -0
- package/src/lib/floorplan/site-plan/site-parts.ts +287 -0
- package/src/lib/floorplan/site-plan/site-plan-layer.tsx +138 -0
- package/src/lib/floorplan/site-plan/street-name.test.ts +69 -0
- package/src/lib/floorplan/site-plan/street-name.ts +302 -0
- package/src/lib/floorplan/site-plan/yards.test.ts +70 -0
- package/src/lib/floorplan/types.ts +1 -27
- package/src/lib/follow-pascal-exterior.test-fixture.ts +17 -0
- package/src/lib/follow-pascal-exterior.test.ts +171 -0
- package/src/lib/follow-pascal-exterior.ts +39 -0
- package/src/lib/follow-pascal-presentation.test.ts +203 -0
- package/src/lib/follow-pascal-presentation.ts +129 -0
- package/src/lib/follow-pascal-sight.ts +84 -0
- package/src/lib/follow-pascal-targets.test.ts +406 -0
- package/src/lib/follow-pascal-targets.ts +198 -0
- package/src/lib/follow-pascal.test.ts +350 -0
- package/src/lib/follow-pascal.ts +284 -0
- package/src/lib/fresh-planar-placement.test.ts +148 -0
- package/src/lib/fresh-planar-placement.ts +114 -37
- package/src/lib/geometry-script/author.ts +157 -0
- package/src/lib/geometry-script/client.ts +159 -0
- package/src/lib/geometry-script/finish-scripts.ts +127 -0
- package/src/lib/geometry-script/protocol.ts +13 -0
- package/src/lib/gesture-lifecycle.test.ts +595 -0
- package/src/lib/gesture-lifecycle.ts +290 -0
- package/src/lib/glb-export-zone-holes.test.ts +41 -0
- package/src/lib/glb-export.test.ts +636 -126
- package/src/lib/glb-export.ts +241 -120
- package/src/lib/history.test.ts +18 -7
- package/src/lib/history.ts +7 -0
- package/src/lib/hud-title.ts +109 -0
- package/src/lib/hydration-gated-storage.ts +49 -0
- package/src/lib/ifc-export.test.ts +174 -0
- package/src/lib/ifc-export.ts +201 -0
- package/src/lib/ifc-parts.ts +15 -0
- package/src/lib/inspector-expanded.test.ts +44 -0
- package/src/lib/inspector-expanded.ts +36 -0
- package/src/lib/interaction/scope.ts +22 -0
- package/src/lib/keyboard-pan.test.ts +129 -7
- package/src/lib/keyboard-pan.ts +161 -12
- package/src/lib/level-selection.test.ts +57 -0
- package/src/lib/level-selection.ts +16 -1
- package/src/lib/live-gesture-round-trip.test.ts +360 -0
- package/src/lib/lot/__fixtures__/map-dossier-miami-shores.json +1 -0
- package/src/lib/lot/__fixtures__/map-dossier-stpete.json +1 -0
- package/src/lib/lot/clean-ring.test.ts +187 -0
- package/src/lib/lot/clean-ring.ts +217 -0
- package/src/lib/lot/dossier.test.ts +202 -0
- package/src/lib/lot/dossier.ts +498 -0
- package/src/lib/lot/drop-in.test.ts +326 -0
- package/src/lib/lot/drop-in.ts +392 -0
- package/src/lib/lot/index.ts +43 -0
- package/src/lib/lot/lot-patch.test.ts +340 -0
- package/src/lib/lot/lot-patch.ts +394 -0
- package/src/lib/lot/parcel-provider.ts +43 -0
- package/src/lib/lot/terrain.test.ts +161 -0
- package/src/lib/lot/terrain.ts +266 -0
- package/src/lib/material-catalog-model.ts +3 -1
- package/src/lib/material-paint-panel-model.ts +9 -5
- package/src/lib/material-paint.ts +4 -0
- package/src/lib/measurement-kind.test.ts +6 -8
- package/src/lib/measurements.test.ts +23 -0
- package/src/lib/mezzanine-actions.test.ts +342 -0
- package/src/lib/mezzanine-draft.test.ts +501 -0
- package/src/lib/mezzanine-draft.ts +278 -0
- package/src/lib/mezzanine-messages.ts +26 -0
- package/src/lib/mezzanine-selection.test.ts +207 -0
- package/src/lib/mezzanine-stairs.ts +46 -0
- package/src/lib/model-export.ts +3 -1
- package/src/lib/node-action-movement.ts +17 -6
- package/src/lib/node-display-label.ts +37 -0
- package/src/lib/orbit-floor-clearance.test.ts +201 -0
- package/src/lib/orbit-floor-clearance.ts +154 -0
- package/src/lib/paint-commit-route.test.ts +37 -0
- package/src/lib/paint-commit-route.ts +17 -0
- package/src/lib/paint-eyedropper.test.tsx +165 -0
- package/src/lib/paint-eyedropper.ts +99 -0
- package/src/lib/paint-pass-through.test.ts +122 -0
- package/src/lib/paint-pass-through.ts +78 -0
- package/src/lib/paint-region-hover.ts +25 -0
- package/src/lib/paint-region-mode.ts +154 -0
- package/src/lib/paint-regions.test.ts +166 -0
- package/src/lib/paint-regions.ts +192 -0
- package/src/lib/paint-scope.test.ts +317 -35
- package/src/lib/paint-scope.ts +267 -25
- package/src/lib/panel-rows.ts +21 -0
- package/src/lib/parametric-node-update.ts +16 -7
- package/src/lib/plate-paint-affected.test.ts +300 -0
- package/src/lib/plate-paint-affected.ts +177 -0
- package/src/lib/plugin-chat.ts +65 -0
- package/src/lib/plugin-panels.test.ts +25 -0
- package/src/lib/plugin-panels.ts +94 -0
- package/src/lib/point-ask/__fixtures__/consumer-browser.tsx +76 -0
- package/src/lib/point-ask/__fixtures__/house.ts +81 -0
- package/src/lib/point-ask/ask-created.test.ts +195 -0
- package/src/lib/point-ask/ask-flow.test.ts +380 -0
- package/src/lib/point-ask/build-context.test.ts +173 -0
- package/src/lib/point-ask/build-context.ts +94 -0
- package/src/lib/point-ask/capture-crop.ts +129 -0
- package/src/lib/point-ask/choreography.ts +69 -0
- package/src/lib/point-ask/compare.test.ts +145 -0
- package/src/lib/point-ask/compare.ts +73 -0
- package/src/lib/point-ask/describe-target.test.ts +165 -0
- package/src/lib/point-ask/describe-target.ts +234 -0
- package/src/lib/point-ask/dictation.ts +79 -0
- package/src/lib/point-ask/edge-marker.test.ts +61 -0
- package/src/lib/point-ask/edge-marker.ts +27 -0
- package/src/lib/point-ask/frame-loop.ts +25 -0
- package/src/lib/point-ask/history-marks.test.ts +94 -0
- package/src/lib/point-ask/history-marks.ts +39 -0
- package/src/lib/point-ask/host-api.ts +32 -0
- package/src/lib/point-ask/outline-box.test.ts +30 -0
- package/src/lib/point-ask/outline-box.ts +11 -0
- package/src/lib/point-ask/overlay-metrics.ts +6 -0
- package/src/lib/point-ask/pick.test.ts +220 -0
- package/src/lib/point-ask/pick.ts +121 -0
- package/src/lib/point-ask/pin-machine.test.ts +494 -0
- package/src/lib/point-ask/pin-machine.ts +217 -0
- package/src/lib/point-ask/placement.test.ts +203 -0
- package/src/lib/point-ask/placement.ts +141 -0
- package/src/lib/point-ask/pointer-tracker.ts +34 -0
- package/src/lib/point-ask/projector.ts +83 -0
- package/src/lib/point-ask/region.test.ts +157 -0
- package/src/lib/point-ask/region.ts +136 -0
- package/src/lib/point-ask/retry.test.ts +217 -0
- package/src/lib/point-ask/retry.ts +37 -0
- package/src/lib/point-ask/scene-commit.test.ts +312 -0
- package/src/lib/point-ask/scene-commit.ts +32 -0
- package/src/lib/point-ask/session.ts +1391 -0
- package/src/lib/point-ask/spring-keyframes.test.ts +45 -0
- package/src/lib/point-ask/spring-keyframes.ts +38 -0
- package/src/lib/point-ask/spring.test.ts +63 -0
- package/src/lib/point-ask/spring.ts +107 -0
- package/src/lib/point-ask/suggestions.test.ts +80 -0
- package/src/lib/point-ask/suggestions.ts +125 -0
- package/src/lib/point-ask/target-scope.test.ts +622 -0
- package/src/lib/point-ask/target-scope.ts +338 -0
- package/src/lib/point-ask/types.ts +48 -0
- package/src/lib/portable-export.test.ts +34 -1
- package/src/lib/portable-export.ts +119 -53
- package/src/lib/print-feature-thickness.ts +10 -1
- package/src/lib/print-roof-solids.test.ts +39 -1
- package/src/lib/print-roof-solids.ts +43 -10
- package/src/lib/print-shell-compiler-manifold-core.ts +1 -1
- package/src/lib/print-shell-compiler.ts +1 -0
- package/src/lib/registered-draft-snap.ts +12 -0
- package/src/lib/roof-duplication.ts +10 -2
- package/src/lib/room-assembly-overlay.test.ts +275 -0
- package/src/lib/room-assembly-overlay.ts +265 -0
- package/src/lib/room-built-on.test.ts +379 -0
- package/src/lib/room-built-on.ts +138 -0
- package/src/lib/room-construction-commands.ts +712 -0
- package/src/lib/room-construction.test.ts +746 -0
- package/src/lib/room-construction.ts +385 -0
- package/src/lib/room-controls-phase6.test.ts +630 -0
- package/src/lib/room-divide-session.ts +523 -0
- package/src/lib/room-handle-drag.ts +1068 -0
- package/src/lib/room-name-catalog.test.ts +90 -0
- package/src/lib/room-name-catalog.ts +168 -0
- package/src/lib/room-push-dimensions.test.ts +311 -0
- package/src/lib/room-push-dimensions.ts +251 -0
- package/src/lib/room-selection-commands.ts +62 -0
- package/src/lib/room-selection.test.ts +1017 -0
- package/src/lib/room-selection.ts +417 -0
- package/src/lib/room-structure-commands.ts +94 -0
- package/src/lib/room-structure.test.ts +921 -0
- package/src/lib/room-transform-session.ts +570 -0
- package/src/lib/room-zone-routing.test.ts +294 -0
- package/src/lib/room-zone-routing.ts +197 -0
- package/src/lib/scene-clipboard.test.ts +610 -1
- package/src/lib/scene-clipboard.ts +269 -58
- package/src/lib/scene-material-refs.test.ts +79 -0
- package/src/lib/scene-material-refs.ts +79 -0
- package/src/lib/scene.test.ts +24 -36
- package/src/lib/scene.ts +33 -57
- package/src/lib/selection-routing.test.ts +129 -45
- package/src/lib/selection-routing.ts +54 -75
- package/src/lib/session-writes.test.ts +120 -0
- package/src/lib/session-writes.ts +205 -0
- package/src/lib/sfx-bus.ts +13 -0
- package/src/lib/sfx-player.test.ts +70 -9
- package/src/lib/sfx-player.ts +6 -0
- package/src/lib/sidebar-panel.ts +62 -0
- package/src/lib/site-boundary.test.ts +4 -6
- package/src/lib/site-boundary.ts +1 -1
- package/src/lib/snapping-mode.test.ts +4 -0
- package/src/lib/snapping-mode.ts +8 -1
- package/src/lib/stair-levels.test.ts +25 -0
- package/src/lib/stair-levels.ts +22 -3
- package/src/lib/terrace-draft.test.ts +145 -0
- package/src/lib/terrace-draft.ts +214 -0
- package/src/lib/tool-cursor-icon.test.ts +16 -0
- package/src/lib/tool-cursor-icon.ts +11 -0
- package/src/lib/typing-target.ts +9 -0
- package/src/lib/units.ts +77 -39
- package/src/lib/vector-edges.test.ts +58 -0
- package/src/lib/vector-edges.ts +400 -0
- package/src/lib/viewer-selection.test.ts +577 -0
- package/src/lib/viewer-selection.ts +580 -0
- package/src/lib/wall-draw-variant.test.ts +71 -0
- package/src/lib/wall-draw-variant.ts +91 -0
- package/src/lib/wall-paint-region-session.ts +246 -0
- package/src/lib/wall-paint-region.test.ts +373 -0
- package/src/lib/wall-placement-pointer.test.ts +42 -0
- package/src/lib/wall-placement-pointer.ts +57 -0
- package/src/lib/wall-polygon-draft.test.ts +262 -0
- package/src/lib/wall-polygon-draft.ts +286 -0
- package/src/lib/wall-push.test.ts +453 -0
- package/src/lib/wall-region-face.ts +352 -0
- package/src/lib/wall-region-handles.test.ts +304 -0
- package/src/lib/wall-region-handles.ts +368 -0
- package/src/lib/wall-region-list.test.ts +119 -0
- package/src/lib/wall-region-list.ts +136 -0
- package/src/lib/wall-region-snap.ts +110 -0
- package/src/lib/window-changes.ts +35 -0
- package/src/lib/window-interaction.ts +14 -0
- package/src/lib/zone-content.ts +4 -1
- package/src/lib/zone-name.test.ts +17 -0
- package/src/lib/zone-name.ts +17 -0
- package/src/store/opens-in-select-mode.test.ts +223 -0
- package/src/store/paint-mode.test.ts +188 -0
- package/src/store/terrain-sculpt-mode.test.ts +19 -21
- package/src/store/tool-mode.test.ts +137 -6
- package/src/store/use-audio.test.ts +146 -0
- package/src/store/use-audio.tsx +127 -3
- package/src/store/use-construction-reveal.test.ts +173 -0
- package/src/store/use-construction-reveal.ts +145 -0
- package/src/store/use-corner-snap-hint.test.ts +24 -0
- package/src/store/use-corner-snap-hint.ts +47 -0
- package/src/store/use-delete-confirmation.ts +28 -1
- package/src/store/use-drawing-view.test.ts +24 -3
- package/src/store/use-drawing-view.ts +29 -1
- package/src/store/use-editor.tsx +432 -321
- package/src/store/use-floorplan-draft-preview.ts +13 -0
- package/src/store/use-floorplan-marquee.ts +12 -2
- package/src/store/use-follow-pascal.test.ts +62 -0
- package/src/store/use-follow-pascal.ts +53 -0
- package/src/store/use-point-ask.ts +247 -0
- package/src/store/use-quick-measurement-hud.ts +3 -3
- package/src/store/use-stair-build-preview.ts +33 -5
- package/src/store/use-wall-move-ghosts.ts +4 -2
- package/src/store/use-wall-region-handles-selection.test.ts +222 -0
- package/src/store/use-wall-region-handles-selection.ts +139 -0
- package/src/store/view-layout.test.ts +201 -0
- package/src/store/view-layout.ts +199 -0
- package/src/test-utils/immediate-animation-frames.ts +16 -0
- package/src/test-utils/live-gesture-round-trip.ts +224 -0
- package/src/test-utils/render-current-markup.tsx +16 -0
- package/src/test-utils/selection-harness.ts +82 -0
- package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +0 -499
- package/src/components/systems/zone/zone-label-editor-system.tsx +0 -333
- package/src/components/tools/fence/fence-drafting.test.ts +0 -100
- package/src/components/tools/fence/fence-drafting.ts +0 -266
- package/src/components/tools/stair/stair-click-guard.test.ts +0 -58
- package/src/components/tools/stair/stair-click-guard.ts +0 -72
- package/src/components/tools/stair/stair-defaults.ts +0 -18
- package/src/components/tools/stair/stair-tool.tsx +0 -634
- package/src/components/ui/sidebar/panels/plugins-panel.tsx +0 -218
- package/src/components/viewer/viewer-units-panel.tsx +0 -116
- package/src/lib/floorplan/stairs.ts +0 -489
- package/src/lib/level-duplication.test.ts +0 -144
- package/src/lib/level-duplication.ts +0 -195
|
@@ -2,10 +2,9 @@ import {
|
|
|
2
2
|
type AnyNode,
|
|
3
3
|
type AnyNodeId,
|
|
4
4
|
type BuildingNode,
|
|
5
|
-
DEFAULT_LEVEL_HEIGHT,
|
|
6
5
|
emitter,
|
|
7
6
|
type GuideNode,
|
|
8
|
-
LevelNode,
|
|
7
|
+
type LevelNode,
|
|
9
8
|
type ScanNode,
|
|
10
9
|
type SiteNode,
|
|
11
10
|
useScene,
|
|
@@ -19,7 +18,9 @@ import {
|
|
|
19
18
|
Copy,
|
|
20
19
|
Eye,
|
|
21
20
|
EyeOff,
|
|
21
|
+
Boxes,
|
|
22
22
|
Group,
|
|
23
|
+
LayoutGrid,
|
|
23
24
|
Loader2,
|
|
24
25
|
MoreHorizontal,
|
|
25
26
|
Pencil,
|
|
@@ -29,7 +30,18 @@ import {
|
|
|
29
30
|
X,
|
|
30
31
|
} from 'lucide-react'
|
|
31
32
|
import { AnimatePresence, LayoutGroup, motion } from 'motion/react'
|
|
32
|
-
import { memo, useEffect, useRef, useState, useSyncExternalStore } from 'react'
|
|
33
|
+
import { type ComponentType, lazy, memo, Suspense, useEffect, useRef, useState, useSyncExternalStore } from 'react'
|
|
34
|
+
import { nodeRegistry } from '@pascal-app/core'
|
|
35
|
+
|
|
36
|
+
/** The site kind's inspector (`parametrics.customPanel`), mounted under the Site header. */
|
|
37
|
+
const SiteKindPanel = lazy(async () => {
|
|
38
|
+
const def = nodeRegistry.get('site') as
|
|
39
|
+
| { parametrics?: { customPanel?: () => Promise<{ default: ComponentType }> } }
|
|
40
|
+
| undefined
|
|
41
|
+
const loader = def?.parametrics?.customPanel
|
|
42
|
+
if (!loader) return { default: () => null }
|
|
43
|
+
return loader()
|
|
44
|
+
})
|
|
33
45
|
import { useShallow } from 'zustand/react/shallow'
|
|
34
46
|
import { ColorDot } from './../../../../../components/ui/primitives/color-dot'
|
|
35
47
|
import {
|
|
@@ -40,8 +52,9 @@ import {
|
|
|
40
52
|
import {
|
|
41
53
|
buildLevelDuplicateCreateOps,
|
|
42
54
|
type LevelDuplicatePreset,
|
|
43
|
-
} from '
|
|
44
|
-
import { getDefaultLevelName } from '@pascal-app/core'
|
|
55
|
+
} from '@pascal-app/core/building'
|
|
56
|
+
import { getDefaultLevelName, getLevelDisplayName } from '@pascal-app/core'
|
|
57
|
+
import { addStoreyOnTop } from './../../../../../lib/add-storey'
|
|
45
58
|
import { deleteLevelWithFallbackSelection } from './../../../../../lib/level-selection'
|
|
46
59
|
import {
|
|
47
60
|
formatAreaLabel,
|
|
@@ -53,12 +66,19 @@ import {
|
|
|
53
66
|
} from './../../../../../lib/measurements'
|
|
54
67
|
import { createLocalGuideImage, createLocalScan } from './../../../../../lib/local-guide-image'
|
|
55
68
|
import { editorHostTreeChildrenRegistry } from './../../../../../lib/host-tree-children'
|
|
69
|
+
import { requestRoomDeletion } from './../../../../../lib/room-structure-commands'
|
|
70
|
+
import {
|
|
71
|
+
selectZoneOrRoom,
|
|
72
|
+
useZoneSelected,
|
|
73
|
+
zoneKindLabel,
|
|
74
|
+
} from './../../../../../lib/room-zone-routing'
|
|
56
75
|
import { createUnitInBuilding, toggleZoneMembership } from './../../../../../lib/units'
|
|
57
76
|
import { cn } from './../../../../../lib/utils'
|
|
58
77
|
import useEditor from './../../../../../store/use-editor'
|
|
59
78
|
import { useUploadStore } from '../../../../../store/use-upload'
|
|
60
79
|
import { MetricControl } from '../../../controls/metric-control'
|
|
61
80
|
import { LevelDuplicateDialog } from '../../../level-duplicate-dialog'
|
|
81
|
+
import { CollectionsSection } from './collection-tree-node'
|
|
62
82
|
import { InlineRenameInput } from './inline-rename-input'
|
|
63
83
|
import { ZoneMembershipCheckbox } from './zone-membership-checkbox'
|
|
64
84
|
import { focusTreeNode, TreeNode, TreeNodeWrapper } from './tree-node'
|
|
@@ -180,7 +200,7 @@ const PropertyLineSection = memo(function PropertyLineSection() {
|
|
|
180
200
|
className={cn(
|
|
181
201
|
'flex h-6 w-6 cursor-pointer items-center justify-center rounded transition-colors',
|
|
182
202
|
isEditing
|
|
183
|
-
? 'bg-orange-500/20 text-orange-400'
|
|
203
|
+
? 'bg-orange-500/20 text-orange-700 dark:text-orange-400'
|
|
184
204
|
: 'text-muted-foreground hover:bg-accent',
|
|
185
205
|
)}
|
|
186
206
|
onClick={handleToggleEdit}
|
|
@@ -236,7 +256,7 @@ const PropertyLineSection = memo(function PropertyLineSection() {
|
|
|
236
256
|
className={cn(
|
|
237
257
|
'flex h-5 w-5 shrink-0 cursor-pointer items-center justify-center rounded',
|
|
238
258
|
points.length > 3
|
|
239
|
-
? 'text-muted-foreground hover:bg-red-500/20 hover:text-red-400'
|
|
259
|
+
? 'text-muted-foreground hover:bg-red-500/20 hover:text-red-600 dark:hover:text-red-400'
|
|
240
260
|
: 'cursor-not-allowed text-muted-foreground/30',
|
|
241
261
|
)}
|
|
242
262
|
disabled={points.length <= 3}
|
|
@@ -719,8 +739,7 @@ const LevelItem = memo(function LevelItem({
|
|
|
719
739
|
const [cameraPopoverOpen, setCameraPopoverOpen] = useState(false)
|
|
720
740
|
const [duplicateDialogOpen, setDuplicateDialogOpen] = useState(false)
|
|
721
741
|
const [isEditing, setIsEditing] = useState(false)
|
|
722
|
-
const
|
|
723
|
-
const updateNodes = useScene((s) => s.updateNodes)
|
|
742
|
+
const applyNodeChanges = useScene((s) => s.applyNodeChanges)
|
|
724
743
|
const itemRef = useRef<HTMLDivElement>(null)
|
|
725
744
|
const isSelected = selectedLevelId === level.id
|
|
726
745
|
const canDeleteLevel = level.level !== 0
|
|
@@ -754,22 +773,14 @@ const LevelItem = memo(function LevelItem({
|
|
|
754
773
|
}
|
|
755
774
|
|
|
756
775
|
const handleDuplicateLevel = (preset: LevelDuplicatePreset = 'everything') => {
|
|
757
|
-
const { createOps, newLevelId,
|
|
776
|
+
const { createOps, newLevelId, updateOps } = buildLevelDuplicateCreateOps({
|
|
758
777
|
nodes: useScene.getState().nodes,
|
|
759
778
|
level,
|
|
760
779
|
levels,
|
|
761
780
|
preset,
|
|
762
781
|
})
|
|
763
782
|
|
|
764
|
-
|
|
765
|
-
updateNodes(
|
|
766
|
-
shiftedLevels.map((shiftedLevel) => ({
|
|
767
|
-
id: shiftedLevel.id as AnyNodeId,
|
|
768
|
-
data: { level: shiftedLevel.level } as Partial<AnyNode>,
|
|
769
|
-
})),
|
|
770
|
-
)
|
|
771
|
-
}
|
|
772
|
-
createNodes(createOps)
|
|
783
|
+
applyNodeChanges({ create: createOps, update: updateOps })
|
|
773
784
|
selectLevel(newLevelId as LevelNode['id'], false)
|
|
774
785
|
setDuplicateDialogOpen(false)
|
|
775
786
|
}
|
|
@@ -838,6 +849,7 @@ const LevelItem = memo(function LevelItem({
|
|
|
838
849
|
/>
|
|
839
850
|
<InlineRenameInput
|
|
840
851
|
defaultName={getDefaultLevelName(level.level)}
|
|
852
|
+
displayName={getLevelDisplayName(level)}
|
|
841
853
|
isEditing={isEditing}
|
|
842
854
|
nodeId={level.id}
|
|
843
855
|
onStartEditing={() => setIsEditing(true)}
|
|
@@ -1002,7 +1014,6 @@ const LevelsSection = memo(function LevelsSection({
|
|
|
1002
1014
|
onUploadAsset?: (projectId: string, levelId: string, file: File, type: 'scan' | 'guide') => void
|
|
1003
1015
|
onDeleteAsset?: (projectId: string, url: string) => void
|
|
1004
1016
|
} = {}) {
|
|
1005
|
-
const createNode = useScene((state) => state.createNode)
|
|
1006
1017
|
const updateNode = useScene((state) => state.updateNode)
|
|
1007
1018
|
const selectedBuildingId = useViewer((state) => state.selection.buildingId)
|
|
1008
1019
|
const selectedLevelId = useViewer((state) => state.selection.levelId)
|
|
@@ -1025,13 +1036,7 @@ const LevelsSection = memo(function LevelsSection({
|
|
|
1025
1036
|
if (!building) return null
|
|
1026
1037
|
|
|
1027
1038
|
const handleAddLevel = () => {
|
|
1028
|
-
const newLevel =
|
|
1029
|
-
level: levels.length,
|
|
1030
|
-
height: DEFAULT_LEVEL_HEIGHT,
|
|
1031
|
-
children: [],
|
|
1032
|
-
parentId: building.id,
|
|
1033
|
-
})
|
|
1034
|
-
createNode(newLevel, building.id)
|
|
1039
|
+
const newLevel = addStoreyOnTop(building.id)
|
|
1035
1040
|
setSelection({ buildingId: building.id, levelId: newLevel.id })
|
|
1036
1041
|
}
|
|
1037
1042
|
|
|
@@ -1149,137 +1154,15 @@ const UnitsSection = memo(function UnitsSection({
|
|
|
1149
1154
|
)
|
|
1150
1155
|
})
|
|
1151
1156
|
|
|
1152
|
-
const
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
: phase === 'furnish'
|
|
1162
|
-
? 'furnish'
|
|
1163
|
-
: phase === 'structure' && structureLayer === 'zones'
|
|
1164
|
-
? 'zones'
|
|
1165
|
-
: 'none'
|
|
1166
|
-
|
|
1167
|
-
return (
|
|
1168
|
-
<div className="relative flex items-center gap-1 border-border/50 border-b bg-[#2C2C2E] p-1">
|
|
1169
|
-
<button
|
|
1170
|
-
className={cn(
|
|
1171
|
-
'relative flex flex-1 cursor-pointer flex-col items-center justify-center rounded-md py-2 font-medium text-[10px] transition-all duration-200',
|
|
1172
|
-
activeTab === 'structure'
|
|
1173
|
-
? 'text-foreground'
|
|
1174
|
-
: 'text-muted-foreground hover:bg-white/5 hover:text-foreground',
|
|
1175
|
-
)}
|
|
1176
|
-
onClick={() => {
|
|
1177
|
-
setPhase('structure')
|
|
1178
|
-
setStructureLayer('elements')
|
|
1179
|
-
}}
|
|
1180
|
-
>
|
|
1181
|
-
{activeTab === 'structure' && (
|
|
1182
|
-
<motion.div
|
|
1183
|
-
className="absolute inset-0 rounded-md bg-[#3e3e3e] shadow-sm ring-1 ring-border/50"
|
|
1184
|
-
layoutId="layerToggleActiveBg"
|
|
1185
|
-
transition={{ type: 'spring', bounce: 0.2, duration: 0.6 }}
|
|
1186
|
-
/>
|
|
1187
|
-
)}
|
|
1188
|
-
<div className="relative z-10 flex flex-col items-center">
|
|
1189
|
-
<img
|
|
1190
|
-
alt="Structure"
|
|
1191
|
-
className={cn(
|
|
1192
|
-
'mb-1 h-6 w-6 transition-all',
|
|
1193
|
-
activeTab !== 'structure' && 'opacity-50 grayscale',
|
|
1194
|
-
)}
|
|
1195
|
-
src="/icons/room.webp"
|
|
1196
|
-
/>
|
|
1197
|
-
Structure
|
|
1198
|
-
</div>
|
|
1199
|
-
<div className="absolute right-1.5 bottom-1 z-10 rounded border border-border/40 bg-background/40 px-1 py-[2px] backdrop-blur-md">
|
|
1200
|
-
<span className="block font-medium font-mono text-[9px] text-muted-foreground/70 leading-none">
|
|
1201
|
-
B
|
|
1202
|
-
</span>
|
|
1203
|
-
</div>
|
|
1204
|
-
</button>
|
|
1205
|
-
|
|
1206
|
-
<button
|
|
1207
|
-
className={cn(
|
|
1208
|
-
'relative flex flex-1 cursor-pointer flex-col items-center justify-center rounded-md py-2 font-medium text-[10px] transition-all duration-200',
|
|
1209
|
-
activeTab === 'furnish'
|
|
1210
|
-
? 'text-foreground'
|
|
1211
|
-
: 'text-muted-foreground hover:bg-white/5 hover:text-foreground',
|
|
1212
|
-
)}
|
|
1213
|
-
onClick={() => {
|
|
1214
|
-
setPhase('furnish')
|
|
1215
|
-
}}
|
|
1216
|
-
>
|
|
1217
|
-
{activeTab === 'furnish' && (
|
|
1218
|
-
<motion.div
|
|
1219
|
-
className="absolute inset-0 rounded-md bg-[#3e3e3e] shadow-sm ring-1 ring-border/50"
|
|
1220
|
-
layoutId="layerToggleActiveBg"
|
|
1221
|
-
transition={{ type: 'spring', bounce: 0.2, duration: 0.6 }}
|
|
1222
|
-
/>
|
|
1223
|
-
)}
|
|
1224
|
-
<div className="relative z-10 flex flex-col items-center">
|
|
1225
|
-
<img
|
|
1226
|
-
alt="Furnish"
|
|
1227
|
-
className={cn(
|
|
1228
|
-
'mb-1 h-6 w-6 transition-all',
|
|
1229
|
-
activeTab !== 'furnish' && 'opacity-50 grayscale',
|
|
1230
|
-
)}
|
|
1231
|
-
src="/icons/couch.webp"
|
|
1232
|
-
/>
|
|
1233
|
-
Furnish
|
|
1234
|
-
</div>
|
|
1235
|
-
<div className="absolute right-1.5 bottom-1 z-10 rounded border border-border/40 bg-background/40 px-1 py-[2px] backdrop-blur-md">
|
|
1236
|
-
<span className="block font-medium font-mono text-[9px] text-muted-foreground/70 leading-none">
|
|
1237
|
-
F
|
|
1238
|
-
</span>
|
|
1239
|
-
</div>
|
|
1240
|
-
</button>
|
|
1241
|
-
|
|
1242
|
-
<button
|
|
1243
|
-
className={cn(
|
|
1244
|
-
'relative flex flex-1 cursor-pointer flex-col items-center justify-center rounded-md py-2 font-medium text-[10px] transition-all duration-200',
|
|
1245
|
-
activeTab === 'zones'
|
|
1246
|
-
? 'text-foreground'
|
|
1247
|
-
: 'text-muted-foreground hover:bg-white/5 hover:text-foreground',
|
|
1248
|
-
)}
|
|
1249
|
-
onClick={() => {
|
|
1250
|
-
setPhase('structure')
|
|
1251
|
-
setStructureLayer('zones')
|
|
1252
|
-
}}
|
|
1253
|
-
>
|
|
1254
|
-
{activeTab === 'zones' && (
|
|
1255
|
-
<motion.div
|
|
1256
|
-
className="absolute inset-0 rounded-md bg-[#3e3e3e] shadow-sm ring-1 ring-border/50"
|
|
1257
|
-
layoutId="layerToggleActiveBg"
|
|
1258
|
-
transition={{ type: 'spring', bounce: 0.2, duration: 0.6 }}
|
|
1259
|
-
/>
|
|
1260
|
-
)}
|
|
1261
|
-
<div className="relative z-10 flex flex-col items-center">
|
|
1262
|
-
<img
|
|
1263
|
-
alt="Zones"
|
|
1264
|
-
className={cn(
|
|
1265
|
-
'mb-1 h-6 w-6 transition-all',
|
|
1266
|
-
activeTab !== 'zones' && 'opacity-50 grayscale',
|
|
1267
|
-
)}
|
|
1268
|
-
src="/icons/kitchen.webp"
|
|
1269
|
-
/>
|
|
1270
|
-
Zones
|
|
1271
|
-
</div>
|
|
1272
|
-
<div className="absolute right-1.5 bottom-1 z-10 rounded border border-border/40 bg-background/40 px-1 py-[2px] backdrop-blur-md">
|
|
1273
|
-
<span className="block font-medium font-mono text-[9px] text-muted-foreground/70 leading-none">
|
|
1274
|
-
Z
|
|
1275
|
-
</span>
|
|
1276
|
-
</div>
|
|
1277
|
-
</button>
|
|
1278
|
-
</div>
|
|
1279
|
-
)
|
|
1280
|
-
})
|
|
1281
|
-
|
|
1282
|
-
const ZoneItem = memo(function ZoneItem({ zone, isLast }: { zone: ZoneNode; isLast?: boolean }) {
|
|
1157
|
+
const ZoneItem = memo(function ZoneItem({
|
|
1158
|
+
zone,
|
|
1159
|
+
depth,
|
|
1160
|
+
isLast,
|
|
1161
|
+
}: {
|
|
1162
|
+
zone: ZoneNode
|
|
1163
|
+
depth: number
|
|
1164
|
+
isLast?: boolean
|
|
1165
|
+
}) {
|
|
1283
1166
|
const [isEditing, setIsEditing] = useState(false)
|
|
1284
1167
|
const [cameraPopoverOpen, setCameraPopoverOpen] = useState(false)
|
|
1285
1168
|
const deleteNode = useScene((state) => state.deleteNode)
|
|
@@ -1289,15 +1172,14 @@ const ZoneItem = memo(function ZoneItem({ zone, isLast }: { zone: ZoneNode; isLa
|
|
|
1289
1172
|
const unit = focusedUnitId ? s.nodes[focusedUnitId] : undefined
|
|
1290
1173
|
return unit?.type === 'unit' ? unit : null
|
|
1291
1174
|
})
|
|
1292
|
-
const selectedZoneId = useViewer((state) => state.selection.zoneId)
|
|
1293
1175
|
const hoveredId = useViewer((state) => state.hoveredId)
|
|
1294
1176
|
const setSelection = useViewer((state) => state.setSelection)
|
|
1295
1177
|
const setHoveredId = useViewer((state) => state.setHoveredId)
|
|
1296
|
-
const setPhase = useEditor((state) => state.setPhase)
|
|
1297
1178
|
const setMode = useEditor((state) => state.setMode)
|
|
1298
1179
|
const unit = useViewer((state) => state.unit)
|
|
1299
1180
|
|
|
1300
|
-
const isSelected =
|
|
1181
|
+
const isSelected = useZoneSelected(zone.id)
|
|
1182
|
+
const isRoom = zone.spaceRole === 'room'
|
|
1301
1183
|
const isHovered = hoveredId === zone.id
|
|
1302
1184
|
|
|
1303
1185
|
const itemRef = useRef<HTMLDivElement>(null)
|
|
@@ -1308,12 +1190,11 @@ const ZoneItem = memo(function ZoneItem({ zone, isLast }: { zone: ZoneNode; isLa
|
|
|
1308
1190
|
}
|
|
1309
1191
|
}, [isSelected])
|
|
1310
1192
|
|
|
1311
|
-
const defaultName =
|
|
1193
|
+
const defaultName = `${zoneKindLabel(zone)} (${formatAreaLabel(calculatePolygonArea(zone.polygon), unit)})`
|
|
1312
1194
|
|
|
1313
1195
|
const handleClick = () => {
|
|
1314
|
-
setSelection({ zoneId: zone.id })
|
|
1315
|
-
setPhase('structure')
|
|
1316
1196
|
setMode('select')
|
|
1197
|
+
selectZoneOrRoom(zone.id)
|
|
1317
1198
|
}
|
|
1318
1199
|
|
|
1319
1200
|
const handleDoubleClick = () => {
|
|
@@ -1322,6 +1203,8 @@ const ZoneItem = memo(function ZoneItem({ zone, isLast }: { zone: ZoneNode; isLa
|
|
|
1322
1203
|
|
|
1323
1204
|
const handleDelete = (e: React.MouseEvent) => {
|
|
1324
1205
|
e.stopPropagation()
|
|
1206
|
+
// A room goes the way the room panel deletes it (its walls, or merged back).
|
|
1207
|
+
if (isRoom) return requestRoomDeletion(zone.id)
|
|
1325
1208
|
deleteNode(zone.id)
|
|
1326
1209
|
if (isSelected) {
|
|
1327
1210
|
setSelection({ zoneId: null })
|
|
@@ -1335,7 +1218,7 @@ const ZoneItem = memo(function ZoneItem({ zone, isLast }: { zone: ZoneNode; isLa
|
|
|
1335
1218
|
return (
|
|
1336
1219
|
<div
|
|
1337
1220
|
className={cn(
|
|
1338
|
-
'group/row relative flex h-8 cursor-pointer select-none items-center border-border/50 border-b
|
|
1221
|
+
'group/row relative flex h-8 cursor-pointer select-none items-center border-border/50 border-b text-sm transition-all duration-200',
|
|
1339
1222
|
isSelected
|
|
1340
1223
|
? 'bg-accent/50 text-foreground'
|
|
1341
1224
|
: isHovered
|
|
@@ -1347,6 +1230,7 @@ const ZoneItem = memo(function ZoneItem({ zone, isLast }: { zone: ZoneNode; isLa
|
|
|
1347
1230
|
onMouseEnter={() => setHoveredId(zone.id)}
|
|
1348
1231
|
onMouseLeave={() => setHoveredId(null)}
|
|
1349
1232
|
ref={itemRef}
|
|
1233
|
+
style={{ paddingLeft: depth * 12 + 28, paddingRight: 12 }}
|
|
1350
1234
|
>
|
|
1351
1235
|
{/* Vertical tree line */}
|
|
1352
1236
|
<div
|
|
@@ -1354,12 +1238,12 @@ const ZoneItem = memo(function ZoneItem({ zone, isLast }: { zone: ZoneNode; isLa
|
|
|
1354
1238
|
'pointer-events-none absolute w-px bg-border/50',
|
|
1355
1239
|
isLast ? 'top-0 bottom-1/2' : 'top-0 bottom-0',
|
|
1356
1240
|
)}
|
|
1357
|
-
style={{ left:
|
|
1241
|
+
style={{ left: (depth - 1) * 12 + 20 }}
|
|
1358
1242
|
/>
|
|
1359
1243
|
{/* Horizontal branch line */}
|
|
1360
1244
|
<div
|
|
1361
1245
|
className="pointer-events-none absolute top-1/2 h-px bg-border/50"
|
|
1362
|
-
style={{ left:
|
|
1246
|
+
style={{ left: (depth - 1) * 12 + 20, width: 4 }}
|
|
1363
1247
|
/>
|
|
1364
1248
|
|
|
1365
1249
|
{focusedUnit && (
|
|
@@ -1476,17 +1360,9 @@ const MultiSelectionBadge = memo(function MultiSelectionBadge() {
|
|
|
1476
1360
|
)
|
|
1477
1361
|
})
|
|
1478
1362
|
|
|
1479
|
-
const
|
|
1363
|
+
const RoomsSection = memo(function RoomsSection() {
|
|
1480
1364
|
const selectedLevelId = useViewer((state) => state.selection.levelId)
|
|
1481
|
-
const
|
|
1482
|
-
const phase = useEditor((state) => state.phase)
|
|
1483
|
-
const setPhase = useEditor((state) => state.setPhase)
|
|
1484
|
-
const setMode = useEditor((state) => state.setMode)
|
|
1485
|
-
const setTool = useEditor((state) => state.setTool)
|
|
1486
|
-
|
|
1487
|
-
const level = useScene((s) =>
|
|
1488
|
-
selectedLevelId ? ((s.nodes[selectedLevelId] as LevelNode | undefined) ?? null) : null,
|
|
1489
|
-
)
|
|
1365
|
+
const armToolMode = useEditor((state) => state.armToolMode)
|
|
1490
1366
|
const levelZones = useScene(
|
|
1491
1367
|
useShallow((s) => {
|
|
1492
1368
|
if (!selectedLevelId) return []
|
|
@@ -1495,6 +1371,82 @@ const ContentSection = memo(function ContentSection() {
|
|
|
1495
1371
|
)
|
|
1496
1372
|
}),
|
|
1497
1373
|
)
|
|
1374
|
+
const [expanded, setExpanded] = useState(true)
|
|
1375
|
+
|
|
1376
|
+
if (!selectedLevelId) return null
|
|
1377
|
+
|
|
1378
|
+
const handleDrawZone = (event: React.MouseEvent) => {
|
|
1379
|
+
event.stopPropagation()
|
|
1380
|
+
armToolMode({ mode: 'build', tool: 'zone' })
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
const rooms = levelZones.filter((zone) => zone.spaceRole === 'room')
|
|
1384
|
+
const others = levelZones.filter((zone) => zone.spaceRole !== 'room')
|
|
1385
|
+
|
|
1386
|
+
return (
|
|
1387
|
+
<div className="subtle-scrollbar max-h-72 shrink-0 overflow-y-auto overflow-x-hidden">
|
|
1388
|
+
<TreeNodeWrapper
|
|
1389
|
+
actions={
|
|
1390
|
+
<button
|
|
1391
|
+
className="flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-black/5 hover:text-foreground dark:hover:bg-white/10"
|
|
1392
|
+
onClick={handleDrawZone}
|
|
1393
|
+
title="Draw a zone"
|
|
1394
|
+
type="button"
|
|
1395
|
+
>
|
|
1396
|
+
<Plus className="h-3 w-3" />
|
|
1397
|
+
</button>
|
|
1398
|
+
}
|
|
1399
|
+
depth={1}
|
|
1400
|
+
expanded={expanded}
|
|
1401
|
+
hasChildren
|
|
1402
|
+
icon={<LayoutGrid className="h-3.5 w-3.5" />}
|
|
1403
|
+
label={
|
|
1404
|
+
<span className="flex items-center gap-1.5">
|
|
1405
|
+
Rooms
|
|
1406
|
+
{rooms.length > 0 && (
|
|
1407
|
+
<span className="text-muted-foreground text-xs">{rooms.length}</span>
|
|
1408
|
+
)}
|
|
1409
|
+
</span>
|
|
1410
|
+
}
|
|
1411
|
+
onClick={() => setExpanded((value) => !value)}
|
|
1412
|
+
onToggle={() => setExpanded((value) => !value)}
|
|
1413
|
+
>
|
|
1414
|
+
{levelZones.length === 0 && (
|
|
1415
|
+
<div className="border-border/50 border-b py-2 pr-3 pl-[52px] text-muted-foreground text-xs">
|
|
1416
|
+
Close walls around a space to make a room.
|
|
1417
|
+
</div>
|
|
1418
|
+
)}
|
|
1419
|
+
{rooms.map((zone, index) => (
|
|
1420
|
+
<ZoneItem
|
|
1421
|
+
depth={2}
|
|
1422
|
+
isLast={others.length === 0 && index === rooms.length - 1}
|
|
1423
|
+
key={zone.id}
|
|
1424
|
+
zone={zone}
|
|
1425
|
+
/>
|
|
1426
|
+
))}
|
|
1427
|
+
{others.length > 0 && (
|
|
1428
|
+
<>
|
|
1429
|
+
<div
|
|
1430
|
+
className="pt-3 pb-1 pl-[52px] font-medium text-[11px] text-muted-foreground"
|
|
1431
|
+
data-other-zones
|
|
1432
|
+
>
|
|
1433
|
+
Other zones
|
|
1434
|
+
</div>
|
|
1435
|
+
{others.map((zone, index) => (
|
|
1436
|
+
<ZoneItem depth={2} isLast={index === others.length - 1} key={zone.id} zone={zone} />
|
|
1437
|
+
))}
|
|
1438
|
+
</>
|
|
1439
|
+
)}
|
|
1440
|
+
</TreeNodeWrapper>
|
|
1441
|
+
</div>
|
|
1442
|
+
)
|
|
1443
|
+
})
|
|
1444
|
+
|
|
1445
|
+
const ContentSection = memo(function ContentSection() {
|
|
1446
|
+
const selectedLevelId = useViewer((state) => state.selection.levelId)
|
|
1447
|
+
const level = useScene((s) =>
|
|
1448
|
+
selectedLevelId ? ((s.nodes[selectedLevelId] as LevelNode | undefined) ?? null) : null,
|
|
1449
|
+
)
|
|
1498
1450
|
const elementChildren = useScene(
|
|
1499
1451
|
useShallow((s) => {
|
|
1500
1452
|
if (!selectedLevelId) return []
|
|
@@ -1506,6 +1458,7 @@ const ContentSection = memo(function ContentSection() {
|
|
|
1506
1458
|
})
|
|
1507
1459
|
}),
|
|
1508
1460
|
)
|
|
1461
|
+
const [expanded, setExpanded] = useState(true)
|
|
1509
1462
|
|
|
1510
1463
|
if (!level) {
|
|
1511
1464
|
return (
|
|
@@ -1513,49 +1466,40 @@ const ContentSection = memo(function ContentSection() {
|
|
|
1513
1466
|
)
|
|
1514
1467
|
}
|
|
1515
1468
|
|
|
1516
|
-
if (structureLayer === 'zones') {
|
|
1517
|
-
const handleAddZone = () => {
|
|
1518
|
-
setPhase('structure')
|
|
1519
|
-
setMode('build')
|
|
1520
|
-
setTool('zone')
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
if (levelZones.length === 0) {
|
|
1524
|
-
return (
|
|
1525
|
-
<div className="px-3 py-4 text-muted-foreground text-sm">
|
|
1526
|
-
No zones on this level.{' '}
|
|
1527
|
-
<button className="cursor-pointer text-primary hover:underline" onClick={handleAddZone}>
|
|
1528
|
-
Add one
|
|
1529
|
-
</button>
|
|
1530
|
-
</div>
|
|
1531
|
-
)
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
return (
|
|
1535
|
-
<div className="flex flex-col">
|
|
1536
|
-
{levelZones.map((zone, index) => (
|
|
1537
|
-
<ZoneItem isLast={index === levelZones.length - 1} key={zone.id} zone={zone} />
|
|
1538
|
-
))}
|
|
1539
|
-
</div>
|
|
1540
|
-
)
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
if (elementChildren.length === 0) {
|
|
1544
|
-
return <div className="px-3 py-4 text-muted-foreground text-sm">No elements on this level</div>
|
|
1545
|
-
}
|
|
1546
1469
|
return (
|
|
1547
|
-
<
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1470
|
+
<TreeNodeWrapper
|
|
1471
|
+
depth={1}
|
|
1472
|
+
expanded={expanded}
|
|
1473
|
+
hasChildren
|
|
1474
|
+
icon={<Boxes className="h-3.5 w-3.5" />}
|
|
1475
|
+
label={
|
|
1476
|
+
<span className="flex items-center gap-1.5">
|
|
1477
|
+
Elements
|
|
1478
|
+
{elementChildren.length > 0 && (
|
|
1479
|
+
<span className="text-muted-foreground text-xs">{elementChildren.length}</span>
|
|
1480
|
+
)}
|
|
1481
|
+
</span>
|
|
1482
|
+
}
|
|
1483
|
+
onClick={() => setExpanded((value) => !value)}
|
|
1484
|
+
onToggle={() => setExpanded((value) => !value)}
|
|
1485
|
+
>
|
|
1486
|
+
{elementChildren.length === 0 ? (
|
|
1487
|
+
<div className="border-border/50 border-b py-2 pr-3 pl-[52px] text-muted-foreground text-xs">
|
|
1488
|
+
No elements on this level
|
|
1489
|
+
</div>
|
|
1490
|
+
) : (
|
|
1491
|
+
<TreeNodeDragProvider>
|
|
1492
|
+
{elementChildren.map((childId, index) => (
|
|
1493
|
+
<TreeNode
|
|
1494
|
+
depth={2}
|
|
1495
|
+
isLast={index === elementChildren.length - 1}
|
|
1496
|
+
key={childId}
|
|
1497
|
+
nodeId={childId}
|
|
1498
|
+
/>
|
|
1499
|
+
))}
|
|
1500
|
+
</TreeNodeDragProvider>
|
|
1501
|
+
)}
|
|
1502
|
+
</TreeNodeWrapper>
|
|
1559
1503
|
)
|
|
1560
1504
|
})
|
|
1561
1505
|
|
|
@@ -1591,7 +1535,7 @@ const BuildingItem = memo(function BuildingItem({
|
|
|
1591
1535
|
const handleSelect = () => {
|
|
1592
1536
|
setSelection({ buildingId: building.id })
|
|
1593
1537
|
if (phase === 'site') {
|
|
1594
|
-
setPhase('
|
|
1538
|
+
setPhase('building')
|
|
1595
1539
|
}
|
|
1596
1540
|
}
|
|
1597
1541
|
|
|
@@ -1713,7 +1657,8 @@ const BuildingItem = memo(function BuildingItem({
|
|
|
1713
1657
|
projectId={projectId}
|
|
1714
1658
|
/>
|
|
1715
1659
|
<UnitsSection buildingId={building.id} />
|
|
1716
|
-
<
|
|
1660
|
+
<RoomsSection />
|
|
1661
|
+
<CollectionsSection />
|
|
1717
1662
|
</div>
|
|
1718
1663
|
<div className="subtle-scrollbar relative min-h-0 flex-1 overflow-y-auto overflow-x-hidden">
|
|
1719
1664
|
<MultiSelectionBadge />
|
|
@@ -1769,7 +1714,14 @@ export function SitePanel({ projectId, onUploadAsset, onDeleteAsset }: SitePanel
|
|
|
1769
1714
|
: 'text-muted-foreground hover:bg-accent/30 hover:text-foreground',
|
|
1770
1715
|
)}
|
|
1771
1716
|
layout="position"
|
|
1772
|
-
onClick={() =>
|
|
1717
|
+
onClick={() => {
|
|
1718
|
+
setPhase('site')
|
|
1719
|
+
// Also SELECT the site node so the registry inspector mounts the
|
|
1720
|
+
// site kind's panel (address / parcel / setbacks / front edge).
|
|
1721
|
+
// The site kind opts out of 3D click selection, so this header is
|
|
1722
|
+
// its only selection entry point. (WS1)
|
|
1723
|
+
setSelection({ selectedIds: [siteNode.id as AnyNodeId], zoneId: null })
|
|
1724
|
+
}}
|
|
1773
1725
|
>
|
|
1774
1726
|
<div className="flex items-center gap-2">
|
|
1775
1727
|
<img
|
|
@@ -1811,6 +1763,12 @@ export function SitePanel({ projectId, onUploadAsset, onDeleteAsset }: SitePanel
|
|
|
1811
1763
|
transition={{ type: 'spring', bounce: 0, duration: 0.4 }}
|
|
1812
1764
|
>
|
|
1813
1765
|
<PropertyLineSection />
|
|
1766
|
+
{/* Address → parcel, setbacks, front edge: the site kind's own
|
|
1767
|
+
panel (packages/nodes/src/site/panel.tsx), loaded through
|
|
1768
|
+
the registry so the editor does not import the nodes package. */}
|
|
1769
|
+
<Suspense fallback={null}>
|
|
1770
|
+
<SiteKindPanel />
|
|
1771
|
+
</Suspense>
|
|
1814
1772
|
</motion.div>
|
|
1815
1773
|
)}
|
|
1816
1774
|
</AnimatePresence>
|
|
@@ -1824,7 +1782,7 @@ export function SitePanel({ projectId, onUploadAsset, onDeleteAsset }: SitePanel
|
|
|
1824
1782
|
<div className="flex min-h-0 flex-1 flex-col">
|
|
1825
1783
|
{buildings.map((building) => {
|
|
1826
1784
|
const isBuildingActive =
|
|
1827
|
-
|
|
1785
|
+
phase === 'building' &&
|
|
1828
1786
|
selectedBuildingId === building.id
|
|
1829
1787
|
|
|
1830
1788
|
return (
|