Unterseiten: Fußball-Übersicht, Mannschaften, Jugend, Verein, Rechtliches

Neue Seiten + Routen: fussball, fussball/{erste-mannschaft,zweite-mannschaft,
damen}, jugendfussball, verein, impressum, datenschutz. Dazu die Komponenten
team, team-cards/-roster/-photo/-bento, faq/faq-contact, key-facts, age-groups,
cta-band, training-location und der contact-slider.

Daten in teams/fussball/jugend/verein.json; club.json um Vorstand, Bankdaten,
Datenschutz-Kontakt erweitert. person-grid bekommt $names-Filter, partner-grid
einen Intro-Stil. Seiten setzen $meta['schema'] via team_/page_schema.
Styles für alle neuen Komponenten in components.css.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KDQZ6FuchNUh2bxSW9PeNv
This commit is contained in:
2026-06-19 08:13:04 +02:00
parent a933b76c4f
commit 3b6f630a72
81 changed files with 2513 additions and 78 deletions

261
app/pages/datenschutz.php Normal file
View File

@@ -0,0 +1,261 @@
<?php
declare(strict_types=1);
/**
* Datenschutzerklärung — zugeschnitten auf den tatsächlichen Stack:
* komplett self-hosted, keine Tracker/Analyse/Werbe-Dienste, keine externen
* Fonts/Maps/Embeds. Einzige Verarbeitungen: Server-Logs (Hoster),
* Kontaktformular (Versand via Brevo SMTP), server-seitig gecachter
* Instagram-Feed (Bilder von unserer Domain). Vereinsdaten aus club.json.
*/
$club = json_load('club');
$addr = $club['address'] ?? [];
$dpo = $club['data_protection_contact'] ?? '';
$meta = [
'title' => 'Datenschutzerklärung',
'description' => 'Datenschutzerklärung des TSV 1908 Kulmbach e. V. welche Daten beim Besuch unserer Website verarbeitet werden. Komplett self-hosted, ohne Tracking und ohne Drittanbieter-Dienste im Browser.',
'schema' => page_schema([
['name' => 'Startseite', 'slug' => ''],
['name' => 'Datenschutz', 'slug' => 'datenschutz'],
]),
];
?>
<section class="section legal">
<div class="container">
<div class="legal__head">
<p class="legal__kicker">Rechtliches</p>
<h1>Datenschutzerklärung</h1>
<p class="legal__lead">
Der Schutz deiner persönlichen Daten ist uns wichtig. Diese Website ist
bewusst datensparsam gebaut: Sie lädt keine externen Schriften, Karten,
Skripte oder Tracking-Dienste dein Browser kontaktiert ausschließlich
unseren eigenen Server.
</p>
</div>
<div class="legal__body">
<section>
<h2>Verantwortlicher</h2>
<p>Verantwortlich für die Datenverarbeitung auf dieser Website ist:</p>
<div class="legal__card">
<address>
<strong><?= e($club['legal_name']) ?></strong><br>
<?= e($addr['street']) ?><br>
<?= e($addr['zip']) ?> <?= e($addr['city']) ?><br>
<br>
E-Mail: <a href="mailto:<?= e($club['email']) ?>"><?= e($club['email']) ?></a>
</address>
</div>
<?php if ($dpo !== ''): ?>
<p class="legal__muted">
Ansprechpartner für Fragen zum Datenschutz: <?= e($dpo) ?>,
erreichbar unter <a href="mailto:<?= e($club['email']) ?>"><?= e($club['email']) ?></a>.
</p>
<?php endif; ?>
</section>
<section>
<h2>Grundsätzliches</h2>
<p>
Wir verarbeiten personenbezogene Daten nur im Rahmen der geltenden
Datenschutzgesetze, insbesondere der Datenschutz-Grundverordnung (DSGVO)
und des Bundesdatenschutzgesetzes (BDSG). „Personenbezogene Daten“ sind
alle Informationen, die sich auf eine identifizierte oder identifizierbare
Person beziehen. Eine Nutzung unserer Website ist grundsätzlich ohne Angabe
personenbezogener Daten möglich.
</p>
</section>
<section>
<h2>Aufruf der Website &amp; Server-Logfiles</h2>
<p>
Unsere Website wird bei folgendem Dienstleister gehostet:
</p>
<div class="legal__card">
<address>
<strong>ALL-INKL.COM Neue Medien Münnich</strong><br>
Inhaber: René Münnich<br>
Hauptstraße 68<br>
02742 Friedersdorf
</address>
</div>
<p>
Bei jedem Aufruf unserer Website werden durch unseren Webhoster automatisch
Informationen erfasst, die dein Browser übermittelt und die technisch
erforderlich sind, um die Seite auszuliefern. Erfasst werden:
</p>
<ul>
<li>die aufgerufene Adresse (URL) und die zuvor besuchte Seite (Referrer)</li>
<li>Datum und Uhrzeit des Zugriffs</li>
<li>verwendeter Browser und Betriebssystem</li>
<li>die IP-Adresse des anfragenden Geräts</li>
</ul>
<p>
Diese Daten dienen ausschließlich dem technischen Betrieb, der Sicherheit
und der Stabilität der Website und werden nicht mit anderen Datenquellen
zusammengeführt. Rechtsgrundlage ist unser berechtigtes Interesse an einer
sicheren und funktionsfähigen Website (Art. 6 Abs. 1 lit. f DSGVO). Die
Logdaten werden nach kurzer Zeit automatisch gelöscht.
</p>
<p class="legal__muted">
Unser Webhoster verarbeitet diese Daten in unserem Auftrag auf Grundlage
eines Vertrags zur Auftragsverarbeitung (Art. 28 DSGVO).
</p>
</section>
<section>
<h2>Verschlüsselung (SSL/TLS)</h2>
<p>
Diese Website nutzt aus Sicherheitsgründen eine SSL- bzw. TLS-Verschlüsselung.
Eine verschlüsselte Verbindung erkennst du am „https://“ in der Adresszeile
deines Browsers. Daten, die du an uns übermittelst, können dadurch nicht ohne
Weiteres von Dritten mitgelesen werden.
</p>
</section>
<section>
<h2>Cookies</h2>
<p>
Diese Website setzt <strong>keine Cookies zu Analyse-, Marketing- oder
Tracking-Zwecken</strong> und bindet keine Dienste ein, die solche Cookies
setzen würden. Aus diesem Grund benötigen wir auch kein Cookie-Banner.
</p>
</section>
<section>
<h2>Kontaktformular &amp; Kontaktaufnahme</h2>
<p>
Wenn du uns über das Kontaktformular oder per E-Mail kontaktierst, verarbeiten
wir die von dir angegebenen Daten, um deine Anfrage zu bearbeiten. Über das
Formular sind das:
</p>
<ul>
<li>Name (Pflichtangabe)</li>
<li>E-Mail-Adresse (Pflichtangabe)</li>
<li>Telefonnummer (freiwillig)</li>
<li>dein Interessensgebiet, Betreff und deine Nachricht</li>
</ul>
<p>
Rechtsgrundlage ist deine Einwilligung (Art. 6 Abs. 1 lit. a DSGVO), die du
mit dem Absenden erteilst, sowie unser berechtigtes Interesse bzw. die
Anbahnung eines (Mitgliedschafts-)Verhältnisses an der Beantwortung deiner
Anfrage (Art. 6 Abs. 1 lit. f und b DSGVO). Die Daten werden gespeichert, bis
deine Anfrage abschließend bearbeitet ist und keine gesetzlichen
Aufbewahrungspflichten entgegenstehen.
</p>
<p>
Für den technischen Versand der Formular-Nachrichten als E-Mail nutzen wir den
Dienstleister Brevo (Sendinblue GmbH, Köln) als Auftragsverarbeiter. Dabei
werden die im Formular angegebenen Daten an die Mailserver von Brevo
übermittelt. Die Übertragung erfolgt verschlüsselt.
</p>
<p class="legal__muted">
Hinweis: Zum Schutz vor automatisiertem Spam verwenden wir ein verstecktes
Pflichtfeld sowie einen signierten Zeitstempel. Dabei werden keine
zusätzlichen personenbezogenen Daten erhoben und keine externen Dienste
(z.&nbsp;B. reCAPTCHA) eingebunden.
</p>
</section>
<section>
<h2>Keine Analyse-, Tracking- oder Werbedienste</h2>
<p>
Wir verzichten bewusst vollständig auf Dienste, die dein Verhalten
auswerten oder Daten an Dritte weitergeben. Insbesondere setzen wir
<strong>nicht</strong> ein:
</p>
<ul>
<li>keine Webanalyse (z.&nbsp;B. Google Analytics, Matomo, Hotjar)</li>
<li>keine externen Schriftarten alle Fonts liegen auf unserem Server</li>
<li>keine eingebetteten Karten (z.&nbsp;B. Google Maps) und keine Video-Embeds</li>
<li>keine Social-Media-Plugins, „Like“-Buttons oder Tracking-Pixel</li>
<li>keine Werbenetzwerke oder Conversion-Tracking</li>
</ul>
</section>
<section>
<h2>Instagram-Inhalte auf dieser Website</h2>
<p>
Auf unserer Website zeigen wir aktuelle Beiträge unseres öffentlichen
Instagram-Profils. Diese Inhalte werden <strong>nicht</strong> über ein
Instagram-Plugin oder einen externen Einbettungscode geladen. Stattdessen
rufen wir die Beiträge in regelmäßigen Abständen serverseitig ab, speichern
sie auf unserem eigenen Server und liefern Bilder und Texte ausschließlich von
unserer Domain aus. Beim Ansehen unserer Website wird dadurch
<strong>keine Verbindung zu Instagram oder Meta hergestellt</strong> und es
werden keine Daten an diese Anbieter übertragen. Erst wenn du aktiv einen
Link zu Instagram anklickst, verlässt du unsere Website (siehe nächster
Abschnitt).
</p>
</section>
<section>
<h2>Externe Links &amp; Social Media</h2>
<p>
Unsere Website enthält Links zu externen Angeboten, etwa zu unseren Profilen
bei Instagram und Facebook oder zu einer Routenplanung über Google Maps. Wenn
du einen solchen Link anklickst, verlässt du unsere Website und es gelten die
Datenschutzbestimmungen des jeweiligen Anbieters. Auf deren Datenverarbeitung
haben wir keinen Einfluss.
</p>
</section>
<section>
<h2>Foto- und Videoaufnahmen</h2>
<p>
Im Rahmen unseres Vereinslebens, von Spielen und Veranstaltungen entstehen
Foto- und Videoaufnahmen, die wir zur Darstellung des Vereins auf dieser
Website, in unseren Social-Media-Kanälen und in Printmedien verwenden. Die
Veröffentlichung erfolgt auf Grundlage einer Einwilligung
(Art. 6 Abs. 1 lit. a DSGVO) bzw. unseres berechtigten Interesses an der
Vereinsöffentlichkeitsarbeit (Art. 6 Abs. 1 lit. f DSGVO). Wenn du mit der
Veröffentlichung einer dich zeigenden Aufnahme nicht einverstanden bist,
genügt eine formlose Nachricht an
<a href="mailto:<?= e($club['email']) ?>"><?= e($club['email']) ?></a> wir
entfernen die entsprechende Aufnahme dann zeitnah.
</p>
</section>
<section>
<h2>Deine Rechte</h2>
<p>Dir stehen hinsichtlich deiner personenbezogenen Daten folgende Rechte zu:</p>
<ul>
<li>Recht auf Auskunft (Art. 15 DSGVO)</li>
<li>Recht auf Berichtigung (Art. 16 DSGVO)</li>
<li>Recht auf Löschung (Art. 17 DSGVO)</li>
<li>Recht auf Einschränkung der Verarbeitung (Art. 18 DSGVO)</li>
<li>Recht auf Datenübertragbarkeit (Art. 20 DSGVO)</li>
<li>Recht auf Widerspruch gegen die Verarbeitung (Art. 21 DSGVO)</li>
</ul>
<p>
Eine erteilte Einwilligung kannst du jederzeit mit Wirkung für die Zukunft
widerrufen. Zur Ausübung deiner Rechte genügt eine Nachricht an die oben
genannten Kontaktdaten.
</p>
<p>
Außerdem hast du das Recht, dich bei einer Datenschutz-Aufsichtsbehörde zu
beschweren. Die für uns zuständige Behörde ist:
</p>
<div class="legal__card">
<address>
<strong>Bayerisches Landesamt für Datenschutzaufsicht (BayLDA)</strong><br>
Promenade 18<br>
91522 Ansbach
</address>
</div>
</section>
<section>
<h2>Aktualität dieser Datenschutzerklärung</h2>
<p class="legal__muted">
Stand: <?= e(date('m/Y')) ?>. Durch die Weiterentwicklung unserer Website
oder geänderte gesetzliche Vorgaben kann es nötig werden, diese
Datenschutzerklärung anzupassen. Es gilt jeweils die hier veröffentlichte
aktuelle Fassung.
</p>
</section>
</div>
</div>
</section>

53
app/pages/fussball.php Normal file
View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
/**
* Fußball-Übersichtsseite (Hub). Inhalt: data/fussball.json + data/teams.json.
* Struktur: Hero → Mannschafts-Karten → Ansprechpartner → CTA → FAQ.
*/
$page = json_load('fussball');
$teams = json_load('teams');
// Karten verlinken auf die vier Unterseiten (3 Senior + Jugend).
$cards = [
['name' => '1. Mannschaft', 'slug' => 'fussball/erste-mannschaft', 'category' => 'Herren', 'league' => 'Kreisklasse', 'image' => $teams['erste-mannschaft']['team_photo']['image'] ?? $teams['erste-mannschaft']['hero']['image']],
['name' => '2. Mannschaft', 'slug' => 'fussball/zweite-mannschaft', 'category' => 'Herren', 'image' => $teams['zweite-mannschaft']['hero']['image']],
['name' => 'Damenmannschaft', 'slug' => 'fussball/damen', 'category' => 'Damen', 'image' => $teams['damen']['hero']['image']],
['name' => 'Jugendfußball', 'slug' => 'jugendfussball', 'category' => 'G- bis C-Jugend', 'image' => [
'base' => 'img/pages/jugendfussball-hero', 'widths' => [640, 1000, 1440], 'alt' => 'Jugendfußball des TSV 08 Kulmbach',
]],
];
$meta = [
'title' => 'Fußball in Kulmbach',
'description' => 'Herren-, Damen- und Jugendfußball beim TSV 08 Kulmbach: erste und zweite Mannschaft auf Kreisklasse-Niveau, Damenmannschaft und Nachwuchs aktiv werden im Katzbachtal.',
'og_image' => 'img/pages/fussball-hero-1600.jpg',
'schema' => page_schema(
[
['name' => 'Startseite', 'slug' => ''],
['name' => 'Fußball', 'slug' => 'fussball'],
],
$page['faq'] ?? []
),
];
component('hero', ['hero' => $page['hero']]);
component('team-cards', [
'teams' => $cards,
'intro' => $page['mannschaften_intro'] ?? '',
'title_hidden' => true,
'intro_below' => true,
]);
component('person-grid', [
'departments' => ['Herrenfußball', 'Damenfußball'],
// Auf dem Hub bewusst nur die beiden Haupt-Ansprechpartner (mannschaftsspezifische
// Zusatzkontakte wie Rustem erscheinen auf der jeweiligen Team-Seite).
'names' => ['Benedikt Höfner', 'Sam Kern'],
'title' => 'Ansprechpartner Fußball',
'intro' => 'Fragen zu Training, Probetraining oder einem Wechsel? Sprich direkt unsere Verantwortlichen an.',
'anchor' => 'kontakt',
]);
component('faq', ['faq' => $page['faq'] ?? []]);

View File

@@ -26,4 +26,5 @@ foreach ($home['sections'] as $section) {
component('stats', ['stats' => $home['stats']]);
component('partner-grid', ['intro' => $home['partners']]);
component('person-grid');
component('contact-form', ['intro' => $home['contact']]);

139
app/pages/impressum.php Normal file
View File

@@ -0,0 +1,139 @@
<?php
declare(strict_types=1);
/**
* Impressum — Angaben gemäß § 5 DDG, Vertretungsberechtigter Vorstand,
* Bankverbindung, Haftungs- und Urheberrechtshinweise.
* Alle Vereinsdaten aus data/club.json (Single Source of Truth).
*/
$club = json_load('club');
$addr = $club['address'] ?? [];
$chair = $club['board']['members'][0]['name'] ?? '';
$meta = [
'title' => 'Impressum',
'description' => 'Impressum des TSV 1908 Kulmbach e. V. Anbieterkennzeichnung, vertretungsberechtigter Vorstand und Kontaktdaten.',
'schema' => page_schema([
['name' => 'Startseite', 'slug' => ''],
['name' => 'Impressum', 'slug' => 'impressum'],
]),
];
?>
<section class="section legal">
<div class="container">
<div class="legal__head">
<p class="legal__kicker">Rechtliches</p>
<h1>Impressum</h1>
<p class="legal__lead">Angaben gemäß § 5 Digitale-Dienste-Gesetz (DDG).</p>
</div>
<div class="legal__body">
<section>
<h2>Anbieter</h2>
<div class="legal__card">
<address>
<strong><?= e($club['legal_name']) ?></strong><br>
<?= e($addr['street']) ?><br>
<?= e($addr['zip']) ?> <?= e($addr['city']) ?><br>
<br>
E-Mail: <a href="mailto:<?= e($club['email']) ?>"><?= e($club['email']) ?></a><br>
Web: <a href="<?= e(config('base_url')) ?>"><?= e(preg_replace('#^https?://#', '', (string) config('base_url'))) ?></a>
</address>
</div>
</section>
<section>
<h2>Vertretungsberechtigter Vorstand</h2>
<p><?= e($club['board']['note']) ?>:</p>
<ul>
<?php foreach ($club['board']['members'] as $member): ?>
<li><?= e($member['name']) ?><?= $member['role'] !== '' ? ' ' . e($member['role']) : '' ?></li>
<?php endforeach; ?>
</ul>
</section>
<section>
<h2>Bankverbindung</h2>
<div class="legal__cards legal__cards--2">
<?php foreach ($club['banking'] as $bank): ?>
<div class="legal__card">
<p>
<strong><?= e($bank['bank']) ?></strong><br>
IBAN: <?= e($bank['iban']) ?><br>
BIC: <?= e($bank['bic']) ?>
</p>
</div>
<?php endforeach; ?>
</div>
</section>
<section>
<h2>Mitgliedschaften</h2>
<ul>
<?php foreach ($club['memberships'] as $membership): ?>
<li><?= e($membership) ?></li>
<?php endforeach; ?>
</ul>
</section>
<section>
<h2>Verantwortlich für den Inhalt</h2>
<p>Verantwortlich für den Inhalt nach § 18 Abs. 2 Medienstaatsvertrag (MStV):</p>
<div class="legal__card">
<address>
<?php if ($chair !== ''): ?>
<strong><?= e($chair) ?></strong><br>
<?php endif; ?>
<?= e($club['legal_name']) ?><br>
<?= e($addr['street']) ?>, <?= e($addr['zip']) ?> <?= e($addr['city']) ?>
</address>
</div>
</section>
<section>
<h2>Urheberrecht</h2>
<p>
Alle Rechte vorbehalten. Sämtliche auf dieser Website veröffentlichten Bilder,
Texte und sonstigen Dateien unterliegen dem Urheberrecht. Eine Verwendung,
Vervielfältigung oder Weitergabe auch auszugsweise ist nur mit ausdrücklicher,
vorheriger Zustimmung des TSV 1908 Kulmbach e. V. gestattet. Soweit Inhalte auf
dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter
beachtet und entsprechend gekennzeichnet. Sollte dir dennoch eine
Urheberrechtsverletzung auffallen, bitten wir um einen Hinweis bei Bekanntwerden
entfernen wir die betreffenden Inhalte umgehend.
</p>
</section>
<section>
<h2>Haftung für Inhalte</h2>
<p>
Die Inhalte dieser Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit,
Vollständigkeit und Aktualität der Inhalte können wir jedoch keine Gewähr übernehmen.
Als Diensteanbieter sind wir gemäß § 7 Abs. 1 DDG für eigene Inhalte auf diesen Seiten
nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 DDG sind wir als
Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde
Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige
Tätigkeit hinweisen.
</p>
</section>
<section>
<h2>Haftung für Links</h2>
<p>
Unser Angebot enthält Links zu externen Websites Dritter, auf deren Inhalte wir keinen
Einfluss haben. Für die Gestaltung und die Inhalte der gelinkten Seiten sind
ausschließlich deren Betreiber verantwortlich. Zum Zeitpunkt der Verlinkung waren keine
rechtswidrigen Inhalte erkennbar. Sollten uns Rechtsverletzungen bekannt werden,
entfernen wir die entsprechenden Links umgehend. Hiermit distanzieren wir uns
ausdrücklich von allen Inhalten sämtlicher verlinkter Seiten.
</p>
</section>
<section>
<h2>Gestaltung &amp; Umsetzung</h2>
<p class="legal__muted">Webdesign und Layout: <?= e($club['webdesign']) ?>.</p>
</section>
</div>
</div>
</section>

View File

@@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
/**
* Jugendfußball-Übersichtsseite. Inhalt: data/jugend.json.
* Komposition: Hero → Intro-Bento (Bild, Mitmachen, Spielort, Altersklassen) →
* Altersklassen-Karten → Ansprechpartner → CTA → FAQ.
*/
$page = json_load('jugend');
$club = json_load('club');
$addr = $club['address'] ?? [];
$mapsQuery = rawurlencode(trim(($addr['venue'] ?? '') . ', ' . ($addr['street'] ?? '') . ', ' . ($addr['zip'] ?? '') . ' ' . ($addr['city'] ?? ''), ', '));
$meta = [
'title' => 'Jugendfußball in Kulmbach',
'description' => 'Jugendfußball in Kulmbach entdecke unsere Mannschaften von der G- bis zur C-Jugend, Betreuer und Trainingszeiten. Probiere Fußball in familiärer Atmosphäre aus.',
'og_image' => 'img/pages/jugendfussball-hero-1440.jpg',
'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('person-grid', [
'departments' => ['Jugendfußball'],
'title' => 'Ansprechpartner Jugendfußball',
'intro' => 'Fragen zum Schnuppertraining oder zur passenden Altersgruppe? Melde dich direkt.',
'anchor' => 'kontakt',
]);
component('cta-band', ['band' => [
'title' => 'Neugierig geworden?',
'text' => 'Komm mit deinem Kind zum kostenlosen Schnuppertraining ganz unverbindlich.',
'ctas' => [
['label' => 'Zum Ansprechpartner', 'slug' => 'jugendfussball#kontakt', 'style' => 'primary'],
['label' => 'Mitglied werden', 'slug' => 'mitglied-werden', 'style' => 'outline'],
],
]]);
component('faq', ['faq' => $page['faq'] ?? []]);

18
app/pages/team-damen.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
/**
* Damenmannschaft (Damenfußball). Inhalt: data/teams.json → damen.
*/
$slug = 'fussball/damen';
$team = json_load('teams')['damen'];
$meta = [
'title' => 'Damenmannschaft Damenfußball Kulmbach',
'description' => $team['hero']['text'],
'og_image' => $team['hero']['image']['base'] . '-1600.jpg',
'schema' => team_schema($team, $slug),
];
component('team', ['team' => $team, 'slug' => $slug]);

18
app/pages/team-erste.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
/**
* 1. Mannschaft (Herrenfußball). Inhalt: data/teams.json → erste-mannschaft.
*/
$slug = 'fussball/erste-mannschaft';
$team = json_load('teams')['erste-mannschaft'];
$meta = [
'title' => '1. Mannschaft Herrenfußball Kreisklasse Kulmbach',
'description' => $team['hero']['text'],
'og_image' => $team['hero']['image']['base'] . '-1600.jpg',
'schema' => team_schema($team, $slug),
];
component('team', ['team' => $team, 'slug' => $slug]);

19
app/pages/team-zwei.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
/**
* 2. Mannschaft (Herrenfußball). Inhalt: data/teams.json → zweite-mannschaft.
*/
$slug = 'fussball/zweite-mannschaft';
$team = json_load('teams')['zweite-mannschaft'];
$meta = [
'title' => '2. Mannschaft Herrenfußball Kulmbach',
'description' => $team['hero']['text'],
'og_image' => $team['hero']['image']['base'] . '-1600.jpg',
'scripts' => (count($team['contact_names'] ?? []) > 1) ? ['contact-slider.js'] : [],
'schema' => team_schema($team, $slug),
];
component('team', ['team' => $team, 'slug' => $slug]);

84
app/pages/verein.php Normal file
View File

@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
/**
* Vereins-Übersichtsseite (Hub). Inhalt: data/verein.json + data/club.json.
* Struktur: Hero → Eckdaten (key-facts) → Leitbild (split) → Abteilungs-Kacheln →
* Gelände/Drohnenbild → CTA → FAQ.
*/
$page = json_load('verein');
$club = json_load('club');
$addr = $club['address'] ?? [];
$mapsQuery = rawurlencode(trim(($addr['venue'] ?? '') . ', ' . ($addr['street'] ?? '') . ', ' . ($addr['zip'] ?? '') . ' ' . ($addr['city'] ?? ''), ', '));
// Zwei Abteilungs-Kacheln. Turnen verlinkt bereits auf /turnen (Seite folgt).
$cards = [
[
'name' => 'Fußball',
'slug' => 'fussball',
'category' => 'Herren · Damen · Jugend',
'image' => ['base' => 'img/pages/fussball-hero', 'widths' => [640, 1000, 1600], 'alt' => 'Fußball beim TSV 08 Kulmbach'],
],
[
'name' => 'Turnabteilung',
'slug' => 'turnen',
'category' => 'Turnen · Trampolin',
'image' => ['base' => 'img/pages/turnen', 'widths' => [640, 1000], 'alt' => 'Turnabteilung des TSV 08 Kulmbach'],
],
];
$meta = [
'title' => 'Der Verein',
'description' => 'Der TSV 1908 Kulmbach e. V. seit 1908 dein Sportverein im Katzbachtal in Kulmbach. Über 650 Mitglieder, die Abteilungen Fußball und Turnen, zuhause auf der Hans-Rausch-Sportanlage.',
'og_image' => 'img/pages/vereinsgelaende-1600.jpg',
'schema' => page_schema(
[
['name' => 'Startseite', 'slug' => ''],
['name' => 'Der Verein', 'slug' => 'verein'],
],
$page['faq'] ?? []
),
];
component('hero', ['hero' => $page['hero']]);
component('key-facts', ['facts' => $page['facts'] ?? [], 'anchor' => 'eckdaten']);
component('section', ['section' => $page['about']]);
component('team-cards', [
'teams' => $cards,
'title' => 'Unsere Abteilungen',
'intro' => $page['abteilungen_intro'] ?? '',
'intro_below' => true,
'anchor' => 'abteilungen',
]);
?>
<section class="section facility" id="gelaende">
<div class="container">
<h2><?= e($page['gelaende']['title']) ?></h2>
<p class="facility__lead"><?= e($page['gelaende']['text']) ?></p>
<figure class="facility__figure">
<?php component('img', ['image' => $page['gelaende']['image'], 'sizes' => '(max-width: 1200px) 100vw, 1200px', 'class' => 'facility__img']); ?>
<?php if (!empty($page['gelaende']['caption'])): ?>
<figcaption class="facility__caption"><?= e($page['gelaende']['caption']) ?></figcaption>
<?php endif; ?>
</figure>
<p class="facility__actions">
<a class="btn btn--outline" 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>
</p>
</div>
</section>
<?php
component('cta-band', ['band' => [
'title' => 'Werde Teil des TSV 08',
'text' => 'Ob Fußball oder Turnen komm unverbindlich vorbei oder schreib uns. Wir finden gemeinsam die passende Gruppe für dich.',
'ctas' => [
['label' => 'Mitglied werden', 'slug' => 'mitglied-werden', 'style' => 'primary'],
['label' => 'Kontakt aufnehmen', 'slug' => '#kontakt', 'style' => 'outline'],
],
]]);
component('faq', ['faq' => $page['faq'] ?? []]);