Wettkampfturnen: Karten offen untereinander statt hinter Tabs
Bei zwei Gruppen verstecken Tabs mehr Inhalt als sie ordnen, und die offene Kartenreihe hält den Bento-Eindruck der Seite (Entscheidung Felix). Das Kinderturnen bleibt bei Tabs, dort sind es drei textreiche Gruppen — die Flamingos-Karte allein ist am Handy 2142px hoch. .group-list--stacked lag vollständig im CSS, wurde aber von KEINEM PHP ausgegeben: totes CSS aus der Zeit vor den Tabs, das heute morgen sogar noch meine minmax(0, …)-Korrektur mitbekommen hat, ohne dass es jemand sehen konnte. Jetzt ist es lebendig. Dritter toter Rest heute: "layout": "blocks" in data/turnen.json las ebenfalls niemand, ist raus. Der Karteninhalt steht dafür jetzt einmal statt zweimal. Er wird in zwei Fassungen gebraucht (Tab-Panel mit role/aria und gestapelt ohne) und ist deshalb eine Closure geworden — eine zweite Kopie wäre die Stelle, an der beide in einem halben Jahr auseinanderlaufen. Die Überschrift ist visually-hidden, nicht entfernt: sonst hätte die Sektion keinen zugänglichen Namen und die Überschriften-Gliederung eine Lücke. Dasselbe Muster wie $title_hidden in team-cards. Damit braucht die Seite auch kein group-tabs.js mehr, das ich zwei Commits vorher erst dazugeschrieben hatte. Zwei Nachbesserungen, beide gemessen: - Die versteckte Überschrift hinterließ ein Loch. Zwischen Dashboard und erster Karte standen 160px (80 unten von der einen Sektion, 80 oben von der anderen), in denen nur nackte Hintergrund-Textur zu sehen war — vorher füllte die Überschrift diesen Raum. .group-list-section--tight nimmt das obere Padding weg, jetzt 80px. - Die gestapelten Karten hatten feste 40px Innenabstand; auf --pad-card-lg umgestellt, dieselbe Korrektur wie heute morgen beim Tab-Panel. Am Desktop unverändert 40px, am Handy 28px. Nicht behoben, weil kein Fehler: die Hintergrund-Textur wirkt in leeren Flächen weich. Sie ist 1920x2545 groß und wird bei 1478px Fensterbreite auf Faktor 0,77 VERKLEINERT, ist also nicht unscharf gerechnet. Sichtbar wurde sie durch den Leerraum plus background-attachment: fixed, das sie beim Scrollen stehen lässt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
This commit is contained in:
@@ -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 ?? '';
|
||||||
@@ -86,6 +95,56 @@ $renderSession = static function (array $s): void {
|
|||||||
<?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">Ü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; ?>
|
||||||
|
<?php
|
||||||
|
};
|
||||||
|
|
||||||
$soleSessions = $single ? ($groups[0]['sessions'] ?? []) : [];
|
$soleSessions = $single ? ($groups[0]['sessions'] ?? []) : [];
|
||||||
$soleNote = $single ? ($groups[0]['note'] ?? '') : '';
|
$soleNote = $single ? ($groups[0]['note'] ?? '') : '';
|
||||||
?>
|
?>
|
||||||
@@ -150,10 +209,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 +241,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",
|
||||||
|
|||||||
@@ -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