Pfeile am Bildrand, und „Mehr" bleibt, wo es ist

**Pfeile.** Der Aufmacher hatte nur die Punkte; die Pfeile, die du gedrückt
hast, gehörten zur Reihe darunter. Jetzt stehen links und rechts über dem
Bild zwei grosse Knöpfe. Am Telefon gibt es sie nicht — dort nähme ein
Knopf über dem Bild ein Drittel der Breite —, dafür lässt sich wischen.
Nur waagerecht und erst ab 48 Pixeln, sonst käme man am Aufmacher nicht
mehr vorbeigescrollt.

**Und die Knöpfe springen nicht mehr.** „Abspielen" ist 128 Pixel breit,
„Fortsetzen ab 1:23:45" 207, der Terminhinweis 257 — alles in derselben
Flexreihe, also wanderte „Mehr" bei jedem Umblättern mit, und das
Karussell blättert von allein. Der vordere Platz hat jetzt eine feste
Breite. Gemessen: „Mehr" steht auf allen sieben Folien an derselben Stelle.

Dabei fielen zwei Dinge auf, die nicht am Umbau lagen:

**Der Textblock war so breit wie sein längster Satz.** Als blosses Flexkind
richtete er sich nach dem Inhalt — bei einer kurzen Inhaltsangabe schmaler
als bei einer langen. Auf dem Telefon rückte „Mehr" dadurch um fünfzig
Pixel, und mit dem festen Platz lief die Zeile sogar über den Bildschirm
hinaus; `overflow: hidden` schnitt die rechte Hälfte des Textes ab.

**Ein fehlender Schriftzug liess den Aufmacher namenlos.** Steht ein Logo
in den Metadaten, wurde der Titel daneben versteckt — auch wenn das Bild
gar nicht lud. Zu sehen war ein Platzhalter und sonst nichts. Jetzt tritt
der Name an seine Stelle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-06 16:32:55 +02:00
co-authored by Claude Opus 5
parent 10a5070e58
commit 94c6604e8b
2 changed files with 144 additions and 13 deletions
+94 -12
View File
@@ -83,6 +83,12 @@ export function hero(
schriftzug.className = 'hero-schriftzug'; schriftzug.className = 'hero-schriftzug';
const titel = document.createElement('h1'); const titel = document.createElement('h1');
titel.className = 'hero-titel'; titel.className = 'hero-titel';
// Kommt der Schriftzug nicht an, tritt der Name an seine Stelle.
schriftzug.onerror = () => {
schriftzug.classList.add('hidden');
titel.classList.remove('hidden');
};
const meta = document.createElement('div'); const meta = document.createElement('div');
meta.className = 'hero-meta'; meta.className = 'hero-meta';
const text = document.createElement('p'); const text = document.createElement('p');
@@ -95,19 +101,27 @@ export function hero(
// **Statt des Knopfes, wenn es den Titel noch nicht gibt.** Ein Knopf, der // **Statt des Knopfes, wenn es den Titel noch nicht gibt.** Ein Knopf, der
// „Abspielen" sagt und eine Absage bringt, ist schlimmer als keiner. // „Abspielen" sagt und eine Absage bringt, ist schlimmer als keiner.
//
// Hier einzeilig, anders als auf der Detailseite: zwei Zeilen wären höher
// als ein Knopf, und dann rückte beim Umblättern die ganze Reihe auf und ab.
const bald = document.createElement('div'); const bald = document.createElement('div');
bald.className = 'verfuegbar-ab'; bald.className = 'verfuegbar-ab hero-bald';
const baldText = document.createElement('div'); const baldText = document.createElement('span');
baldText.className = 'verfuegbar-text';
const baldOben = document.createElement('strong');
baldOben.textContent = 'Bald ist es soweit';
const baldUnten = document.createElement('span');
baldText.append(baldOben, baldUnten);
bald.append(iconElement(icons.uhr), baldText); bald.append(iconElement(icons.uhr), baldText);
// **Ein Platz fester Breite für das, was vorne steht.**
//
// „Abspielen", „Fortsetzen ab 1:23:45" und der Termin sind verschieden
// breit. Standen sie im selben Fluss, wanderte „Mehr" bei jedem Umblättern
// mit — und das Karussell blättert von allein. Was sich ändert, soll den
// Rest in Ruhe lassen.
const haupt = document.createElement('div');
haupt.className = 'hero-haupt';
haupt.append(bald, spielen);
const knoepfe = document.createElement('div'); const knoepfe = document.createElement('div');
knoepfe.className = 'hero-knoepfe'; knoepfe.className = 'hero-knoepfe';
knoepfe.append(bald, spielen, mehr); knoepfe.append(haupt, mehr);
inhalt.append(schriftzug, titel, meta, text, knoepfe); inhalt.append(schriftzug, titel, meta, text, knoepfe);
@@ -125,8 +139,29 @@ export function hero(
return b; return b;
}); });
// **Pfeile am Bildrand.**
//
// Die Punkte allein sind drei Pixel hoch und sagen nur, wo man steht —
// zum Blättern muss man sie treffen wollen. Die Pfeile sind gross, liegen
// immer an derselben Stelle und heißen, was sie tun.
//
// Am Telefon gibt es sie nicht: dort nähme ein Knopf über dem Bild ein
// Drittel der Breite weg, und die Geste heisst dort Wischen.
const pfeile = (['links', 'rechts'] as const).map(richtung => {
const p = document.createElement('button');
p.type = 'button';
p.className = `hero-pfeil hero-pfeil-${richtung}`;
p.innerHTML = icons[richtung];
p.setAttribute('aria-label', richtung === 'links' ? 'Vorheriger Titel' : 'Nächster Titel');
p.onclick = () => { zeige(jetzt + (richtung === 'links' ? -1 : 1)); anhalten(); };
return p;
});
wurzel.append(buehne, inhalt); wurzel.append(buehne, inhalt);
if (mitBild.length > 1) wurzel.appendChild(punkte); if (mitBild.length > 1) {
wurzel.append(...pfeile, punkte);
wischenEinrichten();
}
let jetzt = 0; let jetzt = 0;
let takt: number | undefined; let takt: number | undefined;
@@ -141,6 +176,13 @@ export function hero(
}); });
punktknoepfe.forEach((b, n) => b.classList.toggle('an', n === jetzt)); punktknoepfe.forEach((b, n) => b.classList.toggle('an', n === jetzt));
// **Der Name steht immer bereit**, auch wenn der Schriftzug gewinnt.
//
// Gemessen: fehlt das Logo im Bildspeicher — es kommt von TMDB und wird
// beim Auffrischen geholt —, lud das `<img>` nicht, und weil der Titel
// daneben versteckt war, stand im Aufmacher ein kaputtes Bild und sonst
// nichts. Ein Name ist besser als ein Platzhalter.
titel.textContent = e.titel;
const logo = bildAdresse(e.schriftzug); const logo = bildAdresse(e.schriftzug);
if (logo) { if (logo) {
schriftzug.src = logo; schriftzug.src = logo;
@@ -148,8 +190,8 @@ export function hero(
schriftzug.classList.remove('hidden'); schriftzug.classList.remove('hidden');
titel.classList.add('hidden'); titel.classList.add('hidden');
} else { } else {
schriftzug.removeAttribute('src');
schriftzug.classList.add('hidden'); schriftzug.classList.add('hidden');
titel.textContent = e.titel;
titel.classList.remove('hidden'); titel.classList.remove('hidden');
} }
@@ -176,8 +218,10 @@ export function hero(
spielen.classList.toggle('hidden', nochNicht); spielen.classList.toggle('hidden', nochNicht);
if (nochNicht) { if (nochNicht) {
baldUnten.textContent = `Ab ${geplantAb!.toLocaleString('de-CH', // Kurz geschrieben, weil es in eine Knopfzeile passen muss. Der ganze
{ weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', // Satz steht auf der Detailseite.
baldText.textContent = `Ab ${geplantAb!.toLocaleString('de-CH',
{ weekday: 'short', day: 'numeric', month: 'short', year: 'numeric',
hour: '2-digit', minute: '2-digit' })} Uhr`; hour: '2-digit', minute: '2-digit' })} Uhr`;
return; return;
} }
@@ -206,6 +250,44 @@ export function hero(
takt = window.setInterval(weiter, WECHSEL_MS); takt = window.setInterval(weiter, WECHSEL_MS);
} }
/** Wischen — die Geste, wo es keine Pfeile gibt.
*
* **Nur waagerecht, und erst ab einer Strecke.** Senkrecht blättert die
* Seite; fasste der Aufmacher jede Bewegung ab, käme man an ihm nicht mehr
* vorbei. Deshalb entscheidet die erste erkennbare Richtung, wem die Geste
* gehört — und unter der Schwelle gehört sie niemandem.
*/
function wischenEinrichten(): void {
const SCHWELLE = 48;
let start: { x: number; y: number } | null = null;
let waagerecht = false;
wurzel.addEventListener('pointerdown', e => {
if (e.pointerType === 'mouse') return;
start = { x: e.clientX, y: e.clientY };
waagerecht = false;
});
wurzel.addEventListener('pointermove', e => {
if (start === null) return;
const dx = e.clientX - start.x;
const dy = e.clientY - start.y;
if (!waagerecht && Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 12) waagerecht = true;
});
const beenden = (e: PointerEvent): void => {
if (start === null) return;
const dx = e.clientX - start.x;
start = null;
if (!waagerecht || Math.abs(dx) < SCHWELLE) return;
zeige(jetzt + (dx < 0 ? 1 : -1));
anhalten();
};
wurzel.addEventListener('pointerup', beenden);
wurzel.addEventListener('pointercancel', () => { start = null; });
}
wurzel.addEventListener('mouseenter', anhalten); wurzel.addEventListener('mouseenter', anhalten);
wurzel.addEventListener('mouseleave', starten); wurzel.addEventListener('mouseleave', starten);
wurzel.addEventListener('focusin', anhalten); wurzel.addEventListener('focusin', anhalten);
+50 -1
View File
@@ -1119,6 +1119,16 @@ body:has(.pl.pl-klein) .auswahlleiste { bottom: 92px; }
position: relative; position: relative;
padding: var(--s-page); padding: var(--s-page);
max-width: 620px; max-width: 620px;
/* **Sonst drückt der Inhalt den Aufmacher auseinander.** Ein Flexkind
schrumpft von sich aus nicht unter seinen Inhalt; die Knopfzeile war
damit auf dem Telefon breiter als der Bildschirm, und `overflow: hidden`
schnitt die rechte Hälfte des Textes ab. */
min-width: 0;
/* **Volle Breite, nicht die des längsten Satzes.** Als blosses Flexkind war
der Block so breit wie sein Inhalt — bei einer kurzen Inhaltsangabe
schmaler als bei einer langen. Auf dem Telefon rückte „Mehr" dadurch beim
Umblättern um fünfzig Pixel. */
flex: 1 1 auto;
display: flex; flex-direction: column; gap: var(--s-regular); display: flex; flex-direction: column; gap: var(--s-regular);
} }
@@ -1143,9 +1153,40 @@ body:has(.pl.pl-klein) .auswahlleiste { bottom: 92px; }
overflow: hidden; overflow: hidden;
} }
.hero-knoepfe { display: flex; gap: var(--s-snug); margin-top: var(--s-tight); } .hero-knoepfe { display: flex; gap: var(--s-snug); margin-top: var(--s-tight); min-width: 0; }
.hero-knoepfe .btn { height: 40px; padding: 0 var(--s-section); gap: 6px; } .hero-knoepfe .btn { height: 40px; padding: 0 var(--s-section); gap: 6px; }
/* **Fester Platz für das, was vorne steht.**
„Abspielen", „Fortsetzen ab 1:23:45" und der Termin sind verschieden breit.
Ohne feste Breite wanderte „Mehr" bei jedem Umblättern mit — und das
Karussell blättert von allein. */
.hero-haupt { flex: 0 0 258px; display: flex; }
.hero-haupt > * { flex: 1; }
/* Einzeilig und knopfhoch: zwei Zeilen hoben die ganze Reihe an. */
.hero-bald {
height: 40px; padding: 0 var(--s-regular); gap: var(--s-snug);
font-size: 13px; white-space: nowrap; overflow: hidden; min-width: 0;
}
.hero-bald .icon { flex: none; }
.hero-bald span:not(.icon) { overflow: hidden; text-overflow: ellipsis; }
.hero-bald .icon svg { width: 18px; height: 18px; }
/* **Pfeile am Bildrand.** Senkrecht mittig, damit sie nicht über dem Text
liegen, und über allem anderen — sonst fängt der Textblock den Klick ab. */
.hero-pfeil {
position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
width: 44px; height: 44px; display: grid; place-items: center;
border: 0; border-radius: 50%;
background: rgba(11, 11, 13, .55); color: var(--text);
backdrop-filter: blur(6px);
opacity: .72; transition: opacity .15s ease, background .15s ease;
}
.hero-pfeil:hover { opacity: 1; background: rgba(11, 11, 13, .8); }
.hero-pfeil svg { width: 24px; height: 24px; }
.hero-pfeil-links { left: var(--s-regular); }
.hero-pfeil-rechts { right: var(--s-regular); }
.hero-punkte { .hero-punkte {
position: absolute; right: var(--s-page); bottom: calc(var(--s-page) - 12px); position: absolute; right: var(--s-page); bottom: calc(var(--s-page) - 12px);
display: flex; gap: 6px; display: flex; gap: 6px;
@@ -1175,6 +1216,14 @@ body:has(.pl.pl-klein) .auswahlleiste { bottom: 92px; }
} }
.hero-inhalt { padding: var(--s-loose); max-width: none; } .hero-inhalt { padding: var(--s-loose); max-width: none; }
.hero-punkte { right: var(--s-loose); bottom: calc(var(--s-loose) - 12px); } .hero-punkte { right: var(--s-loose); bottom: calc(var(--s-loose) - 12px); }
/* Ein Knopf über dem Bild nähme hier ein Drittel der Breite. Gewischt
wird stattdessen — siehe `wischenEinrichten` in hero.ts. */
.hero-pfeil { display: none; }
/* **Hier füllt der vordere Platz die Zeile.** Eine feste Breite plus „Mehr"
wäre breiter als ein Telefon; so steht „Mehr" am rechten Rand und damit
ebenso fest wie am Schreibtisch. */
.hero-haupt { flex: 1 1 auto; min-width: 0; }
.hero-bald { font-size: 12px; padding: 0 var(--s-snug); }
} }
/* --- Kontextmenü --------------------------------------------------------- /* --- Kontextmenü ---------------------------------------------------------