import Link from "next/link"; import type { Artist } from "@/types/artist"; import ArtistPortrait from "@/components/cards/ArtistPortrait"; import { cn } from "@/lib/cn"; interface Top3PodiumProps { top3: Artist[]; } function formatVotes(v: number): string { if (v >= 10_000) return `${(v / 10_000).toFixed(1)}w`; return v.toLocaleString(); } export default function Top3Podium({ top3 }: Top3PodiumProps) { const [first, second, third] = top3; // 0 票时按编号兜底排出来的"伪冠军"不算 —— 这些位置当作缺位处理 const champ = first && first.votes > 0 ? first : undefined; const runnerUp = second && second.votes > 0 ? second : undefined; const thirdPlace = third && third.votes > 0 ? third : undefined; // 视觉顺序:第二 / 第一(中央) / 第三 · 缺位 = 虚位以待 const order: Array<{ artist: Artist | undefined; rank: 1 | 2 | 3 }> = [ { artist: runnerUp, rank: 2 }, { artist: champ, rank: 1 }, { artist: thirdPlace, rank: 3 }, ]; const lead = champ && runnerUp ? champ.votes - runnerUp.votes : null; return ( // 冠军卡片更宽更高(1.3fr),亚季军等宽(1fr),三张底部对齐; // 整个组合最大宽度受限并横向居中,避免在 1500 版心下占满铺张。
{order.map(({ artist, rank }) => { if (!artist) { return ; } const isFirst = rank === 1; return ( {/* 顶部奖牌 SVG · 悬浮在卡片顶边上方 */} {/* eslint-disable-next-line @next/next/no-img-element */} {`第 {/* 卡片容器(3:4 比例) · #1 金色渐变描边 + 金色辉光;#2 #3 紫色描边 */}
{/* 内层 · #1 用 2px 内填让金色渐变作为描边露出 */}
{/* 立绘填满卡片 */} {/* 底部渐隐 + 信息层 */}
{artist.name}
{formatVotes(artist.votes)}{" "}
{isFirst && lead != null && lead > 0 && (
领先 +{lead.toLocaleString()}
)}
); })}
); } /** 虚位以待 · 任意 rank 缺位时的占位卡片,与正式卡片同 3:4 比例对齐底边 */ function EmptySlot({ rank }: { rank: 1 | 2 | 3 }) { const isFirst = rank === 1; return (
{/* eslint-disable-next-line @next/next/no-img-element */} {`第

Vacant

虚位以待

); }