'use client' import type { DormerNode } from '@pascal-app/core' import { PanelSection, SegmentedControl, SliderControl, ToggleControl } from '@pascal-app/editor' import { useState } from 'react' type WindowShape = DormerNode['windowShape'] type WindowRadiusMode = 'all' | 'individual' function maxSharedRadius(width: number, height: number): number { return Math.max(0, Math.min(width / 2, height / 2)) } /** * The Window tab of the dormer inspector: Hung Wall, Opening, Shape * (with rounded/arch sub-controls), Frame, Grid, Sill. Owns local UI * state for the "All vs Individual" corner-radius view mode — derived * from tuple uniformity by default. */ export function DormerWindowSection({ node, previewProp, commitProp, handleUpdate, }: { node: DormerNode previewProp: (updates: Partial) => void commitProp: (updates: Partial) => void handleUpdate: (updates: Partial) => void }) { const [radiusViewMode, setRadiusViewMode] = useState('all') const windowShape: WindowShape = node.windowShape const windowCornerRadii: [number, number, number, number] = [...node.windowCornerRadii] const windowArchHeight = node.windowArchHeight const maxRadius = Math.max(0.01, maxSharedRadius(node.windowWidth, node.windowHeight)) const tupleIsUniform = windowCornerRadii[0] === windowCornerRadii[1] && windowCornerRadii[1] === windowCornerRadii[2] && windowCornerRadii[2] === windowCornerRadii[3] const sharedRadius = windowCornerRadii[0] const setCornerRadius = (index: number, value: number, commit: boolean) => { const next = [...windowCornerRadii] as [number, number, number, number] next[index] = value if (commit) commitProp({ windowCornerRadii: next }) else previewProp({ windowCornerRadii: next }) } const setAllCornerRadii = (value: number, commit: boolean) => { const next: [number, number, number, number] = [value, value, value, value] if (commit) commitProp({ windowCornerRadii: next }) else previewProp({ windowCornerRadii: next }) } return ( <> previewProp({ wallSkirtHeight: v })} onCommit={(v) => commitProp({ wallSkirtHeight: v })} precision={2} restoreOnCommit={false} step={0.05} unit="m" value={Math.round(node.wallSkirtHeight * 100) / 100} /> previewProp({ windowWidth: v })} onCommit={(v) => commitProp({ windowWidth: v })} precision={2} restoreOnCommit={false} step={0.05} unit="m" value={Math.round(node.windowWidth * 100) / 100} /> previewProp({ windowHeight: v })} onCommit={(v) => commitProp({ windowHeight: v })} precision={2} restoreOnCommit={false} step={0.05} unit="m" value={Math.round(node.windowHeight * 100) / 100} /> previewProp({ windowOffsetX: v })} onCommit={(v) => commitProp({ windowOffsetX: v })} precision={2} restoreOnCommit={false} step={0.05} unit="m" value={Math.round(node.windowOffsetX * 100) / 100} /> previewProp({ windowOffsetY: v })} onCommit={(v) => commitProp({ windowOffsetY: v })} precision={2} restoreOnCommit={false} step={0.05} unit="m" value={Math.round(node.windowOffsetY * 100) / 100} /> handleUpdate({ windowShape: v as WindowShape, ...(v === 'rounded' ? { windowCornerRadii: windowCornerRadii.map((r) => Math.min(r, maxRadius)) as [ number, number, number, number, ], } : {}), }) } options={[ { value: 'rectangle', label: 'Rect' }, { value: 'rounded', label: 'Rounded' }, { value: 'arch', label: 'Arch' }, ]} value={windowShape} /> {windowShape === 'rounded' && (
setRadiusViewMode(v as WindowRadiusMode)} options={[ { value: 'all', label: 'All' }, { value: 'individual', label: 'Individual' }, ]} value={tupleIsUniform ? radiusViewMode : 'individual'} /> {tupleIsUniform && radiusViewMode === 'all' ? ( setAllCornerRadii(v, false)} onCommit={(v) => setAllCornerRadii(v, true)} precision={2} restoreOnCommit={false} step={0.01} unit="m" value={Math.round(sharedRadius * 100) / 100} /> ) : ( ( [ ['Top Left', 0], ['Top Right', 1], ['Bottom Right', 2], ['Bottom Left', 3], ] as const ).map(([label, index]) => ( setCornerRadius(index, v, false)} onCommit={(v) => setCornerRadius(index, v, true)} precision={2} restoreOnCommit={false} step={0.01} unit="m" value={Math.round((windowCornerRadii[index] ?? 0) * 100) / 100} /> )) )}
)} {windowShape === 'arch' && ( previewProp({ windowArchHeight: v })} onCommit={(v) => commitProp({ windowArchHeight: v })} precision={2} restoreOnCommit={false} step={0.05} unit="m" value={Math.round(windowArchHeight * 100) / 100} /> )}
previewProp({ windowFrameThickness: v })} onCommit={(v) => commitProp({ windowFrameThickness: v })} precision={3} restoreOnCommit={false} step={0.005} unit="m" value={Math.round(node.windowFrameThickness * 1000) / 1000} /> previewProp({ windowFrameDepth: v })} onCommit={(v) => commitProp({ windowFrameDepth: v })} precision={3} restoreOnCommit={false} step={0.005} unit="m" value={Math.round(node.windowFrameDepth * 1000) / 1000} /> previewProp({ windowDividerThickness: v })} onCommit={(v) => commitProp({ windowDividerThickness: v })} precision={3} restoreOnCommit={false} step={0.002} unit="m" value={Math.round(node.windowDividerThickness * 1000) / 1000} /> previewProp({ windowColumns: Math.max(1, Math.min(8, Math.round(v))) })} onCommit={(v) => commitProp({ windowColumns: Math.max(1, Math.min(8, Math.round(v))) })} precision={0} restoreOnCommit={false} step={1} value={node.windowColumns} /> previewProp({ windowRows: Math.max(1, Math.min(8, Math.round(v))) })} onCommit={(v) => commitProp({ windowRows: Math.max(1, Math.min(8, Math.round(v))) })} precision={0} restoreOnCommit={false} step={1} value={node.windowRows} /> handleUpdate({ windowSill: checked })} /> {node.windowSill && (
previewProp({ windowSillDepth: v })} onCommit={(v) => commitProp({ windowSillDepth: v })} precision={3} restoreOnCommit={false} step={0.01} unit="m" value={Math.round(node.windowSillDepth * 1000) / 1000} /> previewProp({ windowSillThickness: v })} onCommit={(v) => commitProp({ windowSillThickness: v })} precision={3} restoreOnCommit={false} step={0.005} unit="m" value={Math.round(node.windowSillThickness * 1000) / 1000} />
)}
) }