Eva Wünsch aus der Turnabteilung am 31.07.2026: „Der Sternchentext müsste eigentlich sein, dass die Person mit dem Sternchen Übungsleiter ist. Von daher müsste vor den Namen 'Trainerteam' stehen. Einige sind auch nicht ÜL." Ich hatte davon nur die Fußnote erledigt. Das Label blieb „Übungsleitung" und damit stand die falsche Aussage weiter auf der Seite: neun namentlich genannte Personen liefen unter „Übungsleitung", vier davon sind es. Das ist keine Formulierungsfrage, die Seite behauptete etwas über echte Menschen. Label jetzt „Trainerteam:" an beiden Stellen (Trainingszeit und Gruppe), der Stern bleibt die Auszeichnung und die Fußnote erklärt ihn. So stand es auch auf der alten Seite: „TRAINERTEAM (* = ÜBUNGSLEITER)". Ein Kommentar an der Stelle sagt, warum es nicht zurückbenannt werden darf. Dabei fiel ein zweiter Datenfehler auf: die alte Seite führt „Annelie Frisque*, Eva Wünsch*", bei uns stand Eva Wünsch ohne Stern. Sie ist Übungsleiterin. Geprüft: „Übungsleitung" kommt auf keiner der sechs Turn-Seiten mehr vor, die Grashüpfer-Zeile lautet jetzt Zeichen für Zeichen wie in Evas Screenshot. Die Fußnote erscheint nur in Sektionen mit mehreren Gruppen — nachgezählt, dass beide Disziplinen mit Sternchen-Namen mehrere Gruppen haben, die Einzelgruppen-Disziplinen tragen keine Sterne. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
284 lines
14 KiB
PHP
284 lines
14 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Turn-Disziplin im einheitlichen Bento-Look (wie die Mannschaftsseiten). Props:
|
|
* $location array{venue, street?, zip?, city?} (optional) — Trainingsort + „Route planen"
|
|
* $lead string (optional) — Ansprechperson der Disziplin (Akzent-Kachel)
|
|
* $notice string (optional) — hervorgehobener Hinweis (z. B. Wartelisten-Status)
|
|
* $noticeTitle string (optional) — Überschrift dazu
|
|
* $noticeTone 'info' (Default) | 'stop' — Tonlage, siehe components/notice.php
|
|
* $noticeIcon string (optional) — Icon-Name, siehe components/notice.php
|
|
* Gerendert wird über component('notice') — dieselbe Komponente, die
|
|
* contact-form.php über dem Formular benutzt, damit derselbe Hinweis an
|
|
* beiden Orten gleich aussieht und nur EINMAL in data/turnen.json steht.
|
|
* $groups array von Gruppen:
|
|
* { name, level?, contact?, intro?, details?:[{heading,text}], recommendation?,
|
|
* note?, trainers?:[…], sessions:[{ label?, day, time, note?, trainers?:[…] }] }
|
|
* contact = Ansprechperson NUR dieser Gruppe. Braucht es, sobald eine Disziplin
|
|
* mehrere Gruppen mit verschiedenen Ansprechpersonen hat (Wettkampfturnen:
|
|
* Flamingos → Theresa Diener, Leistungsturnen → Franziska Trotzke) — die
|
|
* Kontakt-Kachel oben kann nur EINE nennen und wäre für die andere falsch.
|
|
* Beschriftet als „Kontakt" wie die Kachel, nicht als „Ansprechpartner":
|
|
* das Label kennt das Geschlecht der Person nicht (Haus-Stil Paarformen).
|
|
* $footnote string (optional) — Erläuterung (z. B. zur Sternchen-Kennzeichnung)
|
|
* $groupsTitle string (optional, Default 'Unsere Gruppen')
|
|
* $groupsTitleHidden bool (optional) — H2 bleibt im DOM (Dokumentgliederung für
|
|
* Screenreader, Sektion behält ihren Namen), ist aber visuell versteckt.
|
|
* Dasselbe Muster wie $title_hidden in team-cards. NICHT die Überschrift
|
|
* weglassen: dann hätte die Sektion keinen zugänglichen Namen mehr.
|
|
* $layout 'tabs' (Default) | 'stacked' — greift nur bei beschreibenden Gruppen.
|
|
* 'stacked' zeigt alle Karten offen untereinander (wenige Gruppen),
|
|
* 'tabs' ordnet viele textreiche Gruppen (Kinderturnen).
|
|
* $anchor string (optional, Default 'training')
|
|
*
|
|
* Eine Gruppe → Trainingszeiten landen als Bento-Kachel im Dashboard.
|
|
* Mehrere → Dashboard zeigt nur Ort/Verantwortlich, darunter eine Gruppen-Sektion.
|
|
* Gruppen mit Beschreibung werden gestapelt, schlichte Gruppen als Raster.
|
|
*/
|
|
$anchor = $anchor ?? 'training';
|
|
$groupsTitle = $groupsTitle ?? 'Unsere Gruppen';
|
|
$groupsTitleHidden = $groupsTitleHidden ?? false;
|
|
$layout = ($layout ?? 'tabs') === 'stacked' ? 'stacked' : 'tabs';
|
|
$lead = $lead ?? '';
|
|
$notice = $notice ?? '';
|
|
$noticeTitle = $noticeTitle ?? '';
|
|
$noticeTone = $noticeTone ?? 'info';
|
|
$noticeIcon = $noticeIcon ?? 'info-circle';
|
|
$footnote = $footnote ?? '';
|
|
$groups = $groups ?? [];
|
|
$location = $location ?? [];
|
|
|
|
if ($groups === []) {
|
|
return;
|
|
}
|
|
|
|
$club = json_load('club');
|
|
$email = $club['email_turnen'] ?? ($club['email'] ?? '');
|
|
|
|
$single = count($groups) === 1;
|
|
$rich = false;
|
|
foreach ($groups as $g) {
|
|
if (!empty($g['intro']) || !empty($g['details'])) {
|
|
$rich = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
$hasVenue = !empty($location['venue']);
|
|
$mapsQuery = $hasVenue ? rawurlencode(trim(
|
|
($location['venue'] ?? '') . ', '
|
|
. ($location['street'] ?? '') . ', '
|
|
. ($location['zip'] ?? '') . ' ' . ($location['city'] ?? ''),
|
|
', '
|
|
)) : '';
|
|
|
|
/**
|
|
* Eine Trainingszeit (Tag/Zeit + optional Label, Notiz, Trainerteam) ausgeben.
|
|
*
|
|
* Das Label heißt „Trainerteam", nicht „Übungsleitung": in der Liste stehen auch
|
|
* Personen, die KEINE Übungsleitung sind (Eva Wünsch aus der Abteilung, 31.07.2026).
|
|
* Wer eine ist, trägt ein Sternchen, und das erklärt die Fußnote der Sektion. Die alte
|
|
* Seite schrieb dafür „TRAINERTEAM (* = ÜBUNGSLEITER)". Nicht zurückbenennen.
|
|
*/
|
|
$renderSession = static function (array $s): void {
|
|
?>
|
|
<li class="schedule-row">
|
|
<?php if (!empty($s['label'])): ?>
|
|
<span class="schedule-row__label"><?= e($s['label']) ?></span>
|
|
<?php endif; ?>
|
|
<span class="schedule-row__when">
|
|
<span class="schedule-row__day"><?= e($s['day']) ?></span>
|
|
<span class="schedule-row__time"><?= e($s['time']) ?></span>
|
|
</span>
|
|
<?php if (!empty($s['note'])): ?>
|
|
<span class="schedule-row__note text-muted"><?= e($s['note']) ?></span>
|
|
<?php endif; ?>
|
|
<?php if (!empty($s['trainers'])): ?>
|
|
<span class="schedule-row__trainers"><span class="schedule-row__trainers-label">Trainerteam:</span> <?= e(implode(', ', $s['trainers'])) ?></span>
|
|
<?php endif; ?>
|
|
</li>
|
|
<?php
|
|
};
|
|
|
|
/**
|
|
* Inhalt einer beschreibenden Gruppen-Karte (ohne das <article> drumherum). Als Closure,
|
|
* weil es diese Karte in zwei Fassungen gibt: als Tab-Panel (mit role/aria) und gestapelt
|
|
* (ohne). Vorher stand das Markup nur in der Tab-Fassung; eine zweite Kopie daneben wäre
|
|
* die Stelle, an der beide auseinanderlaufen.
|
|
*/
|
|
$renderCardBody = static function (array $g) use ($renderSession): void {
|
|
?>
|
|
<div class="group-card__body">
|
|
<div class="group-card__header">
|
|
<h3 class="group-card__name"><?= e($g['name']) ?></h3>
|
|
<?php if (!empty($g['level'])): ?>
|
|
<p class="group-card__level"><?= e($g['level']) ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php if (!empty($g['intro'])): ?>
|
|
<p class="group-card__intro"><?= e($g['intro']) ?></p>
|
|
<?php endif; ?>
|
|
<?php foreach ($g['details'] ?? [] as $det): ?>
|
|
<?php if (!empty($det['heading'])): ?>
|
|
<h4 class="group-card__detail-heading"><?= e($det['heading']) ?></h4>
|
|
<?php endif; ?>
|
|
<?php if (!empty($det['text'])): ?>
|
|
<p class="group-card__detail-text"><?= e($det['text']) ?></p>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
<?php if (!empty($g['recommendation'])): ?>
|
|
<p class="group-card__recommendation text-muted"><?= e($g['recommendation']) ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php if (!empty($g['sessions'])): ?>
|
|
<div class="group-card__schedule">
|
|
<p class="group-card__schedule-title"><?= icon('clock', 'group-card__schedule-icon') ?>Trainingszeiten</p>
|
|
<ul class="schedule-list">
|
|
<?php foreach ($g['sessions'] as $s): $renderSession($s); endforeach; ?>
|
|
</ul>
|
|
<?php if (!empty($g['contact'])): ?>
|
|
<p class="group-card__trainers"><span class="schedule-row__trainers-label">Kontakt:</span> <?= e($g['contact']) ?></p>
|
|
<?php endif; ?>
|
|
<?php if (!empty($g['trainers'])): ?>
|
|
<p class="group-card__trainers"><span class="schedule-row__trainers-label">Trainerteam:</span> <?= e(implode(', ', $g['trainers'])) ?></p>
|
|
<?php endif; ?>
|
|
<?php if (!empty($g['note'])): ?>
|
|
<p class="group-card__note text-muted"><?= e($g['note']) ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php
|
|
};
|
|
|
|
$soleSessions = $single ? ($groups[0]['sessions'] ?? []) : [];
|
|
$soleNote = $single ? ($groups[0]['note'] ?? '') : '';
|
|
?>
|
|
<section class="section turnen-dash-section" id="<?= e($anchor) ?>">
|
|
<div class="container">
|
|
<div class="turnen-dash<?= $single ? ' turnen-dash--single' : '' ?><?= $notice !== '' ? ' turnen-dash--notice' : '' ?>">
|
|
<?php if ($notice !== ''): ?>
|
|
<?php component('notice', [
|
|
'title' => $noticeTitle,
|
|
'text' => $notice,
|
|
'tone' => $noticeTone,
|
|
'icon' => $noticeIcon,
|
|
'class' => 'turnen-dash__notice',
|
|
]); ?>
|
|
<?php endif; ?>
|
|
<?php if ($single): ?>
|
|
<article class="bento__tile turnen-dash__training">
|
|
<h2 class="bento__heading"><?= icon('clock', 'bento__hicon') ?>Trainingszeiten</h2>
|
|
<ul class="bento__sessions">
|
|
<?php foreach ($soleSessions as $s): ?>
|
|
<li>
|
|
<span class="bento__day"><?= e($s['day']) ?></span>
|
|
<span class="bento__time"><?= e($s['time']) ?></span>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
<?php if ($soleNote !== ''): ?>
|
|
<p class="bento__note text-muted"><?= e($soleNote) ?></p>
|
|
<?php endif; ?>
|
|
<span class="bento__deco" aria-hidden="true"><?= icon('clock') ?></span>
|
|
</article>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($lead !== '' || $email !== ''): ?>
|
|
<article class="bento__tile bento__tile--accent turnen-dash__contact">
|
|
<span class="bento__stat-label">Kontakt</span>
|
|
<?php if ($lead !== ''): ?>
|
|
<span class="bento__stat-value"><?= e($lead) ?></span>
|
|
<?php endif; ?>
|
|
<?php if ($email !== ''): ?>
|
|
<a class="turnen-dash__mail" href="mailto:<?= e($email) ?>"><?= icon('envelope', 'turnen-dash__mail-icon') ?>E-Mail schreiben</a>
|
|
<?php endif; ?>
|
|
</article>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($hasVenue): ?>
|
|
<article class="bento__tile turnen-dash__venue">
|
|
<div class="turnen-dash__venue-main">
|
|
<h2 class="bento__heading"><?= icon('geo-alt', 'bento__hicon') ?>Trainingsort</h2>
|
|
<p class="bento__address">
|
|
<strong><?= e($location['venue']) ?></strong>
|
|
<?php if (!empty($location['street'])): ?> · <?= e($location['street']) ?><?php endif; ?>
|
|
<?php if (!empty($location['zip']) || !empty($location['city'])): ?>, <?= e(trim(($location['zip'] ?? '') . ' ' . ($location['city'] ?? ''))) ?><?php endif; ?>
|
|
</p>
|
|
</div>
|
|
<a class="btn btn--outline turnen-dash__route" href="https://www.google.com/maps/search/?api=1&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>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<?php if (!$single): ?>
|
|
<section class="section group-list-section<?= $groupsTitleHidden ? ' group-list-section--tight' : '' ?>" id="gruppen">
|
|
<div class="container">
|
|
<h2 class="group-list__title<?= $groupsTitleHidden ? ' visually-hidden' : '' ?>"><?= e($groupsTitle) ?></h2>
|
|
<?php if ($rich && $layout === 'stacked'): ?>
|
|
<?php /* Karten direkt untereinander, alle sichtbar. Für Disziplinen mit wenigen Gruppen:
|
|
Tabs verstecken dort mehr Inhalt als sie ordnen, und die offene Kartenreihe hält
|
|
den Bento-Eindruck der Seite. Bei vielen textreichen Gruppen (Kinderturnen) sind
|
|
Tabs weiter richtig, sonst wird die Seite endlos. */ ?>
|
|
<div class="group-list group-list--stacked">
|
|
<?php foreach ($groups as $g): ?>
|
|
<article class="group-card">
|
|
<?php $renderCardBody($g); ?>
|
|
</article>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php elseif ($rich): ?>
|
|
<div class="group-tabs" data-group-tabs>
|
|
<div class="group-tabs__bar" role="tablist" aria-label="<?= e($groupsTitle) ?>">
|
|
<?php foreach ($groups as $i => $g): ?>
|
|
<button class="tab group-tabs__tab" role="tab" type="button"
|
|
id="gtab-<?= $i ?>"
|
|
aria-controls="gpanel-<?= $i ?>"
|
|
aria-selected="<?= $i === 0 ? 'true' : 'false' ?>"
|
|
><?= e($g['name']) ?></button>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php foreach ($groups as $i => $g): ?>
|
|
<article class="group-card group-tabs__panel" role="tabpanel"
|
|
id="gpanel-<?= $i ?>"
|
|
aria-labelledby="gtab-<?= $i ?>"
|
|
tabindex="0"
|
|
>
|
|
<?php $renderCardBody($g); ?>
|
|
</article>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="group-list group-list--grid">
|
|
<?php foreach ($groups as $g): ?>
|
|
<article class="group-card">
|
|
<div class="group-card__body">
|
|
<div class="group-card__header">
|
|
<h3 class="group-card__name"><?= e($g['name']) ?></h3>
|
|
<?php if (!empty($g['level'])): ?>
|
|
<p class="group-card__level"><?= e($g['level']) ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<?php if (!empty($g['sessions'])): ?>
|
|
<div class="group-card__schedule">
|
|
<ul class="schedule-list">
|
|
<?php foreach ($g['sessions'] as $s): $renderSession($s); endforeach; ?>
|
|
</ul>
|
|
</div>
|
|
<?php endif; ?>
|
|
</article>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($footnote !== ''): ?>
|
|
<p class="group-list__footnote text-muted"><?= e($footnote) ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
</section>
|
|
<?php endif; ?>
|