brackt/app/components/draft/DraftPickCell.tsx

125 lines
3.6 KiB
TypeScript
Raw Normal View History

2026-04-16 22:00:00 -07:00
import type { CSSProperties, ReactNode } from "react";
2026-04-16 20:46:00 -07:00
import { cn } from "~/lib/utils";
2026-04-16 22:00:00 -07:00
export type CoronaState =
| { type: "eliminated"; points: 0 }
| { type: "pending" }
| { type: "scored"; brightness: number; points: number };
2026-04-16 20:46:00 -07:00
type CoronaVariant =
| "gradient"
| "electric"
| "emerald"
| "amber"
| "coral";
interface DraftPickCellProps {
pickNumber: number;
round: number;
pickInRound: number;
state: "picked" | "current" | "upcoming";
pick?: {
participant: { name: string };
sport: { name: string };
};
corona?: CoronaVariant;
2026-04-16 22:00:00 -07:00
coronaState?: CoronaState;
2026-04-16 20:46:00 -07:00
className?: string;
children?: ReactNode;
}
const coronaClasses: Record<CoronaVariant, string> = {
gradient: "[background:linear-gradient(to_bottom,#adf661,#2ce1c1)]",
electric: "bg-electric",
emerald: "bg-emerald-500",
amber: "bg-amber-accent",
coral: "bg-coral-accent",
};
2026-04-16 22:00:00 -07:00
function getCoronaStyle(cs: CoronaState): CSSProperties {
switch (cs.type) {
case "eliminated":
return { background: "oklch(0.45 0.20 25)" };
case "pending":
return { background: "rgba(255, 255, 255, 0.08)" };
case "scored":
return {
background: "linear-gradient(to bottom, #adf661, #2ce1c1)",
opacity: cs.brightness,
};
}
}
2026-04-16 20:46:00 -07:00
export function DraftPickCell({
pickNumber,
round,
pickInRound,
state,
pick,
corona = "gradient",
2026-04-16 22:00:00 -07:00
coronaState,
2026-04-16 20:46:00 -07:00
className,
children,
}: DraftPickCellProps) {
const showCorona = state === "picked";
return (
<div
className={cn(
"relative flex-1 min-w-32 overflow-hidden",
className,
)}
>
2026-04-16 22:00:00 -07:00
{showCorona && coronaState ? (
<div
className="absolute top-0.5 bottom-0.5 left-0 right-0 rounded-lg"
style={getCoronaStyle(coronaState)}
/>
) : showCorona ? (
2026-04-16 20:46:00 -07:00
<div
className={cn(
"absolute top-0.5 bottom-0.5 left-0 right-0 rounded-lg",
coronaClasses[corona],
)}
/>
2026-04-16 22:00:00 -07:00
) : null}
2026-04-16 20:46:00 -07:00
<div
className={cn(
2026-04-16 22:00:00 -07:00
"relative z-10 h-14 border-2 rounded-lg p-2 transition-all",
2026-04-16 20:46:00 -07:00
showCorona && "mr-1",
state === "current"
? "border-electric bg-electric/20 shadow-lg shadow-electric/30 ring-2 ring-electric/50 animate-pulse"
: state === "picked"
? "bg-muted border-transparent"
: "border-border bg-card",
)}
title={`Overall Pick #${pickNumber}`}
>
2026-04-16 22:00:00 -07:00
<div className="flex gap-1 items-start">
{state === "picked" && pick ? (
<div className="text-sm min-w-0 flex-1">
<div className="font-semibold truncate text-sm">{pick.participant.name}</div>
<div className="text-muted-foreground truncate text-xs">
{pick.sport.name}
</div>
2026-04-16 20:46:00 -07:00
</div>
2026-04-16 22:00:00 -07:00
) : state === "current" ? (
<div className="text-sm font-bold text-electric">On Clock</div>
) : null}
<div className="flex flex-col items-end shrink-0">
<div className="text-xs font-mono text-muted-foreground leading-5">
{round}.{String(pickInRound).padStart(2, "0")}
</div>
{coronaState && coronaState.type !== "pending" && (
<span className={`text-xs font-mono font-bold mt-0.5 ${coronaState.type === "eliminated" ? "text-coral-accent" : "text-emerald-400"}`}>
{coronaState.type === "scored" && "▲"}{coronaState.points}
</span>
)}
2026-04-16 20:46:00 -07:00
</div>
2026-04-16 22:00:00 -07:00
</div>
2026-04-16 20:46:00 -07:00
{children && <div className="absolute inset-0 pointer-events-none [&_*]:pointer-events-auto">{children}</div>}
</div>
</div>
);
}