Files
tsv08kulmbach-website/app/components/section.php
fs a101b0c3ec 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

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>