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
72 lines
3.6 KiB
PHP
72 lines
3.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Alternierende Bild/Text-Sektion. Props:
|
|
* $section array{id, title, text, image?, gallery?, flip?, tinted?, polaroid?, cta?} (aus home.json o.ä.)
|
|
* $level int Überschriften-Ebene (default 2)
|
|
* tinted: sanft aufgehelltes Panel hinter dem Inhalt (Abgrenzung vom Seitenhintergrund).
|
|
* polaroid: Bild als Polaroid (dicker heller Rahmen, leicht gekippt; flip kippt gegenläufig).
|
|
* Trägt ein Bild ein optionales caption-Feld, erscheint es als Bildunterschrift
|
|
* auf dem weißen Unterrand des Rahmens (Abel-Versalien, wie Historie-Captions).
|
|
* gallery: Array von Bildern statt image — erstes Bild groß, weitere darunter
|
|
* halbbreit nebeneinander (Collage). Mit polaroid kippen die Rahmen abwechselnd.
|
|
* text: String oder Liste von Absätzen (mehr als zwei sollten hier nicht stehen —
|
|
* dann ist es keine Bild/Text-Sektion mehr).
|
|
*/
|
|
$level = $level ?? 2;
|
|
$flip = !empty($section['flip']);
|
|
$tinted = !empty($section['tinted']);
|
|
$polaroid = !empty($section['polaroid']);
|
|
// Ohne image UND ohne gallery läuft die Sektion einspaltig („split--plain") —
|
|
// für Textabschnitte, für die es (noch) kein Foto gibt, z. B. „Anfahrt und
|
|
// Parken" auf einer Veranstaltungs-Seite. Ohne diesen Zweig liefe img.php
|
|
// unten auf ein fehlendes Bild.
|
|
$hasMedia = !empty($section['image']) || !empty($section['gallery']);
|
|
$paragraphs = is_array($section['text']) ? $section['text'] : [$section['text']];
|
|
?>
|
|
<section class="section split<?= $flip ? ' split--flip' : '' ?><?= $tinted ? ' section--tinted' : '' ?><?= $polaroid ? ' split--polaroid' : '' ?><?= $hasMedia ? '' : ' split--plain' ?>" id="<?= e($section['id']) ?>">
|
|
<div class="container split__inner">
|
|
<div class="split__text">
|
|
<h<?= $level ?>><?= e($section['title']) ?></h<?= $level ?>>
|
|
<?php foreach ($paragraphs as $paragraph): ?>
|
|
<p><?= e($paragraph) ?></p>
|
|
<?php endforeach; ?>
|
|
<?php if (!empty($section['cta'])): ?>
|
|
<p class="split__cta"><?php component('cta', ['cta' => $section['cta']]); ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php if ($hasMedia): ?>
|
|
<div class="split__media">
|
|
<?php if (!empty($section['gallery'])): ?>
|
|
<div class="split__gallery">
|
|
<?php foreach ($section['gallery'] as $i => $galleryImage): ?>
|
|
<?php $sizes = $i === 0 ? '(max-width: 992px) 100vw, 50vw' : '(max-width: 992px) 50vw, 25vw'; ?>
|
|
<?php if ($polaroid): ?>
|
|
<figure class="polaroid">
|
|
<?php component('img', ['image' => $galleryImage, 'sizes' => $sizes, 'class' => 'split__img']); ?>
|
|
<?php if (!empty($galleryImage['caption'])): ?>
|
|
<figcaption class="polaroid__caption"><?= e($galleryImage['caption']) ?></figcaption>
|
|
<?php endif; ?>
|
|
</figure>
|
|
<?php else: ?>
|
|
<?php component('img', ['image' => $galleryImage, 'sizes' => $sizes, 'class' => 'split__img']); ?>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php elseif ($polaroid): ?>
|
|
<figure class="polaroid">
|
|
<?php component('img', ['image' => $section['image'], 'sizes' => '(max-width: 992px) 100vw, 50vw', 'class' => 'split__img']); ?>
|
|
<?php if (!empty($section['image']['caption'])): ?>
|
|
<figcaption class="polaroid__caption"><?= e($section['image']['caption']) ?></figcaption>
|
|
<?php endif; ?>
|
|
</figure>
|
|
<?php else: ?>
|
|
<?php component('img', ['image' => $section['image'], 'sizes' => '(max-width: 992px) 100vw, 50vw', 'class' => 'split__img']); ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</section>
|