feat: von Station zu Station des günstigsten Pfads (D47)
Mit dem status-bewussten Pfad (D46) zeigt das Diagramm die offene Front — im mitgelieferten Plan 24 Stationen, verteilt über einen Baum von über 20 000 px Breite. Sie zu sehen war damit gelöst, sie abzugehen nicht. Der neue Knopf im Diagramm-Kopf holt sie der Reihe nach in die Mitte: erster Druck die erste (was als Nächstes dran ist), jeder weitere die nächste, nach der letzten wieder die erste. Der Sprung fasst nur das Diagramm an — zentrieren, hervorheben, Tastaturfokus, also buchstäblich die Behandlung des ausdrücklichen Alt+Klicks (D25) samt Puls und hervorgehobenen Abhängigkeits-Kanten. In den Text führt von dort Alt+Enter, dieselbe Geste wie überall. Ohne eigenen Zustand: Fortgesetzt wird am gerade hervorgehobenen Knoten. Ein gemerkter Index wäre schlechter — der Baum wird bei jedem Tastendruck neu gebaut, die Stationsliste ändert sich unter ihm. Verborgen, solange es keine Station gibt (Pfad aus, oder alles erledigt); der Tooltip nennt die Anzahl. i18n `leanNextTooltip` in neun Sprachen. Die Mobil-Kopfzeile trug den neunten Knopf nicht mehr — D17-Nachtrag 5 hatte sie gerade erst auf acht zurechtgemessen. Nachgemessen: bei 375 px reicht es nach Lücke 8->6 px und Innenabstand 10->8 px weiterhin (345 px Inhalt, 359 px Platz, 14 px Luft); bei 320 px passen neun Fingerziele arithmetisch nicht, und unter 29 px zu gehen hat D17-Nachtrag 5 abgelehnt. Die Zeile schiebt dort deshalb (`overflow-x:auto`, Balken ausgeblendet) — 41 px Schiebeweg, Kopfhöhe unverändert 49 px, alle neun Elemente in voller Größe erreichbar. Dabei ein älterer, stiller Fehler gefunden: Bei Platzmangel schrumpfte der Modus-Wähler — das einzige Element ohne feste Größe — auf einen 2-px-Strich zusammen, während sein Icon 38 px breit darüber hinausragte; er sah aus wie ein Trennstrich und war unbenutzbar. `flex:0 0 auto` an allen Kindern der Zeile stellt das ab. 236 Tests grün. SPEC §9 und D47 halten es fest; der Plan bekommt den Knoten als `[x]` (noch nicht deployt), frontend/CLAUDE.md die Kopfzeilen-Stolperfalle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c4a6ff57d4
commit
ecc1b632f6
@@ -166,6 +166,7 @@ function render(){
|
||||
highlightCurrentNode(false);
|
||||
revealFocusMark(); /* `!!!` ins Bild holen, wenn die Marke neu ist (SPEC §1) */
|
||||
updateFreshBtn(); /* Zähler folgt der gerade gerenderten Menge (D28) */
|
||||
updateLeanBtn(); /* Stationen des Pfads haben sich geändert (D47) */
|
||||
}
|
||||
|
||||
/* Fokusmarke `!!!` (SPEC §1): Der erste markierte Knoten wird ins Bild geholt —
|
||||
@@ -1432,6 +1433,47 @@ cheapBtn.addEventListener('click', () => {
|
||||
saveUI();
|
||||
});
|
||||
|
||||
/* ---------- Von Station zu Station (SPEC §9, D47) ----------
|
||||
Kein Umschalter, sondern eine Bewegung: Jeder Druck holt die nächste noch
|
||||
offene Station des günstigsten Pfads in die Mitte — beim ersten Druck die
|
||||
erste, danach der Reihe nach weiter, nach der letzten wieder von vorn.
|
||||
Gegangen wird die DOM-Reihenfolge, also dieselbe, in der die Pfadlinie durch
|
||||
die Stationen fädelt (D18/D46).
|
||||
|
||||
Ohne eigenen Zustand: Fortgesetzt wird an dem Knoten, der GERADE
|
||||
hervorgehoben ist (`currentNodeEl`, D25). Steht der auf einer Station, geht
|
||||
es bei der nächsten weiter; steht er woanders — etwa weil zwischendurch im
|
||||
Text getippt wurde —, beginnt der Gang wieder vorn, also bei dem, was als
|
||||
Nächstes dran ist. Ein gemerkter Index wäre schlechter: Beim Tippen wird der
|
||||
Baum neu gebaut und die Liste ändert sich unter ihm. */
|
||||
function jumpToLeanStation(){
|
||||
const st = [...out.querySelectorAll('.node.cheap-leaf')];
|
||||
if(!st.length) return;
|
||||
const el = st[(st.indexOf(currentNodeEl) + 1) % st.length]; /* -1 ⇒ die erste */
|
||||
/* Auf Mobil ist das Diagramm womöglich gar nicht vorn — erst holen, sonst
|
||||
misst sich der Zielknoten zu null (D17-Nachtrag 1). */
|
||||
if(isMobile()) setMobilePane('diagram', true);
|
||||
/* Genau die Behandlung des ausdrücklichen Alt+Klicks (D25): Fokus ohne
|
||||
eigenes Scrollen, dann hervorheben, pulsen, zentrieren — und die
|
||||
Abhängigkeits-Kanten des Knotens nehmen es mit (D41). */
|
||||
el.focus({preventScroll: true});
|
||||
caretLine = +el.dataset.line || null;
|
||||
highlightCurrentNode(true, 'center');
|
||||
}
|
||||
const leanNextBtn = document.getElementById('leanNextBtn');
|
||||
leanNextBtn.addEventListener('click', jumpToLeanStation);
|
||||
/* Verborgen, solange es nichts anzuspringen gibt — bei ausgeschaltetem Pfad
|
||||
ebenso wie bei einem durchweg erledigten Plan (D46). Dieselbe Zurückhaltung
|
||||
wie beim „Was ist neu?"-Knopf: ein Knopf, der nichts tut, ist Rauschen. */
|
||||
function updateLeanBtn(){
|
||||
const n = out.querySelectorAll('.node.cheap-leaf').length;
|
||||
leanNextBtn.hidden = !n;
|
||||
if(!n) return;
|
||||
const tip = t('leanNextTooltip', {n});
|
||||
leanNextBtn.title = tip;
|
||||
leanNextBtn.setAttribute('aria-label', tip);
|
||||
}
|
||||
|
||||
/* ---------- In die Zwischenablage kopieren ---------- */
|
||||
async function writeClipboard(text){
|
||||
try{ await navigator.clipboard.writeText(text); return; }catch(_){}
|
||||
@@ -1516,6 +1558,7 @@ const I18N = {
|
||||
riskTooltip:"High Risk – Aufwand noch unklar.",
|
||||
discardedTooltip:"Verworfene Knoten samt Teilbaum ein-/ausblenden",
|
||||
cheapTooltip:"Günstigsten Pfad hervorheben – nicht benötigte Alternativen treten zurück",
|
||||
leanNextTooltip:"Zur nächsten Station des günstigsten Pfads springen – was als Nächstes dran ist ({n} offen)",
|
||||
foldSmallTooltip:"Knoten der Größe M und kleiner zuklappen – erneut drücken klappt alle wieder auf",
|
||||
implicitSizeTooltip:"Keine Größe angegeben – für die Kostenschätzung als M angenommen",
|
||||
fullscreenTooltip:"Vollbild – Panels nutzen die ganze Fensterbreite",
|
||||
@@ -1597,6 +1640,7 @@ const I18N = {
|
||||
riskTooltip:"High risk – effort still unclear.",
|
||||
discardedTooltip:"Show/hide discarded nodes and their subtree",
|
||||
cheapTooltip:"Highlight the cheapest path – unneeded alternatives recede",
|
||||
leanNextTooltip:"Jump to the next station on the cheapest path – what to tackle next ({n} open)",
|
||||
foldSmallTooltip:"Collapse nodes of size M and smaller – press again to expand them all",
|
||||
implicitSizeTooltip:"No size given – assumed as M for the cost estimate",
|
||||
fullscreenTooltip:"Full screen – panels use the full window width",
|
||||
@@ -1678,6 +1722,7 @@ const I18N = {
|
||||
riskTooltip:"Alto riesgo – esfuerzo aún incierto.",
|
||||
discardedTooltip:"Mostrar u ocultar los nodos descartados y su subárbol",
|
||||
cheapTooltip:"Resaltar la ruta más económica: las alternativas no necesarias se atenúan",
|
||||
leanNextTooltip:"Ir a la siguiente estación de la ruta más económica: lo próximo que toca ({n} pendientes)",
|
||||
foldSmallTooltip:"Plegar los nodos de talla M o menor: pulsa de nuevo para desplegarlos todos",
|
||||
implicitSizeTooltip:"Sin tamaño indicado: se asume M para el cálculo de costes",
|
||||
fullscreenTooltip:"Pantalla completa – los paneles usan todo el ancho de la ventana",
|
||||
@@ -1759,6 +1804,7 @@ const I18N = {
|
||||
riskTooltip:"Risque élevé – effort encore incertain.",
|
||||
discardedTooltip:"Afficher/masquer les nœuds abandonnés et leur sous-arbre",
|
||||
cheapTooltip:"Mettre en évidence le chemin le moins coûteux – les alternatives inutiles s'estompent",
|
||||
leanNextTooltip:"Aller à la station suivante du chemin le moins coûteux – la prochaine chose à faire ({n} en attente)",
|
||||
foldSmallTooltip:"Replier les nœuds de taille M et moins – appuyez à nouveau pour tout déplier",
|
||||
implicitSizeTooltip:"Aucune taille indiquée – considérée comme M pour l'estimation des coûts",
|
||||
fullscreenTooltip:"Plein écran – les panneaux occupent toute la largeur de la fenêtre",
|
||||
@@ -1840,6 +1886,7 @@ const I18N = {
|
||||
riskTooltip:"Wysokie ryzyko – nakład jeszcze niejasny.",
|
||||
discardedTooltip:"Pokaż/ukryj odrzucone węzły wraz z poddrzewem",
|
||||
cheapTooltip:"Wyróżnij najtańszą ścieżkę – niepotrzebne alternatywy są przygaszone",
|
||||
leanNextTooltip:"Przejdź do następnej stacji najtańszej ścieżki – co dalej ({n} otwartych)",
|
||||
foldSmallTooltip:"Zwiń węzły o rozmiarze M i mniejsze – naciśnij ponownie, aby rozwinąć wszystkie",
|
||||
implicitSizeTooltip:"Nie podano rozmiaru – przyjęto M do szacowania kosztów",
|
||||
fullscreenTooltip:"Pełny ekran – panele wykorzystują całą szerokość okna",
|
||||
@@ -1921,6 +1968,7 @@ const I18N = {
|
||||
riskTooltip:"Высокий риск – оценка ещё не ясна.",
|
||||
discardedTooltip:"Показать/скрыть отклонённые узлы вместе с поддеревом",
|
||||
cheapTooltip:"Выделить самый дешёвый путь — ненужные альтернативы приглушаются",
|
||||
leanNextTooltip:"Перейти к следующей станции самого дешёвого пути — что делать дальше ({n} открыто)",
|
||||
foldSmallTooltip:"Свернуть узлы размера M и меньше — нажмите ещё раз, чтобы развернуть все",
|
||||
implicitSizeTooltip:"Размер не указан — для оценки затрат принят как M",
|
||||
fullscreenTooltip:"Полный экран – панели занимают всю ширину окна",
|
||||
@@ -2002,6 +2050,7 @@ const I18N = {
|
||||
riskTooltip:"उच्च जोखिम – प्रयास अभी अस्पष्ट।",
|
||||
discardedTooltip:"अस्वीकृत नोड्स और उनके उप-वृक्ष दिखाएँ/छिपाएँ",
|
||||
cheapTooltip:"सबसे किफ़ायती पथ को उजागर करें – अनावश्यक विकल्प मंद हो जाते हैं",
|
||||
leanNextTooltip:"सबसे किफ़ायती पथ के अगले पड़ाव पर जाएँ – अगला काम ({n} शेष)",
|
||||
foldSmallTooltip:"आकार M और उससे छोटे नोड समेटें – सभी को खोलने के लिए फिर दबाएँ",
|
||||
implicitSizeTooltip:"कोई आकार नहीं दिया गया – लागत अनुमान के लिए M माना गया",
|
||||
fullscreenTooltip:"पूर्ण स्क्रीन – पैनल पूरी विंडो चौड़ाई का उपयोग करते हैं",
|
||||
@@ -2072,6 +2121,7 @@ const I18N = {
|
||||
fullscreenTooltip:"全屏——面板占据整个窗口宽度",
|
||||
discardedTooltip:"显示/隐藏已放弃的节点及其子树",
|
||||
cheapTooltip:"突出显示成本最低的路径——不需要的备选项将淡化",
|
||||
leanNextTooltip:"跳到成本最低路径的下一站——接下来该做的事(还有 {n} 项)",
|
||||
foldSmallTooltip:"折叠尺寸 M 及更小的节点——再次点击可全部展开",
|
||||
implicitSizeTooltip:"未指定尺寸——成本估算时按 M 计",
|
||||
ghostTooltip:"从 M 号起,元素应进一步细分。",
|
||||
@@ -2153,6 +2203,7 @@ const I18N = {
|
||||
fullscreenTooltip:"全画面 — パネルがウィンドウ幅いっぱいを使用",
|
||||
discardedTooltip:"破棄したノードとその下位ツリーを表示/非表示",
|
||||
cheapTooltip:"最も低コストの経路を強調 – 不要な選択肢は控えめに表示",
|
||||
leanNextTooltip:"最も低コストの経路の次の駅へ移動 – 次にやること(残り {n} 件)",
|
||||
foldSmallTooltip:"サイズ M 以下のノードを折りたたむ – もう一度押すとすべて展開",
|
||||
implicitSizeTooltip:"サイズ未指定 – コスト見積もりのため M として扱う",
|
||||
ghostTooltip:"サイズ M 以上の要素はさらに分解すべきです。",
|
||||
|
||||
+16
-2
@@ -1108,8 +1108,22 @@
|
||||
Ein-Bereich-Modus überhaupt gibt. Die Knöpfe passen längst — es waren die
|
||||
Abstände: 14 px Lücke mal sieben plus 2×16 px Innenabstand sind mehr als
|
||||
ein Drittel von 375 px. Deshalb hier enger und `nowrap` als Riegel; die
|
||||
Knöpfe selbst bleiben unangetastet (Fingergröße). */
|
||||
body.mobile .panel-head{gap:8px;flex-wrap:nowrap;padding-inline:10px}
|
||||
Knöpfe selbst bleiben unangetastet (Fingergröße).
|
||||
Mit dem neunten Bedienelement (Stationssprung, D47) noch einmal enger:
|
||||
6 px Lücke und 8 px Innenabstand. Dazu `flex:0 0 auto` — ohne das schrumpft
|
||||
ausgerechnet der Modus-Wähler (das einzige Element ohne feste Größe) bei
|
||||
Platzmangel auf einen 2-px-Strich zusammen, während sein Icon darüber
|
||||
hinausragt. Ein zerdrücktes Bedienelement ist der schlechtere Fehler als
|
||||
ein sichtbarer Überlauf (D17-Nachtrag 5). */
|
||||
body.mobile .panel-head{gap:6px;flex-wrap:nowrap;padding-inline:8px}
|
||||
body.mobile .panel-head>*{flex:0 0 auto}
|
||||
/* Unterhalb von rund 360 px ist es reine Arithmetik: neun Bedienelemente à
|
||||
29 px plus Lücken brauchen mehr, als dort überhaupt da ist (bei 320 px
|
||||
fehlen 41 px). Kleiner als 29 px darf ein Fingerziel nicht werden
|
||||
(D17-Nachtrag 5), also schiebt die Zeile. Bei 375 px bleiben 14 px Luft —
|
||||
dort ändert die Regel nichts, weil nichts überläuft. */
|
||||
body.mobile .panel-head{overflow-x:auto;scrollbar-width:none}
|
||||
body.mobile .panel-head::-webkit-scrollbar{display:none}
|
||||
/* Inhalte rund 25 % kleiner, damit mehr Plan auf die Fläche passt
|
||||
(D17-Nachtrag 2). Das Diagramm macht das über den CSS-`zoom` (Faktor auf
|
||||
den Nutzer-Zoom, siehe MOBILE_ZOOM in app.js); der Text über die
|
||||
|
||||
Reference in New Issue
Block a user