diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 98cb705..515d98c 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -520,3 +520,25 @@ Knoten-Ecken nicht an (die sind laut D18 schon dicht). Die Regel braucht den any-of-Gruppe (im Test zuerst passiert). Rein visuelle Editierhilfe — im Druck abgeschaltet; im Grafikexport erscheint sie ohnehin nicht, weil `diagramToSvg()` nur Hintergrund, Rahmen, Farbe und Textdekoration ausliest, nie `box-shadow`. + +**Auffindbarkeit (Nachtrag).** Eine Modifier-Geste, die niemand kennt, ist +keine Funktion. Gegenmaßnahmen, absteigend nach Wirkung: + +- **Alt-Modus sichtbar machen:** Solange Alt gedrückt ist, trägt `#out` die + Klasse `alt`; alle Knoten bekommen `cursor:alias` und 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 + Modus muss zusätzlich am `blur` des Fensters zurückgesetzt werden — bei + Alt+Tab kommt kein `keyup` mehr an und er bliebe hängen. +- **Tooltip an jedem Knoten** (siehe oben, `jumpHint`). +- **Legende:** Die aufklappbare Legende endet mit einer abgesetzten + Bedienungs-Zeile (`hint_jump`, `.hint-op` mit gestricheltem Trenner), damit + sie ihre Rolle als *Notations*-Legende behält. + +Erwogen und **verworfen: der einfache Klick springt** (auf Knoten ohne URL, wo +nichts kollidiert — das wären ~97 % der Knoten der Beispieldateien). Hätte die +Geste beiläufig auffindbar gemacht und auf Mobil den langen Druck erspart, +bedeutet aber, dass derselbe Klick je nach Knoten Verschiedenes tut. Ebenfalls +verworfen: ein **einmaliger Hinweis** nach dem ersten Sprung (localStorage-Flag) +— zusätzlicher i18n-Text in 9 Sprachen für einen Effekt, den Cursor und Legende +bereits abdecken. diff --git a/docs/SPEC.md b/docs/SPEC.md index 0b0efac..aff44e5 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -240,6 +240,11 @@ verknüpft (siehe D25): verworfenes Element) heben nichts hervor. - Der **einfache** Klick bleibt unverändert der Link (§6): Ein Knoten mit URL öffnet sie weiterhin im neuen Tab. Deshalb Alt und nicht der einfache Klick. +- **Auffindbarkeit:** Solange **Alt gedrückt** ist, zeigen alle Knoten den + Sprung-Cursor und der Knoten unter dem Zeiger einen Petrol-Ring — die Geste + ist im Moment des Ausprobierens sichtbar, auch auf verlinkten Knoten. Dazu + nennt der Knoten-Tooltip die Geste, und die aufklappbare Legende schließt mit + einer Bedienungs-Zeile ab. - Die Hervorhebung ist eine reine Editierhilfe: nicht im Grafikexport, nicht im Druck. diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md index 96fc062..81b9322 100644 --- a/frontend/CLAUDE.md +++ b/frontend/CLAUDE.md @@ -135,7 +135,10 @@ verworfene Elemente. Quelle sind ES-Module unter `src/`; `index.html` ist der `syncCaret()` setzt die Klasse `current` auf den Knoten der Cursor-Zeile; `render()` stellt sie nach jedem Neubau wieder her (ohne zu scrollen). Die CSS-Regel braucht den `#out`-Präfix (`ul.or .node{box-shadow:none}` ist - spezifischer). + spezifischer). Auffindbarkeit: `setAltMode()` setzt bei gedrückter Alt-Taste + die Klasse `alt` an `#out` (Cursor + Ring am Knoten unter dem Zeiger) — der + `blur`-Handler ist Pflicht, sonst bleibt der Modus nach Alt+Tab hängen; dazu + `jumpHint` im Knoten-Tooltip und `hint_jump` als letzte Zeile der Legende. - Kleiner Bildschirm: `body.mobile` (per `matchMedia`, ≤ 640 px) stapelt Diagramm/Editor mit **stufenlosem** Splitter (kein Snap/Collapse wie auf Desktop): der Gutter-Drag ruft `setMobileDrow()` (klemmt `--drow` zwischen den diff --git a/frontend/src/app.js b/frontend/src/app.js index 6d7380e..406d2d3 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -454,6 +454,16 @@ function syncCaret(){ } for(const ev of ['click','keyup','input','focus']) src.addEventListener(ev, syncCaret); +/* Alt-Modus sichtbar machen: solange Alt gedrückt ist, zeigt jeder Knoten den + Sprung-Cursor und der Knoten unter dem Zeiger einen Petrol-Ring. Das ist die + einzige Rückmeldung, die auch auf verlinkten Knoten funktioniert (dort gehört + der einfache Klick weiterhin dem Link). `blur` ist nötig: bei Alt+Tab kommt + kein keyup mehr an, der Modus bliebe sonst hängen. */ +function setAltMode(on){ out.classList.toggle('alt', on); } +window.addEventListener('keydown', e => { if(e.key === 'Alt') setAltMode(true); }); +window.addEventListener('keyup', e => { if(e.key === 'Alt' || !e.altKey) setAltMode(false); }); +window.addEventListener('blur', () => setAltMode(false)); + const app = document.getElementById('app'); function applyLayout(mode){ out.classList.toggle('vertical', mode === 'vertikal'); @@ -756,7 +766,8 @@ const I18N = { hint_size:"Aufwand als T-Shirt-Größe in Klammern, Link einfach als URL anhängen:", hint_break:"Ab (M) gilt: weiter untergliedern — fehlt die Untergliederung, erscheint ein Platzhalter im Diagramm.", hint_comment:"Kommentare mit %% — als ganze Zeile oder am Zeilenende.", - hint_people:"Personen mit @name — erscheinen unten rechts am Knoten." + hint_people:"Personen mit @name — erscheinen unten rechts am Knoten.", + hint_jump:"Alt+Klick auf einen Knoten (mobil: langer Druck) springt zur zugehörigen Textzeile." }, en: { subtitle:"Werkbaum – Work Breakdown Structure / Lean Pathfinding · Project structure editor (also feature-tree & requirements)", @@ -803,7 +814,8 @@ const I18N = { hint_size:"Effort as a T-shirt size in parentheses; add a link simply as a URL:", hint_break:"From (M) on: break it down further — if the breakdown is missing, a placeholder appears in the diagram.", hint_comment:"Comments with %% — whole line or at the end of a line.", - hint_people:"People with @name — shown at the bottom-right of the node." + hint_people:"People with @name — shown at the bottom-right of the node.", + hint_jump:"Alt+click a node (long press on touch) jumps to its line in the text." }, es: { subtitle:"Werkbaum – EDT / Lean Pathfinding · Editor de estructura de proyectos (también árboles de características y requisitos)", @@ -850,7 +862,8 @@ const I18N = { hint_size:"Esfuerzo como talla de camiseta entre paréntesis; añade un enlace simplemente como URL:", hint_break:"A partir de (M): sigue desglosando — si falta el desglose, aparece un marcador de posición en el diagrama.", hint_comment:"Comentarios con %% — línea completa o al final de la línea.", - hint_people:"Personas con @nombre — aparecen abajo a la derecha del nodo." + hint_people:"Personas con @nombre — aparecen abajo a la derecha del nodo.", + hint_jump:"Alt+clic en un nodo (pulsación larga en táctil) salta a su línea en el texto." }, fr: { subtitle:"Werkbaum – WBS / Lean Pathfinding · Éditeur de structure de projet (aussi pour arbres de fonctionnalités et d'exigences)", @@ -897,7 +910,8 @@ const I18N = { hint_size:"Effort en taille de T-shirt entre parenthèses ; ajoutez un lien simplement comme URL :", hint_break:"À partir de (M) : décomposer davantage — si la décomposition manque, un espace réservé apparaît dans le diagramme.", hint_comment:"Commentaires avec %% — ligne entière ou en fin de ligne.", - hint_people:"Personnes avec @nom — affichées en bas à droite du nœud." + hint_people:"Personnes avec @nom — affichées en bas à droite du nœud.", + hint_jump:"Alt+clic sur un nœud (appui long sur tactile) saute à sa ligne dans le texte." }, pl: { subtitle:"Werkbaum – WBS / Lean Pathfinding · Edytor struktury projektów (również dla drzew funkcji i wymagań)", @@ -944,7 +958,8 @@ const I18N = { hint_size:"Nakład jako rozmiar koszulki w nawiasach; link dodaj po prostu jako URL:", hint_break:"Od (M): dziel dalej — gdy brakuje podziału, w diagramie pojawia się symbol zastępczy.", hint_comment:"Komentarze z %% — cały wiersz lub na końcu wiersza.", - hint_people:"Osoby z @nazwa — pokazywane w prawym dolnym rogu węzła." + hint_people:"Osoby z @nazwa — pokazywane w prawym dolnym rogu węzła.", + hint_jump:"Alt+kliknięcie węzła (długie naciśnięcie na dotyku) przechodzi do jego wiersza w tekście." }, ru: { subtitle:"Werkbaum – СДР / Lean Pathfinding · Редактор структуры проектов (также для деревьев функций и требований)", @@ -991,7 +1006,8 @@ const I18N = { hint_size:"Трудоёмкость как размер футболки в скобках; ссылку добавьте просто как URL:", hint_break:"С (M): дробите дальше — если декомпозиции нет, в диаграмме появляется заполнитель.", hint_comment:"Комментарии через %% — вся строка или в конце строки.", - hint_people:"Люди через @имя — показываются справа внизу узла." + hint_people:"Люди через @имя — показываются справа внизу узла.", + hint_jump:"Alt+клик по узлу (долгое нажатие на сенсоре) переходит к его строке в тексте." }, hi: { subtitle:"Werkbaum – WBS / Lean Pathfinding · परियोजना संरचना संपादक (फ़ीचर और रिक्वायरमेंट ट्री के लिए भी)", @@ -1038,7 +1054,8 @@ const I18N = { hint_size:"प्रयास कोष्ठक में टी-शर्ट आकार के रूप में; लिंक बस URL के रूप में जोड़ें:", hint_break:"(M) से आगे: और विभाजित करें — विभाजन न होने पर आरेख में प्लेसहोल्डर दिखता है।", hint_comment:"%% से टिप्पणियाँ — पूरी पंक्ति या पंक्ति के अंत में।", - hint_people:"@नाम से व्यक्ति — नोड के नीचे-दाएँ दिखते हैं।" + hint_people:"@नाम से व्यक्ति — नोड के नीचे-दाएँ दिखते हैं।", + hint_jump:"किसी नोड पर Alt+क्लिक (टच पर लंबा दबाव) टेक्स्ट में उसकी पंक्ति पर ले जाता है।" }, zh: { subtitle:"Werkbaum – WBS / Lean Pathfinding · 项目结构编辑器(也支持功能树和需求树)", @@ -1085,7 +1102,8 @@ const I18N = { hint_size:"用括号中的 T 恤尺码表示工作量;链接直接作为 URL 附加:", hint_break:"从 (M) 起:继续细分——若缺少细分,图表中会出现占位符。", hint_comment:"用 %% 注释——整行或行尾。", - hint_people:"用 @姓名 表示人员——显示在节点右下角。" + hint_people:"用 @姓名 表示人员——显示在节点右下角。", + hint_jump:"Alt+点击节点(触摸屏为长按)可跳转到文本中对应的行。" }, ja: { subtitle:"Werkbaum – WBS / Lean Pathfinding · プロジェクト構造エディター(フィーチャーツリーと要件ツリーにも対応)", @@ -1132,7 +1150,8 @@ const I18N = { hint_size:"工数は括弧内の T シャツサイズで;リンクは URL としてそのまま追加:", hint_break:"(M) 以上:さらに分解 — 分解がないと図にプレースホルダーが表示されます。", hint_comment:"%% でコメント — 行全体または行末。", - hint_people:"@名前 で担当者 — ノードの右下に表示されます。" + hint_people:"@名前 で担当者 — ノードの右下に表示されます。", + hint_jump:"ノードを Alt+クリック(タッチでは長押し)すると、テキストの該当行へ移動します。" } }; let lang = 'de'; @@ -1161,7 +1180,8 @@ function buildHint(){ - [ ] Backend (L) https://…
${esc(t('hint_break'))}
${esc(t('hint_comment'))} - ${esc(t('hint_people'))}`; + ${esc(t('hint_people'))} +
${esc(t('hint_jump'))}
`; } function applyLang(l){ lang = l; diff --git a/frontend/src/style.css b/frontend/src/style.css index 4203675..72a022a 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -373,6 +373,8 @@ padding:12px 16px;border-top:1px dashed rgba(36,52,71,.18); font-size:.8rem;color:var(--muted);line-height:1.7; } + /* Bedienung statt Notation — abgesetzt, damit die Legende ihre Rolle behält. */ + .hint-op{margin-top:8px;padding-top:8px;border-top:1px dashed rgba(36,52,71,.18)} .hint code{ font-family:'IBM Plex Mono',monospace;font-size:.75rem; background:var(--paper);border:1px solid rgba(36,52,71,.12); @@ -441,6 +443,11 @@ (weiter unten) ist spezifischer als `.node.current` und schluckte den Ring sonst überall unterhalb einer any-of-Gruppe. */ #out .node.current{box-shadow:0 0 0 2px var(--card),0 0 0 4px var(--ink)} + /* Alt gedrückt = Sprung-Geste scharf: Cursor an allen Knoten, Petrol-Ring am + Knoten unter dem Zeiger. Auf verlinkten Knoten ist das die einzige + Rückmeldung, weil dort der einfache Klick dem Link gehört (D25). */ + #out.alt .node{cursor:alias} + #out.alt .node:hover{box-shadow:0 0 0 2px var(--card),0 0 0 4px var(--or)} /* Auf Touch ist der lange Druck die Sprung-Geste — kein iOS-Link-Callout. */ a.node{-webkit-touch-callout:none} .ext{font-size:.72em;margin-left:5px;opacity:.55}