From 38416962b3de79686752f33aa7c99862a9979612 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Wed, 9 Sep 2026 14:45:38 +0200 Subject: [PATCH] Kopfleiste am Handy: alles in einer Reihe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Filipe, mit Bildschirmfoto: "ich will dass es ueberall perfektionniert wird. ich will dass du das richtig geil machst es soll alles in einer reihe sein." Auf dem Bild stand "Abmelden" allein in einer zweiten Zeile, darueber Teilen, Chat, Suche und das Profilbild. --- GEMESSEN, BEVOR ETWAS GEAENDERT WURDE --- Bei 390 px, alle fuenf Rollen: verfuegbar fuer die rechte Gruppe 275 px gebraucht als DogFather 393 px (Sicht 150 · Teilen 38 · Chat 37 · Suche 47 · Bild 28 · Abmelden 93) gebraucht als Scout/Manager/Spicy 243 px gebraucht als Creator 205 px Der Umbruch war also die richtige Antwort auf ein echtes Platzproblem. `flex-wrap` misst und rechnet nicht -- das bleibt so. Geaendert wird der PLATZBEDARF, nicht die Reaktion darauf. Eine Schwelle, ab der nicht mehr umgebrochen wird, waere wieder eine Rechnung von gestern: Beim naechsten Knopf staende alles uebereinander. --- WAS SCHRUMPFT, UND WAS NICHT --- Die drei Zeichen-Knoepfe waren 38, 37 und 47 px breit -- nebeneinander sah das unruhig aus. Jetzt alle 36. "Abmelden" wird auf schmalen Bildschirmen zum Zeichen (93 -> 36). Das Wort bleibt im aria-label und am Rechner sichtbar: Dort ist Platz, und ein Wort ist eindeutiger als ein Bild. Der Aufbau steht in kopf.js und nicht in neunzehn HTML-Dateien -- neunzehn Stellen sind achtzehn Gelegenheiten, eine zu vergessen. Der Sicht-Umschalter wird ein Zeichen-Knopf wie die anderen (150 -> 36), ABER NUR solange die eigene Sicht laeuft. Bei einer fremden behaelt er den Namen, und dann darf die Leiste auch umbrechen: Dass man fremde Zahlen ansieht, ist wichtiger als eine gerade Zeile. Das ist der gefaehrlichste Fall dieser Funktion, und er bleibt unangetastet. --- ZWEI DINGE, DIE ERST DIE MESSUNG GEZEIGT HAT --- 1. `max-width: 30px` am Umschalter-Kasten wirkte NICHT. Gemessen stand da: berechnete Hoechstbreite 30 px, tatsaechliche Breite 104. Der Knopf DARIN behielt seine Groesse und schob den Kasten wieder auf. Wer nur den Rahmen begrenzt, begrenzt nichts -- die Breite kommt vom Inhalt. Jetzt liegt der Knopf unsichtbar UEBER dem Auge: die ganze Flaeche ist das Ziel, der Fokusring bleibt, die Breite ist 36. 2. Bei 360 px brach es weiter um, obwohl es rechnerisch passte. Ursache war eine eigene Regel bei 380 px, die Marke und Bedienelemente ausdruecklich in zwei Zeilen zwang -- richtig, solange die Bedienelemente 243 bis 393 px brauchten, falsch seit sie 136 bis 238 brauchen. Die Schwelle liegt jetzt bei 300 px; darunter gibt es Geraete, auf denen es wirklich nicht reicht. --- Pruefung --- pruef-handy, 15 neue Messungen (fuenf Rollen x 360/390/412): alle Teile der Kopfleiste stehen in einer Reihe, Spanne 4 px. Gemessen wird die ZEILENZAHL ueber die Oberkanten, nicht die Hoehe der Leiste. Eine Hoehengrenze waere wieder eine Zahl von gestern -- sie stimmt, bis jemand die Polsterung anfasst. Ob zwei Dinge in derselben Zeile stehen, sieht man an ihrer Oberkante, und das gilt immer. Ausserdem gruen: pruef-css-klassen. Co-Authored-By: Claude Opus 5 --- server/pruef-handy.mjs | 26 +++++++- workspace/assets/css/start.css | 108 ++++++++++++++++++++++++++++++++- workspace/assets/js/kopf.js | 40 ++++++++++++ workspace/aufgaben.html | 18 +++--- workspace/automation.html | 20 +++--- workspace/bereich.html | 28 ++++----- workspace/calls.html | 22 +++---- workspace/chat.html | 20 +++--- workspace/content.html | 24 ++++---- workspace/dateien.html | 20 +++--- workspace/index.html | 4 +- workspace/kalender.html | 22 +++---- workspace/leistung.html | 20 +++--- workspace/personen.html | 20 +++--- workspace/profil.html | 22 +++---- workspace/report.html | 22 +++---- workspace/scouting.html | 20 +++--- workspace/start.html | 18 +++--- workspace/startcheck.html | 22 +++---- workspace/steckbrief.html | 20 +++--- workspace/uebersicht.html | 20 +++--- workspace/wissen.html | 20 +++--- 22 files changed, 363 insertions(+), 193 deletions(-) diff --git a/server/pruef-handy.mjs b/server/pruef-handy.mjs index 8378b390..f1641983 100644 --- a/server/pruef-handy.mjs +++ b/server/pruef-handy.mjs @@ -452,7 +452,7 @@ console.log("\n=== Kein Licht ohne Zeiger"); werden, und dann faellt es nur bei einer auf. --------------------------------------------------------------------- */ console.log("\n=== Ring und Uhr stehen mittig (alle Rollen)"); -for (const [breite, hoehe] of [[390, 844], [412, 915]]) { +for (const [breite, hoehe] of [[360, 800], [390, 844], [412, 915]]) { for (const [rolle, code] of [["admin", "CODE-DOGI-0001"], ["spicy", "CODE-SPIC-0001"], ["manager", "CODE-MANA-0001"], ["scout", "CODE-SCOU-0001"], ["creator", "CODE-ANNA-0001"]]) { const kontext = await browser.newContext({ viewport: { width: breite, height: hoehe } }); @@ -480,6 +480,30 @@ for (const [breite, hoehe] of [[390, 844], [412, 915]]) { && Math.abs(m.ring) <= 3 && Math.abs(m.uhr) <= 3 && m.ueber <= 1; ok(gut, `${breite}px ${rolle.padEnd(8)} Ring ${m.ring} px, Uhr ${m.uhr} px von der Mitte` + (m.ueber > 1 ? `, Ueberstand ${m.ueber}` : "")); + + /* ---- UND DIE KOPFLEISTE BLEIBT IN EINER REIHE (09.09.2026) ------ + Filipe, mit Bildschirmfoto: "es soll alles in einer reihe sein." + Auf seinem Bild stand "Abmelden" allein in einer zweiten Zeile. + + Gemessen wird die ZEILENZAHL, nicht die Hoehe: Eine Hoehengrenze + waere wieder eine Zahl von gestern -- sie stimmt, bis jemand die + Polsterung anfasst. Ob zwei Dinge in derselben Zeile stehen, + sieht man an ihrer Oberkante, und das gilt immer. */ + const kopf = await seite.evaluate(() => { + const k = document.querySelector(".kopfleiste"); + const teile = [...k.querySelectorAll(".kopfleiste__rechts > *"), k.querySelector(".marke")] + .filter((e) => e && e.getBoundingClientRect().width > 0); + const kanten = teile.map((e) => Math.round(e.getBoundingClientRect().top)); + return { zeilen: new Set(kanten).size, spanne: Math.max(...kanten) - Math.min(...kanten), + anzahl: teile.length, + ueber: document.documentElement.scrollWidth - document.documentElement.clientWidth }; + }); + /* 12 px Nachsicht: Ein Knopf von 36 px und ein Bild von 28 px sind + mittig ausgerichtet und haben deshalb verschiedene Oberkanten -- + das ist dieselbe Zeile. Eine zweite Zeile liegt 40 px tiefer. */ + ok(kopf.anzahl >= 3 && kopf.spanne <= 12 && kopf.ueber <= 1, + `${breite}px ${rolle.padEnd(8)} Kopfleiste: ${kopf.anzahl} Teile in einer Reihe ` + + `(Spanne ${kopf.spanne} px)`); await kontext.close(); } } diff --git a/workspace/assets/css/start.css b/workspace/assets/css/start.css index baee7dc7..0c140021 100644 --- a/workspace/assets/css/start.css +++ b/workspace/assets/css/start.css @@ -3743,7 +3743,18 @@ body[data-fremde-sicht="ja"]::after { Eine zweite Zeile auf einem 320-Pixel-Schirm kostet 44 Pixel Hoehe. Das ist der guenstigste Preis, der hier zu haben ist -- und er faellt nur auf Geraeten an, die wirklich so schmal sind. */ -@media (max-width: 380px) { +/* DIESE SCHWELLE IST AM 09.09.2026 VON 380 AUF 300 GEFALLEN. + + Sie zwang Marke und Bedienelemente ausdruecklich in ZWEI Zeilen -- + und war richtig, solange die Bedienelemente 243 bis 393 px brauchten. + Seit sie gleich grosse Zeichen sind, brauchen sie 136 bis 238; bei + 360 px stehen 334 zur Verfuegung. Die Regel machte ab da zwei Zeilen + aus etwas, das in eine passt. + + 300 px und nicht ganz weg: Darunter gibt es Geraete, auf denen es + wirklich nicht reicht, und dort ist die zweite Zeile besser als ein + Ueberstand. Gemessen bei 360, 390, 412 und 430 -- alle einzeilig. */ +@media (max-width: 300px) { .kopfleiste { flex-wrap: wrap; row-gap: 8px; } /* Die Marke nimmt die erste Zeile ganz ein, die Bedienelemente ruecken geschlossen in die zweite. Ohne das brechen sie mitten @@ -7284,3 +7295,98 @@ body.start .k-leiste .feldschild::after { font-size: .85rem; color: var(--text-still); border: 1px dashed rgba(150, 186, 220, .22); } + +/* ===================================================================== + DIE KOPFLEISTE BLEIBT AUF DEM HANDY IN EINER REIHE (09.09.2026) + + Filipe, mit Bildschirmfoto: "ich will dass es überall perfektionniert + wird. ich will dass du das richtig geil machst es soll alles in einer + reihe sein." + + GEMESSEN, BEVOR ETWAS GEÄNDERT WURDE (390 px, alle fünf Rollen): + + verfügbar für die rechte Gruppe 275 px + gebraucht als DogFather 393 px (Sicht 150 · Teilen 38 · + Chat 37 · Suche 47 · Bild 28 · + Abmelden 93) + gebraucht als Scout/Manager 243 px + gebraucht als Creator 205 px + + Der Umbruch war also die richtige Antwort auf ein echtes + Platzproblem -- `flex-wrap` misst und rechnet nicht, das bleibt auch + so. Geändert wird der PLATZBEDARF, nicht die Reaktion darauf. Eine + Schwelle, ab der nicht mehr umgebrochen wird, wäre wieder eine + Rechnung von gestern: Beim nächsten Knopf stünde alles übereinander. + + Was schrumpft, und was nicht: + * Die drei Zeichen-Knöpfe werden gleich groß (36 px) -- vorher + waren sie 38, 37 und 47, was nebeneinander unruhig aussah. + * "Abmelden" wird zum Zeichen (93 -> 36). Das Wort bleibt für + Vorleseprogramme im aria-label. + * Der Sicht-Umschalter zeigt nur noch das Auge -- ABER NUR, + solange die eigene Sicht läuft. Bei einer fremden Sicht behält + er den Namen, und dann darf die Leiste auch umbrechen: Dass man + fremde Zahlen ansieht, ist wichtiger als eine gerade Zeile. + + Rechnung danach bei 360 px, dem schmalsten Gerät: 36+36+36+28+36 + = 172 plus vier Abstände zu 6 = 196, verfügbar 249. + ===================================================================== */ +@media (max-width: 560px) { + .kopfleiste__rechts { gap: 6px; } + + /* Alle Zeichen-Knöpfe auf ein Maß. 36 px ist knapp über der Grenze, + ab der man danebentippt, und lässt vier davon nebeneinander. */ + .kopfleiste__rechts > .teilen, + .kopfleiste__rechts > .chat-knopf, + .kopfleiste__rechts > .suche-knopf, + .kopfleiste__rechts > .abmelden { + width: 36px; min-width: 36px; height: 36px; min-height: 36px; + padding: 0; gap: 0; + display: inline-grid; place-items: center; + } + .abmelden__text { display: none; } + .abmelden__zeichen { + width: 18px; height: 18px; + fill: none; stroke: currentColor; stroke-width: 1.8; + stroke-linecap: round; stroke-linejoin: round; + } + + /* Der Umschalter wird ein Zeichen-Knopf wie die anderen -- aber NUR, + solange die eigene Sicht laeuft. Bei einer fremden behaelt er den + Namen, und dann darf die Leiste auch umbrechen: Dass man fremde + Zahlen ansieht, ist wichtiger als eine gerade Zeile. + + Der Knopf liegt unsichtbar UEBER dem Auge, statt daneben. Das + bewahrt die Bedienbarkeit (die ganze Flaeche ist das Ziel) und den + Fokusring, kostet aber keine Breite. */ + .sicht:not([data-fremd="ja"]) { + position: relative; + width: 36px; min-width: 36px; height: 36px; + padding: 0; gap: 0; justify-content: center; + } + .sicht:not([data-fremd="ja"]) .sicht__auge { position: relative; z-index: 0; } + .sicht:not([data-fremd="ja"]) .wahl2 { position: absolute; inset: 0; z-index: 1; } + .sicht:not([data-fremd="ja"]) .wahl2__knopf { + width: 100%; height: 100%; padding: 0; + background: none; border-color: transparent; + } + .sicht:not([data-fremd="ja"]) .wahl2__knopf svg { display: none; } + /* DER KNOPF WIRD GEKLAMMERT, NICHT SEIN KASTEN. + + Erster Anlauf war `max-width: 30px` am umgebenden .wahl2. Gemessen + stand danach genau das da: berechnete Hoechstbreite 30 px -- + tatsaechliche Breite 104. Der Knopf DARIN behielt seine Groesse und + schob den Kasten wieder auf. Wer nur den Rahmen begrenzt, begrenzt + nichts; die Breite kommt vom Inhalt. */ + .sicht:not([data-fremd="ja"]) .wahl2, + .sicht:not([data-fremd="ja"]) .wahl2__knopf { max-width: none; min-width: 0; } + .sicht:not([data-fremd="ja"]) .wahl2__text { display: none; } +} + +/* Am Rechner bleibt das Wort -- dort ist Platz, und ein Wort ist + eindeutiger als ein Bild. Das Zeichen steht davor. */ +.abmelden__zeichen { + width: 16px; height: 16px; flex: none; + fill: none; stroke: currentColor; stroke-width: 1.8; + stroke-linecap: round; stroke-linejoin: round; +} diff --git a/workspace/assets/js/kopf.js b/workspace/assets/js/kopf.js index 6167aa69..65977dad 100644 --- a/workspace/assets/js/kopf.js +++ b/workspace/assets/js/kopf.js @@ -594,6 +594,46 @@ } const abmelden = document.getElementById('abmelden'); + /* EIN ZEICHEN NEBEN DAS WORT (09.09.2026). + ------------------------------------------------------------------ + Filipe, mit einem Bildschirmfoto der Kopfleiste vom Handy: "ich + will dass es ueberall perfektionniert wird ... es soll alles in + einer reihe sein." + + Auf seinem Bild stand "Abmelden" allein in einer zweiten Zeile. + Nachgemessen bei 390 px: Die rechte Gruppe hat dort 275 px Platz + und braucht 393 -- der Umbruch war die richtige Reaktion auf ein + Platzproblem, nicht der Fehler. Der Fehler war der Platzbedarf. + + Das Wort allein ist 93 px breit. Als Zeichen sind es 36. Es + verschwindet aber nur auf schmalen Bildschirmen (siehe start.css); + am Rechner steht weiterhin das Wort da, weil dort Platz ist und + ein Wort immer eindeutiger ist als ein Bild. + + Der Aufbau steht HIER und nicht in neunzehn HTML-Dateien: kopf.js + laeuft auf jeder Seite, und eine Aenderung an neunzehn Stellen ist + achtzehn Gelegenheiten, eine zu vergessen. */ + if (abmelden && !abmelden.dataset.zeichenDa) { + abmelden.dataset.zeichenDa = 'ja'; + const wort = (abmelden.textContent || 'Abmelden').trim(); + abmelden.textContent = ''; + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + svg.setAttribute('class', 'abmelden__zeichen'); + svg.setAttribute('viewBox', '0 0 24 24'); + svg.setAttribute('aria-hidden', 'true'); + const pfad = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + /* Tuer mit Pfeil hinaus -- das gebraeuchlichste Zeichen dafuer. */ + pfad.setAttribute('d', 'M15 4.5H6.5a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2H15M12.5 12h7m0 0-3-3m3 3-3 3'); + svg.append(pfad); + const text = document.createElement('span'); + text.className = 'abmelden__text'; + text.textContent = wort; + abmelden.append(svg, text); + /* Die Beschriftung bleibt auch dann, wenn das Wort nicht zu sehen + ist -- sonst waere der Knopf fuer ein Vorleseprogramm leer. */ + abmelden.setAttribute('aria-label', wort); + if (!abmelden.title) abmelden.title = wort; + } if (abmelden) { abmelden.addEventListener('click', async () => { abmelden.disabled = true; diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index 9f78cdd1..c640164e 100644 --- a/workspace/aufgaben.html +++ b/workspace/aufgaben.html @@ -14,10 +14,10 @@ - - - - + + + + @@ -231,10 +231,10 @@ - - - - - + + + + + diff --git a/workspace/automation.html b/workspace/automation.html index d63eee98..fdd36932 100644 --- a/workspace/automation.html +++ b/workspace/automation.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -140,10 +140,10 @@ - - - - - + + + + + diff --git a/workspace/bereich.html b/workspace/bereich.html index 3276a4c6..b8f5efe0 100644 --- a/workspace/bereich.html +++ b/workspace/bereich.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -149,14 +149,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/workspace/calls.html b/workspace/calls.html index 7fe31a11..9748907c 100644 --- a/workspace/calls.html +++ b/workspace/calls.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -82,11 +82,11 @@ - - - - - - + + + + + + diff --git a/workspace/chat.html b/workspace/chat.html index b1a28542..2724db6c 100644 --- a/workspace/chat.html +++ b/workspace/chat.html @@ -14,17 +14,17 @@ - - + + - - - + + + @@ -247,10 +247,10 @@ - - - - - + + + + + diff --git a/workspace/content.html b/workspace/content.html index 32583b6c..6f05889b 100644 --- a/workspace/content.html +++ b/workspace/content.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -172,12 +172,12 @@ - - - - - - - + + + + + + + diff --git a/workspace/dateien.html b/workspace/dateien.html index 96a87aed..5fe0dc67 100644 --- a/workspace/dateien.html +++ b/workspace/dateien.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -101,10 +101,10 @@ - - - - - + + + + + diff --git a/workspace/index.html b/workspace/index.html index f928508d..bf28e21a 100644 --- a/workspace/index.html +++ b/workspace/index.html @@ -32,7 +32,7 @@ - + @@ -401,6 +401,6 @@ - + diff --git a/workspace/kalender.html b/workspace/kalender.html index 39f02fe7..19e0ba47 100644 --- a/workspace/kalender.html +++ b/workspace/kalender.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -340,11 +340,11 @@ - - - - - - + + + + + + diff --git a/workspace/leistung.html b/workspace/leistung.html index 27dfc588..27ff5566 100644 --- a/workspace/leistung.html +++ b/workspace/leistung.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -217,10 +217,10 @@ - - - - - + + + + + diff --git a/workspace/personen.html b/workspace/personen.html index 7af4d41f..c45f75b0 100644 --- a/workspace/personen.html +++ b/workspace/personen.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -335,10 +335,10 @@ - - - - - + + + + + diff --git a/workspace/profil.html b/workspace/profil.html index 44538151..b9239102 100644 --- a/workspace/profil.html +++ b/workspace/profil.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -207,11 +207,11 @@ - - - - - - + + + + + + diff --git a/workspace/report.html b/workspace/report.html index d051ee80..e9c556b9 100644 --- a/workspace/report.html +++ b/workspace/report.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -99,11 +99,11 @@ - - - - - - + + + + + + diff --git a/workspace/scouting.html b/workspace/scouting.html index 57af0c99..da5979cc 100644 --- a/workspace/scouting.html +++ b/workspace/scouting.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -132,10 +132,10 @@ - - - - - + + + + + diff --git a/workspace/start.html b/workspace/start.html index 7edfc37d..5af7a826 100644 --- a/workspace/start.html +++ b/workspace/start.html @@ -14,12 +14,12 @@ - - + + - - + + @@ -667,10 +667,10 @@

- - - - - + + + + + diff --git a/workspace/startcheck.html b/workspace/startcheck.html index 1c8abc22..20965f38 100644 --- a/workspace/startcheck.html +++ b/workspace/startcheck.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -78,11 +78,11 @@ - - - - - - + + + + + + diff --git a/workspace/steckbrief.html b/workspace/steckbrief.html index 967c99fb..7372ad1c 100644 --- a/workspace/steckbrief.html +++ b/workspace/steckbrief.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -119,10 +119,10 @@ - - - - - + + + + + diff --git a/workspace/uebersicht.html b/workspace/uebersicht.html index fa7c5ff4..937fb873 100644 --- a/workspace/uebersicht.html +++ b/workspace/uebersicht.html @@ -14,13 +14,13 @@ - - + + - - - + + + @@ -142,11 +142,11 @@ - + - - - - + + + + diff --git a/workspace/wissen.html b/workspace/wissen.html index c7168c6d..2f823a48 100644 --- a/workspace/wissen.html +++ b/workspace/wissen.html @@ -14,11 +14,11 @@ - - - - - + + + + + @@ -183,10 +183,10 @@ - - - - - + + + + +