Bis hierher kam ein Plan nur per curl auf den Server — der Menueintrag war im Konzept vorgesehen und fehlte. Jetzt legt der Knopf das aktive Dokument an, schaltet dorthin um und schreibt den Link in die Adresszeile und in die Zwischenablage. Die Adresszeile IST der Link: dort sucht man ihn, und ein Neuladen fuehrt ins selbe Dokument zurueck. Die Basis-Adresse ist die eigene Herkunft — produktiv liegt das Backend hinter derselben Domain, wer nichts konfiguriert bekommt also das Richtige. Darueber liegen ?server= (Entwicklung) und die Adresse des offenen Server-Dokuments. Traegt nichts, wird gefragt. Das lokale Dokument bleibt: Wer sein einziges Exemplar einem Server anvertraut, soll es nicht im selben Zug verlieren. Dafuer nennt der Waehler jetzt den Host neben Server-Dokumenten — im Test standen sonst zwei Eintraege "Nur lokal" da, unterscheidbar nur am Tooltip. Und der Knopf verschwindet bei Dokumenten, die schon auf einem Server liegen. Geprueft im Browser gegen ein echtes Backend: Knopf sichtbar bei einem lokalen Dokument, nach dem Klick steht ?live=... in der Adresszeile, das lokale Dokument ist noch da, der Knopf verborgen — und eine getippte Zeile erreicht den Server als Version 2. 523 Frontend-Tests (5 neue fuer serverBase/documentsUrl). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
302 lines
30 KiB
HTML
302 lines
30 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Werkbaum – PSP & Lean Pathfinding Editor (Work Breakdown Structure)</title>
|
||
<meta name="description" content="Werkbaum ist ein textbasierter Editor für PSP/Lean Pathfinding und Projektstrukturpläne (WBS): Schreibe die Struktur als Text, das And/Or-Diagramm entsteht live. Auch für Feature-Trees & Requirements.">
|
||
<link rel="icon" type="image/svg+xml" href="../docs/brand/favicon.svg">
|
||
<!-- PWA (D73): Manifest + Icons liegen als public/-Assets NEBEN der einen
|
||
self-contained Datei (nicht inlinebar — der Browser holt das Manifest
|
||
per URL). Relativer Pfad, damit Pages unter /werkbaum/ und die
|
||
Wurzel-Installation denselben Verweis nutzen; per file:// bleibt der
|
||
Link wirkungslos, die Datei selbst läuft unverändert. -->
|
||
<link rel="manifest" href="manifest.webmanifest">
|
||
<meta name="theme-color" content="#243447">
|
||
</head>
|
||
<body>
|
||
|
||
<header>
|
||
<div class="header-row">
|
||
<h1 style="display:flex;align-items:center;gap:11px">
|
||
<svg width="34" height="34" viewBox="0 0 64 64" aria-hidden="true">
|
||
<rect x="22" y="5" width="20" height="12" rx="3.5" fill="#243447"/>
|
||
<path d="M32 17 V22 M14 22 H50 M14 22 V27 M50 22 V27" fill="none" stroke="#243447" stroke-width="3"/>
|
||
<rect x="4" y="27" width="20" height="12" rx="3.5" fill="#fff" stroke="#243447" stroke-width="3"/>
|
||
<rect x="40" y="27" width="20" height="12" rx="3.5" fill="#fff" stroke="#243447" stroke-width="3"/>
|
||
<path d="M50 39 V46" fill="none" stroke="#0F766E" stroke-width="3" stroke-dasharray="4 4"/>
|
||
<rect x="40" y="46" width="20" height="12" rx="3.5" fill="#fff" stroke="#0F766E" stroke-width="3"/>
|
||
</svg>
|
||
<span data-i18n-title="brandTooltip" title="„Werkbaum“ bedeutet so viel wie ‚Werk-Baum‘ — der Baum des Projektstrukturplans (WBS).">Werk<span style="color:var(--or)">baum</span></span>
|
||
</h1>
|
||
<div class="header-tools">
|
||
<!-- Neuigkeiten (D58): der Stern aus dem Diagramm-Kopf, jetzt permanent.
|
||
Sein Popup zeigt die Änderungen der letzten Tage (aus der git-Historie,
|
||
zur Bauzeit eingelesen); je Tag führt ein Link die betroffenen Knoten
|
||
in der „Was ist neu?"-Ansicht (D28) im Diagramm vor. -->
|
||
<span class="newswrap">
|
||
<button type="button" id="newsBtn" class="fsbtn newsbtn" aria-haspopup="dialog" aria-expanded="false" data-i18n-title="newsTooltip" data-i18n-aria="newsTooltip" title="Neuigkeiten" aria-label="Neuigkeiten">
|
||
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9z"/></svg>
|
||
<span class="freshcount" id="freshCount" aria-hidden="true" hidden>0</span>
|
||
</button>
|
||
<div class="newsmenu" id="newsMenu" role="dialog" data-i18n-aria="newsTitle" aria-label="Neuigkeiten" hidden></div>
|
||
</span>
|
||
<button type="button" id="fsToggle" class="fsbtn" aria-pressed="false" data-i18n-title="fullscreenTooltip" data-i18n-aria="fullscreenTooltip" title="Vollbild – Panels nutzen die ganze Fensterbreite" aria-label="Vollbild – Panels nutzen die ganze Fensterbreite">
|
||
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3"/></svg>
|
||
</button>
|
||
<div class="langsel" role="radiogroup" aria-label="Sprache / Language">
|
||
<button type="button" data-lang="de" title="Deutsch">DE</button>
|
||
<button type="button" data-lang="en" title="English">EN</button>
|
||
<button type="button" data-lang="es" title="Español">ES</button>
|
||
<button type="button" data-lang="fr" title="Français">FR</button>
|
||
<button type="button" class="lang-extra" data-lang="pl" title="Polski">PL</button>
|
||
<button type="button" class="lang-extra" data-lang="ru" title="Русский">RU</button>
|
||
<button type="button" class="lang-extra" data-lang="hi" title="हिन्दी">HI</button>
|
||
<button type="button" class="lang-extra" data-lang="zh" title="中文">中</button>
|
||
<button type="button" class="lang-extra" data-lang="ja" title="日本語">日</button>
|
||
<button type="button" id="langMore" class="langmore" aria-expanded="false" data-i18n-title="langMore" data-i18n-aria="langMore" title="weitere Sprachen" aria-label="weitere Sprachen">…</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p><span class="sub-full" data-i18n="subtitle">Werkbaum – Ein Text-basierter WBS/Projektstrukturplan/Feature-Tree/Requirements-Baum Diagramm-Editor.</span><span class="sub-short" data-i18n="subtitleShort">WBS, Feature- & Requirements-Bäume als Text</span></p>
|
||
</header>
|
||
|
||
<div class="app" id="app">
|
||
<div class="panel editor">
|
||
<div class="panel-head">
|
||
<!-- Gegenstück zum Knopf im Diagramm-Kopf (D17-Nachtrag). Der
|
||
Dokumenten-Wähler steht direkt daneben und ist damit genau dann zu
|
||
sehen, wenn der Text vorn ist — er gehört zu diesem Bereich. -->
|
||
<button type="button" class="copybtn panetoggle" id="paneToDiagram" data-i18n-title="paneToDiagram" data-i18n-aria="paneToDiagram" title="Zum Diagramm wechseln" aria-label="Zum Diagramm wechseln">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="3" width="6" height="4" rx="1"/><rect x="2.5" y="17" width="6" height="4" rx="1"/><rect x="15.5" y="17" width="6" height="4" rx="1"/><path d="M12 7V13M5.5 13H18.5M5.5 13V17M18.5 13V17"/></svg>
|
||
</button>
|
||
<!-- Dokument-Wähler und Snapshot-Knopf stehen zusammen; die Gruppe trägt
|
||
das `margin-right:auto` und ist der Bezug für das Snapshot-Menü. -->
|
||
<span class="docgroup">
|
||
<span class="doctrigger" id="docTrigger" role="button" tabindex="0" aria-haspopup="menu" aria-expanded="false" data-i18n-title="docSwitchTooltip" data-i18n-aria="docSwitchTooltip" title="Dokument wählen oder verwalten" aria-label="Dokument wählen oder verwalten">
|
||
<span class="docname" id="docName"></span>
|
||
<svg class="doc-caret" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
|
||
</span>
|
||
<div class="docmenu" id="docMenu" role="menu" data-i18n-aria="docMenuAria" aria-label="Dokumente" hidden>
|
||
<div class="docmenu-list" id="docList"></div>
|
||
<div class="docmenu-actions">
|
||
<button type="button" class="docact" id="docNew" data-i18n="docNew">Neues Dokument</button>
|
||
<button type="button" class="docact" id="docOpenFile" data-i18n="docOpenFile">Datei öffnen…</button>
|
||
<button type="button" class="docact" id="docSaveFile" data-i18n="docSaveFile">Als Datei speichern</button>
|
||
<button type="button" class="docact" id="docToServer" data-i18n="docToServer">Auf den Server legen</button>
|
||
<button type="button" class="docact" id="docRename" data-i18n="docRename">Umbenennen</button>
|
||
<button type="button" class="docact" id="docRestore" data-i18n="docRestore" hidden>Original wiederherstellen</button>
|
||
<button type="button" class="docact docdel" id="docDelete" data-i18n="docDelete">Löschen</button>
|
||
</div>
|
||
</div>
|
||
<span class="snapwrap">
|
||
<button type="button" class="copybtn snapbtn" id="snapBtn" aria-haspopup="menu" aria-expanded="false" data-i18n-title="snapTooltip" data-i18n-aria="snapTooltip" title="Frühere Stände dieses Dokuments" aria-label="Frühere Stände dieses Dokuments">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 12a8.5 8.5 0 1 0 2.6-6.1"/><path d="M3 4v4h4"/><path d="M12 7.5V12l3 1.8"/></svg>
|
||
</button>
|
||
<div class="snapmenu" id="snapMenu" role="menu" data-i18n-aria="snapMenuAria" aria-label="Frühere Stände" hidden></div>
|
||
</span>
|
||
<!-- Von Hand sichern, z. B. vor einer größeren Änderung. Kamera statt
|
||
Plus: ein Plus neben dem Dokument-Namen läse sich als „neues
|
||
Dokument“ (D54-Nachtrag). -->
|
||
<button type="button" class="copybtn snapaddbtn" id="snapAddBtn" data-i18n-title="snapAddTooltip" data-i18n-aria="snapAddTooltip" title="Aktuellen Stand jetzt sichern" aria-label="Aktuellen Stand jetzt sichern">
|
||
<svg class="ic-main" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 9a2 2 0 0 1 2-2h2.2l1.3-2h6.9l1.3 2H19a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"/><circle cx="12" cy="13" r="3.1"/></svg>
|
||
<svg class="ic-done" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
||
</button>
|
||
</span>
|
||
<button type="button" class="copybtn padview" id="padViewBtn" data-view="text" hidden>
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect class="frame" x="2.5" y="5" width="19" height="14" rx="2"/><line class="ic-both" x1="12" y1="5" x2="12" y2="19"/><rect class="ic-pad" x="3.5" y="6" width="8" height="12" rx="1" fill="currentColor" stroke="none"/><rect class="ic-text" x="12.5" y="6" width="8" height="12" rx="1" fill="currentColor" stroke="none"/></svg>
|
||
</button>
|
||
<a class="copybtn padlink" id="padLink" href="#" target="_blank" rel="noopener" hidden>
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9.5" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
|
||
</a>
|
||
<button type="button" class="copybtn padrefresh" id="padRefresh" hidden>
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg>
|
||
</button>
|
||
<button type="button" class="copybtn" id="copy" data-i18n-title="copyTooltip" data-i18n-aria="copyTooltip" title="Text in die Zwischenablage kopieren" aria-label="Text in die Zwischenablage kopieren">
|
||
<svg class="ic-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
||
<svg class="ic-done" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
||
</button>
|
||
<button type="button" class="copybtn legendbtn" id="legendBtn" data-i18n-title="legendTooltip" data-i18n-aria="legendTooltip" title="Legende ein-/ausblenden" aria-label="Legende ein-/ausblenden">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
|
||
</button>
|
||
<div class="winbtns" aria-label="Editor">
|
||
<button type="button" class="winbtn" data-state="b" data-i18n-title="minimize" title="minimieren">—</button>
|
||
<button type="button" class="winbtn" data-state="normal" data-i18n-title="normal" title="normal">▢</button>
|
||
<button type="button" class="winbtn" data-state="a" data-i18n-title="maximize" title="maximieren">■</button>
|
||
</div>
|
||
</div>
|
||
<div class="editor-body">
|
||
<!-- Pad-Rahmen + interner Spiegel teilen sich einen eigenen Bereich, damit die
|
||
Legenden-Aufteilung (D26) unberührt bleibt. Reihenfolge: Pad, Splitter,
|
||
Spiegel — gezogen wird von der Spiegelseite aus, wie bei der Legende. -->
|
||
<div class="src-area pv-text" id="srcArea">
|
||
<iframe class="padframe" id="padFrame" title="Etherpad" hidden></iframe>
|
||
<div class="pad-gutter" id="padGutter" role="separator" data-i18n-title="gutterTooltip" data-i18n-aria="padGutterAria" title="Ziehen zum Verschieben, Doppelklick setzt zurück" aria-label="Pad und Texteditor größenverändern" hidden></div>
|
||
<!-- Zeilennummern + Textfeld sind eine Spalte: der Splitter oben teilt den
|
||
Rahmen gegen diese Spalte, nicht gegen das nackte Textfeld. -->
|
||
<div class="src-wrap" id="srcWrap">
|
||
<div class="lineno" id="lineNos" aria-hidden="true"><div class="lineno-inner"></div></div>
|
||
<!-- `wrap="off"`: Zeilen werden nicht umbrochen, lange Zeilen bekommen
|
||
einen waagerechten Balken (D49). Die Einrückung trägt hier die
|
||
Hierarchie — ein weicher Umbruch setzt die Fortsetzung an den linken
|
||
Rand und lässt die Ebene verschwinden. -->
|
||
<textarea id="src" wrap="off" spellcheck="false" data-i18n-aria="editorTitle" aria-label="Struktur (Text)"></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="hint-gutter" id="hintGutter" role="separator" data-i18n-title="gutterTooltip" data-i18n-aria="hintGutterAria" title="Ziehen zum Verschieben, Doppelklick setzt zurück" aria-label="Editor und Legende größenverändern" hidden></div>
|
||
<div class="agenda" id="agenda">
|
||
<button type="button" class="agenda-summary" id="agendaToggle" aria-expanded="false" aria-controls="hint" data-i18n="agenda">Agenda</button>
|
||
<div class="hint" id="hint">
|
||
Einrückung (2 Leerzeichen oder Tab) definiert die Hierarchie.<br>
|
||
<code>-</code> Teilpaket, alle erforderlich <em>(all of)</em><br>
|
||
<code>+</code> Zugabe, nicht erforderlich <em>(optional)</em><br>
|
||
<code>!!!</code> hierhin schauen (gemeinsamer Zeigefinger)<br>
|
||
<code class="or-code">|</code> Alternative, eine wählen <em>(any of)</em><br>
|
||
<code class="or-code">=</code> Alternative, genau eine <em>(xor)</em><br>
|
||
Zeile ohne Zeichen = Wurzelknoten. <code class="or-code">|</code>, <code class="or-code">=</code> und <code>-</code>/<code>+</code> nicht mischen.<br>
|
||
Status als Kästchen nach dem Zeichen, z. B. <code>- [~] Frontend</code>:
|
||
<div class="chips">
|
||
<span class="chip st-idee">[?] Idee</span>
|
||
<span class="chip st-geplant">[ ] geplant</span>
|
||
<span class="chip st-arbeit">[~] in Arbeit</span>
|
||
<span class="chip st-durchstich">[/] Durchstich</span>
|
||
<span class="chip st-fertig">[x] fertig</span>
|
||
<span class="chip st-prod">[^] in Produktion</span>
|
||
<span class="chip st-verworfen">[-] verworfen</span>
|
||
</div>
|
||
Aufwand als T-Shirt-Größe in Klammern, Link einfach als URL anhängen:<br>
|
||
<code>- [ ] Backend (L) https://…</code><br>
|
||
Ab <code>(M)</code> gilt: weiter untergliedern — fehlt die Untergliederung, erscheint ein Platzhalter im Diagramm.<br>
|
||
Kommentare mit <code>%%</code> — als ganze Zeile oder am Zeilenende.
|
||
Personen mit <code>@name</code> — erscheinen unten rechts am Knoten.
|
||
Knoten-ID mit <code>#name:</code> vor dem Titel — erscheint im Tooltip des Knotens.
|
||
Abhängigkeiten mit <code>:#name,#name</code> — erscheinen im Tooltip.
|
||
Die Knotenfarbe zeigt den effektiven Status (mit Abhängigkeiten); ist der eigene weiter, steht er als Marke unten links.
|
||
Beschreibungen: <code>"</code> Zeile unter dem Knoten; Langtext hinter <code>---</code> als eingerückter <code>#id</code>-Block — beides im Tooltip (”).
|
||
Falten: <code>- [x] > …</code> startet eingeklappt, <code><</code> holt hervor; ▾/▸ am Knoten klappt um (Tastatur: ←/→).
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="gutter" id="gutter" role="separator" data-i18n-title="gutterTooltip" data-i18n-aria="gutterAria" aria-label="Bereiche größenverändern" title="Ziehen zum Verschieben, Doppelklick setzt zurück"></div>
|
||
|
||
<div class="panel right">
|
||
<div class="panel-head">
|
||
<!-- Nur auf kleinem Bildschirm (D17-Nachtrag): dort ist immer genau ein
|
||
Bereich zu sehen, und dieser Knopf schaltet auf den anderen um. Er
|
||
zeigt das Ziel, nicht den Zustand — der Zustand ist der Bereich, den
|
||
man gerade vor sich hat. -->
|
||
<button type="button" class="copybtn panetoggle" id="paneToText" data-i18n-title="paneToText" data-i18n-aria="paneToText" title="Zum Text wechseln" aria-label="Zum Text wechseln">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6h16M4 10h16M4 14h10M4 18h13"/></svg>
|
||
</button>
|
||
<span data-i18n="diagramTitle">Diagramm</span>
|
||
<button type="button" class="copybtn togglebtn" id="showc" aria-pressed="false" data-i18n-title="discardedTooltip" data-i18n-aria="discardedTooltip" title="Verworfene Knoten samt Teilbaum ein-/ausblenden" aria-label="Verworfene Knoten samt Teilbaum ein-/ausblenden">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="6" width="18" height="12" rx="2" stroke-dasharray="3 2.5"/><path d="M7 12h10"/></svg>
|
||
</button>
|
||
<button type="button" class="copybtn togglebtn" id="cheapBtn" aria-pressed="true" data-i18n-title="cheapTooltip" data-i18n-aria="cheapTooltip" title="Günstigsten Pfad hervorheben – nicht benötigte Alternativen treten zurück" aria-label="Günstigsten Pfad hervorheben – nicht benötigte Alternativen treten zurück">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="5" cy="6" r="2.5"/><circle cx="19" cy="18" r="2.5"/><path d="M7.5 6H14a3 3 0 0 1 0 6H10a3 3 0 0 0 0 6h6.5"/></svg>
|
||
</button>
|
||
<!-- Querverbindungen der Abhängigkeiten ein-/ausblenden (SPEC §9, D75):
|
||
ein Umschalter wie der Pfad daneben; Export und Druck folgen ihm. -->
|
||
<button type="button" class="copybtn togglebtn" id="depBtn" aria-pressed="true" data-i18n-title="depsTooltip" data-i18n-aria="depsTooltip" title="Querverbindungen der Abhängigkeiten anzeigen" aria-label="Querverbindungen der Abhängigkeiten anzeigen">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4.5 19.5 C 9 21.5, 14.5 15.5, 17.3 8.6" stroke-dasharray="0.2 3.4"/><path d="M14.3 7.2 L 18 6.6 L 17.6 10.3"/></svg>
|
||
</button>
|
||
<!-- Von Station zu Station des günstigsten Pfads (SPEC §9, D47). Kein
|
||
Umschalter, sondern eine Bewegung: jeder Druck holt die nächste noch
|
||
offene Station in die Mitte. Verborgen, solange es keine gibt. -->
|
||
<button type="button" class="copybtn" id="leanNextBtn" title="Zur nächsten Station des günstigsten Pfads" aria-label="Zur nächsten Station des günstigsten Pfads" hidden>
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2.5 12h5" stroke-dasharray="2.5 2.5"/><circle cx="11" cy="12" r="3"/><path d="M15 12h6M18.5 9.5l2.5 2.5-2.5 2.5"/></svg>
|
||
</button>
|
||
<!-- Der Stern stand hier bis D58 („Was ist neu?", D28) und ist in die
|
||
Kopfzeile gewandert: Er sagt jetzt nicht nur etwas über das aktive
|
||
Dokument, sondern über das Produkt — und ist deshalb immer da. -->
|
||
<!-- Faltung für den ganzen Baum (SPEC §9, D44/D75): ein DURCHSCHALTER —
|
||
jeder Druck stellt die nächste von vier Voreinstellungen her. Icon
|
||
und Tooltip zeigen den NÄCHSTEN Schritt (was Drücken tun wird);
|
||
welches Icon sichtbar ist, steuert `data-next` per CSS. -->
|
||
<button type="button" class="copybtn foldbtn" id="foldBtn" data-next="small" title="Knoten der Größe M und kleiner zuklappen" aria-label="Knoten der Größe M und kleiner zuklappen">
|
||
<svg class="fc-small" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3.5l4 4 4-4M8 20.5l4-4 4 4"/><text x="12" y="15" text-anchor="middle" font-size="9.5" font-weight="600" fill="currentColor" stroke="none" font-family="inherit">M</text></svg>
|
||
<svg class="fc-path" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3.5l4 4 4-4M8 20.5l4-4 4 4"/><circle cx="12" cy="12" r="2.6"/></svg>
|
||
<svg class="fc-closed" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 21V3M8 8l4 4 4-4M8 16l4-4 4 4"/></svg>
|
||
<svg class="fc-open" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v18M8 7l4-4 4 4M8 17l4 4 4-4"/></svg>
|
||
</button>
|
||
<!-- Knoten-IDs vor dem Titel einblenden (SPEC §9, D56) — geschrieben wie
|
||
im Text: `#some.id: Titel`. Das Zeichen selbst ist das Symbol; ein
|
||
gezeichnetes Icon sagte hier weniger als das `#`. -->
|
||
<button type="button" class="copybtn togglebtn idsbtn" id="idsBtn" aria-pressed="false" data-i18n-title="idsTooltip" data-i18n-aria="idsTooltip" title="Knoten-IDs vor dem Titel einblenden" aria-label="Knoten-IDs vor dem Titel einblenden">
|
||
<span aria-hidden="true">#</span>
|
||
</button>
|
||
<div class="seg" role="radiogroup" aria-label="Darstellung">
|
||
<label data-i18n-title="modeHorizontal" title="Horizontal – Organigramm, Diagramm über dem Editor">
|
||
<input type="radio" name="layout" value="horizontal" checked data-i18n-aria="modeHorizontal" aria-label="Horizontal – Organigramm">
|
||
<span><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="3" width="6" height="4" rx="1"/><rect x="2.5" y="17" width="6" height="4" rx="1"/><rect x="15.5" y="17" width="6" height="4" rx="1"/><path d="M12 7V13M5.5 13H18.5M5.5 13V17M18.5 13V17"/></svg></span>
|
||
</label>
|
||
<label data-i18n-title="modeKompakt" title="Kompakt – alles nach unten, platzsparend">
|
||
<input type="radio" name="layout" value="kompakt" data-i18n-aria="modeKompakt" aria-label="Kompakt – alles nach unten">
|
||
<span><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="6" height="4" rx="1"/><path d="M6 7V20"/><path d="M6 11H10M6 17H10"/><rect x="10" y="9" width="9" height="4" rx="1"/><rect x="10" y="15" width="9" height="4" rx="1"/></svg></span>
|
||
</label>
|
||
<label data-i18n-title="modeVertikal" title="Vertikal – Baum nach rechts, Diagramm neben dem Editor">
|
||
<input type="radio" name="layout" value="vertikal" data-i18n-aria="modeVertikal" aria-label="Vertikal – Baum nach rechts">
|
||
<span><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2.5" y="9.5" width="5" height="5" rx="1"/><rect x="16" y="3" width="6" height="4" rx="1"/><rect x="16" y="17" width="6" height="4" rx="1"/><path d="M7.5 12H12M12 5V19M12 5H16M12 19H16"/></svg></span>
|
||
</label>
|
||
</div>
|
||
<button type="button" class="copybtn" id="copyDiagram" data-i18n-title="copyDiagramTooltip" data-i18n-aria="copyDiagramTooltip" title="Diagramm als PNG-Bild in die Zwischenablage kopieren" aria-label="Diagramm als PNG-Bild in die Zwischenablage kopieren">
|
||
<svg class="ic-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
||
<svg class="ic-done" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
||
</button>
|
||
<div class="dlgroup" id="dlGroup">
|
||
<button type="button" class="copybtn dltrigger" id="dlTrigger" aria-haspopup="true" aria-expanded="false" data-i18n-title="downloadMenu" data-i18n-aria="downloadMenu" title="Diagramm herunterladen (SVG/PNG)" aria-label="Diagramm herunterladen (SVG/PNG)">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12M8 11l4 4 4-4M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg>
|
||
</button>
|
||
<div class="dlmenu">
|
||
<button type="button" class="copybtn dlbtn" id="dlDiagram" data-i18n-title="downloadDiagramTooltip" data-i18n-aria="downloadDiagramTooltip" title="Diagramm als SVG-Datei herunterladen" aria-label="Diagramm als SVG-Datei herunterladen">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12M8 11l4 4 4-4M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg><span class="dl-label">SVG</span>
|
||
</button>
|
||
<button type="button" class="copybtn dlbtn" id="dlDiagramPng" data-i18n-title="downloadPngTooltip" data-i18n-aria="downloadPngTooltip" title="Diagramm als PNG-Datei herunterladen" aria-label="Diagramm als PNG-Datei herunterladen">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12M8 11l4 4 4-4M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg><span class="dl-label">PNG</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="winbtns" aria-label="Diagramm">
|
||
<button type="button" class="winbtn" data-state="a" data-i18n-title="minimize" title="minimieren">—</button>
|
||
<button type="button" class="winbtn" data-state="normal" data-i18n-title="normal" title="normal">▢</button>
|
||
<button type="button" class="winbtn" data-state="b" data-i18n-title="maximize" title="maximieren">■</button>
|
||
</div>
|
||
</div>
|
||
<div class="diagram"><ul class="tree" id="out"></ul></div>
|
||
<div class="warnings" id="warn" role="status" aria-live="polite"></div>
|
||
<div class="zoomctl" data-i18n-aria="zoomAria" aria-label="Zoom (Strg/Cmd + Mausrad)">
|
||
<button type="button" id="zoomToggle" class="zoomToggle" data-i18n-title="zoomTooltip" title="Zoom anzeigen" aria-label="Zoom anzeigen">
|
||
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="10" cy="10" r="6"/><path d="m15 15 4 4M10 7v6M7 10h6"/></svg>
|
||
</button>
|
||
<div class="zoomcontrols">
|
||
<button type="button" id="zoomOut" data-i18n-title="zoomOut" title="verkleinern">−</button>
|
||
<button type="button" id="zoomReset" data-i18n-title="zoomReset" title="zurücksetzen">100 %</button>
|
||
<button type="button" id="zoomIn" data-i18n-title="zoomIn" title="vergrößern">+</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<footer class="site-footer"><a href="https://github.com/mhoennig/werkbaum" target="_blank" rel="noopener">Werkbaum</a> <a class="ver" href="https://github.com/mhoennig/werkbaum/commit/main" target="_blank" rel="noopener">1.0</a> · <a href="llms.md" target="_blank" rel="noopener" title="Werkbaum-Notation für KI-Agenten · Werkbaum notation for AI agents (Markdown)">llms.md</a> – © 2026 <a href="https://michael.hoennig.de" target="_blank" rel="noopener">Michael Hönnig</a> · <span class="vibe" title="Fable 5 and Opus 4.8">Built with Claude Code</span> – <a href="../LICENSE" target="_blank" rel="noopener">License</a> · <a href="https://michael.hoennig.de/imprint.html" target="_blank" rel="noopener" data-i18n="imprint">Impressum</a> · <a id="privacyLink" href="https://michael.hoennig.de/datenschutzerklaerung.html" target="_blank" rel="noopener" data-i18n="privacy">Datenschutz</a></footer>
|
||
|
||
<!-- Knoten-Fenster für Touch-Geräte (D52): Ohne Zeiger gibt es keinen Tooltip.
|
||
Es liegt auf <body> und ist `position:fixed` — in `#out` hinein würde es
|
||
dessen CSS-`zoom` erben (der Text skalierte mit) und von dessen `overflow`
|
||
beschnitten (die Falle aus D50). Inhalt wird bei jedem Öffnen ersetzt. -->
|
||
<!-- `aria-hidden`: Das Fenster ist eine rein visuelle Hilfe — sein ganzer Inhalt
|
||
steht bereits im `aria-label` des Knotens (SPEC §9), ein Screenreader läse
|
||
ihn sonst doppelt. Die Knöpfe darin tragen deshalb `tabindex="-1"`
|
||
(fokussierbare Elemente in einem `aria-hidden`-Bereich wären ein Fehler);
|
||
erreichbar bleibt beides über den Knoten selbst und über Esc. Siehe D57. -->
|
||
<div id="nodeTip" class="nodetip" aria-hidden="true" hidden>
|
||
<button type="button" class="nodetip-x" id="nodeTipClose" tabindex="-1" data-i18n-title="tipClose" title="Schließen">×</button>
|
||
<div class="nodetip-body" id="nodeTipBody"></div>
|
||
<span class="nodetip-arrow" aria-hidden="true"></span>
|
||
</div>
|
||
|
||
<script type="module" src="./src/app.js"></script>
|
||
</body>
|
||
</html>
|