diff --git a/src/model/roomStamp.test.ts b/src/model/roomStamp.test.ts index ac4cc1d..8f9a7e4 100644 --- a/src/model/roomStamp.test.ts +++ b/src/model/roomStamp.test.ts @@ -71,8 +71,8 @@ describe("roomStampExtraLines", () => { { name: "Bad", showFloorArea: true, showUsage: true, floorAreaPrefix: "BF " }, { netArea: 12.345, siaCategory: "HNF", siaLabel: "Hauptnutzfläche" }, ); - expect(lines[0]).toBe("BF 12.35 m²"); - expect(lines[1]).toBe("HNF · Hauptnutzfläche"); + expect(lines[0].text).toBe("BF 12.35 m²"); + expect(lines[1].text).toBe("HNF · Hauptnutzfläche"); }); it("blendet Zeilen aus, wenn Flags falsch", () => { diff --git a/src/model/roomStamp.ts b/src/model/roomStamp.ts index 4e42eab..b796679 100644 --- a/src/model/roomStamp.ts +++ b/src/model/roomStamp.ts @@ -7,7 +7,7 @@ import type { Room, RoomStamp } from "./types"; import type { SiaCategory } from "../geometry/roomArea"; -import type { RichTextDoc, Paragraph, TextRun } from "../text/richText"; +import type { RichTextDoc, Paragraph, TextRun, Align } from "../text/richText"; import { makeRun } from "../text/richText"; /** Grösse (pt) des Raumnamens (Zeile 1) relativ zur Stempel-Basis. */ @@ -43,10 +43,13 @@ export function roomStampToDoc(stamp: RoomStamp): RichTextDoc { } line1.push(makeRun(stamp.name, { bold: true, sizePt: NAME_PT })); - const paragraphs: Paragraph[] = [{ runs: line1 }]; + const paragraphs: Paragraph[] = [{ runs: line1, align: stamp.nameAlign }]; const line2 = (stamp.nameLine2 ?? "").trim(); if (line2) { - paragraphs.push({ runs: [makeRun(line2, { italic: true, sizePt: LINE2_PT })] }); + paragraphs.push({ + runs: [makeRun(line2, { italic: true, sizePt: LINE2_PT })], + align: stamp.line2Align, + }); } return { version: 1, paragraphs }; } @@ -58,18 +61,31 @@ export interface RoomStampContext { siaLabel: string; } +/** Eine Live-Zeile des Stempels mit Text und Ausrichtung. */ +export interface RoomStampLine { + text: string; + align: Align; +} + /** * Die Live-Zeilen unter dem Stempel: Bodenfläche (mit Präfix) wenn showFloorArea, - * Nutzung (SIA-Kürzel · Bezeichnung) wenn showUsage. + * Nutzung (SIA-Kürzel · Bezeichnung) wenn showUsage. Die Ausrichtung folgt den + * Stempel-Feldern; fehlt sie, gilt „zentriert" (Alt-Verhalten). */ -export function roomStampExtraLines(stamp: RoomStamp, ctx: RoomStampContext): string[] { - const lines: string[] = []; +export function roomStampExtraLines(stamp: RoomStamp, ctx: RoomStampContext): RoomStampLine[] { + const lines: RoomStampLine[] = []; if (stamp.showFloorArea) { const prefix = stamp.floorAreaPrefix ?? ""; - lines.push(`${prefix}${ctx.netArea.toFixed(2)} m²`); + lines.push({ + text: `${prefix}${ctx.netArea.toFixed(2)} m²`, + align: stamp.floorAreaAlign ?? "center", + }); } if (stamp.showUsage) { - lines.push(`${ctx.siaCategory} · ${ctx.siaLabel}`); + lines.push({ + text: `${ctx.siaCategory} · ${ctx.siaLabel}`, + align: stamp.usageAlign ?? "center", + }); } return lines; } diff --git a/src/model/types.ts b/src/model/types.ts index 008af69..f630c04 100644 --- a/src/model/types.ts +++ b/src/model/types.ts @@ -16,7 +16,7 @@ export type Vec2 = { x: number; y: number }; import type { SiaCategory } from "../geometry/roomArea"; export type { SiaCategory } from "../geometry/roomArea"; // Rich-Text-Dokument für den Raum-Stempel (frei editierbarer Teil). -import type { RichTextDoc } from "../text/richText"; +import type { RichTextDoc, Align } from "../text/richText"; export type { RichTextDoc } from "../text/richText"; // ── Ressourcen-Bibliotheken (Vectorworks-/DOSSIER-Stil) ──────────────────── @@ -679,6 +679,14 @@ export interface RoomStamp { floorAreaPrefix?: string; /** Nutzung (HNF/… · Bezeichnung) anzeigen (Live-Zeile). */ showUsage: boolean; + /** Ausrichtung der Namenszeile (Zeile 1). Fehlt sie, gilt „links". */ + nameAlign?: Align; + /** Ausrichtung der zweiten Namenszeile. Fehlt sie, gilt „links". */ + line2Align?: Align; + /** Ausrichtung der Bodenflächen-Zeile. Fehlt sie, gilt „zentriert" (Alt-Verhalten). */ + floorAreaAlign?: Align; + /** Ausrichtung der Nutzungs-Zeile. Fehlt sie, gilt „zentriert" (Alt-Verhalten). */ + usageAlign?: Align; } /** Eine Tür, gehostet in einer Wand. Ihr Geschoss ergibt sich aus der Wand. */ diff --git a/src/panels/RoomStampEditor.tsx b/src/panels/RoomStampEditor.tsx index 57f51ba..dacecf5 100644 --- a/src/panels/RoomStampEditor.tsx +++ b/src/panels/RoomStampEditor.tsx @@ -1,5 +1,6 @@ // Schwebender Dialog zum Bearbeiten des strukturierten Raum-Stempels (Feldmodell): -// Raumnummer, Raumname (+ Zeile 2), Bodenfläche (mit Präfix) und Nutzung. Ersetzt +// Raumnummer, Raumname (+ Zeile 2), Bodenfläche (mit Präfix) und Nutzung. Jede +// Zeile trägt zusätzlich eine eigene Ausrichtung (links/mitte/rechts). Ersetzt // für neue Räume den freien Text-Editor. Kontrolliert (value/onApply/onCancel); // arbeitet auf einem lokalen Entwurf, erst „Übernehmen" schreibt zurück. // Bezeichner englisch, UI-Text über t(). @@ -10,6 +11,7 @@ import { useState } from "react"; import { t } from "../i18n"; import type { RoomStamp } from "../model/types"; +import type { Align } from "../text/richText"; export interface RoomStampEditorProps { /** Ausgangsstempel (wird beim Öffnen kopiert; Editor arbeitet lokal). */ @@ -20,11 +22,60 @@ export interface RoomStampEditorProps { onCancel: () => void; } +/** Die drei Ausrichtungen mit Icon und Beschriftung (für die Umschalter). */ +const ALIGN_CELLS: { align: Align; icon: string; titleKey: string }[] = [ + { align: "left", icon: "format_align_left", titleKey: "text.align.left" }, + { align: "center", icon: "format_align_center", titleKey: "text.align.center" }, + { align: "right", icon: "format_align_right", titleKey: "text.align.right" }, +]; + +/** + * Drei-Wege-Umschalter für die Zeilen-Ausrichtung. `value` ist der aktuelle Wert + * (fehlt er, gilt `fallback`); `onChange` liefert die gewählte Ausrichtung. + */ +function AlignToggle({ + value, + fallback, + onChange, + disabled, + label, +}: { + value: Align | undefined; + fallback: Align; + onChange: (align: Align) => void; + disabled?: boolean; + label: string; +}) { + const current = value ?? fallback; + return ( +