Info von Eva aus der Trampolin-Gruppe: neue Kinder können ab September (Schulbeginn) gerne schnuppern kommen. Die Info stand nirgends. Rot wäre dafür falsch gewesen. Die Farbe bekommt deshalb eine Bedeutung: --stop (gefüllt rot) heißt „geht nicht", --info (Glas-Fläche, Rot nur im Icon) heißt „geht". Eine Einladung in Alarmrot liest sich wie eine Absage, und wenn alles rot ist, stumpft Rot ab und der echte Wartelisten-Stopp bei „Tiger" und „Hühner" verliert seine Wirkung. --info ist ab jetzt der Default. Damit steht der Hinweis an drei Stellen, also greift die Bedingung aus dem letzten Commit („kommt ein dritter Ort dazu, gehören die gemeinsamen Eigenschaften in eine geteilte Klasse"): neu app/components/notice.php als einzige Render-Stelle statt dreimal dasselbe Markup. Die beiden bestehenden Klassen schrumpfen auf das, was sie wirklich beitragen — .turnen-dash__notice nur noch grid-area, .contact__notice nur noch die Formularbreite. Die tote .turnen-dash__notice-icon-Regel ist raus, der CSS-Abschnitt neu sortiert (notice als eigener Block hinter turnen-dash statt mitten hinein). Text, Tonlage und Icon stehen wie gehabt in data/turnen.json bei der Disziplin, nicht im Template. Kinderturnen trägt jetzt explizit notice_tone: stop, Trampolin nichts und ist damit neutral. Das Grid-Template für --notice + --single gab es schon, an beiden Breakpoints — die Trampolin-Seite hat eine Gruppe und wäre sonst auseinandergefallen. Gemessen bei 390px: kein Überlauf auf allen drei Seiten, Trampolin-Fläche rgba(0,0,0,0.22) (Glas), die beiden anderen #e20612. Zwölf Seiten geprüft, alle 200. preflight ohne neue Meldungen. OFFEN, mit Eva oder Tina zu klären: der zweite Satz („Schreib uns davor einfach kurz eine Nachricht") ist von mir, Eva hat ihn nicht gesagt. Wenn die Kinder einfach zum Training kommen dürfen, gehört er weg. Und die Einladung steht bisher nur auf /turnen/trampolin, nicht auf der Übersicht /turnen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
235 lines
11 KiB
PHP
235 lines
11 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) — verantwortliche Übungsleitung (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?, intro?, details?:[{heading,text}], recommendation?, note?,
|
|
* trainers?:[…], sessions:[{ label?, day, time, note?, trainers?:[…] }] }
|
|
* $footnote string (optional) — Erläuterung (z. B. zur Sternchen-Kennzeichnung)
|
|
* $groupsTitle string (optional, Default 'Unsere Gruppen')
|
|
* $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';
|
|
$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, Übungsleitung) ausgeben. */
|
|
$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">Übungsleitung:</span> <?= e(implode(', ', $s['trainers'])) ?></span>
|
|
<?php endif; ?>
|
|
</li>
|
|
<?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" id="gruppen">
|
|
<div class="container">
|
|
<h2 class="group-list__title"><?= e($groupsTitle) ?></h2>
|
|
<?php if ($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"
|
|
>
|
|
<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['trainers'])): ?>
|
|
<p class="group-card__trainers"><span class="schedule-row__trainers-label">Übungsleitung:</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; ?>
|
|
</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; ?>
|