83 lines
2.7 KiB
TypeScript
83 lines
2.7 KiB
TypeScript
import type { Artist } from "@/types/artist";
|
||
import { cn } from "@/lib/cn";
|
||
|
||
interface RankCardProps {
|
||
artist: Artist;
|
||
/** 全榜单(用于计算与上下名的差距) */
|
||
allArtists: Artist[];
|
||
className?: string;
|
||
}
|
||
|
||
export default function RankCard({ artist, allArtists, className }: RankCardProps) {
|
||
// 按当前票数排序后定位艺人
|
||
const sorted = [...allArtists].sort((a, b) => b.votes - a.votes);
|
||
const idx = sorted.findIndex((a) => a.id === artist.id);
|
||
const prev = idx > 0 ? sorted[idx - 1] : undefined;
|
||
const next = idx < sorted.length - 1 ? sorted[idx + 1] : undefined;
|
||
|
||
const leadOver = next ? artist.votes - next.votes : null;
|
||
const trailBehind = prev ? prev.votes - artist.votes : null;
|
||
|
||
const isFirst = artist.rank === 1;
|
||
const inTop12 = artist.rank <= 12;
|
||
|
||
return (
|
||
<div
|
||
className={cn(
|
||
"bg-elevated/60 backdrop-blur-md border border-white/10 rounded-xl p-4 sm:p-5 grid grid-cols-2 gap-4",
|
||
className,
|
||
)}
|
||
>
|
||
{/* 当前排名 */}
|
||
<div>
|
||
<div className="font-label text-[10px] tracking-widest uppercase text-white/40 mb-1">
|
||
当前排名
|
||
</div>
|
||
<div className="flex items-end gap-2">
|
||
<span
|
||
className={cn(
|
||
"font-display text-3xl sm:text-4xl tabular-nums leading-none",
|
||
inTop12 ? "text-purple-300 glow-text-purple" : "text-white/70",
|
||
)}
|
||
>
|
||
#{artist.rank}
|
||
</span>
|
||
<span className="text-xs text-white/45 pb-1 tabular-nums">
|
||
{(artist.votes / 10000).toFixed(1)}w 票
|
||
</span>
|
||
</div>
|
||
{inTop12 && (
|
||
<span className="inline-block mt-2 font-label text-[10px] tracking-widest text-pink-400 uppercase">
|
||
✦ 出道位
|
||
</span>
|
||
)}
|
||
</div>
|
||
|
||
{/* 差距信息 */}
|
||
<div className="text-right">
|
||
{isFirst && leadOver != null ? (
|
||
<>
|
||
<div className="font-label text-[10px] tracking-widest uppercase text-white/40 mb-1">
|
||
领先第二名
|
||
</div>
|
||
<div className="font-display text-lg sm:text-xl text-pink-400 tabular-nums">
|
||
+{leadOver.toLocaleString()}
|
||
</div>
|
||
<div className="text-[10px] text-white/40">票</div>
|
||
</>
|
||
) : trailBehind != null ? (
|
||
<>
|
||
<div className="font-label text-[10px] tracking-widest uppercase text-white/40 mb-1">
|
||
距上一名
|
||
</div>
|
||
<div className="font-display text-lg sm:text-xl text-purple-300 tabular-nums">
|
||
−{trailBehind.toLocaleString()}
|
||
</div>
|
||
<div className="text-[10px] text-white/40">票</div>
|
||
</>
|
||
) : null}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|