Files
tsv08kulmbach-website/app/pages/turnen.php
fs 921a55635c Wartelisten-Hinweis für Tiger und Hühner, über dem Anfrageformular
Die Turnabteilung (Maxi) beantwortet laufend Anfragen nach einem Wartelistenplatz
für „Tiger" und „Hühner", den es nicht gibt. Auf der alten Seite stand der Hinweis
direkt über dem Anfrageformular, hier fehlte er.

Schlimmer: an der Stelle stand das GEGENTEIL. Der bisherige Hinweis lautete
"Aktuell sind alle Kinderturngruppen belegt. Bei Interesse setzen wir sie gerne
auf die Warteliste." — für alle Kindergruppen, also auch für die beiden, die
keine Liste führen. Der Satz hat einen Teil der Anfragen vermutlich erst erzeugt.
Er ist nicht gelöscht, sondern auf die übrigen Gruppen eingegrenzt und aufs Du
umgestellt (Haus-Stil; vorher stand dort klein "sie").

Der Text steht genau EINMAL, in data/turnen.json unter
disciplines.eltern-kind-turnen.notice + notice_title. Zwei Stellen lesen ihn:
die rote Kachel auf /turnen/eltern-kind-turnen (gab es schon) und neu ein Block
direkt über dem Formular auf /turnen. Ändert die Abteilung die Lage, ist das eine
Zeile in einer Datei.

Umsetzung:
- notice_title ist neu, weil eine rote Fläche ohne Überschrift wie eine
  Fehlermeldung liest. Abel statt Coolvetica, der Schnitt ist bei ~19px in
  Versalien unleserlich (CLAUDE.md, Design).
- Der Block steht AUSSERHALB des <form> und damit außerhalb der
  role="status"-Region: ein dauerhafter Hinweis, keine Rückmeldung zum Absenden.
  In der Live-Region läse ihn ein Screenreader bei jeder Formularmeldung erneut
  vor. Kein role="alert", er steht schon beim Laden da.
- Überschrift als h3 unter der h2 des Intro-Blocks, damit die Folge nicht springt.
- .contact__notice übernimmt bewusst die Optik von .turnen-dash__notice, damit
  beide Stellen als derselbe Hinweis erkennbar sind. Weiß auf --clr-accent
  erreicht 4,92:1 und trägt damit Fließtext (WCAG 1.4.3). Kommt ein dritter Ort
  dazu, gehören die gemeinsamen Eigenschaften in eine geteilte .notice-Klasse;
  für zwei wäre das verfrüht.

Gemessen: Hinweisbreite gleich Formularbreite (720px bei 1280, 347px bei 390),
kein Überlauf. preflight ohne neue Meldungen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
2026-07-31 21:54:10 +02:00

111 lines
6.6 KiB
PHP

<?php
declare(strict_types=1);
/**
* Turn-Übersichtsseite (Hub + Beiträge + Abteilungskontakt). Inhalt: data/turnen.json.
* Struktur: Hero → Disziplin-Karten → Beiträge → FAQ → Anfrageformular.
*
* Hier stand vorher „Die Detailinhalte (Beiträge, Trainingszeiten) leben auf den
* Disziplin-Unterseiten" — das war falsch, und zwar folgenreich: die Seite gab
* fees/austritt/faq NIE aus, die Unterseiten auch nicht, und damit standen die
* Turn-Beiträge NIRGENDS auf der Website (nachgeprüft 31.07.2026: 0 Treffer auf
* /turnen und allen fünf Unterseiten; /mitglied-werden führt nur die Fußball-
* Beiträge). Die Turnabteilung verlinkt diese Angaben in Einladungen für neue
* Familien, deshalb ist der Beitragsblock hier verankert (#beitraege).
* Die Daten selbst stimmen 1:1 mit der alten Seite überein (gegengeprüft an
* 2024.tsv08kulmbach.de): Zusatzbeitrag 24/48 €, Neumitglieder 84/94/184 €,
* Förderstufen 120/180/240 €, Austritt zum 30. September.
*
* NOCH unbenutzt: overview.cta („Lust aufs Turnen bekommen?"). Der Block verlinkt
* „Zur Turn-Übersicht" und gehört damit auf die Disziplin-Unterseiten, nicht hierher
* — auf der Übersicht wäre das ein Selbstlink.
*
* Das Formular ist die allgemeine contact-form-Komponente mit
* department => 'turnen': Auswahlliste sind die Disziplinen, Empfänger ist die
* Turnabteilung (club.email_turnen) statt info@. Die alte Seite hatte dafür ein
* eigenes, zweites Formular — hier ist es dieselbe Komponente und dieselbe
* Action, damit der Spam-Schutz nicht doppelt gepflegt werden muss.
*/
$page = json_load('turnen')['overview'];
// Heros aller Turn-Seiten zeigen VORÜBERGEHEND das Drohnen-Luftbild des
// Vereinsgeländes (img/pages/vereinsgelaende, Quelle: data/turnen.json) statt des
// Fußballplatz-Bildes. Ehrlicher wäre ein Bild aus der Turnhalle — liegt eines
// vor, tauschen die sechs Hero-Blöcke in data/turnen.json und das og_image der
// sechs Seiten-Dateien. Die Übersichts-Kacheln zeigen weiter die (vorläufigen)
// themenbezogenen Platzhalter aus public/assets/img/pages/.
$cards = [
['name' => 'Erwachsenenturnen', 'slug' => 'turnen/erwachsenenturnen', 'category' => 'Mäximum Gym', 'image' => ['base' => 'img/pages/turnen-erwachsenenturnen', 'widths' => [640, 1000, 1600], 'alt' => 'Erwachsenenturnen beim TSV 08 Kulmbach']],
['name' => 'Eltern-Kind- & Kinderturnen', 'slug' => 'turnen/eltern-kind-turnen', 'category' => 'ab ca. 2 Jahren', 'image' => ['base' => 'img/pages/turnen-eltern-kind', 'widths' => [640, 1000, 1600], 'alt' => 'Eltern-Kind- und Kinderturnen beim TSV 08 Kulmbach']],
['name' => 'Fitness & Pilates', 'slug' => 'turnen/fitness-pilates', 'category' => 'Max-Hundt-Schule', 'image' => ['base' => 'img/pages/turnen-fitness-pilates', 'widths' => [640, 1000, 1600], 'alt' => 'Fitness und Pilates beim TSV 08 Kulmbach']],
['name' => 'Trampolinturnen', 'slug' => 'turnen/trampolin', 'category' => 'Carl-von-Linde-Realschule', 'image' => ['base' => 'img/pages/turnen-trampolin', 'widths' => [640, 1000, 1600], 'alt' => 'Trampolinturnen beim TSV 08 Kulmbach']],
['name' => 'Wettkampfturnen', 'slug' => 'turnen/wettkampfturnen', 'category' => 'Leistungssport', 'image' => ['base' => 'img/pages/turnen-wettkampf', 'widths' => [640, 1000, 1600], 'alt' => 'Wettkampfturnen beim TSV 08 Kulmbach']],
];
$meta = [
'title' => 'Turnen in Kulmbach',
'description' => 'Die Turnabteilung des TSV 08 Kulmbach: Eltern-Kind- und Kinderturnen, Erwachsenenturnen, Fitness und Pilates, Trampolin- und Wettkampfturnen.',
'og_image' => 'img/pages/vereinsgelaende-1600.jpg',
// Zweiter Parameter = FAQ: sichtbare Fragen und FAQPage-Schema kommen aus
// derselben Quelle, damit sie nie auseinanderlaufen (CLAUDE.md).
'schema' => page_schema([
['name' => 'Startseite', 'slug' => ''],
['name' => 'Turnen', 'slug' => 'turnen'],
], $page['faq'] ?? []),
];
component('hero', ['hero' => $page['hero']]);
component('team-cards', [
'teams' => $cards,
'title' => 'Unsere Turngruppen',
'title_hidden' => true,
'intro' => $page['cards_intro'] ?? null,
'anchor' => 'gruppen',
]);
?>
<?php /* Beiträge. Der Anker #beitraege ist die Adresse, die die Turnabteilung in
Einladungen weitergibt — nicht umbenennen. Drei Tabellen über die
bestehende fee-table-Komponente (dieselbe wie auf /mitglied-werden),
darunter die Austrittsregel, weil sie zur Beitragsfrage gehört. */ ?>
<section class="section section--tinted fees" id="beitraege">
<div class="container">
<header class="fees__head">
<h2><?= e($page['fees_title']) ?></h2>
<?php if (!empty($page['fees_intro'])): ?>
<p class="fees__intro"><?= e($page['fees_intro']) ?></p>
<?php endif; ?>
</header>
<div class="fee-tables">
<?php foreach ($page['fees'] as $feeTable): ?>
<?php component('fee-table', ['fees' => $feeTable]); ?>
<?php endforeach; ?>
</div>
<?php /* Bewusst NICHT .prose: dort rendert ein h3 mit 21px Abel, also exakt
Fließtextgröße — in Impressum und Artikeln richtig, hier ist „Austritt"
aber eine Auszeichnung und wäre nicht von Fließtext zu unterscheiden. */ ?>
<?php if (!empty($page['austritt']['title'])): ?>
<div class="fees__note">
<h3 class="fees__note-title"><?= e($page['austritt']['title']) ?></h3>
<p><?= inline_links_html($page['austritt']['text']) ?></p>
</div>
<?php endif; ?>
</div>
</section>
<?php
component('faq', ['faq' => $page['faq'] ?? []]);
/* Der Wartelisten-Hinweis steht DIREKT über dem Formular, so wie auf der alten Seite.
Grund ist Arbeitsaufwand in der Abteilung, kein Design: fuer „Tiger" und „Huehner"
kommen laufend Anfragen nach einem Wartelistenplatz, den es nicht gibt, und jede muss
einzeln beantwortet werden. Wer hier schreibt, soll es vorher lesen. Der Text kommt aus
derselben Stelle wie die Kachel auf der Kinderturn-Unterseite
(disciplines.eltern-kind-turnen.notice), ein Hinweis und eine Quelle. */
$kinderturnen = json_load('turnen')['disciplines']['eltern-kind-turnen'] ?? [];
component('contact-form', [
'intro' => $page['contact'],
'return' => 'turnen',
'department' => 'turnen',
'notice' => $kinderturnen['notice'] ?? '',
'noticeTitle' => $kinderturnen['notice_title'] ?? '',
]);