{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "leaderboard-card",
  "title": "Leaderboard Card",
  "description": "React leaderboard component that composes title, date range, podium, and rankings—one card for competitive gamification UIs. Fits Next.js and React apps. Built on shadcn/ui + Tailwind. Open source.",
  "dependencies": [],
  "registryDependencies": [
    "leaderboard-podium",
    "leaderboard-rankings"
  ],
  "files": [
    {
      "path": "registry/trophy/ui/leaderboard-card.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport {\n  LeaderboardPodium,\n  type LeaderboardRanking as LeaderboardPodiumRanking,\n} from \"@/components/ui/leaderboard-podium\"\nimport {\n  LeaderboardRankings,\n  type LeaderboardRankingItem,\n} from \"@/components/ui/leaderboard-rankings\"\n\ninterface LeaderboardRunOption {\n  id: string\n  label: string\n}\n\ninterface LeaderboardCardProps extends React.HTMLAttributes<HTMLDivElement> {\n  title?: string\n  fromDate: string | Date\n  toDate: string | Date\n  podiumRankings: LeaderboardPodiumRanking[]\n  rankings: LeaderboardRankingItem[]\n  currentUserId?: string\n  runOptions?: LeaderboardRunOption[]\n  selectedRunId?: string\n  onRunChange?: (runId: string) => void\n}\n\nfunction formatRangeDate(date: string | Date) {\n  const parsed = date instanceof Date ? date : new Date(date)\n  if (Number.isNaN(parsed.getTime())) return \"\"\n\n  return parsed.toLocaleDateString(undefined, {\n    month: \"short\",\n    day: \"numeric\",\n    year: \"numeric\",\n  })\n}\n\nconst LeaderboardCard = React.forwardRef<HTMLDivElement, LeaderboardCardProps>(\n  (\n    {\n      className,\n      title = \"Leaderboard\",\n      fromDate,\n      toDate,\n      podiumRankings,\n      rankings,\n      currentUserId,\n      runOptions,\n      selectedRunId,\n      onRunChange,\n      ...props\n    },\n    ref\n  ) => {\n    const fromLabel = formatRangeDate(fromDate)\n    const toLabel = formatRangeDate(toDate)\n    const resolvedRunId = selectedRunId ?? runOptions?.[0]?.id ?? \"\"\n    const hasOnRunChange = Boolean(onRunChange)\n    const [localRunId, setLocalRunId] = React.useState(resolvedRunId)\n\n    React.useEffect(() => {\n      if (hasOnRunChange) return\n      setLocalRunId(resolvedRunId)\n    }, [hasOnRunChange, resolvedRunId])\n\n    const activeRunId = hasOnRunChange ? resolvedRunId : localRunId\n\n    return (\n      <div\n        ref={ref}\n        className={cn(\"bg-card rounded-2xl border p-6 shadow-sm\", className)}\n        {...props}\n      >\n        <div className=\"mb-6 flex items-start justify-between gap-4\">\n          <div className=\"space-y-1\">\n            <h3 className=\"text-xl font-semibold\">{title}</h3>\n            <p className=\"text-muted-foreground text-sm\">\n              {fromLabel} - {toLabel}\n            </p>\n          </div>\n\n          {runOptions && runOptions.length > 0 ? (\n            <select\n              aria-label=\"Select leaderboard run\"\n              value={activeRunId}\n              onChange={(e) => {\n                if (onRunChange) {\n                  onRunChange(e.target.value)\n                  return\n                }\n                setLocalRunId(e.target.value)\n              }}\n              className=\"bg-background text-foreground rounded-md border px-3 py-1.5 text-sm\"\n            >\n              {runOptions.map((option) => (\n                <option key={option.id} value={option.id}>\n                  {option.label}\n                </option>\n              ))}\n            </select>\n          ) : null}\n        </div>\n\n        <LeaderboardPodium rankings={podiumRankings} className=\"mb-6\" />\n\n        <LeaderboardRankings\n          rankings={rankings}\n          currentUserId={currentUserId}\n          showPagination\n          defaultPageSize={10}\n        />\n      </div>\n    )\n  }\n)\n\nLeaderboardCard.displayName = \"LeaderboardCard\"\n\nexport { LeaderboardCard }\nexport type { LeaderboardCardProps, LeaderboardRunOption }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}