Matchcenter: „Nächste Spiele" als Band statt Autoplay-Slider

Der Bereich wirkte deplatziert: der Track war auf 620px begrenzt und zeigte
eine Folie, wodurch die Karte auf breiten Fenstern in ~840px Totraum schwebte;
dazu derselbe Hintergrund wie der Hero direkt darüber, kein Akzent, und ein
einsames „:" zwischen den Wappen, das wie ein fehlendes Ergebnis aussah.

Neu als abgesetztes Band (.section--sunken, nutzt endlich das dafür
vorgesehene, bisher unbenutzte Token --clr-bg-deep) mit roter Oberkante:
links der Aufmacher (match-feature), rechts die folgenden Termine als
verlinkte match-row-Zeilen ohne Kartenfläche.

Der Aufmacher ist die große Variante der Terminzeile — Heim über Gast,
linksbündig, gleiche Struktur wie die Zeilen daneben. Bewusst nur drei
typografische Rollen (Meta-Zeile · Vereinsnamen in Coolvetica · Anstoßzeile
mit Countdown) statt der acht der ersten Fassung, ohne Badges, Icons oder
Button. Die eigene Mannschaft wird über Helligkeit markiert, nicht über
font-weight — Coolvetica hat nur einen Schnitt, bold wäre synthetisch.

match-row bekommt optionale $href/$meta-Props; Raster und Innenabstand liegen
jetzt im __link-Wrapper, damit als Link die ganze Zeilenfläche klickbar ist.
Neue Helper match_when() (ISO + deutscher Countdown, explizit Europe/Berlin,
weil PHP global auf UTC läuft) und match_competition_label().

match-slider.php und match-card.php entfallen — Letztere wurde
ausschließlich vom Slider genutzt. carousel.js treibt damit nur noch den
Banner-Slider der Startseite und wird im Matchcenter nicht mehr geladen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-27 00:39:57 +02:00
parent bee19a2ddc
commit 66c402d9f7
10 changed files with 461 additions and 401 deletions

View File

@@ -125,6 +125,61 @@ function img_intrinsic_attrs(string $rel): string
return $cache[$rel];
}
/**
* Anzeigewerte zu einem Anstoß. $kickoff = Zeit ohne Zonenangabe aus
* data/matchcenter.json (z. B. 2026-08-01T14:00), gelesen als Europe/Berlin —
* PHP läuft hier global auf UTC, deshalb explizit. Liefert:
* iso maschinenlesbar mit Zone (für <time datetime> und den JS-Ticker)
* countdown „heute, 14:00 Uhr" | „morgen, 14:00 Uhr" | „in 6 Tagen" | „in 3 Wochen"
* Unlesbarer Wert → beide Felder leer; bereits angestoßenes Spiel → countdown leer.
*/
function match_when(string $kickoff): array
{
if ($kickoff === '') {
return ['iso' => '', 'countdown' => ''];
}
$tz = new DateTimeZone('Europe/Berlin');
try {
$start = new DateTimeImmutable($kickoff, $tz);
} catch (Exception) {
return ['iso' => '', 'countdown' => ''];
}
$now = new DateTimeImmutable('now', $tz);
if ($start <= $now) {
return ['iso' => $start->format('c'), 'countdown' => ''];
}
// Kalendertage zählen, nicht 24-Stunden-Blöcke: ein Anstoß morgen um 14 Uhr
// ist „morgen", auch wenn es nur 20 Stunden hin sind.
$days = (int) $now->setTime(0, 0)->diff($start->setTime(0, 0))->format('%a');
$time = $start->format('H:i') . ' Uhr';
return [
'iso' => $start->format('c'),
'countdown' => match (true) {
$days === 0 => 'heute, ' . $time,
$days === 1 => 'morgen, ' . $time,
$days < 14 => 'in ' . $days . ' Tagen',
default => 'in ' . (int) round($days / 7) . ' Wochen',
},
];
}
/**
* Anzeigename eines Wettbewerbs aus data/matchcenter.json. Die BFV-API kennt nur
* „Liga" und „Freundschaft": „Liga" wird durch den echten Liganamen ersetzt — ohne
* $league bleibt sie leer, damit Ligaspiele in den Mannschafts-Sektionen nicht
* redundant beschriftet werden (die Sektion nennt die Liga schon). „Freundschaft"
* wird ausgeschrieben, damit erkennbar ist, warum ein Testspiel nicht in der
* Tabelle zählt.
*/
function match_competition_label(string $competition, string $league = ''): string
{
return match ($competition) {
'Liga' => $league,
'Freundschaft' => 'Freundschaftsspiel',
default => $competition,
};
}
/**
* Komponente rendern: component('hero', ['title' => …]).
* Props werden als lokale Variablen extrahiert; Komponenten sind dumme Includes.