Attribute-Panel: ein durchgehendes Grid, volle Breite, doppelten Titel raus

This commit is contained in:
2026-07-05 16:54:04 +02:00
parent fe9f396750
commit ace0dc62a8
2 changed files with 37 additions and 36 deletions
+15 -19
View File
@@ -80,7 +80,6 @@ export function AttributesPanel() {
onChange: (next: UiSource) => void, onChange: (next: UiSource) => void,
) => ( ) => (
<Dropdown <Dropdown
width={104}
value={ui} value={ui}
disabled={!editable} disabled={!editable}
onChange={(v) => onChange(v as UiSource)} onChange={(v) => onChange(v as UiSource)}
@@ -110,7 +109,7 @@ export function AttributesPanel() {
) => ( ) => (
<> <>
<span className="attr-key">{t(labelKey)}</span> <span className="attr-key">{t(labelKey)}</span>
<span className="attr-val" style={{ gap: 6 }}> <span className="attr-val">
{ui === "custom" && valueEditor} {ui === "custom" && valueEditor}
{sourceSelect(editable, ui, onSource)} {sourceSelect(editable, ui, onSource)}
</span> </span>
@@ -159,11 +158,13 @@ export function AttributesPanel() {
return ( return (
<div className="attr-panel"> <div className="attr-panel">
<div className="attr-title">{t("attr.title")}</div> {/* EIN durchgehendes Grid über alle Sektionen — dieselben zwei Spalten
(Label | Wert) für Stift/Füllung/Maße, damit die Wertfelder überall
{/* ── Stift/Strich ──────────────────────────────────────────────── */} bündig in EINER Spalte stehen. Sektion-Balken spannen beide Spalten. */}
<div className="attr-section-label">{t("attr.stroke")}</div>
<div className="attr-grid"> <div className="attr-grid">
{/* ── Stift/Strich ──────────────────────────────────────────── */}
<div className="attr-section-label">{t("attr.stroke")}</div>
{/* Farbe — gilt für Wand UND Drawing2D (Kontrakt setzt beide). */} {/* Farbe — gilt für Wand UND Drawing2D (Kontrakt setzt beide). */}
<span className="attr-key">{t("attr.color")}</span> <span className="attr-key">{t("attr.color")}</span>
<span className="attr-val"> <span className="attr-val">
@@ -208,7 +209,6 @@ export function AttributesPanel() {
onChange={(v) => onChange={(v) =>
host.onSetSelectionLineStyle(v === "__none__" ? undefined : v) host.onSetSelectionLineStyle(v === "__none__" ? undefined : v)
} }
width={120}
options={[ options={[
{ value: "__none__", label: t("attr.lineStyle.none") }, { value: "__none__", label: t("attr.lineStyle.none") },
...project.lineStyles.map((l) => ({ value: l.id, label: l.name })), ...project.lineStyles.map((l) => ({ value: l.id, label: l.name })),
@@ -218,14 +218,13 @@ export function AttributesPanel() {
<span className="attr-readonly">{lineStyle ? lineStyle.name : "—"}</span> <span className="attr-readonly">{lineStyle ? lineStyle.name : "—"}</span>
)} )}
</span> </span>
</div>
{/* ── Füllung (Vordergrund/Hintergrund + Schraffur) ─────────────── */} {/* ── Füllung (Vordergrund/Hintergrund + Schraffur) ─────────── */}
{/* Vordergrund = Muster-/Schraffurfarbe, Hintergrund = Füllfarbe/Poché. {/* Vordergrund = Muster-/Schraffurfarbe, Hintergrund = Füllfarbe/
Jedes Feld: Nach Ebene (LayerCategory erzwingt den Wert) / Nach Bauteil Poché. Jedes Feld: Nach Ebene (LayerCategory erzwingt den Wert) /
(erbt vom Component-Manager, Default) / eigener Wert (Override). */} Nach Bauteil (erbt vom Component-Manager, Default) / eigener Wert. */}
<div className="attr-section-label">{t("attr.fill")}</div> <div className="attr-section-label">{t("attr.fill")}</div>
<div className="attr-grid">
{sourceRow( {sourceRow(
"attr.foreground", "attr.foreground",
pocheEditable, pocheEditable,
@@ -248,7 +247,6 @@ export function AttributesPanel() {
hatchUi, hatchUi,
onHatchSourceChange, onHatchSourceChange,
<Dropdown <Dropdown
width={104}
value={sel.fillHatchId ?? ""} value={sel.fillHatchId ?? ""}
onChange={(v) => host.onSetSelectionFill(v || null)} onChange={(v) => host.onSetSelectionFill(v || null)}
options={[ options={[
@@ -257,11 +255,9 @@ export function AttributesPanel() {
]} ]}
/>, />,
)} )}
</div>
{/* ── Maße (informativ, aus der bbox) ───────────────────────────── */} {/* ── Maße (informativ, aus der bbox) ───────────────────────── */}
<div className="attr-section-label">{t("attr.size")}</div> <div className="attr-section-label">{t("attr.size")}</div>
<div className="attr-grid">
<span className="attr-key">{t("attr.width")}</span> <span className="attr-key">{t("attr.width")}</span>
<span className="attr-val attr-readonly">{formatM(bboxW)}</span> <span className="attr-val attr-readonly">{formatM(bboxW)}</span>
<span className="attr-key">{t("attr.height")}</span> <span className="attr-key">{t("attr.height")}</span>
+22 -17
View File
@@ -3979,10 +3979,6 @@ body {
/* ── Attribute-Palette (AttributesPanel) ─────────────────────────────── */ /* ── Attribute-Palette (AttributesPanel) ─────────────────────────────── */
.attr-panel { .attr-panel {
display: flex;
flex-direction: column;
gap: 4px;
padding: 8px;
overflow-y: auto; overflow-y: auto;
height: 100%; height: 100%;
min-height: 0; min-height: 0;
@@ -3993,28 +3989,29 @@ body {
padding: 8px 4px; padding: 8px 4px;
text-align: center; text-align: center;
} }
.attr-title { /* OCS-artiges Eigenschaften-Grid: EIN durchgehendes Zwei-Spalten-Grid über alle
font-weight: 600; Sektionen (Label | Wert), damit die Wertfelder über Stift/Füllung/Maße hinweg
color: var(--label); in EINER Spalte bündig stehen. Sektion-Balken spannen beide Spalten. Zeilen mit
padding: 0 2px 4px; dezenten Trennlinien; Wertfelder füllen ihre Zelle linksbündig über die volle
} Panel-Breite — einheitlicher Look für Texte/Zahlen/Dropdowns. */
/* OCS-artiges Eigenschaften-Grid: Sektion-Balken über die volle Breite, Zeilen
mit dezenten Trennlinien (klares Grid, ohne aufdringliche Ränder), Wertfelder
füllen ihre Zelle linksbündig — einheitlicher Look für Texte/Zahlen/Dropdowns. */
.attr-section-label { .attr-section-label {
grid-column: 1 / -1;
color: var(--label); color: var(--label);
font-weight: 700; font-weight: 700;
text-transform: uppercase; text-transform: uppercase;
font-size: 10px; font-size: 10px;
letter-spacing: 0.05em; letter-spacing: 0.05em;
margin: 8px 0 0; margin: 8px 0 2px;
padding: 4px 8px; padding: 3px 6px;
background: var(--panel-2); background: var(--panel-2);
border-radius: 3px; border-radius: 3px;
} }
.attr-section-label:first-child {
margin-top: 0;
}
.attr-grid { .attr-grid {
display: grid; display: grid;
grid-template-columns: minmax(84px, auto) 1fr; grid-template-columns: minmax(80px, max-content) 1fr;
align-items: stretch; align-items: stretch;
gap: 0; gap: 0;
padding: 0; padding: 0;
@@ -4024,17 +4021,25 @@ body {
white-space: nowrap; white-space: nowrap;
display: flex; display: flex;
align-items: center; align-items: center;
padding: 4px 10px 4px 6px; padding: 3px 10px 3px 2px;
border-bottom: 1px solid var(--line); border-bottom: 1px solid var(--line);
} }
.attr-val { .attr-val {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
gap: 6px;
min-width: 0; min-width: 0;
padding: 3px 2px 3px 0; padding: 2px 0;
border-bottom: 1px solid var(--line); border-bottom: 1px solid var(--line);
} }
/* Wertfelder (Dropdown-Trigger, Zahlenfeld) füllen die Wert-Spalte — der
Dropdown wächst in die verfügbare Breite (kein fixes width mehr im TSX). */
.attr-val .tb-dd-trigger {
flex: 1 1 auto;
min-width: 0;
justify-content: space-between;
}
.attr-readonly { .attr-readonly {
color: var(--label); color: var(--label);
opacity: 0.85; opacity: 0.85;