This commit is contained in:
2026-06-23 15:56:11 -05:00
parent 93ae2cbf0a
commit 82d093fbb4
4 changed files with 48 additions and 22 deletions

View File

@@ -21,7 +21,8 @@ export async function GET() {
}
const groupTables = computeGroupTables(teams, matches);
const thirdTable = computeThirdPlaceTable(groupTables);
const groupTablesLive = computeGroupTables(teams, matches, true);
const thirdTable = computeThirdPlaceTable(groupTablesLive);
const qGroups = qualifiedThirdGroups(thirdTable);
const annex = qGroups.length === 8 ? resolveAnnexC(qGroups) : null;
@@ -30,6 +31,7 @@ export async function GET() {
teams,
matches,
groupTables,
groupTablesLive,
thirdTable,
annexAssignment: annex,
annexResolved: annex != null,

View File

@@ -13,6 +13,18 @@ function liveMatchFor(group: string, matches: Match[]) {
);
}
function liveTeamIdsFor(group: GroupId, matches: Match[]): Set<string> {
const ids = new Set<string>();
for (const m of matches) {
if (m.group !== group) continue;
if (m.status === "LIVE" || m.status === "IN_PLAY" || m.status === "PAUSED") {
if (m.homeTeamId) ids.add(m.homeTeamId);
if (m.awayTeamId) ids.add(m.awayTeamId);
}
}
return ids;
}
export default function Groups({
tables, teams, matches, onOpenGroup,
}: {
@@ -23,6 +35,7 @@ export default function Groups({
<div className="group-grid">
{tables.map((t) => {
const live = liveMatchFor(t.group, matches);
const liveIds = liveTeamIdsFor(t.group, matches);
return (
<div className="group-card" key={t.group}>
<button
@@ -47,12 +60,14 @@ export default function Groups({
{t.rows.map((r) => {
const team = teamById(teams, r.teamId);
const cls = r.rank <= 2 ? `q${r.rank}` : r.rank === 3 ? "q3" : "";
const isLive = liveIds.has(r.teamId);
return (
<tr key={r.teamId}>
<tr key={r.teamId} className={isLive ? "row-live" : ""}>
<td className="team">
<span className={`rankdot ${cls}`}>{r.rank}</span>
<Flag team={team} size={20} />
<span className="team-name">{team?.name ?? r.teamId}</span>
{isLive && <span className="row-live-dot" title="läuft gerade" />}
</td>
<td>{r.played}</td>
<td>{r.won}</td>

View File

@@ -87,6 +87,7 @@ a { color: inherit; text-decoration: none; }
/* ---------- Tabs ---------- */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin: 0 0 4px; }
.masthead-tabs { width: 100%; border-bottom: none; margin: 0; }
.tab {
font-family: var(--font-display); font-weight: 700;
text-transform: uppercase; letter-spacing: 0.01em;
@@ -149,6 +150,13 @@ table.standings { width: 100%; border-collapse: collapse; }
/* Live-Zeile */
.score-live { color: var(--live); font-weight: 700; }
/* Gruppen-Tab: grüne Hervorhebung für Teams mit laufendem Spiel */
.group-grid .row-live { background: rgba(74, 222, 128, 0.08); }
.group-grid .row-live .team-name { color: var(--turf); }
.group-grid .row-live-dot {
background: var(--turf);
}
/* ---------- Drittplatzierte ---------- */
.third-wrap { margin-top: 8px; }
.third-table { width: 100%; border-collapse: collapse; background: var(--bg-card);
@@ -181,7 +189,7 @@ table.standings { width: 100%; border-collapse: collapse; }
font-family: var(--font-mono); font-size: 12px; color: var(--ink-dim);
}
.bracket-banner .v { font-family: var(--font-mono); font-size: 12px; color: var(--turf); }
.bracket-scroll { overflow-x: auto; padding-bottom: 16px; }
.bracket-scroll { overflow-x: auto; padding-bottom: 28px; }
.bracket {
display: flex; gap: 26px; min-width: max-content; align-items: stretch;
}

View File

@@ -13,6 +13,7 @@ interface ApiData {
teams: Team[];
matches: Match[];
groupTables: GroupTable[];
groupTablesLive: GroupTable[];
thirdTable: ThirdPlaceRow[];
annexAssignment: ThirdAssignment | null;
annexResolved: boolean;
@@ -73,27 +74,27 @@ export default function Home() {
? anyLive ? "Live" : `Aktualisiert ${new Date(data.updatedAt).toLocaleTimeString("de-DE")}`
: "Lade Daten…"}
</span>
<nav className="tabs masthead-tabs">
<button className={`tab ${tab === "groups" ? "active" : ""}`} onClick={() => setTab("groups")}>
Gruppen
</button>
<button
className={`tab ${tab === "fixtures" ? "active" : ""}`}
onClick={() => { if (!fixturesGroup) setFixturesGroup("A"); setTab("fixtures"); }}
>
{fixturesGroup ? `Spiele Gruppe ${fixturesGroup}` : "Spiele"}
</button>
<button className={`tab ${tab === "thirds" ? "active" : ""}`} onClick={() => setTab("thirds")}>
Drittplatzierte
</button>
<button className={`tab ${tab === "bracket" ? "active" : ""}`} onClick={() => setTab("bracket")}>
K.o.-Baum
</button>
</nav>
</div>
</header>
<main className="wrap">
<nav className="tabs">
<button className={`tab ${tab === "groups" ? "active" : ""}`} onClick={() => setTab("groups")}>
Gruppen
</button>
<button
className={`tab ${tab === "fixtures" ? "active" : ""}`}
onClick={() => { if (!fixturesGroup) setFixturesGroup("A"); setTab("fixtures"); }}
>
{fixturesGroup ? `Spiele Gruppe ${fixturesGroup}` : "Spiele"}
</button>
<button className={`tab ${tab === "thirds" ? "active" : ""}`} onClick={() => setTab("thirds")}>
Drittplatzierte
</button>
<button className={`tab ${tab === "bracket" ? "active" : ""}`} onClick={() => setTab("bracket")}>
K.o.-Baum
</button>
</nav>
<section className="section">
{error && (
@@ -112,7 +113,7 @@ export default function Home() {
{data && tab === "groups" && (
<Groups
tables={data.groupTables} teams={data.teams} matches={data.matches}
tables={data.groupTablesLive} teams={data.teams} matches={data.matches}
onOpenGroup={openGroupFixtures}
/>
)}
@@ -127,7 +128,7 @@ export default function Home() {
)}
{data && tab === "bracket" && (
<Bracket
matches={data.matches} teams={data.teams} tables={data.groupTables}
matches={data.matches} teams={data.teams} tables={data.groupTablesLive}
thirds={data.thirdTable} assignment={data.annexAssignment}
annexResolved={data.annexResolved}
/>