Öffnung: ⚙-Knopf springt in den Tür-/Fenstertyp-Editor

Discoverability für die vertieften Bauteil-Typen: neben dem Typ-Dropdown
einer gewählten Öffnung öffnet ein ⚙-Knopf das Ressourcen-Fenster direkt
beim passenden Typeditor-Tab (Tür→doorStyles, Fenster→windowStyles).
- ResourceManager: initialTab-Prop (springt auch bei bereits offenem
  Fenster auf den angeforderten Tab).
- host.onEditOpeningType(kind) + App-Wiring (resourcesTab-State).
tsc + vitest 620 grün.
This commit is contained in:
2026-07-09 01:44:13 +02:00
parent 4ac2ecb504
commit 586c1c99bf
7 changed files with 56 additions and 5 deletions
+9 -1
View File
@@ -93,7 +93,7 @@ import { Viewport3D } from "./viewport/Viewport3D";
import type { DisplayResolver, ViewportContextInfo } from "./viewport/Viewport3D";
import type { Pick3dHit } from "./viewport/Wasm3DViewport";
import { ResourceManager } from "./ui/ResourceManager";
import type { ResourceManagerHandlers } from "./ui/ResourceManager";
import type { ResourceManagerHandlers, TabId as ResourceTabId } from "./ui/ResourceManager";
import { LayoutSheetView } from "./ui/LayoutSheet";
import {
createLayout,
@@ -408,6 +408,9 @@ export default function App() {
// bleibt lokal. Wird über die Oberleiste geöffnet und über X / Hintergrund-
// Klick / Esc geschlossen.
const [resourcesOpen, setResourcesOpen] = useState(false);
// Angeforderter Start-Tab des Ressourcen-Fensters (z. B. „doorStyles", wenn man
// von einer gewählten Tür in den Typeditor springt).
const [resourcesTab, setResourcesTab] = useState<ResourceTabId>("components");
// Aktives Layout-Blatt im HAUPT-Viewport (DOSSIER A3, Phase 2b): Id des offenen
// Layouts oder null (= normale Modell-Ansicht). Transienter UI-State; das
@@ -3109,6 +3112,10 @@ export default function App() {
if (selection?.kind === "opening")
updateOpening(selection.id, { typeId: typeId || undefined });
},
onEditOpeningType: (kind) => {
setResourcesTab(kind === "door" ? "doorStyles" : "windowStyles");
setResourcesOpen(true);
},
// ── Treppen-Attribute (nur bei selektierter Treppe) ────────────────────
onSetStairShape: (shape) => {
if (selection?.kind === "stair") updateStair(selection.id, { shape });
@@ -4910,6 +4917,7 @@ export default function App() {
<ResourceManager
project={project}
handlers={resourceHandlers}
initialTab={resourcesTab}
onClose={() => setResourcesOpen(false)}
/>
)}
+1
View File
@@ -340,6 +340,7 @@ export const de = {
// ── Öffnungs-Attribute (Object-Info-Panel) ──────────────────────────────
"objinfo.opening.section": "Öffnung",
"objinfo.opening.type": "Typ",
"objinfo.opening.editType": "Typ bearbeiten (Ressourcen)",
"objinfo.stair.type": "Typ",
"objinfo.type.none": "(kein Typ)",
"objinfo.opening.kind": "Art",
+1
View File
@@ -340,6 +340,7 @@ export const en: Record<TranslationKey, string> = {
// ── Opening attributes (object info panel) ──────────────────────────────
"objinfo.opening.section": "Opening",
"objinfo.opening.type": "Type",
"objinfo.opening.editType": "Edit type (Resources)",
"objinfo.stair.type": "Type",
"objinfo.type.none": "(no type)",
"objinfo.opening.kind": "Type",
+12 -2
View File
@@ -578,7 +578,8 @@ export function OpeningSection({
<div className="objinfo-sep" />
<div className="objinfo-section-label">{t("objinfo.opening.section")}</div>
{/* Tür-/Fenstertyp (Bibliothek) — je nach Art aus doorTypes bzw. windowTypes. */}
{/* Tür-/Fenstertyp (Bibliothek) je nach Art aus doorTypes bzw. windowTypes.
Der -Knopf springt direkt in den Typeditor (Ressourcen-Fenster). */}
<div className="objinfo-field">
<span className="objinfo-flabel">{t("objinfo.opening.type")}</span>
<Dropdown
@@ -592,8 +593,17 @@ export function OpeningSection({
).map((ty) => ({ value: ty.id, label: ty.name })),
]}
title={t("objinfo.opening.type")}
width={130}
width={106}
/>
<button
type="button"
className="objinfo-typebtn"
title={t("objinfo.opening.editType")}
aria-label={t("objinfo.opening.editType")}
onClick={() => host.onEditOpeningType(isDoor ? "door" : "window")}
>
</button>
</div>
{/* Art-Segment Fenster/Tür. */}
+5
View File
@@ -294,6 +294,11 @@ export interface PanelHostValue {
onSetOpeningLintelLines: (lintelLines: "keine" | "innen" | "aussen" | "beide") => void;
/** Weist der Öffnung einen Tür-/Fenstertyp (Bibliothek) zu; "" löst die Zuweisung. */
onSetOpeningType: (typeId: string) => void;
/**
* Öffnet das Ressourcen-Fenster direkt beim Tür- bzw. Fenstertyp-Editor
* (Discoverability: von der gewählten Öffnung in den Typeditor springen).
*/
onEditOpeningType: (kind: "door" | "window") => void;
// ── Treppen-Attribute (Object-Info-Panel; nur die selektierte Treppe) ───
/** Setzt die Grundform (gerade/L/Wendel). */
+18
View File
@@ -4044,6 +4044,24 @@ body {
letter-spacing: 0.04em;
margin: 2px 2px 4px;
}
/* „Typ bearbeiten"-Knopf (⚙) neben dem Öffnungstyp-Dropdown. */
.objinfo-typebtn {
margin-left: 4px;
width: 22px;
height: 22px;
padding: 0;
border: 1px solid var(--border, #444);
border-radius: 4px;
background: transparent;
color: var(--fg, inherit);
cursor: pointer;
font-size: 12px;
line-height: 1;
}
.objinfo-typebtn:hover {
background: var(--hover, rgba(127, 127, 127, 0.18));
}
/* Mess-Werkzeug: Live-Messwerte im Objekt-Info-Panel. */
.objinfo-measure {
margin: 2px 2px 8px;
+10 -2
View File
@@ -2951,7 +2951,7 @@ function EmptyState({ text }: { text: string }) {
// ── Manager-Schublade ──────────────────────────────────────────────────────
type TabId =
export type TabId =
| "components"
| "hatches"
| "lines"
@@ -3064,12 +3064,20 @@ export function ResourceManager({
project,
onClose,
handlers,
initialTab,
}: {
project: Project;
onClose: () => void;
handlers: ResourceManagerHandlers;
/** Beim Öffnen (bzw. bei erneutem Sprung) direkt aktiver Tab, z. B. „doorStyles". */
initialTab?: TabId;
}) {
const [tab, setTab] = useState<TabId>("components");
const [tab, setTab] = useState<TabId>(initialTab ?? "components");
// Erneuter Sprung aus einem Element heraus (z. B. „Typ bearbeiten" an einer
// Öffnung): auf den angeforderten Tab wechseln, auch wenn das Fenster schon offen ist.
useEffect(() => {
if (initialTab) setTab(initialTab);
}, [initialTab]);
const [rect, setRect] = useState<WindowRect>(initialRect);
// Verschieben über die Kopfzeile: Cursor linke/obere Kante festhalten und die