Files
tsv08kulmbach-website/app/pages/jugendfussball.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

78 lines
3.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
/**
* Jugendfußball-Übersichtsseite. Inhalt: data/jugend.json.
* Komposition: Hero → Intro-Bento (Bild, Mitmachen, Spielort, Altersklassen) →
* Altersklassen-Karten → FAQ + Ansprechpartner (faq-contact, Slider bei mehreren).
*/
$page = json_load('jugend');
$club = json_load('club');
$addr = $club['address'] ?? [];
$mapsQuery = rawurlencode(trim(($addr['venue'] ?? '') . ', ' . ($addr['street'] ?? '') . ', ' . ($addr['zip'] ?? '') . ' ' . ($addr['city'] ?? ''), ', '));
// Ansprechpartner Jugendfußball aus der Single-Source (mehrere → Slider in faq-contact).
$contacts = array_values(array_filter(
json_load('ansprechpartner')['persons'] ?? [],
static fn (array $p): bool => ($p['department'] ?? '') === 'Jugendfußball'
));
$meta = [
'title' => 'Jugendfußball in Kulmbach',
'description' => 'Jugendfußball in Kulmbach beim TSV 08: Teams von der G- bis zur C-Jugend, Trainingszeiten und kostenloses Schnuppertraining. Komm vorbei ins Katzbachtal!',
'og_image' => 'img/pages/jugendfussball-hero-1440.jpg',
'scripts' => count($contacts) > 1 ? ['contact-slider.js'] : [],
'schema' => page_schema(
[
['name' => 'Startseite', 'slug' => ''],
['name' => 'Fußball', 'slug' => 'fussball'],
['name' => 'Jugendfußball', 'slug' => 'jugendfussball'],
],
$page['faq'] ?? []
),
];
component('hero', ['hero' => $page['hero']]);
?>
<section class="section" id="ueber-uns">
<div class="container">
<div class="intro-bento">
<div class="bento__tile intro-bento__image">
<?php component('img', ['image' => $page['hero']['image'], 'sizes' => '(max-width: 900px) 100vw, 40vw', 'class' => 'intro-bento__img']); ?>
</div>
<article class="bento__tile intro-bento__about">
<h2><?= e($page['about']['title']) ?></h2>
<p><?= e($page['about']['text']) ?></p>
</article>
<article class="bento__tile intro-bento__venue">
<h2 class="bento__heading"><?= icon('geo-alt', 'bento__hicon') ?>Spielort</h2>
<p class="bento__address">
<?php if (!empty($addr['venue'])): ?><strong><?= e($addr['venue']) ?></strong><br><?php endif; ?>
<?= e($addr['street']) ?>, <?= e($addr['zip']) ?> <?= e($addr['city']) ?>
</p>
<a class="btn btn--outline intro-bento__route" href="https://www.google.com/maps/search/?api=1&amp;query=<?= e($mapsQuery) ?>" target="_blank" rel="noopener">Route planen<span class="visually-hidden"> (öffnet Google Maps in neuem Tab)</span></a>
<span class="bento__deco" aria-hidden="true"><?= icon('geo-alt') ?></span>
</article>
<article class="bento__tile bento__tile--accent intro-bento__stat">
<span class="bento__stat-label">Altersklassen</span>
<span class="bento__stat-value">G&nbsp;&nbsp;C</span>
</article>
</div>
</div>
</section>
<?php
component('age-groups', ['groups' => $page['groups'] ?? []]);
component('faq-contact', [
'faq' => $page['faq'] ?? [],
'faqIntro' => 'Ruf uns direkt an oder schreib uns unkompliziert per WhatsApp. Wir beantworten alle Fragen rund um Schnuppertraining und die passende Altersgruppe.',
'persons' => $contacts,
'contactTitle' => '',
'anchor' => 'kontakt',
]);