Commit Graph
69 Commits
Author SHA1 Message Date
mhoennigandClaude Opus 4.8 744bb0bcf3 frontend: Strahlenkranz robust machen (Stapelordnung + Pfad-Inversion)
Gemeldet von der deployten Seite: „nur die linke Hälfte gelb, kein Rahmen
drum herum". Zwei Ursachen gefunden — beide betreffen den Kranz, weil er
AUSSERHALB der Knotenbox liegt und damit fremden Malvorgängen ausgeliefert ist:

- Fehlende Stapelordnung: Jedes später kommende Geschwister malt seinen
  undurchsichtigen Hintergrund über den Schein und schneidet ihn einseitig ab —
  übrig bleibt eine gelbe Kante, die wie ein halber Hintergrund aussieht statt
  wie ein Rahmen. Die Geschwister-Abstände (gemessen 24–25 px) liegen nur knapp
  über der Reichweite des Scheins (Blur 16 + Spread 5 = 21 px); bei Zoom,
  längeren Labels oder engeren Layouts reicht das nicht. Jetzt `z-index:2`.
- Pfad-Inversion dimmte die Meldung weg: `.cheap-on .node:not(.cheap)` setzt
  `opacity:.32; filter:saturate(.4)` und traf damit auch den gelben Kranz
  (nachgemessen: Deckkraft 0,32 ⇒ praktisch unsichtbar). Gerade bei einer nicht
  gewählten Alternative ist „das ist jetzt live" aber die interessantere
  Nachricht. Neue Regel hebt beides für `.fresh` auf.

Verifiziert gegen das gebaute dist-Artefakt (dasselbe, das deployt wird):
z-index 2 gesetzt; ein nicht-günstiger Knoten mit .fresh hat wieder
opacity 1 / filter none bei unverändertem Kranz; im kompakten Modus liegt
kein Geschwister mehr über dem Schein. Vitest 46/46.

Nicht reproduziert: die exakte Beschreibung (gelb nur hinter der linken
Texthälfte) trat bei mir weder im Dev-Server noch im dist-Artefakt auf, in
keinem der drei Modi. Die beiden behobenen Defekte erklären sie plausibel,
bewiesen ist das nicht.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 19:51:11 +02:00
mhoennigandClaude Opus 4.8 7a52277b84 frontend: „Was ist neu?" — neu in Produktion mit gelbem Strahlenkranz
Dokumente von außen (mitgeliefert D27, ?sourceUrl= D23) ändern sich, ohne dass
der Betrachter es merkt. Sie zeigen jetzt, was sich seit seinem letzten Besuch
getan hat.

- „Neu" heißt bewusst NICHT „Zeile hinzugefügt", sondern **neu in Produktion**:
  ein Knoten trägt jetzt [^] und tat es in der zuletzt gesehenen Fassung nicht.
  Ein Zeilendiff meldete vor allem Rauschen; die Nachricht, die zählt, ist was
  live gegangen ist. Nebeneffekt: es leuchtet eine Handvoll Knoten, nicht dreißig.
- Basis ist die zuletzt GESEHENE Fassung je Dokument (`werkbaum-seen`), nicht
  die letzte Auslieferung — wer Fassungen überspringt, sieht alles seither.
  Fortgeschrieben wird erst beim Bestätigen, sonst wäre die Meldung nach einem
  Neuladen weg, bevor sie jemand bemerkt. Beim Erstkontakt leuchtet nichts.
- Knoten-Identität ist der Label-Pfad, nicht die Zeilennummer: Umeinrücken und
  Umsortieren erzeugen keine Falschmeldungen; gleichnamige Geschwister per
  Index; Umbenennen gilt als neuer Knoten (der Text ist der Vertrag, D14).
- Darstellung: gelber Strahlenkranz nach außen, kein Blinken (WCAG 2.2.2/2.3.1;
  Blinken zöge dauerhaft den Blick statt einmal zu melden). Außen, weil die
  Füllung dem Status gehört (SPEC §4). Zusammen mit der Cursor-Zeile: Tinte
  innen, Gelb außen. Nicht im Druck und nicht im Grafikexport — die Markierung
  hängt am persönlichen Besuchsstand.
- Knopf im Diagramm-Kopf nur, wenn es etwas gibt; nennt die Anzahl, Klick
  bestätigt. Kein Dauer-Umschalter.
- Bei selbst bearbeitetem mitgeliefertem Dokument wird nichts hervorgehoben —
  dort fehlt die saubere Vergleichsbasis (D27).

Fehler beim Bauen, der zuerst durchrutschte: Die Menge wurde beim Laden aus
einem eigenen Parse-Durchlauf berechnet. Der Zähler stimmte, aber kein Knoten
leuchtete — `Set.has()` prüft Objektidentität, und die gerenderten Knoten kamen
aus einem anderen Parse. `render()` bildet die Menge jetzt bei jedem Durchlauf
aus den gerade geparsten Wurzeln; vorgehalten wird nur der geparste Basisbaum.

Verifiziert: 9 neue Modelltests (Statuswechsel, neuer [^]-Knoten, nicht-[^]
ignoriert, unverändert ignoriert, Erstkontakt leer, Umsortieren/Tabs ohne
Falschmeldung, gleiches Label unter verschiedenen Eltern, gleichnamige
Geschwister, verworfene). Im Browser: Erstkontakt setzt nur die Basis (Knopf
versteckt); zurückgedrehte Basis lässt genau die erwarteten Knoten leuchten
(Zähler 3, dann 1); Bestätigen räumt auf und überlebt das Neuladen; ohne
Bestätigen bleibt die Meldung über ein Neuladen stehen. Vitest 46/46.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 15:18:20 +02:00
mhoennigandClaude Opus 4.8 6888762ac8 frontend: Legende scrollbar + Splitter zwischen Editor und Legende
Die Legende wurde abgeschnitten statt zu scrollen — obwohl `.hint` seit jeher
`flex:1 1 auto; min-height:0; overflow:auto` trägt.

Ursache: Chrome legt den Inhalt eines <details> in das Pseudo-Element
`::details-content`. Damit war `.hint` kein Flex-Kind von `.agenda` mehr, die
Begrenzung griff nicht und der Kasten wuchs auf seine Inhaltshöhe (gemessen
585 px in einem 282 px hohen Container) und wurde geclippt. Eine Regel für
`::details-content` wirkte im Test, ist aber Chrome-eigen — Firefox und Safari
kennen das Pseudo-Element nicht.

- Die Legende ist deshalb kein <details> mehr, sondern `div.agenda` +
  `button.agenda-summary`; der Zustand hängt an der Klasse `open`
  (`aria-expanded` am Button, `#legendBtn` und Splitter-Sichtbarkeit über
  `setAgendaOpen()` synchron). `.hint` ist wieder echtes Flex-Kind und scrollt
  in allen Browsern.
- Neuer Splitter `#hintGutter` im selben Idiom wie der große (Pointer-Capture,
  Doppelklick setzt zurück): horizontal nebeneinander -> Breite `--hcol`,
  gestapelt (side/mobil) -> Höhe `--hrow`. Beide getrennt gehalten und in
  `werkbaum-ui` persistiert (samt Auf-/Zu-Zustand), damit ein Moduswechsel die
  jeweils andere Aufteilung nicht zerstört. Grenzen 90 px bis 85 %.
- Die 85-%-Obergrenze steht zusätzlich als max-width/max-height im CSS: die
  gespeicherte Größe ist ein fester px-Wert und würde den Editor sonst auf 0
  drücken, wenn das Panel später schrumpft (großer Splitter, Drehung,
  Bildschirmtastatur). Verifiziert mit --hrow:9999px -> gekappt bei 85 %.
- Nebenbei: der große Splitter war als einziges Bedienelement nicht lokalisiert
  (fest deutsche title/aria-label). Beide teilen sich nun `gutterTooltip`,
  dazu `gutterAria`/`hintGutterAria` — 9 Sprachen.

Verifiziert im Browser: Legende scrollt (247 px Fenster, 607 px Inhalt);
Ziehen in beiden Ausrichtungen inkl. Unter-/Obergrenze und Doppelklick-Reset;
`--hcol` und `--hrow` überleben den Moduswechsel; nach Neuladen sind
Auf-Zustand, Breite und beide Variablen wiederhergestellt; auf Mobil ist die
Summary-Zeile aus und der Kopf-Knopf steuert. Vitest 37/37.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 14:02:56 +02:00
mhoennigandClaude Opus 4.8 bbdecce75a frontend: Touch-Langdruck springt beim Loslassen (Fokus blieb sonst nicht)
Auf echten Touch-Geräten flackerte die Markierung im Editor nach dem langen
Druck nur kurz auf und der Fokus fiel sofort wieder heraus.

Ursache: Der Sprung lief im 500-ms-Timer, und `focus()` aus einem
Timer-Callback gilt in mobilen Browsern nicht als Nutzergeste — ein Textfeld
darf sich so nicht selbst fokussieren (sonst könnte jede Seite ungefragt die
Bildschirmtastatur aufziehen). `touchend` ist eine Nutzergeste.

- Der Timer setzt jetzt nur noch die Rückmeldung: der Zielknoten bekommt die
  Klasse `armed` mit demselben Petrol-Ring wie unter dem Alt-Zeiger.
  `jumpToLine()` läuft im touchend-Handler; Wischen bricht weiterhin ab.
- Zweiter Beitrag zum selben Symptom: die native Textauswahl bzw. das
  Link-Callout des Browsers startet bei derselben Druckdauer und riss die
  Auswahl an sich. Drei Schichten dagegen, weil keine allein überall wirkt:
  contextmenu-preventDefault während des Drucks (überall), `user-select:none`
  an .node für grobe Zeiger (@media hover:none and pointer:coarse) und
  `-webkit-touch-callout:none` (nur iOS; Chrome kennt es nicht mehr). Die
  frühere Regel `a.node{-webkit-touch-callout:none}` geht darin auf.

Verifiziert (synthetische TouchEvents): während des Drucks nur `armed` +
Petrol-Ring, Auswahl noch unverändert, Fokus noch nicht im Textfeld; beim
Loslassen Sprung, Fokus TEXTAREA, Klick unterdrückt; Wischen und kurzer Druck
springen nicht und lassen den Klick durch. Ring greift auch unterhalb einer
any-of-Gruppe. Vitest 37/37.

Einschränkung: Weder die Nutzergesten-Regel noch die nativen Langdruck-Gesten
lassen sich synthetisch auslösen — der eigentliche Beweis ist ein Test auf
echter Hardware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 13:41:48 +02:00
mhoennigandClaude Opus 4.8 c496850b88 frontend: Alt-Sprung auffindbar machen (Cursor-Rückmeldung + Legenden-Zeile)
Eine Modifier-Geste, die niemand kennt, ist keine Funktion. Zwei Maßnahmen:

- Solange Alt gedrückt ist, trägt #out die Klasse `alt`: alle Knoten zeigen
  `cursor:alias`, der Knoten unter dem Zeiger einen Petrol-Ring. Das wirkt
  auch auf verlinkten Knoten, wo der einfache Klick dem Link gehört und es
  sonst gar keine Rückmeldung gäbe. Der `blur`-Handler ist Pflicht — bei
  Alt+Tab kommt kein keyup mehr an, der Modus bliebe hängen.
- Die aufklappbare Legende endet mit einer abgesetzten Bedienungs-Zeile
  (`hint_jump` in 9 Sprachen, `.hint-op` mit gestricheltem Trenner), damit
  sie ihre Rolle als Notations-Legende behält.

Verworfen (in D25 samt Begründung festgehalten): einfacher Klick springt auf
Knoten ohne URL (~97 % der Knoten der Beispieldateien) — beiläufig auffindbar,
aber dieselbe Geste täte je nach Knoten Verschiedenes; sowie ein einmaliger
Hinweis nach dem ersten Sprung.

Verifiziert im Browser: ohne Alt Cursor auto bzw. pointer (Link), mit Alt
überall `alias`, nach Loslassen zurück, nach blur ohne keyup (Alt+Tab)
zurückgesetzt; Legenden-Zeile sichtbar und abgesetzt. Vitest 37/37.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 13:26:43 +02:00
mhoennigandClaude Opus 4.8 1f6988b047 frontend: Sprung zwischen Diagramm und Text (beide Richtungen)
Knoten und Notationszeile sind nun verknüpft. Der Parser hängte die
Zeilennummer ohnehin schon an jeden Knoten — sie wandert jetzt als data-line
ins Markup.

- Diagramm -> Text: Alt+Klick markiert die ganze Zeile im Editor (Fokus,
  in Sicht gescrollt); Tastatur Alt+Enter, Touch langer Druck (500 ms,
  Wischen bricht ab). Ein zugeklapptes Editor-Panel wird zuerst geöffnet.
- Text -> Diagramm: der Knoten der Cursor-Zeile bekommt weißen Halo +
  Tinte-Ring und wird beim Zeilenwechsel ins Bild gescrollt.
- Alt statt einfachem Klick, weil ein Knoten mit URL als <a> den ganzen
  Kasten belegt (SPEC §6 bleibt unverändert). Der Handler ruft
  preventDefault() — sonst lädt Alt+Klick auf einen Link das Ziel herunter.
  Neuer Tooltip-Hinweis an jedem Knoten (i18n `jumpHint`, 9 Sprachen).
- Gescrollt wird über einen Spiegel-div, nicht über Zeilenhöhe x n: lange
  Zeilen brechen weich um, die naive Rechnung lag im Test bei 60 Zeilen um
  bis zu 525 px daneben.

Beim Verifizieren gefunden und behoben: `ul.or .node{box-shadow:none}` ist
spezifischer als `.node.current` und schluckte den Ring überall unterhalb
einer any-of-Gruppe — die Regel braucht den #out-Präfix.

Verifiziert im Browser (Alt+Klick auf <a>- und div-Knoten, Klick aufs
Größen-Badge, Klick/Enter ohne Alt unverändert, Alt+Enter, kurzer/langer
Druck und Wischen auf Mobil, Panel-Aufklappen aus dem minimierten Zustand,
Zeile nach Sprung immer im sichtbaren Band, Kommentar-/verworfene Zeilen
heben nichts hervor). Vitest 37/37 (3 neue data-line-Tests, Snapshots
aktualisiert). Dokumentiert als D25 + SPEC §9 + frontend/CLAUDE.md + README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 13:14:10 +02:00
mhoennigandClaude Opus 4.8 64e4e60b53 frontend: Dokument-Wähler — Beispiel englisch, Inline-Umbenennen, gezielter Reset
Behebt drei Punkte am Mehrfach-Dokument-Feature (D22):

- Beispiel-Dokument heißt jetzt fest „Example" (englisch, nicht mehr
  lokalisiert „Beispiel") und trägt die reservierte id `example`. Alt-Zustände
  (zufällige id, „Beispiel") werden beim Laden adoptiert, sofern der Text noch
  unverändert ist (=== INITIAL) — echte Inhalte nie.
- Umbenennen läuft inline im Menü (Textfeld: Enter bestätigt, Esc bricht ab,
  Blur bestätigt) statt über window.prompt, das in manchen Browser-Kontexten
  unterdrückt ist („Umbenennen funktioniert nicht").
- Reset (Debug-Knopf, non-prod) setzt nur noch das Beispiel-Dokument auf
  INITIAL/„Example" zurück und verwirft Ansichts-/Sprach-/Update-Flags; alle
  anderen Dokumente bleiben erhalten (vorher wurden pauschal alle werkbaum-*-
  Schlüssel gelöscht).

i18n-Keys docDefaultName/docRenamePrompt entfallen (nicht mehr gebraucht).
D22 + frontend/CLAUDE.md nachgezogen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 12:01:43 +02:00
mhoennigandClaude Opus 4.8 36d79b82c4 frontend: Mehrere umschaltbare Dokumente (Wähler in der Editor-Titelzeile)
Der Editor kann jetzt mehrere Notationstexte halten und zwischen ihnen
umschalten. Der Name des aktiven Dokuments ersetzt die feste Beschriftung
„Struktur (Text)" und öffnet als Dropdown den Wähler mit Wechseln, Neu,
Umbenennen und Löschen.

- Datenmodell (noch kein Backend): Dokumente als [{id,name,text}] in
  localStorage (werkbaum-docs), aktives per id in werkbaum-active; der
  aktive Text bleibt zusätzlich in werkbaum-src gespiegelt.
- Migration verlustfrei: fehlt werkbaum-docs, wird der bestehende Einzeltext
  (oder INITIAL) in ein Dokument gepackt. Reset und Löschen des letzten
  Dokuments säen das Beispiel neu.
- Jedes Dokument ist nur Text + Name (kein Strukturformat, D14) —
  vorwärtskompatibel zum geplanten Backend (D13). Ansichts-State (Modus,
  Zoom, Aufteilung) bleibt global.
- i18n in allen 9 Sprachen; Doc-Namen bleiben Nutzerdaten (nicht übersetzt).
- Dokumentiert als ADR D22 (DECISIONS.md) + frontend/CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 11:48:31 +02:00
mhoennigandClaude Opus 4.8 095dbfb63e frontend: High-Risk-Warndreieck + Prod-Gating der Test-Hilfen
- [!]-Knoten trägt jetzt ein Warndreieck (⚠) an der oberen linken Ecke,
  zusätzlich zur orangen Färbung — im Diagramm, im SVG/PNG-Export und
  barrierefrei (aria-hidden, Status steckt im aria-label). Tooltip in allen
  9 Sprachen.
- SPEC §4: [!]/highrisk-Status nachgetragen (war beim ersten Hinzufügen
  übersprungen), inkl. Warndreieck-Kennzeichnung.
- Beispiel-PSP: Backend als High-Risk ([!]) markiert.
- Debug-Panel + Reset-Button nur außerhalb des Prod-Builds (isProdBuild via
  VITE_BUILD_BADGE); im build:prod eliminiert esbuild den Zweig als toten
  Code. Update-Check + Banner bleiben in allen Builds aktiv.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 10:00:51 +02:00
mhoennigandClaude Haiku 4.5 68322b13d9 feat: Add High Risk status [!] for uncertain effort estimation
Neuer Status-Code [!] für Items mit unbekannter Größe/Aufwand:

Parser:
- STATUS_BY_CODE erweitert: '!' -> {key:'highrisk', name:'High Risk – Aufwand unklar'}

Style:
- .node.st-highrisk: Pastellorange (#FFE5CC) mit orange Rahmen (#F97316)
- .chip.st-highrisk: Gleiche Farben für Agenda-Beispiele

i18n (alle 9 Sprachen):
- DE: "High Risk"
- EN: "high risk"
- ES: "alto riesgo"
- FR: "risque élevé"
- PL: "wysokie ryzyko"
- RU: "высокий риск"
- HI: "उच्च जोखिम"
- ZH: "高风险"
- JA: "高リスク"

Tests:
- parser.test.js aktualisiert: 8 Status-Codes (waren 7)

Damit können Items mit ungeklärtem Aufwand im Lean-Pathfinding-Prozess
gekennzeichnet werden – wichtig für Risk-Flagging in Phase 1.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-23 07:52:02 +02:00
mhoennigandClaude Haiku 4.5 a4ea1f760a frontend: Konsistente Höhe für Zoom-Controls in collapsed/expanded State
- Feste Höhe von 28px für .zoomctl (collapsed und expanded)
- Padding für .zoomToggle angepasst auf 4px 8px (gleich wie andere Buttons)
- SVG-Größe auf 16x16 optimiert

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-23 05:52:47 +02:00
mhoennigandClaude Haiku 4.5 640cb95c27 frontend: Zoom-Controls mit Auto-Collapse-Funktion
- Zoom-Controls collapse automatisch nach 3 Sekunden Inaktivität
- Toggle-Button mit Lupe+Plus-Symbol zum Expandieren der Controls
- Position weiter nach rechts-unten verschoben (6px)
- Event-Delegation für zuverlässige Click-Erfassung
- Lazy-Loading der DOM-Elemente für robuste Initialisierung

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-22 21:16:03 +02:00
mhoennig ae8c32786d frontend: Cleanup mobile viewport height logic for better compatibility
Removed redundant CSS fallbacks for mobile viewport height and replaced them with a streamlined `@supports` block to handle `dvh`-capable browsers. Clarified comments to reduce warnings and improve maintainability.
2026-07-22 10:44:56 +02:00
mhoennig 1cf60e2a75 frontend: Integrate self-hosted IBM Plex fonts, replace Google Fonts
IBM Plex Sans and Mono are now embedded locally (`woff2`) under `src/fonts`, licensed under SIL OFL 1.1. Removed external `<link>` to Google Fonts for enhanced privacy and compliance. Updated `style.css` with `@font-face` and unicode ranges for `latin` and `latin-ext` subsets. Added license details to documentation.
2026-07-22 10:33:09 +02:00
mhoennigandClaude Opus 4.8 6f184222a6 frontend: Build-Badge näher an den Titel (Emoji-Eigenluft kompensiert)
Der sichtbare Abstand kam fast ganz vom internen Weißraum des Emoji-Glyphs
(~11px), nicht vom margin. margin-left auf -.5em gesetzt -> Abstand
Titelende->Badge von 12px auf 5px. Laufzeit-gemessen im Dev-Server.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 06:00:42 +02:00
mhoennigandClaude Opus 4.8 0f27bab905 frontend/ci: Build-Hinweis in die App-Quelle, env-gesteuert; Prod-Build ohne
Der Latest-Build-Hinweis wandert vom Workflow-sed in die App (app.js,
mountBuildBadge), damit ihn auch der Dev-Server zeigt — ein Post-Build-sed
erreicht den Dev-Server nicht. Logik umgekehrt: Hinweis ist der Normalfall,
nur die produktive Installation schaltet ihn ab.

Drei Zustaende ueber Vite-Env VITE_BUILD_BADGE (Auswertung in app.js):
- Dev-Server (import.meta.env.DEV) -> 🔧 "Vorschau/lokaler Entwicklungsstand"
- Default `npm run build` (Env ungesetzt) -> 🚧 "latest build"; der Pages-
  Deploy nutzt den Default und traegt den Hinweis dadurch automatisch (die
  sed-Injektion entfaellt).
- `npm run build:prod` (Vite-Modus prod, .env.prod: VITE_BUILD_BADGE=none)
  -> KEIN Badge; esbuild eliminiert den Zweig als toten Code.

Verifiziert zur Laufzeit (Dev + `vite preview` auf beiden Builds): 🔧 im Dev,
🚧 im Default-Build, gar nichts im Prod-Build (Titel sauber "Werkbaum").
34 Vitest-Tests gruen, Workflow-YAML/Shell gueltig.

Doku: D16 fortgeschrieben (quellbasiert/env statt sed, Begruendung); README
(de/en) mit Prod-Build-Anleitung inkl. LICENSE-/Versions-Caveats; frontend/
CLAUDE.md; .claude/launch.json bekommt einen frontend-dist-Preview (vite
preview, Port 8138) zum Verifizieren gebauter Dateien.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 05:56:59 +02:00
mhoennigandClaude Opus 4.8 8d3ac63574 frontend: Druck-Stylesheet — nur das Diagramm drucken
TASKS Phase 2. @media print in style.css blendet Kopfzeile, Editor-Panel,
Splitter, alle Bedienelemente des Diagramm-Kopfs, Warnungen und Footer aus; das
Diagramm füllt die Seite (App-Grid -> Block, Overflow sichtbar) und darf über
mehrere Seiten laufen. Statusfarben werden mitgedruckt (print-color-adjust:
exact), Knoten brechen nicht über den Seitenrand (break-inside: avoid), der
Günstigster-Pfad-Overlay (in #out) kommt mit.

Verifiziert per Druck-Emulation (Regeln testweise als Screen-Style angewendet):
Editor/Kopf/Splitter/Warnungen/Footer display:none, Diagramm sichtbar, 18
Knoten, Farben + Pfadlinie erhalten. SPEC §9 (Druck) ergänzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 21:12:07 +02:00
mhoennigandClaude Opus 4.8 15699c321c frontend: Barrierefreiheit — aria-Labels, Fokusreihenfolge, Live-Region
TASKS Phase 2. Jeder Diagramm-Knoten bekommt in render.js (nodeAria) einen
sprechenden, lokalisierten aria-label: Label + Status + Aufwand (inkl.
„(angenommen)" beim impliziten M) + Zuständige + Link. Die rein visuellen
Badges (Größe, Tags, ↗) sind aria-hidden, damit der Screenreader nicht „M",
„anna", „↗" kryptisch doppelt vorliest. Neue a11y*-i18n-Keys in allen 9
Sprachen.

Alle Knoten sind fokussierbar (tabindex=0 bzw. der Link) in Dokument-/Lese-
reihenfolge; sichtbarer :focus-visible-Rahmen (Petrol). #warn ist eine
Live-Region (role=status, aria-live=polite) — neue Warnungen werden angesagt.

Verifiziert: aria-label folgt dem Sprachwechsel (DE/EN), Badges aria-hidden,
keine visuelle Regression, keine Konsolenfehler. Renderer-Snapshots
aktualisiert (29 Tests grün). SPEC §9 (Barrierefreiheit) + CLAUDE ergänzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 21:08:41 +02:00
mhoennigandClaude Opus 4.8 78d1000f61 frontend: Projektgerüst mit Vite — Single-HTML in ES-Module + Bündelung
Erster Schritt der Modularisierung (ROADMAP „tragfähige Codebasis",
TASKS Phase 1). Der bisher einzelne index.html-Prototyp wird zur Vite-App:

- CSS -> src/style.css, gesamtes JS -> src/app.js (noch als ein Modul;
  Parser/Renderer werden in den folgenden Checkboxen herausgelöst).
- index.html ist der Vite-Entry (<script type="module" src="/src/app.js">).
- npm run build (vite + vite-plugin-singlefile) inlint JS+CSS+Favicon (als
  data:-URI) in EINE self-contained dist/index.html -> bleibt file://-tauglich.
- Vitest als Testrunner eingerichtet (tests/, passWithNoTests bis Schritt 2/3).
- Pages-Workflow: Node + npm ci + npm test + npm run build, deployt dist/;
  Favicon-sed entfällt (inline), nur ../LICENSE + Footer-Version bleiben.
- .claude/launch.json auf Vite-Dev-Server (Port 8137) umgestellt.

Entscheidung als D19 dokumentiert (weicht D11 „kein Build-Zwang" bewusst auf,
hält aber D16 file://-Versprechen über die gebündelte Datei). README (de/en)
und frontend/CLAUDE.md um Dev-/Build-/Test-Workflow ergänzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 20:47:23 +02:00