Files
tsv08kulmbach-website/app/components/stadionzeitung-gegner.php
fs 0ee75aa93b Stadionzeitung: Ergebnis- und Gegnerseite neu gestaltet
Ergebnisse laufen als Anzeigetafel (Wappen und Name je Seite, Ergebnis gross
in der Mitte) statt als Listenzeilen. Verworfen und im CSS begruendet: Tore
am rechten Blattrand, getoente Karten je Spiel, roter Strich unter der
Mannschaftszeile, graue Verlierer-Ziffern. Vereinsnamen einzeilig, sonst
ausgepunktet.

Die Gegnerseite bekommt ein symmetrisches Duell, eine aus den Tabellenwerten
abgeleitete Aufmacher-Zeile, den Vergleich als Balkenpaar aus der Mitte und
einen Tabellenausschnitt ueber die geteilte league-table-Komponente. Die
Balkenlaengen kommen aus Klassen in 5-Prozent-Stufen, nie aus einem
style-Attribut (die CSP verwirft inline styles stillschweigend).

Das Mitglied-werden-Poster sagt jetzt "Werde Teil unseres Vereins".

Alle geaenderten Seiten auf A5-Hoehe nachgemessen, kein Ueberstand.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hv9SGDu3m3diiPrW9Fmj3v
2026-09-19 10:54:05 +02:00

178 lines
9.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
/**
* Gegnerstatistik der Stadionzeitung. Alle Werte stammen aus dem bereits
* aufgebauten Stadionzeitungs-Snapshot; die Komponente rendert nur. Dadurch
* sind Entwurf und veröffentlichte Druckausgabe konsistent und archivfest.
*
* Props: $info stadionzeitung_live_data($issue)['gegner'][team] — ein Eintrag der
* Map je Team-Key (team_name/opponent/league/season/fixture/own/
* opponent_stats). Normal nur die tragende Mannschaft; in der
* Sportfest-Ausgabe eine Seite je Heimspiel am Fest, deshalb
* nennt der Kicker die Mannschaft.
*/
$info = is_array($info ?? null) ? $info : [];
$teamName = trim((string) ($info['team_name'] ?? ''));
$fixture = is_array($info['fixture'] ?? null) ? $info['fixture'] : [];
$own = is_array($info['own'] ?? null) ? $info['own'] : null;
$opponent = is_array($info['opponent_stats'] ?? null) ? $info['opponent_stats'] : null;
// Gedruckt wird der Anzeigename (Kurzname der Ausgabe, wenn gepflegt) — die
// BFV-Schreibweise „(SG1) TSV Wirsberg I/ FC Kupferberg I" ist ein Suchschlüssel,
// keine Überschrift.
$ausschnitt = is_array($info['table_excerpt'] ?? null) ? $info['table_excerpt'] : [];
$opponentName = (string) ($info['opponent_display'] ?? $info['opponent'] ?? 'Unser Gegner');
// Links steht IMMER unsere Mannschaft (Klasse --own hebt sie hervor), rechts der
// Gegner. Bei einem Heimspiel ist das ohnehin die Reihenfolge Heim/Gast; fährt die
// Mannschaft aber auswärts, trüge die Hervorhebung sonst der gegnerische Verein.
$istHeim = !empty($fixture['is_home']);
$ownName = (string) (($istHeim ? ($fixture['home'] ?? null) : ($fixture['away'] ?? null)) ?? 'TSV 08 Kulmbach');
$ownCrest = ($istHeim ? ($fixture['home_crest'] ?? null) : ($fixture['away_crest'] ?? null)) ?? $own['crest'] ?? null;
$gegnerLabel = $opponentName;
$gegnerCrest = ($istHeim ? ($fixture['away_crest'] ?? null) : ($fixture['home_crest'] ?? null)) ?? $opponent['crest'] ?? null;
$kickoff = (string) ($fixture['kickoff'] ?? '');
$kickoffDate = $kickoff !== '' ? substr($kickoff, 0, 10) : '';
$kickoffTime = $kickoff !== '' ? substr($kickoff, 11, 5) : '';
// Der Tabellenplatz steht NICHT in der Balkenliste: klein ist dort besser,
// ein Balken läge genau falsch herum. Er gehört nach oben neben die Wappen.
// „Spiele“ fällt ebenfalls raus (für beide gleich, steht in der Kopfzeile).
$rows = [
['label' => 'Siege', 'key' => 'won'],
['label' => 'Unentschieden', 'key' => 'drawn'],
['label' => 'Niederlagen', 'key' => 'lost'],
['label' => 'Tordifferenz', 'key' => 'goal_diff', 'signed' => true],
['label' => 'Punkte', 'key' => 'points'],
];
$format = static function (?array $row, string $key, bool $signed = false): string {
if ($row === null || !array_key_exists($key, $row)) {
return '–';
}
$value = (int) $row[$key];
return $signed && $value > 0 ? '+' . $value : (string) $value;
};
// Balkenlänge als KLASSE, nie als style-Attribut: die CSP verwirft inline
// styles stillschweigend (siehe CLAUDE.md), der Balken wäre in Produktion
// unsichtbar. Deshalb 5-Prozent-Stufen, die components.css ausdefiniert.
$barStep = static function (?array $row, ?array $other, string $key): int {
if ($row === null) {
return 0;
}
$value = abs((int) ($row[$key] ?? 0));
$scale = max($value, $other === null ? 0 : abs((int) ($other[$key] ?? 0)));
if ($scale <= 0) {
return 0;
}
return (int) round($value / $scale * 20);
};
// Ein Satz statt einer Zahlenkolonne: derselbe Bestand, nur in Sprache. Die
// erste zutreffende Regel gewinnt, damit immer genau eine Aussage dasteht.
$zahlwort = static function (int $n): string {
$woerter = [0 => 'Kein', 1 => 'Ein', 2 => 'Zwei', 3 => 'Drei', 4 => 'Vier', 5 => 'Fünf',
6 => 'Sechs', 7 => 'Sieben', 8 => 'Acht', 9 => 'Neun', 10 => 'Zehn', 11 => 'Elf',
12 => 'Zwölf', 13 => 'Dreizehn', 14 => 'Vierzehn', 15 => 'Fünfzehn'];
return $woerter[$n] ?? (string) $n;
};
$aufmacher = '';
if ($opponent !== null) {
$played = (int) ($opponent['played'] ?? 0);
$won = (int) ($opponent['won'] ?? 0);
$lost = (int) ($opponent['lost'] ?? 0);
$rank = (int) ($opponent['rank'] ?? 0);
$points = (int) ($opponent['points'] ?? 0);
$diff = (int) ($opponent['goal_diff'] ?? 0);
if ($played > 0 && $lost === 0) {
$aufmacher = 'Noch ohne Niederlage';
} elseif ($played > 0 && $won === 0) {
$aufmacher = 'Noch ohne Sieg';
} elseif ($played > 0 && $won / $played >= 0.7) {
$aufmacher = $zahlwort($won) . ' Siege aus ' . mb_strtolower($zahlwort($played)) . ' Spielen';
} elseif ($rank === 1) {
$aufmacher = 'Tabellenführer mit ' . $points . ' Punkten';
} elseif ($played > 0 && $diff <= -8) {
$aufmacher = $zahlwort(abs($diff)) . ' Tore mehr kassiert als geschossen';
} elseif ($played > 0 && $diff >= 8) {
$aufmacher = $zahlwort($diff) . ' Tore mehr geschossen als kassiert';
} elseif ($played > 0) {
$aufmacher = $points . ' Punkte aus ' . $played . ' Spielen';
}
}
$spieltagInfo = $opponent !== null && (int) ($opponent['played'] ?? 0) > 0
? 'Stand nach ' . (int) $opponent['played'] . ' Spieltagen'
: '';
?>
<div class="stadionzeitung-gegner">
<header class="stadionzeitung-page__head">
<p class="stadionzeitung-page__kicker"><?= e($teamName !== '' ? 'Unser Gegner · ' . $teamName : 'Unser Gegner') ?></p>
<h2 class="stadionzeitung-page__heading"><?= e($opponentName) ?></h2>
<?php if (!empty($info['league']) || !empty($info['season'])): ?>
<p class="stadionzeitung-page__sub"><?= e(trim(implode(' · ', array_filter([(string) ($info['league'] ?? ''), (string) ($info['season'] ?? '')])))) ?></p>
<?php endif; ?>
</header>
<span class="stadionzeitung-page__rule" aria-hidden="true"></span>
<div class="stadionzeitung-gegner__duell">
<div class="stadionzeitung-gegner__club">
<?php component('crest', ['src' => $ownCrest, 'name' => $ownName]); ?>
<span class="stadionzeitung-gegner__club-name"><?= e($ownName) ?></span>
</div>
<div class="stadionzeitung-gegner__vs">
<p class="stadionzeitung-gegner__vs-wort"><?= $istHeim ? 'gegen' : 'bei' ?></p>
<?php if ($kickoffDate !== ''): ?>
<p class="stadionzeitung-gegner__anstoss"><?= e(german_date($kickoffDate)) ?><?php if ($kickoffTime !== ''): ?><br><?= e($kickoffTime) ?> Uhr<?php endif; ?></p>
<?php endif; ?>
</div>
<div class="stadionzeitung-gegner__club">
<?php component('crest', ['src' => $gegnerCrest, 'name' => $gegnerLabel]); ?>
<span class="stadionzeitung-gegner__club-name"><?= e($gegnerLabel) ?></span>
</div>
</div>
<?php if ($aufmacher !== ''): ?>
<p class="stadionzeitung-gegner__aufmacher"><?= e($aufmacher) ?></p>
<?php endif; ?>
<?php if ($own !== null && $opponent !== null): ?>
<div class="stadionzeitung-gegner__vergleich" role="table" aria-label="Tabellenvergleich">
<div class="stadionzeitung-gegner__vergleich-head" role="row">
<?php /* Spaltenköpfe generisch: vorher standen hier „TSV 08" und „ASV" fest im
Markup — das Kürzel des Marktschorgast-Gegners wäre in jeder Ausgabe
mitgedruckt worden. Die Überschrift nennt den Gegner ohnehin. */ ?>
<span role="columnheader">Wir</span>
<span role="columnheader"><?= e($spieltagInfo !== '' ? $spieltagInfo : 'Vergleich') ?></span>
<span role="columnheader">Gegner</span>
</div>
<?php foreach ($rows as $row): ?>
<div class="stadionzeitung-gegner__vergleich-row" role="row">
<strong class="stadionzeitung-gegner__wert" role="cell"><?= e($format($own, (string) $row['key'], (bool) ($row['signed'] ?? false))) ?></strong>
<span class="stadionzeitung-gegner__balken stadionzeitung-gegner__balken--own" aria-hidden="true"><span class="stadionzeitung-gegner__balken-fuellung stadionzeitung-gegner__balken-fuellung--s<?= $barStep($own, $opponent, (string) $row['key']) ?>"></span></span>
<span class="stadionzeitung-gegner__label" role="rowheader"><?= e((string) $row['label']) ?></span>
<span class="stadionzeitung-gegner__balken" aria-hidden="true"><span class="stadionzeitung-gegner__balken-fuellung stadionzeitung-gegner__balken-fuellung--s<?= $barStep($opponent, $own, (string) $row['key']) ?>"></span></span>
<strong class="stadionzeitung-gegner__wert" role="cell"><?= e($format($opponent, (string) $row['key'], (bool) ($row['signed'] ?? false))) ?></strong>
</div>
<?php endforeach; ?>
</div>
<?php else: ?>
<p class="stadionzeitung-gegner__empty">Die aktuellen Vergleichsdaten waren beim letzten Abruf nicht verfügbar.</p>
<?php endif; ?>
<?php /* Der Tabellenplatz stand kurz als zwei lose Ziffern oben im Duell und
wirkte dort unruhig (Felix, 19.09.2026). Hier zeigt ihn der Ausschnitt
im Zusammenhang: wer steht zwischen uns und ihnen. Gerendert mit der
geteilten league-table-Komponente, nie mit einer zweiten Tabelle. */ ?>
<?php if ($ausschnitt !== []): ?>
<div class="stadionzeitung-gegner__ausschnitt">
<p class="stadionzeitung-gegner__ausschnitt-titel">Die Tabelle dazwischen</p>
<?php foreach ($ausschnitt as $block): ?>
<?php component('league-table', ['table' => $block, 'caption' => 'Tabellenausschnitt ' . (string) ($info['league'] ?? '')]); ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>