Oberleisten-/Status-Zustand aus App.tsx in useTopBarState() extrahiert

Bündelt Detailstufe, 3D-Rendermodus, Sichtfeld, Boden-Referenzraster,
Plan-Farbmodus, Achslinien, Linienmodus, Fadenkreuz-/Snap-Farbe,
Papier-Massstab, Live-Zoom, Cursor und Ausschnitt-Auswahl (Teil der
laufenden App.tsx-Verkleinerung).
This commit is contained in:
2026-07-22 00:28:34 +02:00
parent 3b8d48eaf5
commit 18aee59cff
2 changed files with 124 additions and 44 deletions
+32 -44
View File
@@ -158,6 +158,7 @@ import { useContextMenuState } from "./menus/useContextMenuState";
import { InlineEditor } from "./views/InlineEditor"; import { InlineEditor } from "./views/InlineEditor";
import { Content } from "./views/viewportContent"; import { Content } from "./views/viewportContent";
import { useDialogState } from "./state/useDialogState"; import { useDialogState } from "./state/useDialogState";
import { useTopBarState } from "./state/useTopBarState";
import { useThemeModeState } from "./theme/useThemeMode"; import { useThemeModeState } from "./theme/useThemeMode";
import { CommandLine } from "./ui/CommandLine"; import { CommandLine } from "./ui/CommandLine";
import type { CommandLineHandle, CommandLineField, CommandLineOption } from "./ui/CommandLine"; import type { CommandLineHandle, CommandLineField, CommandLineOption } from "./ui/CommandLine";
@@ -396,50 +397,37 @@ export default function App() {
// ── Oberleisten-/Status-Zustand (View-State, kein Modell) ───────────────── // ── Oberleisten-/Status-Zustand (View-State, kein Modell) ─────────────────
// detail wirkt im Grundriss (Symbole + Schraffuren/Linien), renderMode in der // detail wirkt im Grundriss (Symbole + Schraffuren/Linien), renderMode in der
// 3D-Ansicht (3 Modi), referenceLines schaltet die Wand-Achslinien. // 3D-Ansicht (3 Modi), referenceLines schaltet die Wand-Achslinien.
const detail = useStore((s) => s.detail); const {
const setDetail = useStore((s) => s.setDetail); detail,
const renderMode = useStore((s) => s.renderMode); setDetail,
const setRenderMode = useStore((s) => s.setRenderMode); renderMode,
const view3d = useStore((s) => s.view3d); setRenderMode,
const setView3d = useStore((s) => s.setView3d); view3d,
const fov = useStore((s) => s.fov); setView3d,
const setFov = useStore((s) => s.setFov); fov,
// Boden-Referenzraster im 3D-Viewport (wirkt nur im WASM/Nordstern-Pfad, setFov,
// s. Wasm3DViewport.tsx) — Umschalter sitzt als Overlay-Button im Viewport. grid3dVisible,
const grid3dVisible = useStore((s) => s.grid3dVisible); setGrid3dVisible,
const setGrid3dVisible = useStore((s) => s.setGrid3dVisible); planColorMode,
const planColorMode = useStore((s) => s.planColorMode); setPlanColorMode,
const setPlanColorMode = useStore((s) => s.setPlanColorMode); referenceLines,
const referenceLines = useStore((s) => s.referenceLines); setReferenceLines,
const setReferenceLines = useStore((s) => s.setReferenceLines); lineMode,
const lineMode = useStore((s) => s.lineMode); setLineMode,
const setLineMode = useStore((s) => s.setLineMode); marqueeColor,
const marqueeColor = useStore((s) => s.marqueeColor); setMarqueeColor,
const setMarqueeColor = useStore((s) => s.setMarqueeColor); snapColor,
const snapColor = useStore((s) => s.snapColor); setSnapColor,
const setSnapColor = useStore((s) => s.setSnapColor); scaleDenominator,
const scaleDenominator = useStore((s) => s.scaleDenominator); setScaleDenominator,
const setScaleDenominator = useStore((s) => s.setScaleDenominator); liveScale,
// LIVE Papier-Massstab-Nenner aus der View-Transform (PlanView meldet ihn); setLiveScale,
// null = keine Plan-Ansicht aktiv. Transienter UI-State, bleibt lokal. selectedViewSnapshotId,
const [liveScale, setLiveScale] = useState<number | null>(null); setSelectedViewSnapshotId,
// „Angewählter" Ausschnitt (View-Snapshot): bleibt gesetzt, solange der cursor,
// Live-Zustand EXAKT dem Ausschnitt entspricht (siehe Effekt weiter unten). setCursor,
// Steuert die Footer-Bar + die Aktiv-Markierung im Ausschnitte-Panel. zoomPercent,
const [selectedViewSnapshotId, setSelectedViewSnapshotId] = useState< } = useTopBarState();
string | null
>(null);
// Cursor in Modell-Metern (aus der Plan-Ansicht) bzw. null (nicht über Plan).
const [cursor, setCursor] = useState<Vec2 | null>(null);
// Live-Zoom in Prozent RELATIV zum angewandten Papier-Massstab: 100 % =
// Live-Ansicht steht exakt im angewandten Massstab (liveScale == scaleDenominator).
// Reinzoomen > 100 %, Rauszoomen < 100 %. Einzige Quelle: angewandter Nenner
// (scaleDenominator) / Live-Nenner (liveScale). Ohne Live-Massstab (keine
// Plan-Ansicht) Fallback 100 %.
const zoomPercent =
liveScale != null && liveScale > 0
? (scaleDenominator / liveScale) * 100
: 100;
// ── Zeichenwerkzeuge (transienter View-State; bleibt lokal) ─────────────── // ── Zeichenwerkzeuge (transienter View-State; bleibt lokal) ───────────────
// Aktives Werkzeug, Werkzeug-Parameter (Wandtyp/Kategorie/Linienstil), Snap- // Aktives Werkzeug, Werkzeug-Parameter (Wandtyp/Kategorie/Linienstil), Snap-
+92
View File
@@ -0,0 +1,92 @@
// Bündelt den Oberleisten-/Status-Zustand (View-State, kein Modell): Detail-
// stufe, 3D-Rendermodus, Feldweite, Boden-Referenzraster, Plan-Farbmodus,
// Wand-Achslinien, Linienmodus, Fadenkreuz-/Snap-Farbe und Papier-Massstab
// kommen aus dem Store; liveScale/selectedViewSnapshotId/cursor sind rein
// lokaler UI-State (PlanView meldet den Live-Massstab, kein Undo/Redo-Bezug).
// zoomPercent ist daraus abgeleitet. Nur aus App() herausgezogen, um die
// Funktion zu entlasten — reine Zustands-Bündelung, keine Verhaltensänderung.
//
// Extrahiert aus App.tsx. Bezeichner englisch, Kommentare deutsch (CONVENTIONS.md).
import { useState } from "react";
import { useStore } from "./appStore";
import type { Vec2 } from "../model/types";
export function useTopBarState() {
const detail = useStore((s) => s.detail);
const setDetail = useStore((s) => s.setDetail);
const renderMode = useStore((s) => s.renderMode);
const setRenderMode = useStore((s) => s.setRenderMode);
const view3d = useStore((s) => s.view3d);
const setView3d = useStore((s) => s.setView3d);
const fov = useStore((s) => s.fov);
const setFov = useStore((s) => s.setFov);
// Boden-Referenzraster im 3D-Viewport (wirkt nur im WASM/Nordstern-Pfad,
// s. Wasm3DViewport.tsx) — Umschalter sitzt als Overlay-Button im Viewport.
const grid3dVisible = useStore((s) => s.grid3dVisible);
const setGrid3dVisible = useStore((s) => s.setGrid3dVisible);
const planColorMode = useStore((s) => s.planColorMode);
const setPlanColorMode = useStore((s) => s.setPlanColorMode);
const referenceLines = useStore((s) => s.referenceLines);
const setReferenceLines = useStore((s) => s.setReferenceLines);
const lineMode = useStore((s) => s.lineMode);
const setLineMode = useStore((s) => s.setLineMode);
const marqueeColor = useStore((s) => s.marqueeColor);
const setMarqueeColor = useStore((s) => s.setMarqueeColor);
const snapColor = useStore((s) => s.snapColor);
const setSnapColor = useStore((s) => s.setSnapColor);
const scaleDenominator = useStore((s) => s.scaleDenominator);
const setScaleDenominator = useStore((s) => s.setScaleDenominator);
// LIVE Papier-Massstab-Nenner aus der View-Transform (PlanView meldet ihn);
// null = keine Plan-Ansicht aktiv. Transienter UI-State, bleibt lokal.
const [liveScale, setLiveScale] = useState<number | null>(null);
// „Angewählter" Ausschnitt (View-Snapshot): bleibt gesetzt, solange der
// Live-Zustand EXAKT dem Ausschnitt entspricht (siehe Effekt weiter unten).
// Steuert die Footer-Bar + die Aktiv-Markierung im Ausschnitte-Panel.
const [selectedViewSnapshotId, setSelectedViewSnapshotId] = useState<
string | null
>(null);
// Cursor in Modell-Metern (aus der Plan-Ansicht) bzw. null (nicht über Plan).
const [cursor, setCursor] = useState<Vec2 | null>(null);
// Live-Zoom in Prozent RELATIV zum angewandten Papier-Massstab: 100 % =
// Live-Ansicht steht exakt im angewandten Massstab (liveScale == scaleDenominator).
// Reinzoomen > 100 %, Rauszoomen < 100 %. Einzige Quelle: angewandter Nenner
// (scaleDenominator) / Live-Nenner (liveScale). Ohne Live-Massstab (keine
// Plan-Ansicht) Fallback 100 %.
const zoomPercent =
liveScale != null && liveScale > 0
? (scaleDenominator / liveScale) * 100
: 100;
return {
detail,
setDetail,
renderMode,
setRenderMode,
view3d,
setView3d,
fov,
setFov,
grid3dVisible,
setGrid3dVisible,
planColorMode,
setPlanColorMode,
referenceLines,
setReferenceLines,
lineMode,
setLineMode,
marqueeColor,
setMarqueeColor,
snapColor,
setSnapColor,
scaleDenominator,
setScaleDenominator,
liveScale,
setLiveScale,
selectedViewSnapshotId,
setSelectedViewSnapshotId,
cursor,
setCursor,
zoomPercent,
};
}