4faedd60c4
Design handoff steps 4-5: - LivePage: headline live-match hero (gradient card, live ring, smallcaps stage/venue + minute, big mono score, 3-segment in-play win-prob bar); favorite team's live match takes the hero slot - MatchCard: played matches as stacked team rows with the beaten side dimmed; scheduled matches as a centered 'vs' pairing (model hint and venue stay) - GroupTable: Form column — tiny W/D/L bars (accent/gold/loss) computed from finished group matches - BracketPage: one round-selector layout on every screen size (cards in a 2-col grid, losers dimmed), gold 'Projected champion' banner on the Final view; what-if mode, advance bars, R32 and the third-place play-off all unchanged - Predict title race: leader bar, rank and percentage in gold Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
87 lines
3.6 KiB
TypeScript
87 lines
3.6 KiB
TypeScript
import { Link } from '@tanstack/react-router';
|
||
import { cn } from '@/lib/cn';
|
||
import { teamFlag } from '@/lib/teams';
|
||
import { fmt, useT } from '@/lib/i18n';
|
||
import type { StandingRow } from '@/lib/types';
|
||
|
||
export type FormLetter = 'W' | 'D' | 'L';
|
||
|
||
/** Tiny result bars, oldest → newest: W accent · D gold · L loss. */
|
||
function FormBars({ form }: { form: FormLetter[] }) {
|
||
const t = useT();
|
||
if (!form.length) return <span className="text-faint">–</span>;
|
||
return (
|
||
<span className="inline-flex items-end gap-[3px]" role="img" aria-label={form.join(' ')}>
|
||
{form.map((r, i) => (
|
||
<span
|
||
key={i}
|
||
title={t.groups.formLetter[r]}
|
||
className={cn(
|
||
'inline-block w-1.5 rounded-[2px]',
|
||
r === 'W' && 'h-3.5 bg-accent',
|
||
r === 'D' && 'h-2.5 bg-gold',
|
||
r === 'L' && 'h-2.5 bg-loss',
|
||
)}
|
||
/>
|
||
))}
|
||
</span>
|
||
);
|
||
}
|
||
|
||
/** One group's standings. Top 2 qualify directly; 3rd may advance as a best-third. */
|
||
export function GroupTable({ group, rows, form }: { group: string; rows: StandingRow[]; form?: Record<string, FormLetter[]> }) {
|
||
const t = useT();
|
||
return (
|
||
<div className="overflow-hidden rounded-xl border border-line bg-panel">
|
||
<div className="flex items-center justify-between border-b border-line px-3 py-2">
|
||
<span className="font-display text-sm font-bold text-ink">{fmt(t.common.group, { group })}</span>
|
||
<span className="smallcaps">{t.groups.tableHeaderPldPts}</span>
|
||
</div>
|
||
<table className="w-full border-collapse text-sm">
|
||
<thead>
|
||
<tr className="text-[11px] uppercase tracking-wide text-faint">
|
||
<th className="px-3 py-1.5 text-left font-semibold">{t.groups.colTeam}</th>
|
||
<th className="w-8 py-1.5 text-center font-semibold">{t.groups.colPlayed}</th>
|
||
<th className="w-8 py-1.5 text-center font-semibold">{t.groups.colGoalDiff}</th>
|
||
<th className="w-9 py-1.5 text-center font-semibold">{t.groups.colPoints}</th>
|
||
{form && <th className="w-10 py-1.5 pr-3 text-center font-semibold">{t.groups.colForm}</th>}
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{rows.map((r) => (
|
||
<tr
|
||
key={r.team}
|
||
className={cn(
|
||
'border-t border-line/60',
|
||
r.rank <= 2 && 'bg-accent-glow',
|
||
r.rank === 3 && 'bg-gold/5',
|
||
)}
|
||
>
|
||
<td className="px-3 py-1.5">
|
||
<Link to="/team/$name" params={{ name: r.team }} className="flex items-center gap-2 hover:text-accent">
|
||
<span
|
||
className={cn(
|
||
'w-4 text-center text-[11px] font-bold tabular-nums',
|
||
r.rank <= 2 ? 'text-accent' : r.rank === 3 ? 'text-gold' : 'text-faint',
|
||
)}
|
||
>
|
||
{r.rank}
|
||
</span>
|
||
<span aria-hidden className="text-base leading-none">{teamFlag(r.team)}</span>
|
||
<span className="truncate text-ink">{r.team}</span>
|
||
</Link>
|
||
</td>
|
||
<td className="py-1.5 text-center tabular-nums text-muted">{r.played}</td>
|
||
<td className="py-1.5 text-center tabular-nums text-muted">
|
||
{r.gd > 0 ? `+${r.gd}` : r.gd}
|
||
</td>
|
||
<td className="py-1.5 text-center font-bold tabular-nums text-ink">{r.points}</td>
|
||
{form && <td className="py-1.5 pr-3 text-center"><FormBars form={form[r.team] ?? []} /></td>}
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
);
|
||
}
|