Release 0.5.12

This commit is contained in:
hnzio committed 2026-10-24 02:08:32 +02:00
1 parent bd9ffe6faa
commit ec596d442e
11 files changed
+126 -31

No files matched your search

+1 -1
View File
@@ -3,7 +3,7 @@
"title": "Sendewerk", "title": "Sendewerk",
"description": "Redaktionelle Planung und Durchführung von heinzlive-Sendungen.", "description": "Redaktionelle Planung und Durchführung von heinzlive-Sendungen.",
"tagline": "Vom Fundstück bis zur Livesendung", "tagline": "Vom Fundstück bis zur Livesendung",
"version": "0.5.0", "version": "0.5.12",
"healthCheckPath": "/healthz", "healthCheckPath": "/healthz",
"httpPort": 3000, "httpPort": 3000,
"addons": { "addons": {
+19 -7
View File
@@ -413,16 +413,22 @@
- reale OBS-Browserquelle, echte YouTube-/TikTok-Wiedergabe und Safari auf einem - reale OBS-Browserquelle, echte YouTube-/TikTok-Wiedergabe und Safari auf einem
iOS-Gerät nicht ausgeführt; Anbieterrequests wurden lokal abgefangen iOS-Gerät nicht ausgeführt; Anbieterrequests wurden lokal abgefangen
## Kompakte Live-Regie und Verwaltungskorrektur 0.5.11 ## Verwaltungskorrektur 0.5.11
| Kriterium | Nachweis | Stand |
| ------------------------------------------ | ---------------------------------------------------------------------------------------- | --------------------- |
| Werkzeugdialog ist initial geschlossen | Chromium prüft den Dialog vor jeder Bedienaktion bei 390 und 1280 Pixeln | erfüllt am 23.10.2026 |
| Dialog öffnet nur nach bewusster Aktion | Browser legt ein Werkzeug an und öffnet ein bestehendes Werkzeug anschließend zum Ändern | erfüllt am 23.10.2026 |
| Bestehender Werkzeugablauf bleibt erhalten | Browser prüft Icon, Format, Deaktivierung und Piece-Zuordnung nach erneutem Laden | erfüllt am 23.10.2026 |
| Themen-Iconpicker bleibt im Viewport | Chromium prüft Öffnen und Auswahl bei 390, 960 und 1280 Pixeln | erfüllt am 23.10.2026 |
## Kompakte Live-Regie 0.5.12
| Kriterium | Nachweis | Stand | | Kriterium | Nachweis | Stand |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------ | --------------------- | | ------------------------------------------- | ------------------------------------------------------------------------------------------------ | --------------------- |
| Werkzeugdialog ist initial geschlossen | Chromium prüft den Dialog vor jeder Bedienaktion bei 390 und 1280 Pixeln | erfüllt am 24.10.2026 |
| Dialog öffnet nur nach bewusster Aktion | Browser legt ein Werkzeug an und öffnet ein bestehendes Werkzeug anschließend zum Ändern | erfüllt am 24.10.2026 |
| Bestehender Werkzeugablauf bleibt erhalten | Browser prüft Icon, Format, Deaktivierung und Piece-Zuordnung nach erneutem Laden | erfüllt am 24.10.2026 |
| Themen-Iconpicker bleibt im Viewport | Chromium prüft Öffnen und Auswahl bei 390, 960 und 1280 Pixeln | erfüllt am 24.10.2026 |
| Globale Navigation bleibt aus der Regie | Chromium findet weder Seitenleiste noch mobilen App-Header oder Bottomnavigation | erfüllt am 24.10.2026 | | Globale Navigation bleibt aus der Regie | Chromium findet weder Seitenleiste noch mobilen App-Header oder Bottomnavigation | erfüllt am 24.10.2026 |
| Kleines Desktopfenster bleibt zweispaltig | Chromium prüft Moderation, Ablauf und feste Aktionen bei 900 × 450 Pixeln | erfüllt am 24.10.2026 | | Kleines Desktopfenster bleibt zweispaltig | Chromium prüft Moderation, Ablauf und feste Aktionen bei 900 × 450 Pixeln | erfüllt am 24.10.2026 |
| Niedrige Desktophöhe wird berücksichtigt | 900 × 450 aktiviert kompakte Abstände ohne Transform oder CSS-Zoom | erfüllt am 24.10.2026 |
| Lange Inhalte scrollen innerhalb der Fläche | Synthetischer Langtext und zusätzliche Ablaufabschnitte erzeugen zwei unabhängige Scroller | erfüllt am 24.10.2026 | | Lange Inhalte scrollen innerhalb der Fläche | Synthetischer Langtext und zusätzliche Ablaufabschnitte erzeugen zwei unabhängige Scroller | erfüllt am 24.10.2026 |
| Mobile Regie verwendet ein Ablauf-Sheet | 390 × 700 prüft Endlage, Fokus, Escape, Aktionsschließen und Wechsel auf 900 Pixel | erfüllt am 24.10.2026 | | Mobile Regie verwendet ein Ablauf-Sheet | 390 × 700 prüft Endlage, Fokus, Escape, Aktionsschließen und Wechsel auf 900 Pixel | erfüllt am 24.10.2026 |
| Leseposition bleibt am Piece | Nach tiefem Scrollen beginnt ein direkt gewähltes anderes Piece am oberen Rand | erfüllt am 24.10.2026 | | Leseposition bleibt am Piece | Nach tiefem Scrollen beginnt ein direkt gewähltes anderes Piece am oberen Rand | erfüllt am 24.10.2026 |
@@ -430,14 +436,20 @@
| Erstes und letztes Piece direkt wählbar | Browser wechselt per stabiler Usage-ID auf Desktop und aus dem mobilen Sheet in beide Richtungen | erfüllt am 24.10.2026 | | Erstes und letztes Piece direkt wählbar | Browser wechselt per stabiler Usage-ID auf Desktop und aus dem mobilen Sheet in beide Richtungen | erfüllt am 24.10.2026 |
| Navigation veröffentlicht nicht automatisch | Öffentliche Ausgabe bleibt bei direkter Auswahl unverändert | erfüllt am 24.10.2026 | | Navigation veröffentlicht nicht automatisch | Öffentliche Ausgabe bleibt bei direkter Auswahl unverändert | erfüllt am 24.10.2026 |
| Timer und Livezustand überleben Reload | Aktuelles Piece und laufender Abschnittscountdown bleiben nach Neuladen erhalten | erfüllt am 24.10.2026 | | Timer und Livezustand überleben Reload | Aktuelles Piece und laufender Abschnittscountdown bleiben nach Neuladen erhalten | erfüllt am 24.10.2026 |
| Wiederaufnahme nur bei Unterbrechung | Während eines aktiven Pieces fehlt die Aktion; nach unterbrochenem Stand ist sie prominent | erfüllt am 24.10.2026 |
| Sendungsende ist eindeutig | Letztes Piece zeigt Endaktion ohne horizontalen Überlauf; danach fehlen Weiter-Aktionen | erfüllt am 24.10.2026 | | Sendungsende ist eindeutig | Letztes Piece zeigt Endaktion ohne horizontalen Überlauf; danach fehlen Weiter-Aktionen | erfüllt am 24.10.2026 |
## Ausgeführte Prüfungen 0.5.11 ## Ausgeführte Prüfungen 0.5.12
- gezielter Chromium-Test des Werkzeugablaufs: 1 von 1 erfolgreich
- `npm run lint`: erfolgreich - `npm run lint`: erfolgreich
- `npm run check`: 0 Fehler und 0 Warnungen - `npm run check`: 0 Fehler und 0 Warnungen
- `npm test`: 40 Tests in 7 Dateien erfolgreich - `npm test`: 40 Tests in 7 Dateien erfolgreich
- gezielter Live-Regie-Lauf: 1 von 1 Chromium-Test erfolgreich
- `npm run test:e2e`: 16 von 16 Chromium-Browsertests erfolgreich - `npm run test:e2e`: 16 von 16 Chromium-Browsertests erfolgreich
- Screenshots der Live-Regie bei 1440 × 900, 900 × 450 und 390 × 700 Pixeln
einschließlich mobilem Ablauf-Sheet visuell kontrolliert
- `npm run build`: erfolgreich mit `@sveltejs/adapter-node` - `npm run build`: erfolgreich mit `@sveltejs/adapter-node`
- Versionsgleichheit `0.5.12` in Paket, Lockdatei und Cloudron-Manifest geprüft
- `bash -n start.sh` und `git diff --check`: erfolgreich - `bash -n start.sh` und `git diff --check`: erfolgreich
- reale OBS-Browserquelle, echte YouTube-/TikTok-Wiedergabe und Safari auf einem
iOS-Gerät nicht ausgeführt; Anbieterrequests wurden lokal abgefangen
+8 -6
View File
@@ -287,12 +287,14 @@ Die private Route `/live` verwendet ebenfalls einen eigenen authentifizierten
Layoutmodus ohne allgemeine Seitenleiste, mobilen App-Header oder Layoutmodus ohne allgemeine Seitenleiste, mobilen App-Header oder
Bottomnavigation. Ihre Regiefläche belegt die verfügbare Viewporthöhe als Raster Bottomnavigation. Ihre Regiefläche belegt die verfügbare Viewporthöhe als Raster
aus fester Statuszeile, unabhängig scrollender Piece- und Ablaufspalte sowie aus fester Statuszeile, unabhängig scrollender Piece- und Ablaufspalte sowie
fester Aktionszeile. Unterhalb des schmalen Breakpoints wird ausschließlich die fester Aktionszeile. Die Breite entscheidet über zwei Spalten oder das mobile
Ablaufspalte als modales Sheet mit Fokusbegrenzung eingeblendet; beim Wechsel Sheet; eine geringe Desktophöhe verdichtet zusätzlich Abstände und Leisten,
auf einen breiteren Viewport wird dieser Modalzustand aufgehoben. Dieser ohne Schrift oder Oberfläche zu skalieren. Unterhalb des schmalen Breakpoints
Layoutmodus ändert weder die Live-Actions noch die getrennte öffentliche wird ausschließlich die Ablaufspalte als modales Sheet mit Fokusbegrenzung
`/heinzlive`-Projektion. Lokale Lesepositionen sind an die jeweilige Verwendung eingeblendet; beim Wechsel auf einen breiteren Viewport wird dieser Modalzustand
gebunden und werden nicht zwischen Pieces übertragen. aufgehoben. Dieser Layoutmodus ändert weder die Live-Actions noch die getrennte
öffentliche `/heinzlive`-Projektion. Lokale Lesepositionen sind an die jeweilige
Verwendung gebunden und werden nicht zwischen Pieces übertragen.
Icons werden aus dem lokalen Font-Awesome-Classic-Regular-Sprite unter Icons werden aus dem lokalen Font-Awesome-Classic-Regular-Sprite unter
`static/icons` gerendert. Die Verwaltung lädt zusätzlich die durchsuchbaren `static/icons` gerendert. Die Verwaltung lädt zusätzlich die durchsuchbaren
+4 -2
View File
@@ -366,8 +366,10 @@ Lizenz stehen in `THIRD_PARTY_NOTICES.md`.
Die authentifizierte Live-Steuerung nutzt einen eigenen Root-Layoutmodus und Die authentifizierte Live-Steuerung nutzt einen eigenen Root-Layoutmodus und
rendert die allgemeine App-Navigation nicht. Kopf- und Aktionszeile bleiben fest; rendert die allgemeine App-Navigation nicht. Kopf- und Aktionszeile bleiben fest;
Moderation und Ablauf sind die einzigen unabhängig scrollenden Arbeitsflächen. Moderation und Ablauf sind die einzigen unabhängig scrollenden Arbeitsflächen.
Die Umschaltung zum mobilen Sheet hängt ausschließlich von der Fensterbreite ab, Die Umschaltung zum mobilen Sheet hängt von der Fensterbreite ab, damit ein
damit ein breites, niedriges Desktopfenster weiterhin zwei Spalten verwendet. breites, niedriges Desktopfenster weiterhin zwei Spalten verwendet. Die Höhe
steuert dort unabhängig die Dichte von Abständen und Bedienleisten. Textgröße
und Gesamtoberfläche werden nicht skaliert.
Diese Darstellung ist keine neue Live-Zustandsgrenze. Start, direkte Auswahl, Diese Darstellung ist keine neue Live-Zustandsgrenze. Start, direkte Auswahl,
Erledigen, Überspringen, Reserveeinfügung und Präsentation bleiben unveränderte Erledigen, Überspringen, Reserveeinfügung und Präsentation bleiben unveränderte
+31 -8
View File
@@ -1,10 +1,10 @@
# Release Notes # Release Notes
## 0.5.11 - Kompakte Live-Regie ## 0.5.12 - Kompakte Live-Regie
Veröffentlicht am 23. Oktober 2026 Veröffentlicht am 24. Oktober 2026
Sendewerk 0.5.11 macht aus der privaten Live-Steuerung eine kompakte Regieansicht Sendewerk 0.5.12 macht aus der privaten Live-Steuerung eine kompakte Regieansicht
für Vollbild, Smartphone und kleine Desktopfenster neben OBS oder Firebot. Das für Vollbild, Smartphone und kleine Desktopfenster neben OBS oder Firebot. Das
aktuelle Piece, die Position im Ablauf, der Abschnittscountdown und die aktuelle Piece, die Position im Ablauf, der Abschnittscountdown und die
wichtigsten Aktionen bleiben gleichzeitig erreichbar. Die öffentliche wichtigsten Aktionen bleiben gleichzeitig erreichbar. Die öffentliche
@@ -19,6 +19,8 @@ heinzlive-Ausgabe und die gespeicherten Livezustände bleiben technisch getrennt
- Moderation und Ablauf bleiben auch bei einem nur 900 × 450 Pixel großen - Moderation und Ablauf bleiben auch bei einem nur 900 × 450 Pixel großen
Desktopfenster nebeneinander. Lange Inhalte scrollen innerhalb ihrer Desktopfenster nebeneinander. Lange Inhalte scrollen innerhalb ihrer
Arbeitsfläche; Kopf- und Aktionszeile bleiben sichtbar. Arbeitsfläche; Kopf- und Aktionszeile bleiben sichtbar.
- Niedrige Desktopfenster verdichten Abstände und Bedienleisten anhand der
verfügbaren Höhe, ohne Text oder die gesamte Oberfläche zu skalieren.
- Die feste Fußleiste bündelt nächstes Piece, „Präsentieren“, „Überspringen“ und - Die feste Fußleiste bündelt nächstes Piece, „Präsentieren“, „Überspringen“ und
„Erledigen & weiter“. Beim letzten offenen Piece wird das Sendungsende „Erledigen & weiter“. Beim letzten offenen Piece wird das Sendungsende
eindeutig benannt. eindeutig benannt.
@@ -51,15 +53,13 @@ heinzlive-Ausgabe und die gespeicherten Livezustände bleiben technisch getrennt
Ausgabe. Ausgabe.
- Abschnittstimer, tatsächliche Laufzeiten, Livefortschritt und Wiederaufnahme - Abschnittstimer, tatsächliche Laufzeiten, Livefortschritt und Wiederaufnahme
verwenden unverändert die vorhandenen persistenten Zustände. verwenden unverändert die vorhandenen persistenten Zustände.
- „Live-Stand wiederaufnehmen“ erscheint nur bei einem tatsächlich
unterbrochenen Ablauf, nicht während eines aktiven Pieces.
### Einstellungen und Verwaltung ### Einstellungen
- Ausgabekanal verbinden, Schlüssel erneuern, Kanal trennen, Theme wechseln, - Ausgabekanal verbinden, Schlüssel erneuern, Kanal trennen, Theme wechseln,
Zeiten ein-/ausblenden und „Zur Planung“ bleiben im Regiemenü erreichbar. Zeiten ein-/ausblenden und „Zur Planung“ bleiben im Regiemenü erreichbar.
- Der Dialog „Werkzeug hinzufügen“ bleibt beim Aufruf der Verwaltungsseite
zuverlässig geschlossen und erscheint erst nach einer bewussten Aktion.
- Die Iconauswahl unter „Inhaltliche Zuordnung“ bleibt auf Desktop und
Smartphone vollständig im sichtbaren Browserbereich.
### Update und Kompatibilität ### Update und Kompatibilität
@@ -67,6 +67,29 @@ heinzlive-Ausgabe und die gespeicherten Livezustände bleiben technisch getrennt
Konfiguration. Konfiguration.
- Bestehende Sendungen, Livezustände, Timer, Ausgabekanäle und - Bestehende Sendungen, Livezustände, Timer, Ausgabekanäle und
Präsentationssnapshots bleiben erhalten. Präsentationssnapshots bleiben erhalten.
- Paket, Lockdatei und Cloudron-Manifest tragen gemeinsam Version `0.5.12`.
### Prüfung
- 40 Unit- und Verhaltenstests sowie 16 Chromium-E2E-Abläufe sind erfolgreich.
- Die Live-Regie wurde bei 1440 × 900, 900 × 450 und 390 × 700 Pixeln mit
langen Inhalten, unabhängigen Scrollflächen und mobilem Ablauf-Sheet geprüft;
die erzeugten Screenshots wurden visuell kontrolliert.
- Reales OBS, echte YouTube-/TikTok-Wiedergabe und Safari auf einem iOS-Gerät
standen nicht zur Verfügung.
## 0.5.11 - Verwaltungskorrektur
Veröffentlicht am 23. Oktober 2026
- Der Dialog „Werkzeug hinzufügen“ bleibt beim Aufruf der Verwaltungsseite
wieder zuverlässig geschlossen.
- Der Dialog erscheint erst, wenn ein neues Werkzeug angelegt oder ein
bestehendes Werkzeug bearbeitet wird.
- Die Iconauswahl unter „Inhaltliche Zuordnung“ bleibt auf Desktop und
Smartphone vollständig im sichtbaren Browserbereich.
- Die Korrektur gilt gleichermaßen für Desktop- und Smartphone-Ansichten und
verändert keine vorhandenen Werkzeuge oder Zuordnungen.
## 0.5.10 - Editor-Erlebnis ## 0.5.10 - Editor-Erlebnis
+16 -3
View File
@@ -7,7 +7,7 @@ Anmeldung, Rollen, persistente Inhaltsbearbeitung, Sendungsplanung,
Live-Steuerung, Präsentationsausgabe und lokaler Betriebsweg sind dokumentiert. Live-Steuerung, Präsentationsausgabe und lokaler Betriebsweg sind dokumentiert.
Etappe 6 wurde nicht begonnen. Etappe 6 wurde nicht begonnen.
## Kompakte Live-Regie 0.5.11 ## Kompakte Live-Regie 0.5.12
- fokussierte private Liveansicht ohne normale App-Seitenleiste oder mobile - fokussierte private Liveansicht ohne normale App-Seitenleiste oder mobile
Bottomnavigation; Planung, Theme, Schriftgröße, Zeitdarstellung und Bottomnavigation; Planung, Theme, Schriftgröße, Zeitdarstellung und
@@ -18,6 +18,8 @@ Etappe 6 wurde nicht begonnen.
- aktuelle Moderation und schmale Ablaufspalte bleiben auch bei 900 × 450 Pixeln - aktuelle Moderation und schmale Ablaufspalte bleiben auch bei 900 × 450 Pixeln
nebeneinander; beide Arbeitsflächen scrollen unabhängig, ohne die ganze Seite nebeneinander; beide Arbeitsflächen scrollen unabhängig, ohne die ganze Seite
oder einzelne Textblöcke zu verschachtelten Scrollcontainern zu machen oder einzelne Textblöcke zu verschachtelten Scrollcontainern zu machen
- bei niedrigen Desktopfenstern werden Abstände und Bedienleisten anhand der
verfügbaren Höhe verdichtet, ohne Text oder Gesamtoberfläche zu skalieren
- auf schmalen Ansichten bleibt das Piece die Hauptfläche und der Ablauf öffnet - auf schmalen Ansichten bleibt das Piece die Hauptfläche und der Ablauf öffnet
als separates, safe-area-fähiges Sheet mit Fokusführung und Escape-Schließen als separates, safe-area-fähiges Sheet mit Fokusführung und Escape-Schließen
- kompakter aufklappbarer Ablauf mit ausgeschriebenen Zuständen, direkter - kompakter aufklappbarer Ablauf mit ausgeschriebenen Zuständen, direkter
@@ -30,11 +32,22 @@ Etappe 6 wurde nicht begonnen.
leere Moderationsbereiche werden nicht dargestellt leere Moderationsbereiche werden nicht dargestellt
- Livefortschritt, direkte Auswahl, Abschnittstimer und öffentliche Präsentation - Livefortschritt, direkte Auswahl, Abschnittstimer und öffentliche Präsentation
verwenden unverändert ihre getrennten persistenten Zustände verwenden unverändert ihre getrennten persistenten Zustände
- der Werkzeugdialog bleibt nach dem Laden der Verwaltungsseite geschlossen; - die Wiederaufnahmeaktion erscheint nur bei tatsächlich unterbrochenem
die Themen-Iconauswahl bleibt vollständig innerhalb des Viewports Live-Stand statt während eines laufenden Pieces
Etappe 6 bleibt unverändert unbegonnen. Etappe 6 bleibt unverändert unbegonnen.
Die lokale Prüfmatrix umfasst 40 Verhaltenstests und 16 Chromium-Abläufe.
Reales OBS, echte YouTube-/TikTok-Wiedergabe sowie Safari auf einem iOS-Gerät
bleiben mangels verfügbarer Umgebung offen.
## Verwaltungskorrektur 0.5.11
- der Werkzeugdialog bleibt beim Laden geschlossen und öffnet erst nach einer
bewussten Aktion
- die Themen-Iconauswahl bleibt bei mobilen und breiten Ansichten vollständig
innerhalb des Viewports
## Editor-Erlebnis 0.5.10 ## Editor-Erlebnis 0.5.10
- direkte, tastaturbedienbare Titelbearbeitung in Fundus- und Sendungsfassungen - direkte, tastaturbedienbare Titelbearbeitung in Fundus- und Sendungsfassungen
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "sendewerk", "name": "sendewerk",
"version": "0.5.11", "version": "0.5.12",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "sendewerk", "name": "sendewerk",
"version": "0.5.11", "version": "0.5.12",
"dependencies": { "dependencies": {
"@node-rs/argon2": "^2.2.2", "@node-rs/argon2": "^2.2.2",
"better-sqlite3": "^13.0.3", "better-sqlite3": "^13.0.3",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "sendewerk", "name": "sendewerk",
"private": true, "private": true,
"version": "0.5.11", "version": "0.5.12",
"type": "module", "type": "module",
"engines": { "engines": {
"node": ">=22.17 <25" "node": ">=22.17 <25"
+33
View File
@@ -1723,6 +1723,39 @@ textarea:focus {
font-size: 0.75rem; font-size: 0.75rem;
} }
@media (min-width: 46.001rem) and (max-height: 36rem) {
.live-page {
gap: 0.35rem;
padding: max(0.4rem, env(safe-area-inset-top)) max(0.4rem, env(safe-area-inset-right))
max(0.4rem, env(safe-area-inset-bottom)) max(0.4rem, env(safe-area-inset-left));
}
.live-command-header,
.live-action-bar {
padding: 0.4rem 0.55rem;
}
.section-countdown {
padding: 0.25rem 0.45rem;
}
.live-workspace {
gap: 0.45rem;
}
.live-current-scroll {
padding: clamp(0.75rem, 1.7vw, 1.25rem);
}
.live-piece-heading {
padding-bottom: 0.55rem;
}
.live-script-section {
padding: 0.7rem 0;
}
}
@media (max-width: 46rem) { @media (max-width: 46rem) {
.live-page { .live-page {
gap: 0.4rem; gap: 0.4rem;
+1 -1
View File
@@ -358,7 +358,7 @@
</section> </section>
<section> <section>
<strong>Sendung</strong> <strong>Sendung</strong>
{#if data.live.startedAtUtc}<form {#if needsResume}<form
method="POST" method="POST"
action={liveAction('start')} action={liveAction('start')}
use:enhance={enhanceCommand} use:enhance={enhanceCommand}
+10
View File
@@ -1084,6 +1084,9 @@ test('live control persists state and exposes only explicit presentation data',
await page.getByRole('button', { name: 'Sendung starten' }).click(); await page.getByRole('button', { name: 'Sendung starten' }).click();
await expect(page.locator('#current-title')).toHaveText('Die kleine Konsole mit dem großen Dreh'); await expect(page.locator('#current-title')).toHaveText('Die kleine Konsole mit dem großen Dreh');
await expect(page.locator('.section-countdown')).toContainText(/0[45]:\d{2}/); await expect(page.locator('.section-countdown')).toContainText(/0[45]:\d{2}/);
await expect(
page.locator('.live-menu button', { hasText: 'Live-Stand wiederaufnehmen' })
).toHaveCount(0);
await page.getByText('Quellen · 1', { exact: true }).click(); await page.getByText('Quellen · 1', { exact: true }).click();
await expect(page.locator('.live-materials')).toContainText('Herstellerseite'); await expect(page.locator('.live-materials')).toContainText('Herstellerseite');
await expect( await expect(
@@ -1238,12 +1241,16 @@ test('live control persists state and exposes only explicit presentation data',
const current = document.querySelector('.live-current')?.getBoundingClientRect(); const current = document.querySelector('.live-current')?.getBoundingClientRect();
const rail = document.querySelector('.live-rail')?.getBoundingClientRect(); const rail = document.querySelector('.live-rail')?.getBoundingClientRect();
const footer = document.querySelector('.live-action-bar')?.getBoundingClientRect(); const footer = document.querySelector('.live-action-bar')?.getBoundingClientRect();
const pageStyle = getComputedStyle(document.querySelector('.live-page') as HTMLElement);
const pieceScroll = document.querySelector('.live-current-scroll'); const pieceScroll = document.querySelector('.live-current-scroll');
const railScroll = document.querySelector('.live-run-scroll'); const railScroll = document.querySelector('.live-run-scroll');
return { return {
pageFits: document.documentElement.scrollHeight <= innerHeight, pageFits: document.documentElement.scrollHeight <= innerHeight,
twoColumns: Boolean(current && rail && rail.x > current.x + current.width - 1), twoColumns: Boolean(current && rail && rail.x > current.x + current.width - 1),
footerVisible: Boolean(footer && footer.bottom <= innerHeight && footer.top >= 0), footerVisible: Boolean(footer && footer.bottom <= innerHeight && footer.top >= 0),
shortViewportDensity: parseFloat(pageStyle.gap) < 8,
unscaled: pageStyle.transform === 'none',
unzoomed: ['', '1', 'normal'].includes(pageStyle.getPropertyValue('zoom')),
pieceScrolls: Boolean(pieceScroll && pieceScroll.scrollHeight > pieceScroll.clientHeight), pieceScrolls: Boolean(pieceScroll && pieceScroll.scrollHeight > pieceScroll.clientHeight),
railScrolls: Boolean(railScroll && railScroll.scrollHeight > railScroll.clientHeight) railScrolls: Boolean(railScroll && railScroll.scrollHeight > railScroll.clientHeight)
}; };
@@ -1252,6 +1259,9 @@ test('live control persists state and exposes only explicit presentation data',
pageFits: true, pageFits: true,
twoColumns: true, twoColumns: true,
footerVisible: true, footerVisible: true,
shortViewportDensity: true,
unscaled: true,
unzoomed: true,
pieceScrolls: true, pieceScrolls: true,
railScrolls: true railScrolls: true
}); });