From c8f8160ecafbe38fe6d49d7c14a5532e2e151d96 Mon Sep 17 00:00:00 2001 From: mhoennig Date: Tue, 21 Jul 2026 16:47:29 +0200 Subject: [PATCH] =?UTF-8?q?frontend:=20G=C3=BCnstigster-Pfad-Hervorhebung?= =?UTF-8?q?=20per=20Inversion=20+=20implizites=20M?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Umschalter im Diagramm-Kopf (Default an, Zustand in werkbaum-ui persistiert) - nötige Knoten: all-of ⇒ alle Kinder, any-of ⇒ günstigste Alternative (kleinste rekursive Kosten; Gleichstand ⇒ erste); verworfene zählen nie mit - Darstellung per Inversion: nicht benötigte Knoten treten blass/entsättigt zurück (kein Zusatzrahmen an den ohnehin dichten Knoten-Ecken) - fehlende T-Shirt-Größe wird für die Kostenschätzung als M gewertet; invertiertes M-Badge (weiß mit Petrol-Rand) macht die Annahme sichtbar - neue Tooltips i18n (DE-Quelle + 8 Übersetzungen, 50 Keys × 9) - SPEC §9 (Günstigster Pfad) und DECISIONS D18 mitgeführt Co-Authored-By: Claude Opus 4.8 --- docs/DECISIONS.md | 23 ++++++++++++ docs/SPEC.md | 21 +++++++++++ frontend/CLAUDE.md | 3 +- frontend/index.html | 92 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 135 insertions(+), 4 deletions(-) diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 39d610e..7c8fb3d 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -150,3 +150,26 @@ Sprachleiste zeigt nur Englisch + aktive Sprache + „…“. Voreinstellung ist `matchMedia`), damit CSS und JS denselben Schwellwert teilen; die Vollbild- Voreinstellung greift nur, wenn noch **keine** gespeicherte Nutzerwahl vorliegt (eine bewusste Abschaltung bleibt so erhalten, siehe localStorage-Persistenz). + +## D18 — Günstigsten Pfad per Inversion zeigen, fehlende Größe = M +Der kostengünstigste Weg durch den Baum wird hervorgehoben (Umschalter im +Diagramm-Kopf, Default an, Zustand persistiert). Nötig sind bei **all of** alle +Kinder, bei **any of** nur die günstigste Alternative (kleinste rekursive +Kosten; Gleichstand ⇒ erste). + +**Darstellung per Inversion, nicht per Betonung:** Getestet wurde zuerst ein +doppelt dicker Rand an den nötigen Knoten. Da der Baum aber fast überall all-of +ist, war damit *fast alles* dick umrandet — das Signal lag ohnehin nur in der +*Abwesenheit* des Rands bei den ausgeschlossenen Alternativen. Deshalb wird +invertiert: die **nicht benötigten** Knoten (nicht-gewählte any-of-Alternativen +samt Teilbaum) treten zurück (blass, entsättigt), der Pfad hebt sich von selbst +ab. Kein Zusatzrahmen, weil die Knoten-Ecken (Größe, Tags, ↗) schon dicht sind. + +**Fehlende T-Shirt-Größe wird für die Kostenschätzung als `M` gewertet** — die +kleinste Größe mit Untergliederungspflicht (§5/D8), also die konservative +Annahme „mindestens M". Damit sind auch ungrößte Alternativen vergleichbar. +Wo `M` nur implizit angenommen ist, zeigt der Knoten ein **invertiertes** +Größen-Badge (weiß mit Petrol-Rand statt gefüllt) samt Tooltip, damit die +Annahme sichtbar und von einer echten `(M)`-Angabe unterscheidbar bleibt. Die +Größen-Semantik in SPEC §5 bleibt unberührt (die Wertung gilt nur der +Pfad-Kostenrechnung). diff --git a/docs/SPEC.md b/docs/SPEC.md index 6eafca7..49dfd9f 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -155,6 +155,27 @@ und die aktive Sprache plus „…“ (das alle Sprachen aufklappt). Der **Unter wird auf eine garantiert einzeilige Kurzfassung reduziert. Voreinstellung auf kleinem Bildschirm ist **Vollbild** (siehe D17). +### Günstigster Pfad (Kosten-Hervorhebung) +Ein Umschalter (Icon-Button im Diagramm-Kopf, Voreinstellung **an**, Zustand +persistiert) hebt den kostengünstigsten Weg durch den Baum hervor. Ermittelt +werden die für die günstigste Realisierung **nötigen** Knoten: + +- **all of:** alle Kinder sind nötig. +- **any of:** nur die **günstigste** Alternative ist nötig. „Günstig" = + kleinste rekursive Kosten (eigene T-Shirt-Größe plus — je Gate — Summe bzw. + Minimum der Kinder). Bei Gleichstand gewinnt die **erste** Alternative. +- Verworfene Knoten zählen nie mit (unabhängig vom „verworfene einblenden"- + Filter). +- **Fehlende Größe wird als `M` gewertet** (nur für diese Kostenschätzung; die + SPEC-Semantik der Größen in §5 bleibt unberührt). + +Darstellung per **Inversion**: nicht benötigte Knoten (nicht-gewählte +any-of-Alternativen samt Teilbaum) treten zurück (blass, entsättigt); der +günstige Pfad hebt sich dadurch von selbst ab — kein zusätzlicher Rahmen an den +ohnehin dichten Knoten-Ecken. Wo die Größe **implizit** als `M` angenommen wird, +zeigt der Knoten ein **invertiertes** Größen-Badge (weiß mit petrolfarbenem +Rand/Text statt gefüllt) mit erläuterndem Tooltip. Siehe D18. + ### Grafikexport des Diagramms Das Diagramm wird aus der Live-Geometrie in ein eigenständiges SVG (nur Formen + Text, keine externen Ressourcen) nachgezeichnet. Zwei Icon-Schaltflächen: diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md index ca1267c..4a4eaf5 100644 --- a/frontend/CLAUDE.md +++ b/frontend/CLAUDE.md @@ -26,7 +26,8 @@ Diagramm rechts, Toggles für transponierte Ansicht und verworfene Elemente). `visibleChildren()` und muss bei Renderer-Umbauten erhalten bleiben. - Zustand wird im `localStorage` gehalten (noch kein Backend): `werkbaum-lang` (Sprache), `werkbaum-src` (Editortext), `werkbaum-ui` (JSON: Modus, - verworfene, Split-Zustand inkl. `--col`/`--drow`, Zoom, Vollbild). Neue + verworfene, günstigster Pfad, Split-Zustand inkl. `--col`/`--drow`, Zoom, + Vollbild). Neue GUI-Einstellungen in `saveUI()`/`restoreState()` mitführen; `saveUI` liefert während `restoring===true` nichts, damit das Wiederherstellen nicht sofort zurückschreibt. Fehlender `werkbaum-src` fällt auf `INITIAL` zurück, ein diff --git a/frontend/index.html b/frontend/index.html index 000c6d4..6e3cf77 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -354,6 +354,13 @@ } .root-node{background:var(--ink);border-color:var(--ink);color:#fff;font-weight:600;padding:9px 20px} + /* Günstigster Pfad (Inversion): nicht benötigte Knoten (nicht-gewählte + any-of-Alternativen samt Teilbaum) treten zurück (blass, entsättigt); + der günstige Pfad hebt sich dadurch von allein ab. */ + .cheap-on .node:not(.cheap){opacity:.32;filter:saturate(.4)} + /* implizit als M angenommene Größe: invertiertes Badge (weiß statt petrol) */ + .size.implicit{background:var(--card);color:var(--or);border-color:var(--or)} + /* --- ALL OF: Kinder nebeneinander, durchgezogener Verteiler --- */ ul.and{display:flex;align-items:flex-start;position:relative;padding-top:14px} ul.and::before{ @@ -610,6 +617,9 @@ +