Web: Kategorie-Elternwahl als aufklappbarer Baum statt "— —"-Select

Die uebergeordnete Kategorie wird nicht mehr ueber ein <select> mit
"— —"-Einrueckung gewaehlt, sondern ueber einen aufklappbaren Baum-Picker
(CategorySelect): echte Einrueckung, Aeste per Pfeil auf-/zuklappbar wie in der
Liste. Das Menue haengt per Portal am <body>, damit der horizontal scrollende
Tabellenrahmen es nicht abschneidet. Ersetzt beide Stellen (Zeilen-Elternwahl
und Anlege-Formular); die kompakten Knoepfe machen die Zeile schmaler, sodass
die Tabelle nicht mehr seitwaerts ueber den Block hinauslaeuft.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-26 11:44:03 +02:00
parent 914118e33a
commit f35126cb7b
3 changed files with 200 additions and 18 deletions

View File

@@ -320,6 +320,44 @@ td select { width: auto; min-width: 0; max-width: 100%; }
.tree-toggle .icon.rotated { transform: rotate(90deg); }
/* Platzhalter, damit Zeilen ohne Unterkategorien buendig zu denen mit stehen. */
.tree-spacer { display: inline-block; flex: 0 0 auto; width: 24px; }
/* Aufklappbarer Kategorie-Baum als Auswahlfeld (CategorySelect). Der Knopf sieht
aus wie ein <select>, das Menue haengt per Portal am <body>. */
.tree-select-btn {
width: 100%; margin-top: 5px;
display: flex; align-items: center; gap: 8px;
padding: 8px 10px;
border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
background: var(--surface); color: var(--text);
font-size: 0.9rem; font-family: inherit; text-align: left; cursor: pointer;
transition: border-color .12s, box-shadow .12s;
}
.tree-select-btn > span { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tree-select-btn:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.tree-select-btn:disabled { opacity: 0.6; cursor: default; }
.tree-select-btn .caret { flex: 0 0 auto; color: var(--muted); transform: rotate(90deg); transition: transform .12s ease; }
.tree-select-btn .caret.open { transform: rotate(-90deg); }
.tree-pop {
position: fixed; z-index: 1000;
max-height: min(60vh, 360px); overflow-y: auto;
padding: 5px;
background: var(--surface); border: 1px solid var(--border-strong);
border-radius: var(--radius); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
.tree-pop-line { display: flex; align-items: center; gap: 4px; }
.tree-pop-opt {
flex: 1 1 auto; min-width: 0; width: 100%; margin: 0;
padding: 6px 8px; border: 0; border-radius: var(--radius-sm);
background: transparent; color: var(--text); font: inherit; font-size: 0.9rem;
text-align: left; cursor: pointer; white-space: nowrap;
}
.tree-pop-opt:hover { background: var(--surface-2); }
.tree-pop-opt.sel { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.tree-spacer-sm { display: inline-block; flex: 0 0 auto; width: 20px; }
.tree-pop .tree-toggle { display: inline-flex; cursor: pointer; color: var(--muted); border-radius: var(--radius-sm); }
.tree-pop .tree-toggle:hover { background: var(--surface-2); }
.tree-pop-empty { padding: 8px; color: var(--muted); font-size: 0.85rem; }
/* In Zahlenspalten sitzt der Inhalt rechts, passend zur Ausrichtung der Spalte. */
.table td.num .cell-row { justify-content: flex-end; }
.table tbody tr:last-child td { border-bottom: none; }