'use client' // Lightweight viewer-settings toolbar for the converter preview. Drives // the same `useViewer` store the editor's own toolbar drives — the full // `@pascal-app/editor` Editor shell didn't fit (its CSS expects a // full-page layout) and we don't need its editing tools here. // // Once the editor extracts its toolbar into a reusable shell component, // this file can collapse to an import. import { type AnyNode, type LevelNode, useScene } from '@pascal-app/core' import { useViewer } from '@pascal-app/viewer' import { Box, Grid2x2, Layers, Layers2, Maximize, ScanLine, Square } from 'lucide-react' import { type ReactNode, useMemo } from 'react' const levelModes = ['stacked', 'solo', 'exploded', 'manual'] as const const wallModes = ['up', 'cutaway', 'down'] as const const levelLabel: Record<(typeof levelModes)[number], string> = { stacked: 'Stack', solo: 'Solo', exploded: 'Exploded', manual: 'Manual', } const wallLabel: Record<(typeof wallModes)[number], string> = { up: 'Full', cutaway: 'Cutaway', down: 'Down', } function cycle(list: readonly T[], current: T): T { const i = list.indexOf(current) return list[(i + 1) % list.length] ?? list[0]! } function ToolButton({ active, label, icon, onClick, }: { active?: boolean label: string icon: ReactNode onClick: () => void }) { return ( ) } export function PreviewToolbar() { const cameraMode = useViewer((s) => s.cameraMode) const setCameraMode = useViewer((s) => s.setCameraMode) const showGrid = useViewer((s) => s.showGrid) const setShowGrid = useViewer((s) => s.setShowGrid) const levelMode = useViewer((s) => s.levelMode) const setLevelMode = useViewer((s) => s.setLevelMode) const wallMode = useViewer((s) => s.wallMode) const setWallMode = useViewer((s) => s.setWallMode) return (
) : ( ) } label={cameraMode === 'perspective' ? 'Perspective' : 'Orthographic'} onClick={() => setCameraMode(cameraMode === 'perspective' ? 'orthographic' : 'perspective')} /> : } label={`Levels: ${levelLabel[levelMode]}`} onClick={() => setLevelMode(cycle(levelModes, levelMode))} /> } label={`Walls: ${wallLabel[wallMode]}`} onClick={() => setWallMode(cycle(wallModes, wallMode))} /> } label="Grid" onClick={() => setShowGrid(!showGrid)} />
) } export function FitSceneButton({ onFit }: { onFit: () => void }) { return ( ) } /** * Vertical level picker, top-floor first (matches the way you'd read a * building section). Highlights `useViewer.selection.levelId` so it * stays in sync with the editor's own LevelSystem (e.g. when Solo mode * hides every level except the selected one). Hidden when the scene * has 0 or 1 levels — no point picking from a list of one. */ export function LevelSelector() { const nodes = useScene((s) => s.nodes) const selection = useViewer((s) => s.selection) const setSelection = useViewer((s) => s.setSelection) const levels = useMemo(() => { const list = Object.values(nodes as Record).filter( (n): n is LevelNode => n.type === 'level', ) // Top floor first. return list.slice().sort((a, b) => b.level - a.level) }, [nodes]) if (levels.length <= 1) return null const selectedId = selection.levelId return (
{levels.map((level) => { const active = level.id === selectedId return ( ) })}
) }