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>
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>
- docs/ROADMAP.md: neuer Abschnitt „Gemeinsam an einem Diagramm arbeiten" in
drei Stufen — Lesen teilen (?sourceUrl=, vorhanden), asynchron über Git
(heute schon möglich, weil der Plan Text ist: git diff/blame sind lesbar;
Ausbau = Backend committet jede Änderung), live tippen (Transport ist der
kleinere Teil, das Zusammenführen gleichzeitiger Änderungen der eigentliche;
Text-CRDT passt wegen D14 ohne eigene Merge-Logik). Notiert auch, warum Git
direkt aus dem Browser kein Live-Sync ist (Sync auf Zuruf, CORS-Proxy nötig,
Konfliktmarker mitten in der Notation) und was vor einer Entscheidung offen
ist (erste Laufzeit-Abhängigkeit, Commit-Granularität, Rechte).
- docs/examples/example-werkbaum.werkbaum: passender Zweig „Working together
on one plan" (94 Knoten, parst ohne Warnung).
Dabei aufgefallen: Das mitgelieferte Dokument wurde nur EINMAL angelegt — die
Ergänzung hätte niemanden erreicht, der die Seite schon geöffnet hatte.
`werkbaum-seeded` hält deshalb statt '1' den Fingerabdruck (FNV-1a) der
ausgelieferten Fassung; bei neuer Fassung wird der Text nachgezogen, aber nur
wenn der Nutzer ihn nicht bearbeitet hat. Gelöscht bleibt gelöscht.
`resetToDefaults()` setzt den Merker mit.
Verifiziert im Browser, vier Fälle: alte unveränderte Fassung wird nachgezogen
(98 Zeilen, neuer Zweig da); selbst geänderter Text bleibt unangetastet;
gelöschtes Dokument kehrt nicht zurück; frischer Zustand zeigt die neue
Fassung (89 sichtbare Knoten, keine Warnung). Vitest 37/37.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
„Werkbank" war ein Vertipper, gemeint war der Projektname.
- WERKBAUM_NAME auf „Werkbaum" gesetzt.
- `loadDocs()` zieht den Namen bei bereits angelegten Dokumenten nach — aber
nur, solange er unverändert der ausgelieferte „Werkbank" ist. Eine eigene
Umbenennung des Nutzers bleibt stehen; ein fremdes Dokument, das zufällig
„Werkbank" heißt, wird nicht angefasst (die Regel greift über die
reservierte id, nicht über den Namen).
Verifiziert im Browser: Bestandszustand mit drei Dokumenten (Example,
id=werkbaum/„Werkbank", eigenes d9/„Werkbank") -> nach dem Laden ist nur
id=werkbaum umbenannt, d9 bleibt unberührt; frischer Zustand zeigt „Example"
und „Werkbaum" im Wähler, Wechsel rendert 75 Knoten ohne Warnung.
Vitest 37/37.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der interessanteste Beispielbaum war nur über einen ?sourceUrl=-Link
erreichbar. Er steht jetzt direkt im Dokument-Wähler.
- Eine Quelle, keine Kopie: `?raw`-Import aus
docs/examples/example-werkbaum.werkbaum — derselben Datei, die auch der
?sourceUrl=-Link lädt. Vite bettet sie in die eine Ausgabedatei ein (D19),
nichts wird nachgeladen (D20). Die Beispieldatei ist damit Build-Eingabe.
- `seedShippedDocs()` legt das Dokument genau EINMAL an — auch für
Bestandsnutzer mit vorhandener Dokumentenliste — und merkt sich das in
`werkbaum-seeded`. Ohne Merker gäbe es nur schlechte Alternativen: entweder
bekämen bestehende Nutzer es nie, oder ein bewusst gelöschtes Dokument
kehrte bei jedem Laden zurück. Das aktive Dokument bleibt unverändert.
- Fester, nicht lokalisierter Name wie „Example" (D22). Der Reset setzt jetzt
beide mitgelieferten Dokumente zurück; eigene bleiben unangetastet.
Verifiziert im Browser: frischer Zustand -> Example + Werkbank, aktiv bleibt
Example; Wechsel auf Werkbank rendert 75 Knoten ohne Warnung; Bestandsnutzer
mit eigener Liste bekommt Werkbank ergänzt, ohne aus seinem Dokument gerissen
zu werden; nach Löschen kehrt es nicht zurück. Build bleibt eine einzelne
Datei (361 kB), Vitest 37/37.
Offen (in D27 notiert): der Text wird nach dem Anlegen nicht mehr
aktualisiert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
Nach dem Sprung erschien auf Touch-Geräten sofort die virtuelle Tastatur und
nahm den halben Bildschirm — auch bei angeschlossener Bluetooth-Tastatur.
Das ist kein Fehler der App: Eine Webseite erfährt nichts über verbundene
Tastaturen, sie fordert nur Fokus an; alles Weitere entscheidet das OS (Android
hat dafür den Schalter „Bildschirmtastatur anzeigen" unter Physische Tastatur,
vielerorts an). Statt darauf zu verweisen, fordert der Sprung sie erst gar
nicht an:
- `jumpToLine()` setzt vor dem Fokussieren `inputmode="none"` — das unterdrückt
nur die VIRTUELLE Tastatur, Hardware-Tastaturen tippen unverändert weiter.
- Die Sperre fällt, sobald der Nutzer das Textfeld selbst antippt
(`pointerdown` läuft vor dem Fokus). Der Sprung ist damit „hinschauen", der
erste Tipp ins Textfeld „bearbeiten".
- `newDoc()` hebt die Sperre ausdrücklich auf — bei einem neuen, leeren
Dokument ist Tippen gemeint.
Verifiziert im Browser: Sprung setzt inputmode=none bei Fokus im Textfeld und
korrekter Zeilenmarkierung; Feld bleibt editierbar (nicht readOnly/disabled);
eigenes pointerdown entfernt das Attribut; erneuter Sprung setzt es wieder;
„Neues Dokument" fokussiert ohne Sperre. Vitest 37/37.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>
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>
Mit nur einem Beispiel ließ sich das Umschalten zwischen Dokumenten (D22)
nicht zeigen — jeder ?sourceUrl=-Link legt genau ein Dokument an (D23), erst
mehrere nacheinander geöffnete füllen den Wähler.
- Neue Endung `.werkbaum` (D24, SPEC §12): macht Notationstexte zuordenbar
(spätere Editor-Zuordnung, Syntax-Highlighting, Öffnen/Speichern). Konvention,
kein Vertrag — `?sourceUrl=` wertet weder Endung noch Content-Type aus, `.txt`
bleibt gültig. `.gitattributes` führt `*.werkbaum` als Text (LF).
- docs/example-plan.txt -> docs/examples/example-plan-0.werkbaum (Inhalt bis
auf die Kopfzeile unverändert); README-Links nachgezogen.
- Neu, je einen anderen Aspekt zeigend:
example-plan-1 (Küche: kein Software-Plan, alternativenlastig — günstigster
Pfad), example-plan-2 (Konferenz: breiter Fächer, viele Beteiligte),
example-plan-3 (drei Wurzeln = drei Bäume nebeneinander, dazu ein Knoten
ohne Größe für das implizite-M-Badge),
example-werkbaum (Werkbaum selbst: Bestand + mögliche Weiterentwicklung,
destilliert aus ROADMAP/TASKS/DECISIONS).
- README.md / README.de.md: Tabelle mit den fünf Live-Links samt Hinweis, dass
sie nacheinander geöffnet den Dokument-Wähler füllen.
Verifiziert: alle fünf parsen headless ohne Warnungen und ohne gemischte Gates
(19/26/43/28/79 Knoten, 3 Wurzeln in Beispiel 3); Vitest 34/34 grün.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Live-Beispiel-Link zeigte auf werkbaum.javagil.de — die stabile Instanz
wird manuell deployt (scripts/deploy-prod.sh) und kennt ?sourceUrl= noch nicht
(verifiziert: 0 Treffer im ausgelieferten HTML). Der Parameter waere dort
stillschweigend ignoriert worden. Der Link zeigt nun auf die automatisch aus
main deployte Pages-Instanz, die das Feature hat.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Für ?sourceUrl= (D23) fehlte bislang eine ladbare Beispieldatei — im Repo lagen
nur Markdown-Dokumente (rendern als Chaos) und VERSION.
- docs/example-plan.txt: englischer Beispielplan, der die Notation vorführt —
alle acht Status (inkl. [!] mit Warndreieck und einer verworfenen
Alternative), beide Gates, Größen, Tags, URLs, Kommentare sowie zwei
Geister-Knoten für die Untergliederungspflicht ab M.
- README.md / README.de.md: neuer Abschnitt „Loading a diagram from a URL" /
„Diagramm aus einer URL laden" mit klickbarem Live-Beispiel, dem Hinweis auf
URL-als-Dokumentname und der CORS-Einschränkung.
Verifiziert: Die Datei parst ohne Warnungen (18 Knoten, 7 sichtbare Status,
1 Warndreieck, 2 Geister-Knoten).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Editor kann den Text aus einer externen Textdatei beziehen:
…/index.html?sourceUrl=https://example.org/plan.txt
- Das Geladene wird als eigenes Dokument (D22) geführt, dessen Name die URL
ist; die id leitet sich aus der URL ab, derselbe Link aktualisiert also
dieses Dokument, statt bei jedem Aufruf ein neues anzulegen. Eigene
Dokumente bleiben unberührt. Die volle URL steht zusätzlich im Tooltip
(der Name wird in der Titelzeile elidiert).
- Ist der Parameter gesetzt, wird bei jedem Laden neu geholt — die URL ist
die Quelle der Wahrheit.
- Nur http(s) (relative Angaben werden aufgelöst), credentials:'omit';
file:/data:/javascript: werden abgewiesen. Fremder Text ist ungefährlich:
Labels werden escaped, der Parser erkennt als Link nur https?:// (SPEC §1).
- Fehler (CORS, 404, Netz) landen als zeilenlose Warnung `sourceLoad` im
Warnbereich und nennen CORS ausdrücklich als wahrscheinliche Ursache; der
bisherige Stand bleibt stehen. i18n in allen 9 Sprachen.
- Nebenbei: checkForUpdates() baut die Cache-Buster-URL nun über
URL/searchParams — mit vorhandenem Query-String hätte '?t=' ein zweites
'?' erzeugt.
Verifiziert headless (jsdom gegen den gebauten Bundle: Erfolg, CORS-Fehler,
404, ohne Parameter, verbotenes Schema) und im Browser gegen
raw.githubusercontent.com. Dokumentiert als D23 + SPEC §9 + frontend/CLAUDE.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>
Letzter deutscher Rest im INITIAL-Beispiel entfernt, damit das
Standard-Diagramm ein breiteres Publikum anspricht.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Node 20 ist seit ~April 2026 End-of-Life. Node 24 "Krypton" ist der aktuelle
Active LTS und passt zur node24-Laufzeit der Actions.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GitHub erzwingt node24 für node20-Actions (Deprecation vom 2025-09-19). Die fünf
Pages-Actions auf ihren jeweils ersten node24-Major gehoben:
checkout v4->v5, setup-node v4->v5, configure-pages v5->v6,
upload-pages-artifact v3->v5, deploy-pages v4->v5.
Der Build-`node-version: 20` (für npm ci/test/build) ist davon unberührt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Erkennung hashte nur die ersten + letzten 300 Zeichen der Seite. Da der
Editor eine self-contained Datei ist (D19), liegen der gesamte App-Code UND die
Footer-Version als inline-Bundle in der Mitte — außerhalb des abgetasteten
Fensters. Anfang/Ende sind Build-übergreifend identisch, daher wurde eine neue
Version nie erkannt (nur die ETag änderte sich -> "Metadaten geändert, aber
Inhalt gleich").
- hashContent() (cyrb53) über den GESAMTEN Text als alleinige Wahrheit.
- ETag/Last-Modified-Vergleich entfernt: GitHub Pages liefert je Cache-Knoten
wechselnde ETags für identischen Inhalt und löste damit die irreführende
Metadaten-Meldung aus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ohne gespeicherte werkbaum-lang wählt detectLang() die erste vom Browser
gemeldete Sprache (navigator.languages), für die eine Übersetzung existiert
(Primär-Subtag; de-AT->de, zh-Hans->zh), sonst Deutsch. Greift auch nach dem
Reset. Deutsch bleibt Quellsprache. Als D21 dokumentiert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- [!]-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>
Reset-Button gehört in den Header neben dem Fullscreen-Button,
nicht ins Debug-Panel.
Changes:
- Reset-Button (🔄) oben rechts neben Fullscreen-Toggle
- Benutzt gleiche Styling-Klasse (fsbtn) für Konsistenz
- Title: \"App auf Defaults zurücksetzen (für Testing)\"
- Debug-Panel vereinfacht (nur Log-Text, kein Button mehr)
Intuitivere Platzierung für Testing-Feature.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Reset-Button gehört ins Debug-Panel (Testing-Feature):
Changes:
- Debug-Panel erweitert mit flexiblem Layout (flex-column)
- 🔄 Reset-Button hinzugefügt (klickbar, hover-Effekt)
- ✕ Close-Button für Panel (zum Schließen)
- Bessere Styling: halbtransparente Buttons, klare Hover-States
Reset ist nur während Testing nötig — gehört ins Debug-Panel,
nicht in die Haupt-UI. Das 📦-Icon im Footer bleibt für
verfügbare Updates.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Statt Reset-Button im Footer:
- 📦-Symbol rechts neben Version (nur wenn Update verfügbar)
- Klick zeigt die Update-Benachrichtigung wieder an
- Hilft, wenn man den Banner auf \"Später\" verschoben hat
Features:
- Icon nur sichtbar wenn werkbaum-update-available Flag gesetzt
- Hover-Effekt: Icon wird größer (scale 1.2)
- Tooltip erklärt Funktion
- Auto-Update nach Benachrichtigung
Reset-Button entfernt (Nutzer wünscht sich das oben neben Fullscreen,
wenn überhaupt benötigt).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Reset-Button war zu unauffällig (nur 🔄-Symbol).
Jetzt prominenter:
- Label: \"🔄 Reset\" statt nur 🔄
- Border: dünne Linie um den Button
- Hover-Effekt: Farbe ändert sich zu Petrol (#0F766E)
- Cursor zeigt es ist klickbar
Button sitzt im Footer zwischen Versionsnummer und Links.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Besseres Logging zum Verständnis von Cache-Verhalten:
- \"✓ Alles aktuell\" = Content + Headers gleich
- \"⚙ Metadaten geändert, aber Inhalt gleich\" = Headers unterschiedlich,
aber HTML-Inhalt identisch (nur Build-Metadaten/ETag geändert)
- \"✅ NEUE VERSION ERKANNT!\" = echter neuer Inhalt entdeckt
Hilft zu verstehen, ob GitHub Pages cacht oder ob wirklich
eine neue Version deployed wurde.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
HEAD-Request hat auf GitHub Pages zu Netzwerkfehlern geführt.
Vereinfachter Ansatz:
- Zurück zu einfachem GET-Request (statt HEAD)
- Cache-Busting via Timestamp: location.href + '?t=' + Date.now()
- ETag/Last-Modified Vergleich + Content-Hash Fallback
- Besseres Error-Logging: unterscheidet "Netzwerk/CORS" von anderen Fehlern
Robuster auf instabilen Netzwerk-Bedingungen (Smartphone).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Neuer Button im Footer (🔄) zum Zurücksetzen aller Einstellungen:
Features:
- Löscht alle werkbaum-* localStorage-Einträge (Editor, Einstellungen, Update-Flags)
- Confirm-Dialog mit Warnung (Editor-Inhalt geht verloren)
- Reagiert auf alle Bildschirmgrößen
- Nach Confirm: kurze Verzögerung (Logging sichtbar), dann auto-reload
Hilfreich zum Testen:
- Update-Detection testen (Editor-Inhalt neu setzen)
- High-Risk-Status sehen (mit Reset auf Defaults und neuem Beispiel)
- Alle Einstellungen auf Default zurückbringen
Der Button sitzt unauffällig im Footer als 🔄-Symbol.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Problem: Nach Klick auf "Jetzt laden" wird die Seite neu geladen,
aber das werkbaum-update-available Flag bleibt in localStorage.
Beim Laden der neuen Version wird der alte Check noch vorhanden,
also wird der Banner wieder angezeigt (auch wenn die neue Version
schon da ist).
Lösung: Vor window.location.reload() das Flag löschen.
Damit nach dem Reload die neue Version sauber geladen wird.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Neue Debug-Features für Fehlersuche ohne Dev-Konsole:
- Update-Check alle 15 Sekunden (statt 60, für schnelleres Feedback beim Test)
- Logging in localStorage mit Zeitstempel
- Sichtbares Debug-Panel unten rechts (schwarz, Petrol-Rand)
* Zeigt die letzten 6 Update-Check-Einträge
* Klick zum Schließen
* Hilft ohne Browser Dev-Tools zu sehen, was passiert
Logging zeigt:
- ✅ Neue Version erkannt!
- ✓ Alles aktuell
- ⚠ Fehler: ... (falls Fetch fehlschlägt)
So kann Update-Detection auch auf Smartphone (ohne Dev-Konsole) debugged werden.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Service Worker mit Blob-URL funktionierte nicht zuverlässig (blob: Protocol
nicht registrierbar in einigen Browsern). Neue Lösung:
- Client-seitige Prüfung statt Service Worker
- Alle 60 Sekunden fetch() der index.html (mit Cache-Busting via Timestamp)
- Einfacher Hash-Check (erste + letzte 200 Zeichen des Content)
- localStorage speichert Hash zum Vergleichen
- Update-Flag wird gesetzt wenn sich Hash ändert
- Benachrichtigung nur wenn User aktiv ist (Page Visibility API)
- Erste Prüfung nach 3 Sekunden, dann alle 60 Sekunden
Viel zuverlässiger als der frühere SW-Ansatz. Funktioniert überall ohne Browser-Limit.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Texte unter dem Titel angepasst, um Work Breakdown Structure (PSP/WBS) und
Lean Pathfinding gleich prominent zu zeigen. Feature-Tree nur erwähnt, wenn
Platz ist. Kurzversionen auf Mobile: „PSP · Lean Pathfinding Editor".
Alle 9 Sprachen angepasst (DE/EN/ES/FR/PL/RU/HI/ZH/JA).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Service Worker prüft im Hintergrund auf neue Versionen (jede 5 Minuten)
- Update-Status wird in localStorage gespeichert
- Benachrichtigung erscheint nur wenn:
* User zur App zurückkommt (Page Visibility API)
* Oder beim initialen Laden wenn Update verfügbar
- "Später" Button zum Dismissieren, "Jetzt laden" für Reload
- Keine Browser-Permission nötig
- localStorage-Daten bleiben beim Reload erhalten
- Pragmatisch: User sieht Updates nur wenn er arbeitet
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Service Worker prüft periodisch auf neue Versionen (jede Minute)
- Bei verfügbarem Update: Benachrichtigung oben auf der Seite
- "Jetzt laden" Button triggert page reload
- Benachrichtigung verschwindet nach 30s oder bei Klick
- Service Worker als Blob registriert (Single-File-App kompatibel)
- localStorage-Daten bleiben erhalten beim Reload
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Rename variables to avoid conflicts with existing declarations
- Wrap ResizeObserver code in IIFE for local scope isolation
- Fixes build error: 'editorPanel' and 'legendBtn' already declared
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- ResizeObserver überwacht .editor-body Höhe
- Copy und Agenda Buttons werden versteckt wenn Body-Höhe < Head-Höhe
- Schwellwert: Buttons nur sichtbar wenn mindestens Titelzeilenhöhe Inhalt vorhanden ist
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- 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>
- 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>
Attached the `aria-labelledby` attribute to the editor textarea and added an ID to the editor title. Corrected the relative path for the script reference.
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.
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.
"Claude Code" bleibt als Produktname unveraendert. Der Credit ist hartkodiert
(kein data-i18n) und damit wie zuvor sprachunabhaengig englisch — keine
Uebersetzungen betroffen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DEPLOY_TARGET wird jetzt aus der .env im Repo-Wurzelordner gelesen (die von der
bestehenden .gitignore-Regel ohnehin ignoriert wird; Vite liest sie nicht, da
dessen Env unter frontend/ liegt). scripts/deploy.env(.example) entfaellt; neue
Vorlage .env.example im Wurzelordner. Argument hat weiterhin Vorrang, ~ bleibt
fuer die Remote-Seite erhalten (kein source).
.gitignore: eigene scripts/deploy.env-Zeile zurueckgenommen, Kommentar an der
.env-Regel ergaenzt. README (de/en) entsprechend aktualisiert.
Lokal verifiziert: Fallback liest aus Wurzel-.env, .env ignoriert, .env.example
getrackt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>