From 0924a8d2ae54f985cecac537d633b8508c3db1fc Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Oct 2026 09:40:06 +0000 Subject: [PATCH] =?UTF-8?q?Hustler-Pixelwelt=20T13:=20Korrekturen=20Pult?= =?UTF-8?q?=20und=20Keller=20(Sperre=20laufender=20Aktionen,=20Fokus,=20Ko?= =?UTF-8?q?ntrast,=20Handy-Tippfl=C3=A4chen,=20Pause)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pult: laufende Anfragen je Eintrags-Id in PultList (laufRef, Brief meldet Beginn/Ende): Brief schließen und denselben Eintrag wieder öffnen sperrt alle Aktionsknöpfe, kein zweites reply/paste/start-build (P1); spätes Ergebnis nennt den Titel (P1b); Original und Entwurf pre-wrap (P3); Überschrift nimmt beim Einhängen den Fokus (M2); „Pult zuklappen“ mit aria-expanded (K4); paused -> hk-steht an der Szene (R3); Brief z-index 9 (R4); Textlinks am Handy 40 px (K7). Keller: Überschrift-Fokus (M2), Reiter-Fokusring innen (M3), Seitenzeile/Punkte/Reiterzahl in Pixelify Sans 13 px (K5), Suchfeld und Akte-Link 40 px am Handy (K7), Ortszeile mit title (W2), paused -> hk-steht (R3), Akte z-index 9 (R4); Arne ohne Eintrag neutral (R5). Tests: Sperre laufender Aktionen, Titel im späten Ergebnis, Fokus, aria-expanded, paused, pre-wrap, z-index, Tippflächen, Reiter-Fokus, Schrift, Kontrast (WCAG) von .hk-zeile-alt/.hk-kl-tag auf Papier und Hover, Arne neutral (alte „Arne schläft ohne Eintrag“-Prüfung ersetzt). Co-Authored-By: Claude Sonnet 5.5 --- src/components/workers/BotLeadList.jsx | 16 +- src/components/workers/PultList.jsx | 40 +++- src/components/workers/keller/KellerSzene.jsx | 7 +- .../workers/keller/RegisterBuch.jsx | 3 +- src/components/workers/pult/Brief.jsx | 90 +++++--- src/components/workers/pult/PultSzene.jsx | 6 +- src/lib/hustlerKeller.js | 11 +- src/styles/hustler/hustler-keller-ui.css | 23 +- src/styles/hustler/hustler-pult-ui.css | 11 +- tests/unit/hustlerKeller.test.mjs | 217 +++++++++++++++++- tests/unit/hustlerKellerLib.test.mjs | 18 +- tests/unit/hustlerPult.test.mjs | 123 +++++++++- tests/unit/workersPultUi.test.mjs | 102 ++++++++ 13 files changed, 597 insertions(+), 70 deletions(-) diff --git a/src/components/workers/BotLeadList.jsx b/src/components/workers/BotLeadList.jsx index 2035ac3..57e2f8e 100644 --- a/src/components/workers/BotLeadList.jsx +++ b/src/components/workers/BotLeadList.jsx @@ -14,14 +14,15 @@ const browserDocument = () => (typeof document === 'undefined' ? null : document // Bildschirm „Keller“ (Hustler-Pixelwelt T10, Spec E12/E13; Dateiname bleibt BotLeadList): die Archiv-Szene mit Arne (keller/KellerSzene), davor Arnes Register-Buch // (keller/RegisterBuch) mit den Betrieben, die nicht angeschrieben werden, samt Grund, und die Akte zu einem Eintrag (keller/Akte). Reine Liste, nichts wird gesendet -// oder angerufen. Props: api, bot, onClearBot, kpis (botLeads für die Zahl am Schild), workers (Hustler-Tabelle der Seite: Arnes Status), onBack (◂ Hochhaus). +// oder angerufen. Props: api, bot, onClearBot, kpis (botLeads für die Zahl am Schild), workers (Hustler-Tabelle der Seite: Arnes Status), paused (Hustler angehalten: +// die Szene steht still, Klasse hk-steht), onBack (◂ Hochhaus). Beim Einhängen nimmt die Überschrift „Bot-Leads“ (tabIndex -1) den Fokus, ohne dass die Seite springt (T13 M2). // Die Liste holt sich ihre Daten bei jeder Änderung von Raum, Suche, Seite oder bot selbst; es gibt kein Polling. Nur die jüngste Anfrage zählt: eine späte // Antwort (auch ein später Fehler) einer älteren Anfrage oder nach dem Abbau wird verworfen. Scheitert eine Anfrage, steht der Satz des Dienstes mit „Erneut versuchen“, // das genau diese Anfrage (Raum, Suche, Seite oder Eintrag) noch einmal stellt; Raum und Suche gehen weiterhin. // bot (aus ?bot= der Adresse, Link aus dem Ereignisstrom): zeigt genau diesen Eintrag, hervorgehoben, mit „Alle anzeigen“ (onClearBot nimmt bot aus der Adresse). // Alle Texte der Zeilen sind Textknoten; Links entstehen nur aus row.sourceHref (botleadRow prüft die Adresse mit safeHref: nur http und https, keine Zugangsdaten), und zwar // nur in der Akte. Kein CSS-Import (WorkersPage hängt die Stile ein), keine Bilder, kein HTML-Einschub. -export default function BotLeadList({ api, bot, onClearBot, kpis, workers, onBack }) { +export default function BotLeadList({ api, bot, onClearBot, kpis, workers, paused = false, onBack }) { const botId = typeof bot === 'string' ? bot : '' const single = botId !== '' const [view, setView] = useState(START_VIEW) @@ -32,6 +33,7 @@ export default function BotLeadList({ api, bot, onClearBot, kpis, workers, onBac const [akte, setAkte] = useState(null) // Nr. des Eintrags in der gezeigten Seite, dessen Akte offen ist const timerRef = useRef(null) const seqRef = useRef(0) + const h1Ref = useRef(null) // Überschrift „Bot-Leads“: nimmt beim Einhängen den Fokus (Bildschirmwechsel) // Tastaturfokus: Wer „Alle anzeigen“ oder ◂/▸ drückt, verliert den Knopf mit dem Fokus (Einzelansicht und Seitenzeile werden ausgetauscht oder // hängen beim Laden aus); ohne Zutun fiele der Fokus auf , an den Seitenanfang. Gemerkt wird nur, was der Nutzer als Letztes bedient hat. const reiterRef = useRef(null) // aktiver Raum-Reiter: Ziel nach „Alle anzeigen“ @@ -72,6 +74,12 @@ export default function BotLeadList({ api, bot, onClearBot, kpis, workers, onBac useEffect(() => () => window.clearTimeout(timerRef.current), []) + // Bildschirmwechsel (M2): Tastatur und Screenreader beginnen in diesem Bildschirm, nicht auf oder dem ausgehängten „Hochhaus“-Knopf des alten + useEffect(() => { + const h1 = h1Ref.current + if (h1 && typeof h1.focus === 'function') h1.focus({ preventScroll: true }) + }, []) + const onRetry = () => setAttempt((n) => n + 1) const onClear = () => { clearedRef.current = true @@ -126,7 +134,7 @@ export default function BotLeadList({ api, bot, onClearBot, kpis, workers, onBac return (
- +