Die Regieleiste steht jetzt über dem Saal

Filipe: „ich hätte das gerne oben also nicht in dieser kachel sondern
über der kachel wo die videos laufen werden und das soll extrem
perfektioniert werden."

WARUM DAS MEHR IST ALS EIN UMHÄNGEN
Die Register standen INNERHALB des einklappbaren Teils. Wer die Regie
zuklappte, um mehr Bild zu haben, hatte sie nicht mehr — und genau
dann braucht man sie. Oben ändert sich ihre Aufgabe: aus dem
Inhaltsverzeichnis einer Schublade wird eine Steuerleiste über der
Sendung. Daraus folgen vier Dinge, die vorher nicht nötig waren:

1. EIN REGISTER MACHT DIE ZUGEKLAPPTE REGIE AUF. Vorher wechselte nur
   der Reiter, die Tafel lag im zugeklappten Teil — sichtbar passierte
   nichts. Nur auf, nie zu: Zugemacht wird mit dem Griff. Ein Knopf,
   der beim zweiten Druck das Gegenteil tut, versteckt irgendwann
   etwas, das jemand gerade liest.

2. SIE BRICHT NICHT UM, SIE ROLLT. Sieben Register in zwei Zeilen
   kosten am oberen Rand rund 90 px — und zwar dem Video. Gemessen:
   eine Zeile auf 1440 px wie auf 390 px, dort mit Einrasten und
   weichen Rändern als Auskunft, dass es weitergeht.

3. SIE LÖST EIN, WAS `role="tablist"` VERSPRICHT. Pfeiltasten wandern,
   Pos1/Ende springen, genau ein Register liegt in der Tabulatorfolge.
   Steht die Rolle im Markup und tut das Programm es nicht, sagt ein
   Vorleser etwas an, was nicht stimmt — schlimmer als keine Rolle.
   Gemessen wird das gedrückt, nicht gelesen: fünf Tastendrücke, und
   Fokus, Auswahl und offene Tafel müssen jedes Mal dasselbe sagen.

4. EINE GLEITENDE MARKE zeigt, wo man steht — Glas mit Lichtkante,
   darunter ein roter Streifen zur offenen Tafel. Ist die Regie
   zugeklappt, wird er leise: Der Streifen führt dann nirgendwohin.
   Dazu ein Schild „Regie" links (am Handy weg), damit die sieben
   Wörter am oberen Rand nicht wie eine zweite Navigation aussehen.

DER FEHLER, DER MICH ZWEI ANLÄUFE GEKOSTET HAT
Die Leiste war im Browser 1 px hoch, ihre Register standen 55 px hoch
daneben und ragten über das Video. Ursache: 900 Zeilen weiter unten
stand eine ZWEITE `grid-template-rows` für `.saal` (aus der Zeit, als
der Saal zwei Zeilen hatte). Sie stand später und gewann — die Leiste
landete in der `1fr`-Zeile und bekam null Pixel.

Und fast hätte ich das Falsche repariert: Beim Durchprobieren habe ich
`style.gridTemplateRows` gesetzt — ein Stilattribut schlägt jede Regel
im Stilblatt. Damit „funktionierten" `auto` und `min-content` gleich
gut, weil beide die zweite Regel aushebelten, und es sah nach einem
Unterschied zwischen den beiden aus. Erst nach dem Entfernen der
Doppelung hat die Gegenprobe gezeigt: `auto` tut es genauso. Eine
Probe, die mehr ändert als das, wonach man sucht, beantwortet eine
andere Frage. Es gibt jetzt eine Prüfung, dass genau EINE Regel die
Zeilen des Saals bestimmt.

ZWEI WEITERE FUNDE AUS DER MESSUNG
Am Handy blieben bei offener Regie 131 px für das Bild — ein Streifen.
Mein erster Versuch (62dvh → 52dvh) machte es auf 75 px SCHLECHTER:
Die Ursache lag woanders, die Leiste des Pults bricht dort in vier
Zeilen um und ist rund 200 px hoch, wovon ein Anteil der Fensterhöhe
nichts wissen kann. Mit `min(52dvh, 19rem)` sind es 210 px.

Und die Spendenkarte wurde als „steht aus dem Bild heraus" gemeldet:
413 statt 430 px, links −1. 413 ist genau das 0,96-fache — die Messung
hatte die Karte im Ausblenden erwischt. Sie wartet jetzt auf
`data-da="ja"` und misst nur, was ganz da ist.

GEPRUEFT
pruef-reaktion 280 (vorher 260), 0 Fehler — Abschnitt 18 neu.
mess-reaktion: Rückgabewert 0, kein ACHTUNG; misst die Leiste jetzt
auf 1440 und auf 390 px, samt Tastatur und Aufklappen.
Dazu grün: handy, buehne, struktur, css-klassen, tippziele.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-28 14:13:07 +02:00
co-authored by Claude Opus 5
parent d2f02ba84e
commit 2b02d88767
49 changed files with 1917 additions and 1255 deletions
+126 -5
View File
@@ -216,6 +216,11 @@
chatStufeZeichnen();
/* ---- Das Pult ---- */
/* DIE LEISTE ZUERST. Sie steht über dem Saal und muss sichtbar
sein, BEVOR `pultAufbauen()` die Marke misst -- ein verborgenes
Element hat kein Rechteck, und die Marke säße auf null. */
const leiste = $('regieleiste');
if (leiste) leiste.hidden = !lage.ich.host;
const pult = $('pult');
pult.hidden = !lage.ich.host;
if (lage.ich.host && !pults) { pultAufbauen(); pults = true; }
@@ -1511,10 +1516,24 @@
const pult = $('pult');
pult.dataset.auf = 'ja';
/* ---- Die Register ---- */
for (const knopf of $('reiter').children) {
/* ---- Die Register ----
Sie stehen seit dem 28.09. oben über dem Saal und nicht mehr
im einklappbaren Teil. Verdrahtet werden sie trotzdem hier:
Sie gehören zur Regie, und wer kein Pult hat, hat auch keine
Register. */
for (const knopf of reiterKnoepfe()) {
knopf.addEventListener('click', () => reiterWechseln(knopf.dataset.tafel));
}
reiterTastatur();
/* DIE MARKE BRAUCHT EINE GEMESSENE BREITE. Beim ersten Zeichnen
ist die Hausschrift oft noch nicht da; ein Knopf ist dann
schmaler als gleich darauf. Also einmal jetzt und einmal,
sobald die Schriften stehen. */
reiterMarke();
if (document.fonts && document.fonts.ready) {
document.fonts.ready.then(() => reiterMarke()).catch(() => { });
}
window.addEventListener('resize', reiterMarke);
/* ---- Die Regler ---- */
const reihe = $('regler');
@@ -1675,13 +1694,109 @@
setInterval(lastMessen, 2500); // was die eigene Leitung traegt
}
function reiterWechseln(name) {
for (const knopf of $('reiter').children) {
knopf.setAttribute('aria-selected', String(knopf.dataset.tafel === name));
/* =================================================================
DIE REGIELEISTE
Filipe, 28.09.2026: „ich hätte das gerne oben also nicht in
dieser kachel sondern über der kachel wo die videos laufen."
Sie steht damit über dem Saal und ist der einzige Teil der
Regie, der auch bei zugeklapptem Pult sichtbar bleibt.
================================================================= */
/** Die Register -- ohne die Marke, die mit im Behälter liegt. */
function reiterKnoepfe() {
return [...$('reiter').querySelectorAll('.reiter__knopf')];
}
function reiterWechseln(name, vomMenschen = true) {
const knoepfe = reiterKnoepfe();
for (const knopf of knoepfe) {
const gewaehlt = knopf.dataset.tafel === name;
knopf.setAttribute('aria-selected', String(gewaehlt));
/* WANDERNDER TABULATOR. In einer Registerleiste liegt genau
EIN Register in der Tabulatorfolge; zwischen ihnen wandert
man mit den Pfeiltasten. Sieben Tabulatorschritte durch
Register, bevor man an den Inhalt kommt, sind das Gegenteil
von bedienbar. */
knopf.tabIndex = gewaehlt ? 0 : -1;
}
for (const tafel of document.querySelectorAll('.pult-tafel')) {
tafel.hidden = tafel.dataset.tafel !== name;
}
/* EIN REGISTER ANZUTIPPEN MACHT DIE REGIE AUF.
Seit die Leiste oben steht, kann das Pult zugeklappt sein,
während man ein Register wählt -- der Reiter wechselte dann,
und auf dem Bildschirm passierte nichts. Genau die Sorte
Knopf, die man für kaputt hält.
NUR AUF, NIE ZU: Zugemacht wird mit dem Griff am Pult. Ein
Knopf, der beim zweiten Druck das Gegenteil tut, versteckt
irgendwann etwas, das jemand gerade lesen wollte. */
if (vomMenschen) {
const pult = $('pult');
if (pult && pult.dataset.auf !== 'ja') {
pult.dataset.auf = 'ja';
$('pult-griff')?.setAttribute('aria-expanded', 'true');
}
}
reiterMarke();
/* Das gewählte Register in den sichtbaren Bereich rollen -- auf
dem Handy liegen von sieben Registern nur drei im Bild. */
const aktiv = knoepfe.find((k) => k.dataset.tafel === name);
aktiv?.scrollIntoView({ block: 'nearest', inline: 'center', behavior: 'smooth' });
}
/** Die Marke unter das gewählte Register schieben.
*
* GEMESSEN UND NICHT GERECHNET: `offsetLeft` und `offsetWidth`
* gegen den Behälter, der `position: relative` trägt. Damit ist
* es gleichgültig, wie breit ein Wort ist, wie weit die Leiste
* gerollt wurde oder welche Schrift gerade geladen ist.
*
* Und wenn hier etwas schiefgeht, bleibt die gefüllte Pille als
* zweite, rechnungsfreie Anzeige stehen. */
function reiterMarke() {
const marke = $('reiter-marke');
if (!marke) return;
const aktiv = reiterKnoepfe().find((k) => k.getAttribute('aria-selected') === 'true');
if (!aktiv || !aktiv.offsetWidth) { marke.hidden = true; return; }
marke.hidden = false;
/* Breite UND Höhe aus dem gemessenen Knopf. Die Höhe könnte man
auch über `top`/`bottom` erschlagen -- dann bezöge sie sich
aber auf die Polsterbox der Leiste und wäre elf Pixel zu
hoch. Zwei gemessene Zahlen sind ehrlicher als eine
Annahme über das Polster. */
marke.style.width = `${aktiv.offsetWidth}px`;
marke.style.height = `${aktiv.offsetHeight}px`;
marke.style.transform = `translate(${aktiv.offsetLeft}px, ${aktiv.offsetTop}px)`;
}
/** Was eine Registerleiste versprochen hat, muss sie auch tun.
*
* `role="tablist"` sagt Hilfsmitteln zu: Pfeiltasten wandern,
* Pos1 und Ende springen. Steht das Versprechen im Markup und
* löst es das Programm nicht ein, sagt der Vorleser etwas an, was
* nicht stimmt -- schlimmer als gar keine Rolle. */
function reiterTastatur() {
const leiste = $('reiter');
if (!leiste) return;
leiste.addEventListener('keydown', (e) => {
const knoepfe = reiterKnoepfe();
const jetzt = knoepfe.indexOf(document.activeElement);
if (jetzt < 0) return;
let ziel = -1;
if (e.key === 'ArrowRight') ziel = (jetzt + 1) % knoepfe.length;
else if (e.key === 'ArrowLeft') ziel = (jetzt - 1 + knoepfe.length) % knoepfe.length;
else if (e.key === 'Home') ziel = 0;
else if (e.key === 'End') ziel = knoepfe.length - 1;
if (ziel < 0) return;
e.preventDefault();
reiterWechseln(knoepfe[ziel].dataset.tafel);
knoepfe[ziel].focus();
});
}
function stummSchalten(schluessel) {
@@ -2143,6 +2258,10 @@
if (zahl) {
zahl.textContent = String(offen.length);
zahl.dataset.leer = offen.length ? 'nein' : 'ja';
/* DIE ZAHL AENDERT DIE BREITE DES REGISTERS. Aus „0" wird
„12" -- der Knopf wird breiter, und die Marke darunter
stünde falsch, wenn sie nicht nachgezogen wird. */
reiterMarke();
}
$('sp-offen-zahl').textContent = offen.length === 1 ? '1 Meldung' : `${offen.length} Meldungen`;
@@ -2235,6 +2354,8 @@
const zahl = $('reiter-liste-zahl');
zahl.textContent = String(liste.length);
zahl.dataset.leer = liste.length ? 'nein' : 'ja';
/* Siehe oben: eine breitere Zahl verschiebt die Marke. */
reiterMarke();
const kasten = $('warteliste');
kasten.textContent = '';