Files
tsv08kulmbach-website/app/components/stadionzeitung-druck.php

99 lines
4.5 KiB
PHP
Raw Normal View History

Stadionzeitung, Veranstaltungen, News-Artikel, Lightbox und Anzeigen-Verteilung Stadionzeitung: Live-Seiten (Tabellen, Ergebnisse, Vorschau, Termine, News, Kontakt, Historie, Sportheim, Partner, Momente, Impressum), automatisches Cover, Swipe-Viewer mit Vollbildmodus und die Druckfassung als Falt-Heft. Anzeigen kommen jetzt aus dem Bestand und werden gleichmäßig verteilt, nie mehr als zwei hintereinander (vorher vier Blöcke à fünf). Die Doppelseiten-Regel rechnet das Skript selbst, statt sie von Hand zu prüfen. Veranstaltungen: Bereich /veranstaltungen mit Detailseite pro Fest, Lebenszyklus über das Datum (Ankündigung vor dem Fest, Rückblick danach), Galerie mit Lightbox. veranstaltungen.json ist dritte Termin-Quelle, damit ein Fest nie doppelt gepflegt wird. News-Artikel als dritte dynamische Prefix-Route, gemeinsamer detail-head. Behobene Fehler: - Wappen-Kontexte setzten Zeilen-Layout auf .crest statt auf die Zeile; das Wappen wurde zum Grid, Vereinsname und Tore rutschten darunter zusammen (Ergebnis-Rückblick, Vorschau, Cover). - --header-h (60px) unterschätzt die Kopfleiste um 32px (Logo 72px + 20px Versatz): neues abgeleitetes --header-space, sonst klebten Zurück-Links unter dem Logo. - base_url in der Produktions-Config ohne www, während .htaccess auf www umleitet; preflight prüft das jetzt. - .lightbox brauchte display:none mit (0,2,0), sonst lag das Overlay offen. Neue Werkzeuge: bin/anzeige-add.php (Anzeigen-Bestand), bin/veranstaltung-bilder.php (Plakate und Galerien, Alt-Texte folgen der Quelldatei), bin/qr.php (Druck-QR mit Warnung, wenn base_url nicht auf die echte Domain zeigt). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 14:55:27 +02:00
<?php
declare(strict_types=1);
/**
* Druckfassung einer Stadionzeitung-Ausgabe (Route ?druck=1, siehe
* app/pages/stadionzeitung-ausgabe.php) die Seiten in BROSCHÜREN-Reihenfolge
* statt Lesereihenfolge: das Heft wird als A4 quer beidseitig gedruckt, die
* Blätter werden gestapelt und mittig gefaltet. Damit dabei vorn das Cover
* und innen die richtige Abfolge liegt, trägt Blatt 1 vorne [letzte Seite |
* Seite 1], hinten [Seite 2 | vorletzte Seite] usw. die klassische
* Sattelheftungs-Montage. Deshalb liegt die Montage HIER im PHP (die
* DOM-Reihenfolge selbst ist die Druckreihenfolge), nicht in Druck-CSS:
* CSS kann Seiten nicht über Blattgrenzen hinweg umsortieren.
*
* Die Seitenzahl wird dafür auf ein Vielfaches von 4 gebracht: fehlende
* Seiten füllt eine weiße Leerseite VOR der Rückseite auf (die Rückseite
* bleibt immer außen). Die Regel fürs Heft bleibt trotzdem: Lücken beim
* Erzeugen gemeinsam sauber lösen, Leerseiten sind der Notnagel.
*
* Auf dem Bildschirm zeigt die Route eine Blatt-Vorschau (jedes Blatt als
* A4-quer-Fläche mit Beschriftung „Blatt 1 · Vorderseite") plus
* Druck-Anleitung; assets/js/stadionzeitung-druck.js liefert den
* „Jetzt drucken"-Button (progressive enhancement — ohne JS druckt der
* Browser-Dialog dieselbe Ansicht).
*
* Props: $issue Eintrag aus data/stadionzeitung.json
*/
$issue = $issue ?? [];
$pages = $issue['images'] ?? [];
if ($pages === []) {
return;
}
$hasLive = false;
foreach ($pages as $entry) {
if (($entry['type'] ?? 'image') === 'live') {
$hasLive = true;
break;
}
}
$liveData = $hasLive ? stadionzeitung_live_data($issue) : [];
// Auf Vielfaches von 4 auffüllen — Leerseiten direkt vor der letzten Seite,
// damit die gelieferte Rückseite die äußere Rückseite des Hefts bleibt.
$fill = (4 - count($pages) % 4) % 4;
if ($fill > 0) {
array_splice($pages, count($pages) - 1, 0, array_fill(0, $fill, ['type' => 'leer']));
}
$n = count($pages);
// Sattelheftung: Blatt k (0-basiert) trägt vorne [n-1-2k | 2k] und hinten
// [2k+1 | n-2-2k] (0-basierte Seitenindizes). Beim beidseitigen Druck an der
// KURZEN Kante spiegeln, sonst steht jede Rückseite kopf.
$sides = [];
for ($k = 0; $k < intdiv($n, 4); $k++) {
$sides[] = ['label' => 'Blatt ' . ($k + 1) . ' · Vorderseite', 'pages' => [$n - 1 - 2 * $k, 2 * $k]];
$sides[] = ['label' => 'Blatt ' . ($k + 1) . ' · Rückseite', 'pages' => [2 * $k + 1, $n - 2 - 2 * $k]];
}
?>
<section class="stadionzeitung-druck">
<ol class="stadionzeitung-druck__blaetter">
<?php foreach ($sides as $side): ?>
<li class="stadionzeitung-druck__blatt">
<p class="stadionzeitung-druck__blatt-label" aria-hidden="true"><?= e($side['label']) ?></p>
<div class="stadionzeitung-druck__flaeche">
<?php foreach ($side['pages'] as $pageIndex): ?>
<div class="stadionzeitung-druck__slot">
<?php component('stadionzeitung-seite', [
'entry' => $pages[$pageIndex],
'issue' => $issue,
'data' => $liveData,
// In der Druckfassung wird JEDE Seite sofort geladen:
// lazy geladene Bilder, die nie im Sichtfeld waren,
// druckt Chrome sonst als leere Flächen.
'eager' => true,
]); ?>
</div>
<?php endforeach; ?>
</div>
</li>
<?php endforeach; ?>
</ol>
<?php /* Anleitung + Druck-Button bewusst UNTER den Blättern (Wunsch Felix,
29.07.2026): erst die Vorschau komplett durchsehen, ganz unten
drucken. */ ?>
<div class="stadionzeitung-druck__hilfe">
<h2 class="stadionzeitung-druck__hilfe-title">Drucken</h2>
<p>
<?= intdiv($n, 4) ?> Blätter A4 quer<?= $fill > 0 ? ', mit ' . $fill . ' weißen Füllseiten auf ' . $n . ' Seiten aufgefüllt' : ' (' . $n . ' Seiten)' ?>.
Beidseitig drucken und dabei <strong>an der kurzen Kante spiegeln</strong>,
danach alle Blätter aufeinanderlegen und mittig falten fertig ist das Heft.
</p>
<button class="btn stadionzeitung-druck__print-btn" type="button" data-druck-print hidden>
<?= icon('printer') ?> Jetzt drucken
</button>
</div>
</section>