Schnittlinie editierbar: Objektinfo-Sektion + Entf-Taste

Gewaehlte Schnitt-/Ansichtslinie erscheint als SectionLineSection im Attribut-
Panel (ueber host.sectionLine, da eine Linie kein Projekt-Bauteil ist): Name,
Blickrichtung umkehren (directionSign-Flip), Endpunkt-Koordinaten und Schnitt-
Tiefe editierbar; Loeschen/Entf setzt linePoints zurueck (Ebene bleibt). Host-
Kontrakt um sectionLine/onSetSectionLinePatch/onDeleteSectionLine erweitert,
verdrahtet ueber patchLevel. i18n de/en.
This commit is contained in:
2026-07-11 00:26:49 +02:00
parent 39bceedc17
commit ef7eb295d9
6 changed files with 197 additions and 1 deletions
+114
View File
@@ -19,10 +19,12 @@ import { t } from "../i18n";
import type { TranslationKey } from "../i18n";
import { flattenCategories, formatM } from "../model/types";
import type {
DrawingLevel,
RoofShape,
SiaCategory,
SliceTermination,
StairShape,
Vec2,
VerticalAnchor,
WallReferenceLine,
} from "../model/types";
@@ -314,6 +316,118 @@ export function RoomSection({
);
}
// ── Schnitt-/Ansichtslinien-Abschnitt (Object-Info; nur die gewählte Linie) ──
// Name (editierbar), Blickrichtung umkehren (directionSign-Flip), Endpunkt-
// Koordinaten (editierbar) + Schnitt-Tiefe; Löschen setzt linePoints zurück
// (die Ebene bleibt bestehen). Eine Schnittlinie ist KEIN Projekt-Bauteil,
// darum kommt sie über `host.sectionLine` (nicht über `selection`).
export function SectionLineSection({
level,
host,
}: {
level: DrawingLevel;
host: ReturnType<typeof usePanelHost>;
}) {
const line = level.linePoints;
const kindLabel =
level.kind === "elevation"
? t("objinfo.sectionLine.kind.elevation")
: t("objinfo.sectionLine.kind.section");
const patchPoint = (which: 0 | 1, axis: "x" | "y", value: number) => {
if (!line) return;
const next: [Vec2, Vec2] = [{ ...line[0] }, { ...line[1] }];
next[which] = { ...next[which], [axis]: value };
host.onSetSectionLinePatch({ linePoints: next });
};
const coordField = (labelKey: TranslationKey, value: number, on: (v: number) => void) => (
<div className="objinfo-field">
<span className="objinfo-flabel">{t(labelKey)}</span>
<input
type="number"
className="objinfo-text"
step={0.1}
value={value}
onChange={(e) => {
const v = Number(e.target.value);
if (Number.isFinite(v)) on(v);
}}
title={t(labelKey)}
/>
</div>
);
return (
<>
<div className="objinfo-sep" />
<div className="objinfo-section-label">
{t("objinfo.sectionLine.section")} · {kindLabel}
</div>
{/* Name (editierbar). */}
<div className="objinfo-field">
<span className="objinfo-flabel">{t("objinfo.sectionLine.name")}</span>
<input
type="text"
className="objinfo-text"
value={level.name}
onChange={(e) => host.onSetSectionLinePatch({ name: e.target.value })}
title={t("objinfo.sectionLine.name")}
/>
</div>
{/* Blickrichtung umkehren (directionSign-Flip). */}
<button
type="button"
className="objinfo-btn"
onClick={() =>
host.onSetSectionLinePatch({
directionSign: (level.directionSign ?? 1) === 1 ? -1 : 1,
})
}
>
{t("objinfo.sectionLine.flip")}
</button>
{/* Endpunkt-Koordinaten (nur wenn eine Linie gesetzt ist). */}
{line && (
<>
{coordField("objinfo.sectionLine.startX", line[0].x, (v) => patchPoint(0, "x", v))}
{coordField("objinfo.sectionLine.startY", line[0].y, (v) => patchPoint(0, "y", v))}
{coordField("objinfo.sectionLine.endX", line[1].x, (v) => patchPoint(1, "x", v))}
{coordField("objinfo.sectionLine.endY", line[1].y, (v) => patchPoint(1, "y", v))}
</>
)}
{/* Schnitt-Tiefe (leer = unbegrenzt). */}
<div className="objinfo-field">
<span className="objinfo-flabel">{t("objinfo.sectionLine.depth")}</span>
<input
type="number"
className="objinfo-text"
step={0.5}
min={0}
value={level.depth ?? ""}
placeholder={t("objinfo.sectionLine.depthHint")}
onChange={(e) => {
const raw = e.target.value.trim();
if (raw === "") {
host.onSetSectionLinePatch({ depth: undefined });
return;
}
const v = Number(raw);
if (Number.isFinite(v) && v > 0) host.onSetSectionLinePatch({ depth: v });
}}
title={t("objinfo.sectionLine.depth")}
/>
</div>
{/* Löschen: linePoints zurücksetzen (die Ebene bleibt bestehen). */}
<button type="button" className="objinfo-btn" onClick={() => host.onDeleteSectionLine()}>
{t("objinfo.sectionLine.delete")}
</button>
</>
);
}
// ── Extrusions-Attribut-Abschnitt (truck-Integration) ───────────────────────
// Höhe editierbar (löst Re-Extrusion aus); Grundfläche + Geschoss read-only.
export function ExtrudedSolidSection({