fixes
This commit is contained in:
@@ -12,7 +12,10 @@ function Side({
|
|||||||
// fix = ein echtes Team steht fest (nicht vorläufig). Eigene Klasse für klares Styling.
|
// fix = ein echtes Team steht fest (nicht vorläufig). Eigene Klasse für klares Styling.
|
||||||
const fix = s.teamId != null && !s.provisional;
|
const fix = s.teamId != null && !s.provisional;
|
||||||
return (
|
return (
|
||||||
<div className={`side ${s.isWinner ? "win" : ""} ${s.provisional ? "prov" : ""} ${fix ? "fix" : ""}`}>
|
<div
|
||||||
|
className={`side ${s.isWinner ? "win" : ""} ${s.provisional ? "prov" : ""} ${fix ? "fix" : ""}`}
|
||||||
|
title={s.tooltip ?? undefined}
|
||||||
|
>
|
||||||
<span className="nm">
|
<span className="nm">
|
||||||
{s.teamId ? (
|
{s.teamId ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -189,10 +189,15 @@ table.standings { width: 100%; border-collapse: collapse; }
|
|||||||
font-family: var(--font-mono); font-size: 12px; color: var(--ink-dim);
|
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-banner .v { font-family: var(--font-mono); font-size: 12px; color: var(--turf); }
|
||||||
.bracket-scroll { overflow-x: auto; padding-bottom: 36px; }
|
.bracket-scroll {
|
||||||
|
max-height: calc(100vh - 260px);
|
||||||
|
overflow: auto;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
}
|
||||||
.bracket {
|
.bracket {
|
||||||
display: flex; gap: 26px; min-width: max-content; align-items: stretch;
|
display: flex; gap: 26px; min-width: max-content; align-items: stretch;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 8px;
|
||||||
}
|
}
|
||||||
.round { display: flex; flex-direction: column; min-width: 220px; }
|
.round { display: flex; flex-direction: column; min-width: 220px; }
|
||||||
.round-label {
|
.round-label {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export interface ResolvedSide {
|
|||||||
score: number | null;
|
score: number | null;
|
||||||
isWinner: boolean;
|
isWinner: boolean;
|
||||||
provisional: boolean; // true = nur auf Basis aktueller Tabelle, noch nicht fix
|
provisional: boolean; // true = nur auf Basis aktueller Tabelle, noch nicht fix
|
||||||
|
tooltip: string | null; // Hover-Erklärung (Herkunft + ob fix)
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResolvedTie {
|
export interface ResolvedTie {
|
||||||
@@ -64,19 +65,23 @@ function resolveR32Slot(
|
|||||||
matches: Match[],
|
matches: Match[],
|
||||||
teams: Team[],
|
teams: Team[],
|
||||||
annexResolved: boolean,
|
annexResolved: boolean,
|
||||||
): { teamId: string | null; provisional: boolean } {
|
): { teamId: string | null; provisional: boolean; tooltip: string | null } {
|
||||||
const table = (g: GroupId) => tables.find((t) => t.group === g);
|
const table = (g: GroupId) => tables.find((t) => t.group === g);
|
||||||
if (slot.type === "W") {
|
if (slot.type === "W") {
|
||||||
const t = table(slot.group!);
|
const t = table(slot.group!);
|
||||||
const teamId = t?.rows.find((r) => r.rank === 1)?.teamId ?? null;
|
const teamId = t?.rows.find((r) => r.rank === 1)?.teamId ?? null;
|
||||||
// Sieger fix, sobald Platz 1 rechnerisch gesichert ist (auch vor Gruppenende).
|
// Sieger fix, sobald Platz 1 rechnerisch gesichert ist (auch vor Gruppenende).
|
||||||
return { teamId, provisional: !placeIsSecure(slot.group!, 1, teams, matches) };
|
const provisional = !placeIsSecure(slot.group!, 1, teams, matches);
|
||||||
|
const prefix = provisional ? "aktuell " : "";
|
||||||
|
return { teamId, provisional, tooltip: `${prefix}1. Gruppe ${slot.group}` };
|
||||||
}
|
}
|
||||||
if (slot.type === "R") {
|
if (slot.type === "R") {
|
||||||
const t = table(slot.group!);
|
const t = table(slot.group!);
|
||||||
const teamId = t?.rows.find((r) => r.rank === 2)?.teamId ?? null;
|
const teamId = t?.rows.find((r) => r.rank === 2)?.teamId ?? null;
|
||||||
// Zweiter fix, sobald Platz 2 rechnerisch gesichert ist.
|
// Zweiter fix, sobald Platz 2 rechnerisch gesichert ist.
|
||||||
return { teamId, provisional: !placeIsSecure(slot.group!, 2, teams, matches) };
|
const provisional = !placeIsSecure(slot.group!, 2, teams, matches);
|
||||||
|
const prefix = provisional ? "aktuell " : "";
|
||||||
|
return { teamId, provisional, tooltip: `${prefix}2. Gruppe ${slot.group}` };
|
||||||
}
|
}
|
||||||
// 3. Platz: braucht Annex-C-Zuordnung + den Gruppensieger dieses Spiels
|
// 3. Platz: braucht Annex-C-Zuordnung + den Gruppensieger dieses Spiels
|
||||||
if (slot.type === "3" && assignment && winnerGroup) {
|
if (slot.type === "3" && assignment && winnerGroup) {
|
||||||
@@ -86,16 +91,27 @@ function resolveR32Slot(
|
|||||||
// Fix nur, wenn Annex C aufgelöst UND die Quellgruppe abgeschlossen ist
|
// Fix nur, wenn Annex C aufgelöst UND die Quellgruppe abgeschlossen ist
|
||||||
// (Drittplatzierten-Qualifikation ist gruppenübergreifend, bis zuletzt offen).
|
// (Drittplatzierten-Qualifikation ist gruppenübergreifend, bis zuletzt offen).
|
||||||
const fix = annexResolved && groupFinished(thirdGroup, matches);
|
const fix = annexResolved && groupFinished(thirdGroup, matches);
|
||||||
return { teamId: row?.teamId ?? null, provisional: !fix };
|
const provisional = !fix;
|
||||||
|
const prefix = provisional ? "aktuell " : "";
|
||||||
|
return {
|
||||||
|
teamId: row?.teamId ?? null,
|
||||||
|
provisional,
|
||||||
|
tooltip: `${prefix}3. der Gruppe ${thirdGroup}`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { teamId: null, provisional: true };
|
if (slot.type === "3") {
|
||||||
|
const pool = slot.thirdPool?.join("") ?? "?";
|
||||||
|
return { teamId: null, provisional: true, tooltip: `aktuell 3. Gruppe ${pool}` };
|
||||||
|
}
|
||||||
|
return { teamId: null, provisional: true, tooltip: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
function sideFrom(
|
function sideFrom(
|
||||||
teamId: string | null, fallbackLabel: string,
|
teamId: string | null, fallbackLabel: string,
|
||||||
teams: Team[], feed: Match | undefined, which: "home" | "away",
|
teams: Team[], feed: Match | undefined, which: "home" | "away",
|
||||||
provisional: boolean,
|
provisional: boolean,
|
||||||
|
tooltip: string | null,
|
||||||
): ResolvedSide {
|
): ResolvedSide {
|
||||||
const team = teamId ? teams.find((t) => t.id === teamId) : undefined;
|
const team = teamId ? teams.find((t) => t.id === teamId) : undefined;
|
||||||
const score = feed
|
const score = feed
|
||||||
@@ -109,6 +125,7 @@ function sideFrom(
|
|||||||
score,
|
score,
|
||||||
isWinner: teamId != null && w === teamId,
|
isWinner: teamId != null && w === teamId,
|
||||||
provisional: teamId != null && provisional,
|
provisional: teamId != null && provisional,
|
||||||
|
tooltip,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,8 +150,8 @@ export function resolveBracket(
|
|||||||
|
|
||||||
const h = resolveR32Slot(rm.home, winnerGroup, tables, assignment, thirds, matches, teams, annexResolved);
|
const h = resolveR32Slot(rm.home, winnerGroup, tables, assignment, thirds, matches, teams, annexResolved);
|
||||||
const a = resolveR32Slot(rm.away, winnerGroup, tables, assignment, thirds, matches, teams, annexResolved);
|
const a = resolveR32Slot(rm.away, winnerGroup, tables, assignment, thirds, matches, teams, annexResolved);
|
||||||
const home = sideFrom(h.teamId, slotLabel(rm.home, assignment, winnerGroup), teams, feed, "home", h.provisional);
|
const home = sideFrom(h.teamId, slotLabel(rm.home, assignment, winnerGroup), teams, feed, "home", h.provisional, h.tooltip);
|
||||||
const away = sideFrom(a.teamId, slotLabel(rm.away, assignment, winnerGroup), teams, feed, "away", a.provisional);
|
const away = sideFrom(a.teamId, slotLabel(rm.away, assignment, winnerGroup), teams, feed, "away", a.provisional, a.tooltip);
|
||||||
|
|
||||||
winners.set(rm.matchNumber, winnerOf(feed));
|
winners.set(rm.matchNumber, winnerOf(feed));
|
||||||
losers.set(rm.matchNumber, loserOf(feed));
|
losers.set(rm.matchNumber, loserOf(feed));
|
||||||
@@ -156,8 +173,10 @@ export function resolveBracket(
|
|||||||
const awayProv = !(decided.get(km.fromAway) ?? false);
|
const awayProv = !(decided.get(km.fromAway) ?? false);
|
||||||
const homeLabel = `${km.losers ? "Verlierer" : "Sieger"} ${km.fromHome}`;
|
const homeLabel = `${km.losers ? "Verlierer" : "Sieger"} ${km.fromHome}`;
|
||||||
const awayLabel = `${km.losers ? "Verlierer" : "Sieger"} ${km.fromAway}`;
|
const awayLabel = `${km.losers ? "Verlierer" : "Sieger"} ${km.fromAway}`;
|
||||||
const home = sideFrom(homeId, homeLabel, teams, feed, "home", homeProv);
|
const homeTtip = `${km.losers ? "Verlierer" : "Sieger"} aus Spiel ${km.fromHome}`;
|
||||||
const away = sideFrom(awayId, awayLabel, teams, feed, "away", awayProv);
|
const awayTtip = `${km.losers ? "Verlierer" : "Sieger"} aus Spiel ${km.fromAway}`;
|
||||||
|
const home = sideFrom(homeId, homeLabel, teams, feed, "home", homeProv, homeTtip);
|
||||||
|
const away = sideFrom(awayId, awayLabel, teams, feed, "away", awayProv, awayTtip);
|
||||||
winners.set(km.matchNumber, winnerOf(feed));
|
winners.set(km.matchNumber, winnerOf(feed));
|
||||||
losers.set(km.matchNumber, loserOf(feed));
|
losers.set(km.matchNumber, loserOf(feed));
|
||||||
decided.set(km.matchNumber, feed?.status === "FINISHED");
|
decided.set(km.matchNumber, feed?.status === "FINISHED");
|
||||||
|
|||||||
Reference in New Issue
Block a user