"use client" import * as React from "react" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Skeleton } from "@/components/ui/skeleton" import { cn } from "@/lib/utils" import type { LeaderboardEntry } from "@/lib/services/leaderboard" interface LeaderboardPodiumProps { items: LeaderboardEntry[] loading?: boolean } type PodiumRank = 1 | 2 | 3 function formatBalance(value: string) { return Number.parseFloat(value).toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2, }) } const rankConfig = { 1: { numColor: "from-amber-500/60 to-amber-500/8", scoreColor: "text-amber-500", avatarSize: "size-16 sm:size-[72px]", numSize: "text-[72px] sm:text-[88px]", nameSize: "text-base font-bold", scoreSize: "text-lg font-black", avatarNegMt: "-mt-6 sm:-mt-7", order: "md:order-2", shift: "", }, 2: { numColor: "from-zinc-400/45 to-zinc-400/5", scoreColor: "text-zinc-400", avatarSize: "size-12 sm:size-[52px]", numSize: "text-[52px] sm:text-[64px]", nameSize: "text-sm font-semibold", scoreSize: "text-sm font-bold", avatarNegMt: "-mt-5", order: "md:order-1", shift: "md:translate-y-9", }, 3: { numColor: "from-orange-500/55 to-orange-500/8", scoreColor: "text-orange-500", avatarSize: "size-12 sm:size-[52px]", numSize: "text-[52px] sm:text-[64px]", nameSize: "text-sm font-semibold", scoreSize: "text-sm font-bold", avatarNegMt: "-mt-5", order: "md:order-3", shift: "md:translate-y-14", }, } as const function PodiumSkeleton() { return (
{([2, 1, 3] as PodiumRank[]).map((rank) => { const cfg = rankConfig[rank] return (
) })}
) } function PodiumColumn({ entry, rank }: { entry: LeaderboardEntry; rank: PodiumRank }) { const cfg = rankConfig[rank] return (
{String(rank).padStart(2, "0")}
{entry.username.slice(0, 2).toUpperCase()}
{entry.username}
{formatBalance(entry.available_balance)}
) } export const LeaderboardPodium = React.memo(function LeaderboardPodium({ items, loading, }: LeaderboardPodiumProps) { if (loading) return if (items.length === 0) { return
暂无排行数据
} const ordered = [ items[1] ? { entry: items[1], rank: 2 as PodiumRank } : null, items[0] ? { entry: items[0], rank: 1 as PodiumRank } : null, items[2] ? { entry: items[2], rank: 3 as PodiumRank } : null, ].filter(Boolean) as Array<{ entry: LeaderboardEntry; rank: PodiumRank }> return (
{ordered.map(({ entry, rank }) => ( ))}
) })