2026-06-21 11:56:15 -07:00
|
|
|
/**
|
|
|
|
|
* Stacked stat column: label / value / delta. The delta slot is always rendered
|
|
|
|
|
* (a muted "—" placeholder when there is no change) so that every row reserves the
|
|
|
|
|
* same vertical space and the columns line up across the standings table.
|
|
|
|
|
*/
|
2026-04-23 13:52:34 -07:00
|
|
|
export function StatColumn({
|
|
|
|
|
label,
|
2026-06-21 11:56:15 -07:00
|
|
|
value,
|
|
|
|
|
delta,
|
|
|
|
|
reserveDelta = false,
|
2026-04-23 13:52:34 -07:00
|
|
|
}: {
|
|
|
|
|
label: string;
|
2026-06-21 11:56:15 -07:00
|
|
|
value: React.ReactNode;
|
|
|
|
|
/** Optional change indicator rendered on its own line below the value. */
|
|
|
|
|
delta?: React.ReactNode;
|
|
|
|
|
/**
|
|
|
|
|
* When true, the delta line is always rendered (a muted placeholder when there is
|
|
|
|
|
* no delta) so columns stay vertically aligned across rows. When false and no delta
|
|
|
|
|
* is provided, the line is omitted entirely.
|
|
|
|
|
*/
|
|
|
|
|
reserveDelta?: boolean;
|
2026-04-23 13:52:34 -07:00
|
|
|
}) {
|
2026-06-21 11:56:15 -07:00
|
|
|
const showDeltaLine = delta !== undefined || reserveDelta;
|
2026-04-23 13:52:34 -07:00
|
|
|
return (
|
|
|
|
|
<div className="text-right shrink-0 flex-1 sm:flex-none">
|
|
|
|
|
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
|
|
|
|
{label}
|
|
|
|
|
</p>
|
2026-06-21 11:56:15 -07:00
|
|
|
<div className="flex items-baseline justify-end">{value}</div>
|
|
|
|
|
{showDeltaLine && (
|
|
|
|
|
<div className="flex items-baseline justify-end leading-none mt-0.5">
|
|
|
|
|
{delta ?? <span className="text-xs text-muted-foreground/60">—</span>}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-04-23 13:52:34 -07:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 11:56:15 -07:00
|
|
|
export function StatDivider({ className = "h-12" }: { className?: string } = {}) {
|
|
|
|
|
return <div className={`${className} w-px bg-border shrink-0 self-center`} />;
|
2026-04-23 13:52:34 -07:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 11:56:15 -07:00
|
|
|
/**
|
|
|
|
|
* 7-day change indicator. `rank` deltas are unitless places; `points` deltas are
|
|
|
|
|
* rounded point totals. Positive = up (green ▲), negative = down (coral ▼).
|
|
|
|
|
*/
|
|
|
|
|
export function DeltaBadge({
|
|
|
|
|
delta,
|
|
|
|
|
kind,
|
|
|
|
|
}: {
|
|
|
|
|
delta: number;
|
|
|
|
|
kind: "rank" | "points";
|
|
|
|
|
}) {
|
|
|
|
|
const magnitude = kind === "rank" ? Math.abs(delta) : Math.abs(Math.round(delta));
|
|
|
|
|
const up = delta > 0;
|
|
|
|
|
const label =
|
|
|
|
|
kind === "rank"
|
|
|
|
|
? up
|
|
|
|
|
? `up ${magnitude}`
|
|
|
|
|
: `down ${magnitude}`
|
|
|
|
|
: up
|
|
|
|
|
? `+${magnitude} points`
|
|
|
|
|
: `-${magnitude} points`;
|
|
|
|
|
|
|
|
|
|
if (up) {
|
2026-04-23 13:52:34 -07:00
|
|
|
return (
|
2026-06-21 11:56:15 -07:00
|
|
|
<span className="text-xs font-semibold text-primary" aria-label={label}>
|
|
|
|
|
▲{magnitude}
|
2026-04-23 13:52:34 -07:00
|
|
|
</span>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return (
|
|
|
|
|
<span
|
|
|
|
|
className="text-xs font-semibold"
|
|
|
|
|
style={{ color: "var(--coral-accent, #ef4444)" }}
|
2026-06-21 11:56:15 -07:00
|
|
|
aria-label={label}
|
2026-04-23 13:52:34 -07:00
|
|
|
>
|
2026-06-21 11:56:15 -07:00
|
|
|
▼{magnitude}
|
2026-04-23 13:52:34 -07:00
|
|
|
</span>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 11:11:20 -07:00
|
|
|
export function RankingDisplay({
|
|
|
|
|
displayRank,
|
|
|
|
|
rankChange,
|
2026-06-21 11:56:15 -07:00
|
|
|
reserveDelta = false,
|
2026-04-24 11:11:20 -07:00
|
|
|
}: {
|
|
|
|
|
displayRank: string | number;
|
|
|
|
|
rankChange?: number;
|
2026-06-21 11:56:15 -07:00
|
|
|
reserveDelta?: boolean;
|
2026-04-24 11:11:20 -07:00
|
|
|
}) {
|
|
|
|
|
return (
|
2026-06-21 11:56:15 -07:00
|
|
|
<StatColumn
|
|
|
|
|
label="Ranking"
|
|
|
|
|
reserveDelta={reserveDelta}
|
|
|
|
|
value={<span className="text-2xl font-bold leading-none">{displayRank}</span>}
|
|
|
|
|
delta={
|
|
|
|
|
rankChange !== undefined && rankChange !== 0 ? (
|
|
|
|
|
<DeltaBadge delta={rankChange} kind="rank" />
|
|
|
|
|
) : undefined
|
|
|
|
|
}
|
|
|
|
|
/>
|
2026-04-23 13:52:34 -07:00
|
|
|
);
|
|
|
|
|
}
|