// Einstellungs-Fenster (modal). HANDOVER-Backlog Punkt 4: Default-Farbe des // Auswahlrahmens (Marquee) + der Snap-/Endpunkt-Hervorhebung im Grundriss, // beide mit freiem Farbpicker + Akzent-Schnellauswahl; dazu ein Projekt-Feld // für die Referenzhöhe des Erdgeschosses (m ü. M.). // // Rein gesteuert: Marquee-/Snap-Farbe kommen aus der ViewSlice (App reicht // Wert + Setter durch), das MüM-Feld schreibt direkt ins Projekt über die // bestehende `setProject`-Aktion. Muster wie ExportDxfDialog (abgedunkeltes // Overlay, Klick auf Hintergrund + Esc schliessen). // Bezeichner englisch, UI-Text/Kommentare deutsch (CONVENTIONS.md). import { useEffect, useState } from "react"; import type { ReactNode } from "react"; import { t } from "../i18n"; import { ACCENT_SWATCHES } from "../theme/accents"; import type { Project } from "../model/types"; import { ColorHexField } from "./ColorHexField"; import type { RendererMode } from "./StatusBar"; export interface SettingsDialogProps { marqueeColor: string; onMarqueeColorChange: (hex: string) => void; snapColor: string; onSnapColorChange: (hex: string) => void; project: Project; setProject: (next: Project | ((p: Project) => Project)) => void; /** Aktuell gewählter Plan-Renderer (aus dem `?engine`-URL-Param abgeleitet). */ rendererMode: RendererMode; /** Ist `navigator.gpu` vorhanden? Steuert, ob „Nordstern" wählbar ist. */ webGpuAvailable: boolean; /** * Renderer wechseln (setzt/entfernt den `engine`-URL-Param und lädt neu — kein * Live-Remount der Renderer-Hooks). */ onRendererModeChange: (mode: RendererMode) => void; /** Arbeitsumgebung-Auswahl (Fenster-/Dock-Layouts) — früher in der TopBar. */ layoutMenu: ReactNode; onClose: () => void; } export function SettingsDialog({ marqueeColor, onMarqueeColorChange, snapColor, onSnapColorChange, project, setProject, rendererMode, webGpuAvailable, onRendererModeChange, layoutMenu, onClose, }: SettingsDialogProps) { useEffect(() => { const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [onClose]); // Lokaler Textzustand fürs MüM-Feld: erlaubt Zwischenzustände beim Tippen // (leer, "412." etc.), ohne bei jedem Tastendruck einen ungültigen/ // gerundeten Projektwert zu schreiben. Synchronisiert sich, wenn sich das // Projekt von aussen ändert (z. B. Undo/Import). const [elevationText, setElevationText] = useState( project.referenceElevationMasl != null ? String(project.referenceElevationMasl) : "", ); useEffect(() => { setElevationText( project.referenceElevationMasl != null ? String(project.referenceElevationMasl) : "", ); }, [project.referenceElevationMasl]); const commitElevation = (raw: string) => { setElevationText(raw); const trimmed = raw.trim(); if (trimmed === "") { setProject((p) => ({ ...p, referenceElevationMasl: undefined })); return; } const n = Number(trimmed); if (Number.isFinite(n)) { setProject((p) => ({ ...p, referenceElevationMasl: n })); } }; return (