Stadionzeitung: Galerie-Seite als Bento-Raster

Optionale Live-Seite hinter dem Ergebnis-Rückblick mit Fotos vom letzten
Spiel. bin/stadionzeitung-add.php liest sie aus <ordner>/galerie/, Kopf und
Alt-Texte sind Chat-Pflege und hängen an source. Preflight meldet fehlende
Galerie-Dateien.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PCMNXcfkM9RcaVjqoJjRsz
This commit is contained in:
2026-10-02 11:10:57 +02:00
parent 7aae3d5ca9
commit fbb23a8732
6 changed files with 235 additions and 2 deletions

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
/**
* Galerie-Seite der Stadionzeitung (Live-Seite, optional) — Fotos vom letzten
* Spiel als Bento-Raster: ein großes Aufmacherfoto, die übrigen in kleineren
* Kacheln darum. Das Raster füllt die ganze Blattfläche unter dem Kopf, die
* Fotos werden per object-fit auf ihre Kachel beschnitten.
*
* Props: $issue Eintrag aus data/stadionzeitung.json. Gelesen wird das Feld
* `galerie`: `kicker`, `heading`, `text?` sind Chat-Pflege, `bilder[]`
* (base/widths/alt/source) schreibt bin/stadionzeitung-add.php aus
* <ordner>/galerie/. Alt-Texte kommen aus dem Chat und hängen an `source`.
*
* Die Bilder liegen im Ausgaben-Ordner und werden von keinem Sync angefasst,
* deshalb braucht die Seite keinen Snapshot.
*/
$galerie = is_array($issue['galerie'] ?? null) ? $issue['galerie'] : [];
$bilder = array_slice(array_values(array_filter(
$galerie['bilder'] ?? [],
static fn ($b): bool => is_array($b) && !empty($b['base']) && !empty($b['widths'])
)), 0, 7);
$kicker = trim((string) ($galerie['kicker'] ?? 'Rückblick'));
$heading = trim((string) ($galerie['heading'] ?? 'Fotos vom letzten Spiel'));
$text = trim((string) ($galerie['text'] ?? ''));
?>
<div class="stadionzeitung-galerie">
<header class="stadionzeitung-page__head">
<?php if ($kicker !== ''): ?>
<p class="stadionzeitung-page__kicker"><?= e($kicker) ?></p>
<?php endif; ?>
<h2 class="stadionzeitung-page__heading"><?= e($heading) ?></h2>
<?php if ($text !== ''): ?>
<p class="stadionzeitung-galerie__text"><?= e($text) ?></p>
<?php endif; ?>
</header>
<?php if ($bilder !== []): ?>
<div class="stadionzeitung-galerie__bento stadionzeitung-galerie__bento--n<?= count($bilder) ?>">
<?php foreach ($bilder as $i => $bild): ?>
<?php component('img', [
'image' => $bild,
// Aufmacher gut zwei Drittel der Seitenbreite, die Kacheln ein Drittel.
'sizes' => $i === 0 ? '(min-width: 520px) 340px, 70vw' : '(min-width: 520px) 240px, 50vw',
'class' => 'stadionzeitung-galerie__foto',
]); ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>

View File

@@ -11,7 +11,8 @@ declare(strict_types=1);
* type 'image' (base/widths/alt),
* type 'live' (page: cover|vorwort|interview|programm|aufruf|turnier|
* tabelle|termine|news|ergebnisse|gegner|vorschau|kontakt|
* mitglied|historie|sportheim|partner|danke|momente|impressum;
* mitglied|historie|sportheim|partner|danke|momente|galerie|
* impressum;
* tabelle und gegner optional mit team: Team-Key aus
* matchcenter.json; turnier mit turnier: Key aus
* veranstaltungen.json → turniere[] der Ausgaben-Veranstaltung),
@@ -96,6 +97,9 @@ $type = $entry['type'] ?? 'image';
wie jede andere Anzeige in images[] eingefroren ist. */ ?>
<?php component('stadionzeitung-danke', ['anzeige' => $entry['anzeige'] ?? null]); ?>
<?php break; ?>
<?php case 'galerie': ?>
<?php component('stadionzeitung-galerie', ['issue' => $issue]); ?>
<?php break; ?>
<?php case 'momente': ?>
<?php component('stadionzeitung-momente', ['items' => $data['momente'] ?? []]); ?>
<?php break; ?>