Feinschliff: Navigation, Hero-Center, Personen-Karten & Tokens
Querschnitt-Verbesserungen ohne eigenes Feature: - Navigation: Untermenü-Trenner (separator) + Mitmachen-Link, rote Akzent-Leiste - Startseiten-Hero zentriert (align center, ohne Hero-CTAs); .hero--center-Styles - person-card/person-grid: Kontakt-Layout, 3-Spalten-Raster (Startseite) - jsonld: geo aus club.json; cta unterstützt #hash-Anker - verein: hartcodierten Maps-Link/Inline-CTA entfernt, .facility zentriert - tokens: Sepia-Farben für Timeline; base: globale p-max-width entfernt - historie: Timeline um 2024/2025 ergänzt - Icons link-45deg (Footer) und robot (meta) nachgereicht Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HGzc6GhWhmLJt1jC2q1SRZ
This commit is contained in:
@@ -12,4 +12,4 @@ $class = 'btn'
|
||||
. ($style === 'outline' ? ' btn--outline' : '')
|
||||
. ($size === 'lg' ? ' btn--lg' : ($size === 'sm' ? ' btn--sm' : ''));
|
||||
?>
|
||||
<a class="<?= e($class) ?>" href="<?= e(url($cta['slug'])) ?>"><?= e($cta['label']) ?></a>
|
||||
<a class="<?= e($class) ?>" href="<?= e(url($cta['slug'])) . (!empty($cta['hash']) ? '#' . e($cta['hash']) : '') ?>"><?= e($cta['label']) ?></a>
|
||||
|
||||
@@ -32,6 +32,11 @@ $clubNode = [
|
||||
'addressCountry' => $club['address']['country'],
|
||||
],
|
||||
'sameAs' => array_values(array_filter($club['social'])),
|
||||
'geo' => [
|
||||
'@type' => 'GeoCoordinates',
|
||||
'latitude' => $club['geo']['lat'],
|
||||
'longitude' => $club['geo']['lng'],
|
||||
],
|
||||
];
|
||||
|
||||
$graph = [
|
||||
|
||||
@@ -38,7 +38,7 @@ $href = static function (string $slug): string {
|
||||
<button class="site-nav__sublink" type="button" aria-expanded="false" aria-controls="<?= e($submenuId) ?>"<?= $childActive ? ' data-current' : '' ?>><?= e($item['label']) ?><?= icon('chevron-down', 'site-nav__chevron') ?></button>
|
||||
<ul class="site-nav__submenu" id="<?= e($submenuId) ?>">
|
||||
<?php foreach ($item['children'] as $child): ?>
|
||||
<li>
|
||||
<li<?= !empty($child['separator']) ? ' class="site-nav__submenu-sep"' : '' ?>>
|
||||
<a href="<?= e($href($child['slug'])) ?>"<?= $child['slug'] === $current ? ' aria-current="page"' : '' ?>><?= e($child['label']) ?></a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
|
||||
@@ -5,10 +5,17 @@ declare(strict_types=1);
|
||||
/**
|
||||
* Visitenkarte für eine Person. Props:
|
||||
* $person array{department, name, phone?, email?, image?, whatsapp?}
|
||||
* $level string — Überschriften-Ebene des department-Headings (Default 'h3').
|
||||
* Eingebettet (z. B. in position-card unter einem h3) auf 'h4' setzen,
|
||||
* damit die Heading-Outline nicht abflacht. Styling bleibt klassenbasiert.
|
||||
* Ohne image greift der Platzhalter-Avatar (img/persons/platzhalter.jpg).
|
||||
* Kontakt-Link: phone → tel:, sonst email → mailto:.
|
||||
* Optional zusätzlich WhatsApp (wa.me) bei phone + whatsapp=true (opt-in pro Person).
|
||||
*/
|
||||
$level = $level ?? 'h3';
|
||||
if (!in_array($level, ['h2', 'h3', 'h4', 'h5'], true)) {
|
||||
$level = 'h3';
|
||||
}
|
||||
$image = $person['image'] ?? null;
|
||||
$src = $image ?: 'img/persons/platzhalter.jpg';
|
||||
|
||||
@@ -35,7 +42,7 @@ $waHref = (!empty($person['whatsapp']) && !empty($person['phone']))
|
||||
width="480" height="600" loading="lazy" decoding="async">
|
||||
</div>
|
||||
<div class="person-card__body">
|
||||
<h3 class="person-card__department"><?= e($person['department']) ?></h3>
|
||||
<<?= $level ?> class="person-card__department"><?= e($person['department']) ?></<?= $level ?>>
|
||||
<p class="person-card__name"><?= e($person['name']) ?></p>
|
||||
<?php if ($contactHref !== null): ?>
|
||||
<a class="person-card__contact" href="<?= e($contactHref) ?>">
|
||||
|
||||
@@ -11,10 +11,12 @@ declare(strict_types=1);
|
||||
* $intro string — Intro-Text überschreiben (Default aus JSON; '' = ausblenden).
|
||||
* $anchor string — Sektions-ID (Default 'ansprechpartner').
|
||||
* $tinted bool — aufgehelltes Vollbreite-Band (Default true).
|
||||
* $columns int — Spaltenanzahl auf Desktop (null = automatisch bis 5).
|
||||
*/
|
||||
$data = json_load('ansprechpartner');
|
||||
$anchor = $anchor ?? 'ansprechpartner';
|
||||
$tinted = $tinted ?? true;
|
||||
$columns = $columns ?? null;
|
||||
$title = $title ?? $data['title'];
|
||||
$intro = $intro ?? ($data['intro'] ?? '');
|
||||
|
||||
@@ -42,7 +44,7 @@ if ($persons === []) {
|
||||
<?php if ($intro !== ''): ?>
|
||||
<p class="persons__intro"><?= e($intro) ?></p>
|
||||
<?php endif; ?>
|
||||
<ul class="persons__grid">
|
||||
<ul class="persons__grid<?= $columns ? ' persons__grid--cols-' . (int)$columns : '' ?>">
|
||||
<?php foreach ($persons as $person): ?>
|
||||
<li>
|
||||
<?php component('person-card', ['person' => $person]); ?>
|
||||
|
||||
@@ -30,5 +30,6 @@ component('partner-grid', ['intro' => $home['partners']]);
|
||||
// vollständige Turn-Disziplin-Liste lebt auf /ansprechpartner.
|
||||
component('person-grid', [
|
||||
'departments' => ['Herrenfußball', 'Damenfußball', 'Jugendfußball', 'Erwachsenenturnen'],
|
||||
'columns' => 3,
|
||||
]);
|
||||
component('contact-form', ['intro' => $home['contact']]);
|
||||
|
||||
@@ -3,16 +3,11 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Vereins-Übersichtsseite (Hub). Inhalt: data/verein.json + data/club.json.
|
||||
* Struktur: Hero → Eckdaten (key-facts) → Leitbild (split) → Abteilungs-Kacheln →
|
||||
* Gelände/Drohnenbild → CTA → FAQ.
|
||||
* Vereins-Übersichtsseite (Hub). Inhalt: data/verein.json.
|
||||
* Struktur: Hero → Abteilungs-Kacheln → Gelände → Leitbild → Historien-Teaser → FAQ.
|
||||
*/
|
||||
$page = json_load('verein');
|
||||
|
||||
$club = json_load('club');
|
||||
$addr = $club['address'] ?? [];
|
||||
$mapsQuery = rawurlencode(trim(($addr['venue'] ?? '') . ', ' . ($addr['street'] ?? '') . ', ' . ($addr['zip'] ?? '') . ' ' . ($addr['city'] ?? ''), ', '));
|
||||
|
||||
// Zwei Abteilungs-Kacheln. Turnen verlinkt bereits auf /turnen (Seite folgt).
|
||||
$cards = [
|
||||
[
|
||||
@@ -44,19 +39,16 @@ $meta = [
|
||||
|
||||
component('hero', ['hero' => $page['hero']]);
|
||||
|
||||
component('key-facts', ['facts' => $page['facts'] ?? [], 'anchor' => 'eckdaten']);
|
||||
|
||||
component('section', ['section' => $page['about']]);
|
||||
|
||||
component('team-cards', [
|
||||
'teams' => $cards,
|
||||
'title' => 'Unsere Abteilungen',
|
||||
'title_hidden' => true,
|
||||
'intro' => $page['abteilungen_intro'] ?? '',
|
||||
'intro_below' => true,
|
||||
'anchor' => 'abteilungen',
|
||||
]);
|
||||
?>
|
||||
<section class="section facility" id="gelaende">
|
||||
<section class="section section--tinted facility" id="gelaende">
|
||||
<div class="container">
|
||||
<h2><?= e($page['gelaende']['title']) ?></h2>
|
||||
<p class="facility__lead"><?= e($page['gelaende']['text']) ?></p>
|
||||
@@ -66,19 +58,12 @@ component('team-cards', [
|
||||
<figcaption class="facility__caption"><?= e($page['gelaende']['caption']) ?></figcaption>
|
||||
<?php endif; ?>
|
||||
</figure>
|
||||
<p class="facility__actions">
|
||||
<a class="btn btn--outline" 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>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
<?php
|
||||
component('cta-band', ['band' => [
|
||||
'title' => 'Werde Teil des TSV 08',
|
||||
'text' => 'Ob Fußball oder Turnen – komm unverbindlich vorbei oder schreib uns. Wir finden gemeinsam die passende Gruppe für dich.',
|
||||
'ctas' => [
|
||||
['label' => 'Mitglied werden', 'slug' => 'mitglied-werden', 'style' => 'primary'],
|
||||
['label' => 'Kontakt aufnehmen', 'slug' => '#kontakt', 'style' => 'outline'],
|
||||
],
|
||||
]]);
|
||||
component('section', ['section' => $page['about']]);
|
||||
|
||||
component('section', ['section' => $page['historie_teaser']]);
|
||||
|
||||
component('faq', ['faq' => $page['faq'] ?? []]);
|
||||
|
||||
Reference in New Issue
Block a user