({
projectName,
owner,
canShowScans = true,
canShowGuides = true,
onBack,
}: ViewerOverlayProps)
| 240 | } |
| 241 | |
| 242 | export const ViewerOverlay = ({ |
| 243 | projectName, |
| 244 | owner, |
| 245 | canShowScans = true, |
| 246 | canShowGuides = true, |
| 247 | onBack, |
| 248 | }: ViewerOverlayProps) => { |
| 249 | const selection = useViewer((s) => s.selection) |
| 250 | const showScans = useViewer((s) => s.showScans) |
| 251 | const showGuides = useViewer((s) => s.showGuides) |
| 252 | const cameraMode = useViewer((s) => s.cameraMode) |
| 253 | const levelMode = useViewer((s) => s.levelMode) |
| 254 | const wallMode = useViewer((s) => s.wallMode) |
| 255 | |
| 256 | // Subscribe only to the specific nodes we read so that creating an unrelated |
| 257 | // node elsewhere in the scene doesn't re-render this overlay. |
| 258 | const firstSelectedId = selection.selectedIds[0] ?? null |
| 259 | const building = useScene((s) => |
| 260 | selection.buildingId ? (s.nodes[selection.buildingId] as BuildingNode | undefined) : null, |
| 261 | ) |
| 262 | const level = useScene((s) => |
| 263 | selection.levelId ? (s.nodes[selection.levelId] as LevelNode | undefined) : null, |
| 264 | ) |
| 265 | const zone = useScene((s) => |
| 266 | selection.zoneId ? (s.nodes[selection.zoneId] as ZoneNode | undefined) : null, |
| 267 | ) |
| 268 | const selectedNode = useScene((s) => |
| 269 | firstSelectedId ? (s.nodes[firstSelectedId as AnyNodeId] as AnyNode | undefined) : null, |
| 270 | ) |
| 271 | const levels = useScene( |
| 272 | useShallow((s) => { |
| 273 | if (!building) return [] |
| 274 | return building.children |
| 275 | .map((id) => s.nodes[id as AnyNodeId] as LevelNode | undefined) |
| 276 | .filter((n): n is LevelNode => n?.type === 'level') |
| 277 | .sort((a, b) => a.level - b.level) |
| 278 | }), |
| 279 | ) |
| 280 | |
| 281 | const handleLevelClick = (levelId: LevelNode['id']) => { |
| 282 | // When switching levels, deselect zone and items |
| 283 | useViewer.getState().setSelection({ levelId }) |
| 284 | } |
| 285 | |
| 286 | const handleBreadcrumbClick = (depth: 'root' | 'building' | 'level' | 'zone') => { |
| 287 | switch (depth) { |
| 288 | case 'root': |
| 289 | useViewer.getState().resetSelection() |
| 290 | break |
| 291 | case 'building': |
| 292 | useViewer.getState().setSelection({ levelId: null }) |
| 293 | break |
| 294 | case 'level': |
| 295 | useViewer.getState().setSelection({ zoneId: null }) |
| 296 | break |
| 297 | } |
| 298 | } |
| 299 |
nothing calls this directly
no test coverage detected
searching dependent graphs…