/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * SheetSetupPanel - Configure drawing sheet for architectural output * * Provides controls for: * - Paper size selection (ISO, ANSI, ARCH) * - Drawing frame style * - Scale selection * - Title block configuration * - Scale bar and north arrow */ import React, { useCallback, useState, useMemo } from 'react'; import { X, FileText, ChevronDown, ChevronRight, Ruler, Compass, Edit3, Save, Trash2, Plus, } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Label } from '@/components/ui/label'; import { Switch } from '@/components/ui/switch'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from '@/components/ui/collapsible'; import { useViewerStore } from '@/store'; import { PAPER_SIZE_REGISTRY, FRAME_PRESETS, TITLE_BLOCK_PRESETS, COMMON_SCALES, type FrameStyle, type TitleBlockLayout, type DrawingScale, } from '@ifc-lite/drawing-2d'; interface SheetSetupPanelProps { onClose: () => void; onOpenTitleBlockEditor?: () => void; } // Group paper sizes by category const PAPER_SIZE_GROUPS = { ISO: ['A0_PORTRAIT', 'A0_LANDSCAPE', 'A1_PORTRAIT', 'A1_LANDSCAPE', 'A2_PORTRAIT', 'A2_LANDSCAPE', 'A3_PORTRAIT', 'A3_LANDSCAPE', 'A4_PORTRAIT', 'A4_LANDSCAPE'], ANSI: ['LETTER_PORTRAIT', 'LETTER_LANDSCAPE', 'LEGAL_PORTRAIT', 'LEGAL_LANDSCAPE', 'TABLOID_PORTRAIT', 'TABLOID_LANDSCAPE', 'ANSI_C', 'ANSI_D', 'ANSI_E'], ARCH: ['ARCH_A', 'ARCH_B', 'ARCH_C', 'ARCH_D', 'ARCH_E', 'ARCH_E1'], }; const FRAME_STYLE_OPTIONS: { value: FrameStyle; label: string }[] = [ { value: 'simple', label: 'Simple' }, { value: 'professional', label: 'Professional' }, { value: 'minimal', label: 'Minimal' }, { value: 'iso', label: 'ISO Standard' }, ]; const TITLE_BLOCK_LAYOUT_OPTIONS: { value: TitleBlockLayout; label: string }[] = [ { value: 'standard', label: 'Standard (Bottom Right)' }, { value: 'extended', label: 'Extended (Full Width)' }, { value: 'compact', label: 'Compact (Smaller)' }, ]; export function SheetSetupPanel({ onClose, onOpenTitleBlockEditor }: SheetSetupPanelProps): React.ReactElement { const activeSheet = useViewerStore((s) => s.activeSheet); const sheetEnabled = useViewerStore((s) => s.sheetEnabled); const setSheetEnabled = useViewerStore((s) => s.setSheetEnabled); const createSheet = useViewerStore((s) => s.createSheet); const setPaperSize = useViewerStore((s) => s.setPaperSize); const setFrameStyle = useViewerStore((s) => s.setFrameStyle); const setDrawingScale = useViewerStore((s) => s.setDrawingScale); const setTitleBlockLayout = useViewerStore((s) => s.setTitleBlockLayout); const toggleScaleBar = useViewerStore((s) => s.toggleScaleBar); const toggleNorthArrow = useViewerStore((s) => s.toggleNorthArrow); const savedSheetTemplates = useViewerStore((s) => s.savedSheetTemplates); const saveAsTemplate = useViewerStore((s) => s.saveAsTemplate); const loadTemplate = useViewerStore((s) => s.loadTemplate); const deleteTemplate = useViewerStore((s) => s.deleteTemplate); // Section state const [paperSizeOpen, setPaperSizeOpen] = useState(true); const [frameOpen, setFrameOpen] = useState(true); const [scaleOpen, setScaleOpen] = useState(true); const [titleBlockOpen, setTitleBlockOpen] = useState(true); const [scaleBarOpen, setScaleBarOpen] = useState(true); const [templatesOpen, setTemplatesOpen] = useState(false); const [newTemplateName, setNewTemplateName] = useState(''); // Get current paper size ID const currentPaperId = useMemo(() => { if (!activeSheet) return 'A3_LANDSCAPE'; const paper = activeSheet.paper; // Find matching paper in registry for (const [id, def] of Object.entries(PAPER_SIZE_REGISTRY)) { if (def.widthMm === paper.widthMm && def.heightMm === paper.heightMm) { return id; } } return 'A3_LANDSCAPE'; }, [activeSheet]); // Initialize sheet if needed const handleEnableSheet = useCallback((enabled: boolean) => { if (enabled && !activeSheet) { createSheet(); } setSheetEnabled(enabled); }, [activeSheet, createSheet, setSheetEnabled]); // Paper size change const handlePaperSizeChange = useCallback((paperId: string) => { setPaperSize(paperId); }, [setPaperSize]); // Frame style change const handleFrameStyleChange = useCallback((style: string) => { setFrameStyle(style as FrameStyle); }, [setFrameStyle]); // Scale change const handleScaleChange = useCallback((scaleName: string) => { const scale = COMMON_SCALES.find((s) => s.name === scaleName); if (scale) { setDrawingScale(scale); } }, [setDrawingScale]); // Title block layout change const handleTitleBlockLayoutChange = useCallback((layout: string) => { setTitleBlockLayout(layout as TitleBlockLayout); }, [setTitleBlockLayout]); // Save template const handleSaveTemplate = useCallback(() => { if (newTemplateName.trim()) { saveAsTemplate(newTemplateName.trim()); setNewTemplateName(''); } }, [newTemplateName, saveAsTemplate]); return (
{/* Header */}

Drawing Sheet

{/* Content */}
{!activeSheet && !sheetEnabled ? (

Enable drawing sheet to configure paper size, frame, and title block.

) : ( <> {/* Paper Size Section */}
{activeSheet && (
{activeSheet.paper.widthMm} × {activeSheet.paper.heightMm} mm
)}
{/* Frame Section */}
{activeSheet && (
Margins: {activeSheet.frame.margins.top}/{activeSheet.frame.margins.right}/{activeSheet.frame.margins.bottom}/{activeSheet.frame.margins.left}mm
)}
{/* Scale Section */}
{/* Title Block Section */}
{activeSheet && (
{activeSheet.titleBlock.widthMm} × {activeSheet.titleBlock.heightMm}mm
{activeSheet.titleBlock.fields.length} fields configured
)}
{/* Scale Bar & North Arrow Section */}
{/* Scale Bar Toggle */}
{/* North Arrow Toggle */}
{/* Templates Section */}
{/* Save current as template */}
setNewTemplateName(e.target.value)} className="h-8 text-sm flex-1" />
{/* Template list */} {savedSheetTemplates.length === 0 ? (
No saved templates
) : (
{savedSheetTemplates.map((template) => (
{template.name}
))}
)}
{/* Viewport Info */} {activeSheet && (
Drawing Area:{' '} {activeSheet.viewportBounds.width.toFixed(1)} ×{' '} {activeSheet.viewportBounds.height.toFixed(1)} mm
Scale: {activeSheet.scale.name}
)} )}
); }