@pascal-app/editor 1.0.6 → 1.0.7

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.
Files changed (317) hide show
  1. package/package.json +18 -15
  2. package/src/components/editor/action-menu-button.tsx +4 -1
  3. package/src/components/editor/alignment-3d-guide-layer.tsx +102 -11
  4. package/src/components/editor/bake-thumbnail.tsx +3 -2
  5. package/src/components/editor/custom-camera-controls.tsx +20 -8
  6. package/src/components/editor/elevation-3d-guide-layer.tsx +1 -1
  7. package/src/components/editor/first-person-controls.tsx +72 -61
  8. package/src/components/editor/floating-action-menu.tsx +27 -9
  9. package/src/components/editor/floating-building-action-menu.tsx +1 -1
  10. package/src/components/editor/floorplan-panel.test.ts +220 -0
  11. package/src/components/editor/floorplan-panel.tsx +285 -132
  12. package/src/components/editor/footprint-height-handle.tsx +1 -1
  13. package/src/components/editor/grid.tsx +24 -15
  14. package/src/components/editor/group-actions.ts +19 -1
  15. package/src/components/editor/group-floating-action-menu.tsx +1 -1
  16. package/src/components/editor/group-move-3d.ts +27 -2
  17. package/src/components/editor/group-selection-box-3d.tsx +4 -1
  18. package/src/components/editor/group-transform-shared.ts +20 -0
  19. package/src/components/editor/index.tsx +130 -20
  20. package/src/components/editor/inspector-extension-actions.tsx +36 -0
  21. package/src/components/editor/localized-html.tsx +22 -0
  22. package/src/components/editor/node-action-menu.tsx +46 -12
  23. package/src/components/editor/node-arrow-handles.tsx +1 -2
  24. package/src/components/editor/open-wall-ends-3d-layer.tsx +1 -1
  25. package/src/components/editor/opening-guides-3d-layer.tsx +1 -1
  26. package/src/components/editor/registry-action-contributions.test.tsx +67 -6
  27. package/src/components/editor/registry-action-contributions.tsx +115 -15
  28. package/src/components/editor/riser-diagram-panel.tsx +59 -9
  29. package/src/components/editor/room-controls.tsx +1 -1
  30. package/src/components/editor/room-handles-2d.tsx +156 -6
  31. package/src/components/editor/room-handles.tsx +241 -51
  32. package/src/components/editor/room-highlight.tsx +2 -0
  33. package/src/components/editor/room-labels.tsx +29 -15
  34. package/src/components/editor/selection-manager.tsx +15 -102
  35. package/src/components/editor/separator-end-grip.tsx +74 -0
  36. package/src/components/editor/site-edge-labels.tsx +1 -1
  37. package/src/components/editor/thumbnail-generator.test.ts +15 -6
  38. package/src/components/editor/thumbnail-generator.tsx +26 -1
  39. package/src/components/editor/use-floorplan-background-placement.ts +55 -52
  40. package/src/components/editor/views/view-bar.tsx +111 -26
  41. package/src/components/editor/wall-measurement-label.tsx +1 -1
  42. package/src/components/editor/wall-move-side-handles.tsx +5 -1
  43. package/src/components/editor/wall-pull-grip.tsx +193 -0
  44. package/src/components/editor/wall-snap-beacon-layer.tsx +81 -1
  45. package/src/components/editor-2d/floorplan-adjacent-walls-layer.test.ts +76 -0
  46. package/src/components/editor-2d/floorplan-adjacent-walls-layer.tsx +186 -0
  47. package/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +63 -3
  48. package/src/components/editor-2d/floorplan-group-move.tsx +31 -3
  49. package/src/components/editor-2d/floorplan-measurement-tool-layer.test.ts +6 -0
  50. package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +22 -13
  51. package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +11 -3
  52. package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +7 -1
  53. package/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +96 -4
  54. package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +52 -12
  55. package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +12 -1
  56. package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +197 -37
  57. package/src/components/procedural-items/inspector.tsx +59 -12
  58. package/src/components/systems/ceiling/ceiling-bracket-batch.test.ts +2 -0
  59. package/src/components/systems/ceiling/ceiling-system.test.ts +141 -0
  60. package/src/components/systems/ceiling/ceiling-system.tsx +53 -18
  61. package/src/components/tools/distribution/distribution-run-tool.tsx +50 -26
  62. package/src/components/tools/item/placement-history.test.tsx +1 -1
  63. package/src/components/tools/item/placement-strategies.test.ts +64 -1
  64. package/src/components/tools/item/placement-strategies.ts +5 -9
  65. package/src/components/tools/item/use-placement-coordinator.tsx +30 -34
  66. package/src/components/tools/registry/item-surface-move.test.ts +11 -0
  67. package/src/components/tools/select/select-candidates.test.ts +45 -0
  68. package/src/components/tools/select/select-candidates.ts +13 -2
  69. package/src/components/tools/shared/cursor-sphere.tsx +10 -3
  70. package/src/components/tools/shared/draft-measurement-label.tsx +1 -1
  71. package/src/components/tools/shared/placement-box.tsx +1 -1
  72. package/src/components/tools/shared/placement-dimension-guides.tsx +1 -1
  73. package/src/components/tools/site/terrain-brush-cursor.tsx +1 -1
  74. package/src/components/tools/wall/wall-drafting.test.ts +299 -23
  75. package/src/components/tools/wall/wall-drafting.ts +132 -24
  76. package/src/components/tools/wall/wall-pull-snap.test.ts +274 -0
  77. package/src/components/tools/wall/wall-pull-snap.ts +563 -0
  78. package/src/components/tools/wall/wall-snap-geometry.test.ts +113 -1
  79. package/src/components/tools/wall/wall-snap-geometry.ts +137 -0
  80. package/src/components/tools/zone/zone-tool.tsx +3 -3
  81. package/src/components/ui/action-menu/action-button.tsx +2 -0
  82. package/src/components/ui/action-menu/camera-actions.tsx +8 -7
  83. package/src/components/ui/action-menu/control-modes.tsx +9 -5
  84. package/src/components/ui/action-menu/follow-pascal-pill.tsx +3 -1
  85. package/src/components/ui/action-menu/follow-pascal-toggle.tsx +7 -1
  86. package/src/components/ui/action-menu/furnish-tools.tsx +7 -6
  87. package/src/components/ui/action-menu/index.tsx +1 -0
  88. package/src/components/ui/action-menu/measurement-control.tsx +35 -29
  89. package/src/components/ui/action-menu/point-ask-button.tsx +4 -3
  90. package/src/components/ui/action-menu/structure-tools.tsx +25 -23
  91. package/src/components/ui/action-menu/view-toggles.test.ts +18 -0
  92. package/src/components/ui/action-menu/view-toggles.tsx +256 -51
  93. package/src/components/ui/build-panel/build-panel.tsx +163 -25
  94. package/src/components/ui/command-palette/editor-commands.tsx +38 -11
  95. package/src/components/ui/controls/finish-swatch.tsx +45 -19
  96. package/src/components/ui/controls/material-picker.tsx +24 -17
  97. package/src/components/ui/controls/metric-control.test.ts +52 -0
  98. package/src/components/ui/controls/metric-control.tsx +62 -24
  99. package/src/components/ui/controls/segmented-control.tsx +5 -2
  100. package/src/components/ui/controls/slider-control.test.tsx +23 -0
  101. package/src/components/ui/controls/slider-control.tsx +30 -14
  102. package/src/components/ui/floating-level-selector.tsx +100 -48
  103. package/src/components/ui/helpers/building-helper.tsx +5 -3
  104. package/src/components/ui/helpers/contextual-helper-panel.tsx +97 -37
  105. package/src/components/ui/helpers/helper-manager.test.tsx +53 -3
  106. package/src/components/ui/helpers/helper-manager.tsx +82 -57
  107. package/src/components/ui/helpers/item-helper.tsx +6 -4
  108. package/src/components/ui/helpers/registered-tool-helper.tsx +3 -1
  109. package/src/components/ui/level-duplicate-dialog.tsx +32 -23
  110. package/src/components/ui/level-wall-copy-prompt.tsx +124 -0
  111. package/src/components/ui/panels/collections/collections-popover.tsx +11 -11
  112. package/src/components/ui/panels/deck-boards-fields.tsx +136 -0
  113. package/src/components/ui/panels/floor-foundation-panel.tsx +113 -38
  114. package/src/components/ui/panels/floor-opening-panel.tsx +73 -25
  115. package/src/components/ui/panels/inspector-extensions.tsx +66 -0
  116. package/src/components/ui/panels/mobile-panel-sheet.tsx +3 -1
  117. package/src/components/ui/panels/mobile-selection-bar.tsx +8 -6
  118. package/src/components/ui/panels/multi-field-value.test.ts +27 -0
  119. package/src/components/ui/panels/multi-field-value.ts +20 -1
  120. package/src/components/ui/panels/multi-height-mode.tsx +8 -7
  121. package/src/components/ui/panels/multi-parametric-inspector.tsx +122 -34
  122. package/src/components/ui/panels/multi-selection-panel.tsx +75 -35
  123. package/src/components/ui/panels/node-display.ts +35 -24
  124. package/src/components/ui/panels/panel-manager.tsx +5 -3
  125. package/src/components/ui/panels/panel-wrapper.tsx +22 -109
  126. package/src/components/ui/panels/parametric-field-control.tsx +13 -10
  127. package/src/components/ui/panels/parametric-inspector.tsx +18 -12
  128. package/src/components/ui/panels/reference-panel.tsx +51 -35
  129. package/src/components/ui/panels/room-construction-rows.tsx +464 -65
  130. package/src/components/ui/panels/room-name-options.test.ts +36 -3
  131. package/src/components/ui/panels/room-name-options.ts +110 -11
  132. package/src/components/ui/panels/room-openings-field.tsx +21 -12
  133. package/src/components/ui/panels/room-panel.tsx +206 -99
  134. package/src/components/ui/panels/shape-choice.tsx +7 -5
  135. package/src/components/ui/panels/wall-region-list.tsx +7 -7
  136. package/src/components/ui/primitives/shortcut-token.tsx +10 -6
  137. package/src/components/ui/sidebar/icon-rail.tsx +11 -9
  138. package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +10 -10
  139. package/src/components/ui/sidebar/panels/items-panel/index.tsx +10 -9
  140. package/src/components/ui/sidebar/panels/settings-panel/index.tsx +3 -0
  141. package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +102 -32
  142. package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +4 -3
  143. package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +4 -2
  144. package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +4 -2
  145. package/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +7 -5
  146. package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +4 -2
  147. package/src/components/ui/sidebar/panels/site-panel/default-names.ts +75 -0
  148. package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +4 -2
  149. package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +4 -2
  150. package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +4 -2
  151. package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +4 -2
  152. package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +4 -2
  153. package/src/components/ui/sidebar/panels/site-panel/index.tsx +117 -64
  154. package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +36 -3
  155. package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +4 -2
  156. package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +7 -4
  157. package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +8 -2
  158. package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +8 -5
  159. package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +4 -2
  160. package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +8 -3
  161. package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +4 -2
  162. package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +4 -2
  163. package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +8 -7
  164. package/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +7 -6
  165. package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +16 -1
  166. package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +15 -8
  167. package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +4 -2
  168. package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +4 -2
  169. package/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx +3 -1
  170. package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +18 -8
  171. package/src/components/ui/sidebar/panels/zone-panel/index.tsx +25 -14
  172. package/src/components/ui/sidebar/tab-bar.tsx +4 -1
  173. package/src/components/ui/sidebar/use-plugin-panels.tsx +19 -10
  174. package/src/components/ui/snap-target-badge.tsx +7 -6
  175. package/src/components/ui/wall-type/wall-type-editor-dialog.tsx +721 -0
  176. package/src/components/ui/wall-type/wall-type-menu.tsx +167 -0
  177. package/src/components/viewer/floorplan-compass-button.tsx +12 -3
  178. package/src/components/viewer/floorplan-preview.tsx +27 -19
  179. package/src/components/viewer/render-settings-menu.tsx +294 -0
  180. package/src/components/viewer/sky-control.tsx +710 -0
  181. package/src/components/viewer/use-viewer-ui-sounds.test.ts +15 -0
  182. package/src/components/viewer/use-viewer-ui-sounds.ts +46 -0
  183. package/src/components/viewer/viewer-controls-bar.tsx +278 -260
  184. package/src/components/viewer/viewer-hover-label.tsx +12 -4
  185. package/src/components/viewer/viewer-rooms.tsx +61 -4
  186. package/src/components/viewer/viewer-scene-header.tsx +28 -17
  187. package/src/components/viewer/viewer-stage-switcher.tsx +4 -2
  188. package/src/components/viewer-overlay.tsx +8 -0
  189. package/src/components/walkthrough-hud.tsx +75 -2
  190. package/src/hooks/use-keyboard.test.ts +85 -4
  191. package/src/hooks/use-keyboard.ts +65 -7
  192. package/src/hooks/use-selected-room.ts +12 -1
  193. package/src/i18n/floor-footprint-name.ts +30 -0
  194. package/src/i18n/level-name.ts +39 -0
  195. package/src/i18n/locales/en/messages.po +15117 -0
  196. package/src/i18n/locales/en/messages.ts +1 -0
  197. package/src/i18n/locales/en-XA/messages.ts +1 -0
  198. package/src/i18n/locales/es/messages.po +37501 -0
  199. package/src/i18n/locales/es/messages.ts +1 -0
  200. package/src/i18n/locales/fr/messages.po +37501 -0
  201. package/src/i18n/locales/fr/messages.ts +1 -0
  202. package/src/i18n/locales/ja/messages.po +37501 -0
  203. package/src/i18n/locales/ja/messages.ts +1 -0
  204. package/src/i18n/locales/zh-CN/messages.po +37501 -0
  205. package/src/i18n/locales/zh-CN/messages.ts +1 -0
  206. package/src/i18n/locales.test.ts +63 -0
  207. package/src/i18n/locales.ts +32 -0
  208. package/src/i18n/message-slot.tsx +25 -0
  209. package/src/i18n/node-messages.ts +169 -0
  210. package/src/i18n/pseudo-locale.ts +17 -0
  211. package/src/i18n/published-entry.test.ts +17 -0
  212. package/src/i18n/scene-theme-name.ts +16 -0
  213. package/src/index.tsx +156 -4
  214. package/src/lib/add-storey.test.ts +3 -3
  215. package/src/lib/contextual-help.test.ts +20 -1
  216. package/src/lib/contextual-help.ts +95 -19
  217. package/src/lib/continuation.ts +38 -11
  218. package/src/lib/floor-footprints.test.ts +2 -1
  219. package/src/lib/floor-foundation-support.test.ts +7 -3
  220. package/src/lib/floorplan/dimension-drive.test.ts +36 -2
  221. package/src/lib/floorplan/dimension-drive.ts +68 -3
  222. package/src/lib/floorplan/floorplan-export.test.ts +16 -5
  223. package/src/lib/floorplan/floorplan-export.tsx +13 -16
  224. package/src/lib/floorplan/floorplan-extension.test.ts +11 -12
  225. package/src/lib/floorplan/floorplan-extension.ts +37 -18
  226. package/src/lib/floorplan/floorplan-mode.test.ts +13 -6
  227. package/src/lib/floorplan/floorplan-mode.ts +14 -12
  228. package/src/lib/floorplan/floorplan-plugin-install.test.tsx +1 -1
  229. package/src/lib/floorplan/floorplan-readonly.ts +3 -3
  230. package/src/lib/floorplan/schedules.ts +10 -6
  231. package/src/lib/floorplan/site-plan/site-annotations.test.ts +46 -1
  232. package/src/lib/floorplan/site-plan/site-annotations.ts +3 -0
  233. package/src/lib/floorplan/site-plan/site-parts.ts +6 -3
  234. package/src/lib/geometry-script/author.test.ts +114 -0
  235. package/src/lib/geometry-script/author.ts +55 -23
  236. package/src/lib/geometry-script/client.ts +3 -0
  237. package/src/lib/geometry-script/finish-scripts.ts +7 -7
  238. package/src/lib/glb-export.test.ts +327 -0
  239. package/src/lib/glb-export.ts +70 -2
  240. package/src/lib/grid-frame.test.ts +56 -3
  241. package/src/lib/grid-frame.ts +28 -1
  242. package/src/lib/history.test.ts +2 -1
  243. package/src/lib/hud-title.ts +48 -24
  244. package/src/lib/ifc-export.test.ts +41 -1
  245. package/src/lib/inspector-card-mode.test.ts +3 -31
  246. package/src/lib/inspector-card-mode.ts +5 -10
  247. package/src/lib/inspector-expanded.test.ts +13 -0
  248. package/src/lib/inspector-expanded.ts +13 -1
  249. package/src/lib/keyboard-pan.test.ts +7 -0
  250. package/src/lib/keyboard-pan.ts +9 -2
  251. package/src/lib/layer-thickness.test.ts +22 -0
  252. package/src/lib/layer-thickness.ts +79 -0
  253. package/src/lib/lot/drop-in.test.ts +59 -1
  254. package/src/lib/lot/drop-in.ts +42 -50
  255. package/src/lib/material-swatch-style.ts +24 -0
  256. package/src/lib/measurement-parser.ts +7 -3
  257. package/src/lib/measurements.test.ts +17 -0
  258. package/src/lib/measurements.ts +20 -5
  259. package/src/lib/mezzanine-selection.test.ts +3 -1
  260. package/src/lib/orbit-near-plane.test.ts +12 -0
  261. package/src/lib/orbit-near-plane.ts +13 -0
  262. package/src/lib/paint-regions.test.ts +8 -5
  263. package/src/lib/paint-scope.test.ts +53 -0
  264. package/src/lib/paint-scope.ts +18 -4
  265. package/src/lib/panel-rows.ts +17 -8
  266. package/src/lib/reference-scale.ts +83 -0
  267. package/src/lib/room-built-on.test.ts +26 -12
  268. package/src/lib/room-built-on.ts +20 -2
  269. package/src/lib/room-construction.test.ts +28 -1
  270. package/src/lib/room-construction.ts +14 -0
  271. package/src/lib/room-controls-phase6.test.ts +140 -0
  272. package/src/lib/room-handle-drag.ts +557 -42
  273. package/src/lib/room-name-catalog.test.ts +8 -0
  274. package/src/lib/room-name-catalog.ts +8 -1
  275. package/src/lib/room-name-messages.test.ts +132 -0
  276. package/src/lib/room-name-messages.ts +147 -0
  277. package/src/lib/room-name-storage.test.ts +334 -0
  278. package/src/lib/room-push-dimensions.test.ts +37 -0
  279. package/src/lib/room-push-dimensions.ts +226 -2
  280. package/src/lib/room-selection.test.ts +23 -6
  281. package/src/lib/scene-clipboard.test.ts +70 -49
  282. package/src/lib/scene-clipboard.ts +9 -4
  283. package/src/lib/selection-cycle.ts +63 -0
  284. package/src/lib/separator-edit.test.ts +431 -0
  285. package/src/lib/separator-edit.ts +179 -0
  286. package/src/lib/separator-lines.ts +38 -0
  287. package/src/lib/sfx-bus.ts +27 -1
  288. package/src/lib/sfx-player.ts +16 -0
  289. package/src/lib/tool-cursor-icon.ts +5 -1
  290. package/src/lib/tool-shortcuts.ts +130 -0
  291. package/src/lib/viewer-selection.test.ts +28 -24
  292. package/src/lib/viewer-selection.ts +20 -5
  293. package/src/lib/wall-draw-variant.test.ts +7 -6
  294. package/src/lib/wall-draw-variant.ts +107 -6
  295. package/src/lib/wall-nudge.test.ts +44 -0
  296. package/src/lib/wall-nudge.ts +131 -0
  297. package/src/lib/wall-parallel-snap.test.ts +83 -0
  298. package/src/lib/wall-parallel-snap.ts +176 -0
  299. package/src/lib/wall-placement-pointer.test.ts +23 -0
  300. package/src/lib/wall-placement-pointer.ts +18 -0
  301. package/src/lib/wall-pull.test.ts +245 -0
  302. package/src/lib/wall-pull.ts +209 -0
  303. package/src/lib/wall-push-line-up.test.ts +132 -0
  304. package/src/lib/wall-region-list.ts +14 -5
  305. package/src/lib/wall-run-snap.test.ts +188 -0
  306. package/src/lib/wall-run-snap.ts +83 -0
  307. package/src/lib/wall-type.test.ts +125 -0
  308. package/src/lib/wall-type.ts +119 -0
  309. package/src/lib/window-interaction.test.ts +42 -0
  310. package/src/lib/window-interaction.ts +47 -5
  311. package/src/lib/world-grid-snap.test.ts +139 -2
  312. package/src/lib/world-grid-snap.ts +102 -105
  313. package/src/store/use-alignment-guides.ts +27 -1
  314. package/src/store/use-editor.tsx +48 -0
  315. package/src/store/use-floorplan-annotation-visibility.test.ts +64 -0
  316. package/src/store/use-floorplan-annotation-visibility.ts +47 -22
  317. package/src/store/use-wall-snap-indicator.ts +15 -2
@@ -6,7 +6,9 @@ import {
6
6
  loadAssetUrl,
7
7
  type ScanNode,
8
8
  saveAsset,
9
- useScene,
9
+ useLocale,
10
+ useScene, usePascalI18n,
11
+ type PascalI18n,
10
12
  } from '@pascal-app/core'
11
13
  import {
12
14
  Eye,
@@ -23,6 +25,7 @@ import {
23
25
  import { useCallback, useEffect, useRef, useState } from 'react'
24
26
  import { guideEmitter } from '../../../lib/guide-events'
25
27
  import { getGuideImageName } from '../../../lib/local-guide-image'
28
+ import { formatReferenceScaleLabel } from '../../../lib/reference-scale'
26
29
  import { cn } from '../../../lib/utils'
27
30
  import useEditor from '../../../store/use-editor'
28
31
  import { isViewVisible, VIEW_2D } from '../../../store/view-layout'
@@ -33,16 +36,29 @@ import { PanelWrapper } from './panel-wrapper'
33
36
 
34
37
  type ReferenceNode = ScanNode | GuideNode
35
38
 
36
- function getScaleStatus(guide: GuideNode, scaleReferenceVisible: boolean) {
39
+ function getScaleStatus(
40
+ guide: GuideNode,
41
+ scaleReferenceVisible: boolean,
42
+ locale: string,
43
+ i18n: PascalI18n,
44
+ ) {
37
45
  const reference = guide.scaleReference
38
46
  if (!reference) {
39
- return 'Uncalibrated'
47
+ return i18n._({ id: 'editor.panels.referencePanel.uncalibrated', message: 'Uncalibrated' })
40
48
  }
41
-
42
- return `${scaleReferenceVisible ? 'Scaled' : 'Scaled (hidden)'} · ${reference.label}`
49
+ const scale = formatReferenceScaleLabel(reference, locale)
50
+ return scaleReferenceVisible
51
+ ? i18n._({ id: 'editor.panels.referencePanel.scaled', message: 'Scaled · {scale}', values: { scale } })
52
+ : i18n._({
53
+ id: 'editor.panels.referencePanel.scaledHidden',
54
+ message: 'Scaled (hidden) · {scale}',
55
+ values: { scale },
56
+ })
43
57
  }
44
58
 
45
59
  export function ReferencePanel() {
60
+ const i18n = usePascalI18n()
61
+ const locale = useLocale()
46
62
  const selectedReferenceId = useEditor((s) => s.selectedReferenceId)
47
63
  const setSelectedReferenceId = useEditor((s) => s.setSelectedReferenceId)
48
64
  const guideUi = useEditor((s) =>
@@ -173,17 +189,17 @@ export function ReferencePanel() {
173
189
  const isScan = node.type === 'scan'
174
190
  const guideLocked = !isScan && guideUi?.locked === true
175
191
  const scaleReferenceVisible = !isScan && guideUi?.scaleReferenceVisible !== false
176
- const scaleStatus = isScan ? null : getScaleStatus(node, scaleReferenceVisible)
192
+ const scaleStatus = isScan ? null : getScaleStatus(node, scaleReferenceVisible, locale, i18n)
177
193
 
178
194
  return (
179
195
  <PanelWrapper
180
196
  onClose={handleClose}
181
- title={node.name || (isScan ? 'Capture' : 'Guide Image')}
197
+ title={node.name || (isScan ? i18n._({ id: 'editor.panels.referencePanel.capture', message: 'Capture' }) : i18n._({ id: 'editor.panels.referencePanel.guideImage', message: 'Guide Image' }))}
182
198
  width={300}
183
199
  >
184
200
  {!isScan && (
185
201
  <>
186
- <PanelSection title="Image">
202
+ <PanelSection title={i18n._({ id: 'editor.panels.referencePanel.image', message: 'Image' })}>
187
203
  <input
188
204
  accept="image/*"
189
205
  className="hidden"
@@ -202,13 +218,13 @@ export function ReferencePanel() {
202
218
  <ActionButton
203
219
  disabled={isReplacing}
204
220
  icon={<Upload className="h-3.5 w-3.5" />}
205
- label={isReplacing ? 'Replacing...' : 'Replace'}
221
+ label={isReplacing ? i18n._({ id: 'editor.panels.referencePanel.replacing', message: 'Replacing...' }) : i18n._({ id: 'editor.panels.referencePanel.replace', message: 'Replace' })}
206
222
  onClick={() => replaceInputRef.current?.click()}
207
223
  />
208
224
  <ActionButton
209
225
  className="text-destructive hover:bg-destructive/10"
210
226
  icon={<Trash2 className="h-3.5 w-3.5" />}
211
- label="Delete"
227
+ label={i18n._({ id: 'editor.panels.referencePanel.delete', message: 'Delete' })}
212
228
  onClick={handleDeleteGuide}
213
229
  />
214
230
  </ActionGroup>
@@ -222,7 +238,7 @@ export function ReferencePanel() {
222
238
  <Eye className="h-3.5 w-3.5" />
223
239
  )
224
240
  }
225
- label={node.visible === false ? 'Show' : 'Hide'}
241
+ label={node.visible === false ? i18n._({ id: 'editor.panels.referencePanel.show', message: 'Show' }) : i18n._({ id: 'editor.panels.referencePanel.hide', message: 'Hide' })}
226
242
  onClick={() => handleUpdate({ visible: node.visible === false })}
227
243
  />
228
244
  <ActionButton
@@ -233,7 +249,7 @@ export function ReferencePanel() {
233
249
  <Unlock className="h-3.5 w-3.5" />
234
250
  )
235
251
  }
236
- label={guideLocked ? 'Unlock' : 'Lock'}
252
+ label={guideLocked ? i18n._({ id: 'editor.panels.referencePanel.unlock', message: 'Unlock' }) : i18n._({ id: 'editor.panels.referencePanel.lock', message: 'Lock' })}
237
253
  onClick={() => setGuideLocked(node.id, !guideLocked)}
238
254
  />
239
255
  </ActionGroup>
@@ -246,12 +262,12 @@ export function ReferencePanel() {
246
262
 
247
263
  {isAssetMissing && (
248
264
  <div className="rounded-md border border-amber-500/35 bg-amber-500/10 px-2 py-1.5 text-amber-700 text-xs dark:text-amber-300">
249
- Overlay image unavailable. Replace the image to restore it.
265
+ {i18n._({ id: 'editor.panels.referencePanel.overlayImageUnavailableReplaceTheImage', message: 'Overlay image unavailable. Replace the image to restore it.' })}
250
266
  </div>
251
267
  )}
252
268
  </PanelSection>
253
269
 
254
- <PanelSection title="Reference Scale">
270
+ <PanelSection title={i18n._({ id: 'editor.panels.referencePanel.referenceScale', message: 'Reference Scale' })}>
255
271
  <div className="flex items-center gap-2 rounded-md border border-border/50 bg-background/40 px-2.5 py-2 text-sm">
256
272
  <Ruler
257
273
  className={cn(
@@ -265,8 +281,8 @@ export function ReferencePanel() {
265
281
  {!node.scaleReference && (
266
282
  <p className="px-0.5 text-muted-foreground text-xs leading-snug">
267
283
  {isScaleFlowActive
268
- ? 'Click both ends of a known distance on the plan, then type its real length.'
269
- : 'Draw a line over a known dimension on the plan, then type its real length to scale the image exactly.'}
284
+ ? i18n._({ id: 'editor.panels.referencePanel.clickBothEndsOfAKnown', message: 'Click both ends of a known distance on the plan, then type its real length.' })
285
+ : i18n._({ id: 'editor.panels.referencePanel.drawALineOverAKnown', message: 'Draw a line over a known dimension on the plan, then type its real length to scale the image exactly.' })}
270
286
  </p>
271
287
  )}
272
288
 
@@ -278,7 +294,7 @@ export function ReferencePanel() {
278
294
  'border-primary/50 bg-primary/15 text-primary hover:bg-primary/25 active:bg-primary/25',
279
295
  )}
280
296
  label={
281
- isScaleFlowActive ? 'Cancel' : node.scaleReference ? 'Edit Scale' : 'Set Scale'
297
+ isScaleFlowActive ? i18n._({ id: 'editor.panels.referencePanel.cancel', message: 'Cancel' }) : node.scaleReference ? i18n._({ id: 'editor.panels.referencePanel.editScale', message: 'Edit Scale' }) : i18n._({ id: 'editor.panels.referencePanel.setScale', message: 'Set Scale' })
282
298
  }
283
299
  onClick={isScaleFlowActive ? handleCancelScale : handleStartScale}
284
300
  />
@@ -287,11 +303,11 @@ export function ReferencePanel() {
287
303
  {node.scaleReference && (
288
304
  <ActionGroup>
289
305
  <ActionButton
290
- label={scaleReferenceVisible ? 'Hide Scale' : 'Show Scale'}
306
+ label={scaleReferenceVisible ? i18n._({ id: 'editor.panels.referencePanel.hideScale', message: 'Hide Scale' }) : i18n._({ id: 'editor.panels.referencePanel.showScale', message: 'Show Scale' })}
291
307
  onClick={() => setGuideScaleReferenceVisible(node.id, !scaleReferenceVisible)}
292
308
  />
293
309
  <ActionButton
294
- label="Clear Scale"
310
+ label={i18n._({ id: 'editor.panels.referencePanel.clearScale', message: 'Clear Scale' })}
295
311
  onClick={() => {
296
312
  handleUpdate({ scaleReference: null } as Partial<GuideNode>)
297
313
  // Calibrating auto-locked the guide; clearing the scale
@@ -303,11 +319,11 @@ export function ReferencePanel() {
303
319
  )}
304
320
  </PanelSection>
305
321
 
306
- <PanelSection title="Quick Actions">
322
+ <PanelSection title={i18n._({ id: 'editor.panels.referencePanel.quickActions', message: 'Quick Actions' })}>
307
323
  <ActionGroup>
308
324
  <ActionButton
309
325
  icon={<LocateFixed className="h-3.5 w-3.5" />}
310
- label="Center"
326
+ label={i18n._({ id: 'editor.panels.referencePanel.center', message: 'Center' })}
311
327
  onClick={() =>
312
328
  handleUpdate({
313
329
  position: [0, node.position[1], 0],
@@ -316,7 +332,7 @@ export function ReferencePanel() {
316
332
  />
317
333
  <ActionButton
318
334
  icon={<RotateCcw className="h-3.5 w-3.5" />}
319
- label="Reset Rotation"
335
+ label={i18n._({ id: 'editor.panels.referencePanel.resetRotation', message: 'Reset Rotation' })}
320
336
  onClick={() =>
321
337
  handleUpdate({
322
338
  rotation: [node.rotation[0], 0, node.rotation[2]],
@@ -327,7 +343,7 @@ export function ReferencePanel() {
327
343
  <ActionGroup>
328
344
  <ActionButton
329
345
  icon={<Ruler className="h-3.5 w-3.5" />}
330
- label="Reset Image Scale"
346
+ label={i18n._({ id: 'editor.panels.referencePanel.resetImageScale', message: 'Reset Image Scale' })}
331
347
  onClick={() => handleUpdate({ scale: 1 } as Partial<GuideNode>)}
332
348
  />
333
349
  </ActionGroup>
@@ -336,11 +352,11 @@ export function ReferencePanel() {
336
352
  )}
337
353
 
338
354
  {isScan && (
339
- <PanelSection title="Capture">
355
+ <PanelSection title={i18n._({ id: 'editor.panels.referencePanel.capture', message: 'Capture' })}>
340
356
  <ActionGroup>
341
357
  <ActionButton
342
358
  icon={<Move className="h-3.5 w-3.5" />}
343
- label="Move"
359
+ label={i18n._({ id: 'editor.panels.referencePanel.move', message: 'Move' })}
344
360
  onClick={handleMoveScan}
345
361
  />
346
362
  <ActionButton
@@ -351,18 +367,18 @@ export function ReferencePanel() {
351
367
  <Eye className="h-3.5 w-3.5" />
352
368
  )
353
369
  }
354
- label={node.visible === false ? 'Show' : 'Hide'}
370
+ label={node.visible === false ? i18n._({ id: 'editor.panels.referencePanel.show', message: 'Show' }) : i18n._({ id: 'editor.panels.referencePanel.hide', message: 'Hide' })}
355
371
  onClick={() => handleUpdate({ visible: node.visible === false })}
356
372
  />
357
373
  </ActionGroup>
358
374
  </PanelSection>
359
375
  )}
360
376
 
361
- <PanelSection title="Position">
377
+ <PanelSection title={i18n._({ id: 'editor.panels.referencePanel.position', message: 'Position' })}>
362
378
  <SliderControl
363
379
  label={
364
380
  <>
365
- X<sub className="ml-[1px] text-[11px] opacity-70">pos</sub>
381
+ X<sub className="ml-[1px] text-[11px] opacity-70">{i18n._({ id: 'editor.panels.referencePanel.pos', message: 'pos' })}</sub>
366
382
  </>
367
383
  }
368
384
  max={50}
@@ -380,7 +396,7 @@ export function ReferencePanel() {
380
396
  <SliderControl
381
397
  label={
382
398
  <>
383
- Y<sub className="ml-[1px] text-[11px] opacity-70">pos</sub>
399
+ Y<sub className="ml-[1px] text-[11px] opacity-70">{i18n._({ id: 'editor.panels.referencePanel.pos', message: 'pos' })}</sub>
384
400
  </>
385
401
  }
386
402
  max={50}
@@ -398,7 +414,7 @@ export function ReferencePanel() {
398
414
  <SliderControl
399
415
  label={
400
416
  <>
401
- Z<sub className="ml-[1px] text-[11px] opacity-70">pos</sub>
417
+ Z<sub className="ml-[1px] text-[11px] opacity-70">{i18n._({ id: 'editor.panels.referencePanel.pos', message: 'pos' })}</sub>
402
418
  </>
403
419
  }
404
420
  max={50}
@@ -415,11 +431,11 @@ export function ReferencePanel() {
415
431
  />
416
432
  </PanelSection>
417
433
 
418
- <PanelSection title="Rotation">
434
+ <PanelSection title={i18n._({ id: 'editor.panels.referencePanel.rotation', message: 'Rotation' })}>
419
435
  <SliderControl
420
436
  label={
421
437
  <>
422
- Y<sub className="ml-[1px] text-[11px] opacity-70">rot</sub>
438
+ Y<sub className="ml-[1px] text-[11px] opacity-70">{i18n._({ id: 'editor.panels.referencePanel.rot', message: 'rot' })}</sub>
423
439
  </>
424
440
  }
425
441
  max={180}
@@ -455,11 +471,11 @@ export function ReferencePanel() {
455
471
  </div>
456
472
  </PanelSection>
457
473
 
458
- <PanelSection title="Scale & Opacity">
474
+ <PanelSection title={i18n._({ id: 'editor.panels.referencePanel.scaleOpacity', message: 'Scale & Opacity' })}>
459
475
  <SliderControl
460
476
  label={
461
477
  <>
462
- XYZ<sub className="ml-[1px] text-[11px] opacity-70">scale</sub>
478
+ {i18n._({ id: 'editor.panels.referencePanel.xyz', message: 'XYZ' })}<sub className="ml-[1px] text-[11px] opacity-70">{i18n._({ id: 'editor.panels.referencePanel.scale', message: 'scale' })}</sub>
463
479
  </>
464
480
  }
465
481
  max={10}
@@ -475,7 +491,7 @@ export function ReferencePanel() {
475
491
  />
476
492
 
477
493
  <SliderControl
478
- label="Opacity"
494
+ label={i18n._({ id: 'editor.panels.referencePanel.opacity', message: 'Opacity' })}
479
495
  max={100}
480
496
  min={0}
481
497
  onChange={(v) => handleUpdate({ opacity: v })}