Compare commits
2 Commits
f3f004d13e
...
133c3f926e
| Author | SHA1 | Date | |
|---|---|---|---|
| 133c3f926e | |||
| 146471bae8 |
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
|||||||
/**
|
/**
|
||||||
* Turn-Disziplin im einheitlichen Bento-Look (wie die Mannschaftsseiten). Props:
|
* Turn-Disziplin im einheitlichen Bento-Look (wie die Mannschaftsseiten). Props:
|
||||||
* $location array{venue, street?, zip?, city?} (optional) — Trainingsort + „Route planen"
|
* $location array{venue, street?, zip?, city?} (optional) — Trainingsort + „Route planen"
|
||||||
* $lead string (optional) — verantwortliche Übungsleitung (Akzent-Kachel)
|
* $lead string (optional) — Ansprechperson der Disziplin (Akzent-Kachel)
|
||||||
* $notice string (optional) — hervorgehobener Hinweis (z. B. Wartelisten-Status)
|
* $notice string (optional) — hervorgehobener Hinweis (z. B. Wartelisten-Status)
|
||||||
* $noticeTitle string (optional) — Überschrift dazu
|
* $noticeTitle string (optional) — Überschrift dazu
|
||||||
* $noticeTone 'info' (Default) | 'stop' — Tonlage, siehe components/notice.php
|
* $noticeTone 'info' (Default) | 'stop' — Tonlage, siehe components/notice.php
|
||||||
@@ -24,6 +24,13 @@ declare(strict_types=1);
|
|||||||
* das Label kennt das Geschlecht der Person nicht (Haus-Stil Paarformen).
|
* das Label kennt das Geschlecht der Person nicht (Haus-Stil Paarformen).
|
||||||
* $footnote string (optional) — Erläuterung (z. B. zur Sternchen-Kennzeichnung)
|
* $footnote string (optional) — Erläuterung (z. B. zur Sternchen-Kennzeichnung)
|
||||||
* $groupsTitle string (optional, Default 'Unsere Gruppen')
|
* $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')
|
* $anchor string (optional, Default 'training')
|
||||||
*
|
*
|
||||||
* Eine Gruppe → Trainingszeiten landen als Bento-Kachel im Dashboard.
|
* Eine Gruppe → Trainingszeiten landen als Bento-Kachel im Dashboard.
|
||||||
@@ -32,6 +39,8 @@ declare(strict_types=1);
|
|||||||
*/
|
*/
|
||||||
$anchor = $anchor ?? 'training';
|
$anchor = $anchor ?? 'training';
|
||||||
$groupsTitle = $groupsTitle ?? 'Unsere Gruppen';
|
$groupsTitle = $groupsTitle ?? 'Unsere Gruppen';
|
||||||
|
$groupsTitleHidden = $groupsTitleHidden ?? false;
|
||||||
|
$layout = ($layout ?? 'tabs') === 'stacked' ? 'stacked' : 'tabs';
|
||||||
$lead = $lead ?? '';
|
$lead = $lead ?? '';
|
||||||
$notice = $notice ?? '';
|
$notice = $notice ?? '';
|
||||||
$noticeTitle = $noticeTitle ?? '';
|
$noticeTitle = $noticeTitle ?? '';
|
||||||
@@ -65,7 +74,14 @@ $mapsQuery = $hasVenue ? rawurlencode(trim(
|
|||||||
', '
|
', '
|
||||||
)) : '';
|
)) : '';
|
||||||
|
|
||||||
/** Eine Trainingszeit (Tag/Zeit + optional Label, Notiz, Übungsleitung) ausgeben. */
|
/**
|
||||||
|
* 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 {
|
$renderSession = static function (array $s): void {
|
||||||
?>
|
?>
|
||||||
<li class="schedule-row">
|
<li class="schedule-row">
|
||||||
@@ -80,12 +96,62 @@ $renderSession = static function (array $s): void {
|
|||||||
<span class="schedule-row__note text-muted"><?= e($s['note']) ?></span>
|
<span class="schedule-row__note text-muted"><?= e($s['note']) ?></span>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if (!empty($s['trainers'])): ?>
|
<?php if (!empty($s['trainers'])): ?>
|
||||||
<span class="schedule-row__trainers"><span class="schedule-row__trainers-label">Übungsleitung:</span> <?= e(implode(', ', $s['trainers'])) ?></span>
|
<span class="schedule-row__trainers"><span class="schedule-row__trainers-label">Trainerteam:</span> <?= e(implode(', ', $s['trainers'])) ?></span>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</li>
|
</li>
|
||||||
<?php
|
<?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'] ?? []) : [];
|
$soleSessions = $single ? ($groups[0]['sessions'] ?? []) : [];
|
||||||
$soleNote = $single ? ($groups[0]['note'] ?? '') : '';
|
$soleNote = $single ? ($groups[0]['note'] ?? '') : '';
|
||||||
?>
|
?>
|
||||||
@@ -150,10 +216,22 @@ $soleNote = $single ? ($groups[0]['note'] ?? '') : '';
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<?php if (!$single): ?>
|
<?php if (!$single): ?>
|
||||||
<section class="section group-list-section" id="gruppen">
|
<section class="section group-list-section<?= $groupsTitleHidden ? ' group-list-section--tight' : '' ?>" id="gruppen">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2 class="group-list__title"><?= e($groupsTitle) ?></h2>
|
<h2 class="group-list__title<?= $groupsTitleHidden ? ' visually-hidden' : '' ?>"><?= e($groupsTitle) ?></h2>
|
||||||
<?php if ($rich): ?>
|
<?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" data-group-tabs>
|
||||||
<div class="group-tabs__bar" role="tablist" aria-label="<?= e($groupsTitle) ?>">
|
<div class="group-tabs__bar" role="tablist" aria-label="<?= e($groupsTitle) ?>">
|
||||||
<?php foreach ($groups as $i => $g): ?>
|
<?php foreach ($groups as $i => $g): ?>
|
||||||
@@ -170,45 +248,7 @@ $soleNote = $single ? ($groups[0]['note'] ?? '') : '';
|
|||||||
aria-labelledby="gtab-<?= $i ?>"
|
aria-labelledby="gtab-<?= $i ?>"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<div class="group-card__body">
|
<?php $renderCardBody($g); ?>
|
||||||
<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">Ü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>
|
</article>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ declare(strict_types=1);
|
|||||||
* Turnen → Wettkampfturnen. Inhalt: data/turnen.json (disciplines.wettkampfturnen).
|
* Turnen → Wettkampfturnen. Inhalt: data/turnen.json (disciplines.wettkampfturnen).
|
||||||
* Struktur: Hero → Gruppen/Trainingszeiten.
|
* Struktur: Hero → Gruppen/Trainingszeiten.
|
||||||
*
|
*
|
||||||
* Zwei Gruppen: das Wettkampftraining selbst und die Flamingos, die am 31.07.2026 vom
|
* Zwei Gruppen: die Flamingos, die am 31.07.2026 vom Kinderturnen hierher gezogen sind,
|
||||||
* Kinderturnen hierher gezogen sind. Dadurch läuft die Seite nicht mehr im
|
* und das Leistungsturnen. Dadurch läuft die Seite nicht mehr im Einzelgruppen-Layout
|
||||||
* Einzelgruppen-Layout (Trainingszeiten als Kachel im Dashboard), sondern zeigt die
|
* (Trainingszeiten als Kachel im Dashboard), sondern zeigt die Gruppen darunter als
|
||||||
* Gruppen darunter als Tabs — deshalb group-tabs.js und die Sternchen-Fußnote.
|
* offene Kartenreihe (layout => 'stacked') — deshalb die Sternchen-Fußnote.
|
||||||
*/
|
*/
|
||||||
$slug = 'turnen/wettkampfturnen';
|
$slug = 'turnen/wettkampfturnen';
|
||||||
$data = json_load('turnen');
|
$data = json_load('turnen');
|
||||||
@@ -19,10 +19,6 @@ $meta = [
|
|||||||
'title' => 'Wettkampfturnen in Kulmbach',
|
'title' => 'Wettkampfturnen in Kulmbach',
|
||||||
'description' => 'Leistungsorientiertes Gerätturnen mit Training und Wettkämpfen: Wettkampfturnen beim TSV 08 Kulmbach im Mäximum Gym. Trainingszeiten und Kontakt im Überblick.',
|
'description' => 'Leistungsorientiertes Gerätturnen mit Training und Wettkämpfen: Wettkampfturnen beim TSV 08 Kulmbach im Mäximum Gym. Trainingszeiten und Kontakt im Überblick.',
|
||||||
'og_image' => 'img/pages/vereinsgelaende-1600.jpg',
|
'og_image' => 'img/pages/vereinsgelaende-1600.jpg',
|
||||||
// Seit die Flamingos hier stehen, sind es zwei Gruppen, davon eine mit
|
|
||||||
// Beschreibung — group-schedule rendert dann eine Tab-Leiste, und die braucht
|
|
||||||
// dieses Skript. Ohne es wären die Tab-Knöpfe tote Schaltflächen.
|
|
||||||
'scripts' => ['group-tabs.js'],
|
|
||||||
'schema' => page_schema([
|
'schema' => page_schema([
|
||||||
['name' => 'Startseite', 'slug' => ''],
|
['name' => 'Startseite', 'slug' => ''],
|
||||||
['name' => 'Turnen', 'slug' => 'turnen'],
|
['name' => 'Turnen', 'slug' => 'turnen'],
|
||||||
@@ -35,6 +31,15 @@ component('group-schedule', [
|
|||||||
'location' => $d['location'] ?? [],
|
'location' => $d['location'] ?? [],
|
||||||
'lead' => $d['lead'] ?? '',
|
'lead' => $d['lead'] ?? '',
|
||||||
'groups' => $d['groups'] ?? [],
|
'groups' => $d['groups'] ?? [],
|
||||||
|
// Zwei Gruppen, beide offen untereinander statt hinter Tabs: bei so wenigen
|
||||||
|
// Gruppen verstecken Tabs mehr Inhalt als sie ordnen, und die offene Kartenreihe
|
||||||
|
// hält den Bento-Eindruck der Seite. Damit braucht die Seite auch kein
|
||||||
|
// group-tabs.js mehr. Das Kinderturnen bleibt bei Tabs, dort sind es drei
|
||||||
|
// textreiche Gruppen.
|
||||||
|
'layout' => 'stacked',
|
||||||
|
// Überschrift „Unsere Gruppen" nur für Screenreader: die Karten erklären sich
|
||||||
|
// selbst, und ohne die Zeile bleibt der Bento-Fluss ruhiger.
|
||||||
|
'groupsTitleHidden' => true,
|
||||||
// Drei Flamingos-Trainerinnen tragen ein Sternchen. Ohne die Fußnote stünden
|
// Drei Flamingos-Trainerinnen tragen ein Sternchen. Ohne die Fußnote stünden
|
||||||
// hier drei unerklärte Sterne auf der Seite.
|
// hier drei unerklärte Sterne auf der Seite.
|
||||||
'footnote' => $data['footnote'] ?? '',
|
'footnote' => $data['footnote'] ?? '',
|
||||||
|
|||||||
@@ -101,7 +101,6 @@
|
|||||||
"image": { "base": "img/pages/vereinsgelaende", "widths": [640, 1000, 1600], "alt": "Luftaufnahme unserer Hans-Rausch-Sportanlage im Katzbachtal" },
|
"image": { "base": "img/pages/vereinsgelaende", "widths": [640, 1000, 1600], "alt": "Luftaufnahme unserer Hans-Rausch-Sportanlage im Katzbachtal" },
|
||||||
"ctas": []
|
"ctas": []
|
||||||
},
|
},
|
||||||
"layout": "blocks",
|
|
||||||
"location": { "venue": "Mäximum Gym", "street": "Thurnauer Str. 51", "zip": "95326", "city": "Kulmbach" },
|
"location": { "venue": "Mäximum Gym", "street": "Thurnauer Str. 51", "zip": "95326", "city": "Kulmbach" },
|
||||||
"lead": "Annelie Frisque",
|
"lead": "Annelie Frisque",
|
||||||
"notice_tone": "stop",
|
"notice_tone": "stop",
|
||||||
@@ -120,7 +119,7 @@
|
|||||||
"recommendation": "Bei besonderem Potenzial für Wettkampf- oder Leistungsgruppen sprechen unsere Trainer eine Empfehlung aus.",
|
"recommendation": "Bei besonderem Potenzial für Wettkampf- oder Leistungsgruppen sprechen unsere Trainer eine Empfehlung aus.",
|
||||||
"sessions": [
|
"sessions": [
|
||||||
{ "label": "Kängurus", "day": "Dienstag", "time": "16:30–17:15 Uhr", "trainers": ["Carina Schleicher*"] },
|
{ "label": "Kängurus", "day": "Dienstag", "time": "16:30–17:15 Uhr", "trainers": ["Carina Schleicher*"] },
|
||||||
{ "label": "Grashüpfer", "day": "Donnerstag", "time": "15:30–16:15 Uhr", "trainers": ["Annelie Frisque*", "Eva Wünsch"] }
|
{ "label": "Grashüpfer", "day": "Donnerstag", "time": "15:30–16:15 Uhr", "trainers": ["Annelie Frisque*", "Eva Wünsch*"] }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2869,6 +2869,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Versteckte Überschrift: dann fehlt der Zeile, die den Raum zwischen Dashboard und
|
||||||
|
erster Karte gefüllt hat, ihr Inhalt. Übrig blieben 160px (80 unten von der
|
||||||
|
Dashboard-Sektion + 80 oben von dieser), in denen nur nackte Hintergrund-Textur stand
|
||||||
|
— gemessen und als Loch aufgefallen (31.07.2026). Die 80px des Dashboards reichen. */
|
||||||
|
.group-list-section--tight {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Schlichte Gruppen (z. B. Kurse) als Raster, beschreibende Gruppen gestapelt. */
|
/* Schlichte Gruppen (z. B. Kurse) als Raster, beschreibende Gruppen gestapelt. */
|
||||||
.group-list--grid {
|
.group-list--grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -2901,7 +2909,10 @@
|
|||||||
grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
|
grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
|
||||||
gap: var(--space-4xl);
|
gap: var(--space-4xl);
|
||||||
align-items: start;
|
align-items: start;
|
||||||
padding: var(--space-3xl) var(--space-3xl);
|
/* --pad-card-lg statt fester 40px, dieselbe Korrektur wie beim Tab-Panel:
|
||||||
|
auf schmalen Handys stapeln sich Container- und Kartenabstand sonst so, dass
|
||||||
|
dem Inhalt kaum Breite bleibt. Obergrenze ist der bisherige Wert. */
|
||||||
|
padding: var(--pad-card-lg) var(--pad-card-lg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|||||||
Reference in New Issue
Block a user