{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "contributions-card",
  "title": "Contributions",
  "description": "Year heatmap of daily activity with a count-up headline and stat tiles.",
  "registryDependencies": [
    "https://components.exe.xyz/r/chart-card.json"
  ],
  "files": [
    {
      "path": "src/components/charts/contributions-card.tsx",
      "content": "import { useMemo, useState } from \"react\"\n\nimport {\n  ChartCard,\n  ChartPeriodSwitch,\n  ChartTiles,\n  formatNumber,\n} from \"@/components/charts/chart-card\"\n\nexport type ContributionDay = { date: string; count: number }\n\nconst MONTHS = [\n  \"Jan\",\n  \"Feb\",\n  \"Mar\",\n  \"Apr\",\n  \"May\",\n  \"Jun\",\n  \"Jul\",\n  \"Aug\",\n  \"Sep\",\n  \"Oct\",\n  \"Nov\",\n  \"Dec\",\n]\n\nconst LEVEL_FILL = [\n  \"var(--muted)\",\n  \"color-mix(in srgb, var(--chart-2) 35%, var(--card))\",\n  \"color-mix(in srgb, var(--chart-2) 70%, var(--card))\",\n  \"color-mix(in srgb, var(--chart-1) 72%, var(--chart-2))\",\n  \"var(--chart-1)\",\n]\n\nfunction toISO(date: Date) {\n  const y = date.getFullYear()\n  const m = String(date.getMonth() + 1).padStart(2, \"0\")\n  const d = String(date.getDate()).padStart(2, \"0\")\n  return `${y}-${m}-${d}`\n}\n\nfunction parseISO(iso: string) {\n  return new Date(`${iso}T12:00:00`)\n}\n\nfunction demoDays(): ContributionDay[] {\n  const end = parseISO(\"2026-08-20\")\n  const start = new Date(end)\n  start.setDate(start.getDate() - 364)\n  const days: ContributionDay[] = []\n  for (\n    const cursor = new Date(start);\n    cursor <= end;\n    cursor.setDate(cursor.getDate() + 1)\n  ) {\n    const iso = toISO(cursor)\n    const dow = cursor.getDay()\n    const weekend = dow === 0 || dow === 6\n    const seed = (cursor.getMonth() + 1) * 17 + cursor.getDate() * 13\n    let count = weekend ? seed % 4 : seed % 12\n    if (seed % 11 === 0) count = 0\n    days.push({ date: iso, count })\n  }\n  return days\n}\n\nfunction levelFor(count: number, max: number) {\n  if (count <= 0) return 0\n  const t = count / Math.max(max, 1)\n  if (t < 0.25) return 1\n  if (t < 0.5) return 2\n  if (t < 0.75) return 3\n  return 4\n}\n\nconst DEFAULT_STATS = [\n  { label: \"Lifetime tokens\", value: \"9B\" },\n  { label: \"Peak tokens\", value: \"562.7M\" },\n  { label: \"Longest task\", value: \"12h 54m\" },\n  { label: \"Top streak\", value: \"62 days\" },\n]\n\nconst PERIODS = [\n  { id: \"weekly\", label: \"Weekly\" },\n  { id: \"monthly\", label: \"Monthly\" },\n  { id: \"yearly\", label: \"Yearly\" },\n]\n\nexport function ContributionsCard({\n  title = \"Contributions this year\",\n  headline = 7462,\n  headlineFormat = (n) => `$${formatNumber(Math.round(n))}`,\n  delta = 14.8,\n  days,\n  stats = DEFAULT_STATS,\n  period,\n  onPeriodChange,\n}: {\n  title?: string\n  headline?: number\n  headlineFormat?: (n: number) => string\n  delta?: number\n  days?: ContributionDay[]\n  stats?: { label: string; value: string }[]\n  period?: string\n  onPeriodChange?: (id: string) => void\n}) {\n  const [internalPeriod, setInternalPeriod] = useState(period ?? \"yearly\")\n  const selected = period ?? internalPeriod\n  const plotDays = days ?? demoDays()\n  const max = Math.max(1, ...plotDays.map((day) => day.count))\n  const byDate = useMemo(\n    () => new Map(plotDays.map((day) => [day.date, day.count])),\n    [plotDays]\n  )\n\n  const weeks = useMemo(() => {\n    const sorted = [...plotDays].sort((a, b) => a.date.localeCompare(b.date))\n    const first = parseISO(sorted[0]?.date ?? \"2026-01-01\")\n    const last = parseISO(sorted[sorted.length - 1]?.date ?? \"2026-08-20\")\n    const start = new Date(first)\n    start.setDate(start.getDate() - start.getDay())\n    const columns: ContributionDay[][] = []\n    let week: ContributionDay[] = []\n    for (\n      const cursor = new Date(start);\n      cursor <= last || week.length > 0;\n      cursor.setDate(cursor.getDate() + 1)\n    ) {\n      if (cursor > last && week.length === 0) break\n      const iso = toISO(cursor)\n      week.push({ date: iso, count: byDate.get(iso) ?? 0 })\n      if (week.length === 7) {\n        columns.push(week)\n        week = []\n        if (cursor >= last) break\n      }\n    }\n    return columns\n  }, [plotDays, byDate])\n\n  const monthLabels = weeks.flatMap((week, index) => {\n    const first = week.find((day) => parseISO(day.date).getDate() === 1)\n    if (!first) return []\n    return [{ week: index, name: MONTHS[parseISO(first.date).getMonth()] }]\n  })\n\n  const peak = plotDays.reduce(\n    (best, day) => (day.count > best.count ? day : best),\n    plotDays[0] ?? { date: \"2026-01-01\", count: 0 }\n  )\n  const total = plotDays.reduce((sum, day) => sum + day.count, 0)\n  const peakLabel = parseISO(peak.date).toLocaleDateString(\"en-US\", {\n    month: \"long\",\n    day: \"numeric\",\n  })\n  const summary = `${formatNumber(headline)} contributions this year, best day ${peakLabel}`\n\n  const cell = 10\n  const gap = 3\n  const left = 18\n  const top = 14\n  const width = left + weeks.length * (cell + gap)\n  const height = top + 7 * (cell + gap)\n  const [tip, setTip] = useState<{ x: number; y: number; text: string } | null>(\n    null\n  )\n\n  return (\n    <ChartCard\n      title={title}\n      headline={headline}\n      headlineFormat={headlineFormat}\n      delta={delta}\n      periodControl={\n        <ChartPeriodSwitch\n          value={selected}\n          onChange={(id) => {\n            setInternalPeriod(id)\n            onPeriodChange?.(id)\n          }}\n          options={PERIODS}\n        />\n      }\n      summary={summary}\n      tiles={\n        <ChartTiles\n          items={stats.map((stat) => ({\n            id: stat.label,\n            label: stat.label,\n            value: stat.value,\n          }))}\n        />\n      }\n    >\n      <div\n        className=\"relative overflow-x-auto\"\n        onMouseLeave={() => setTip(null)}\n      >\n        <svg\n          role=\"img\"\n          aria-label={summary}\n          viewBox={`0 0 ${width} ${height + 16}`}\n          className=\"h-auto w-full min-w-0 sm:min-w-[28rem]\"\n        >\n          {monthLabels.map((label) => (\n            <text\n              key={`${label.name}-${label.week}`}\n              x={left + label.week * (cell + gap)}\n              y={10}\n              fill=\"var(--muted-foreground)\"\n              fontSize={9}\n              fontFamily=\"var(--font-mono)\"\n            >\n              {label.name}\n            </text>\n          ))}\n          {[\"S\", \"M\", \"T\", \"W\", \"T\", \"F\", \"S\"].map((day, index) =>\n            index % 2 === 1 ? (\n              <text\n                key={`${day}-${index}`}\n                x={0}\n                y={top + index * (cell + gap) + 8}\n                fill=\"var(--muted-foreground)\"\n                fontSize={9}\n                fontFamily=\"var(--font-mono)\"\n              >\n                {day}\n              </text>\n            ) : null\n          )}\n          {weeks.map((week, x) =>\n            week.map((day, y) => {\n              const inRange = byDate.has(day.date)\n              const level = inRange ? levelFor(day.count, max) : 0\n              const label = parseISO(day.date).toLocaleDateString(\"en-US\", {\n                month: \"long\",\n                day: \"numeric\",\n              })\n              return (\n                <rect\n                  key={day.date}\n                  x={left + x * (cell + gap)}\n                  y={top + y * (cell + gap)}\n                  width={cell}\n                  height={cell}\n                  rx={1}\n                  fill={LEVEL_FILL[level]}\n                  opacity={inRange ? 1 : 0.35}\n                  onMouseEnter={(event) => {\n                    const host = event.currentTarget.ownerSVGElement\n                    if (!host) return\n                    const box = host.getBoundingClientRect()\n                    setTip({\n                      x: event.clientX - box.left,\n                      y: event.clientY - box.top,\n                      text: `${day.count} contribution${day.count === 1 ? \"\" : \"s\"} on ${label}`,\n                    })\n                  }}\n                />\n              )\n            })\n          )}\n          {LEVEL_FILL.map((fill, index) => (\n            <rect\n              key={fill}\n              x={width - (5 - index) * (cell + 2) - 28}\n              y={height + 4}\n              width={cell}\n              height={cell}\n              rx={1}\n              fill={fill}\n            />\n          ))}\n          <text\n            x={width - 5 * (cell + 2) - 52}\n            y={height + 13}\n            fill=\"var(--muted-foreground)\"\n            fontSize={9}\n            fontFamily=\"var(--font-mono)\"\n          >\n            Less\n          </text>\n          <text\n            x={width - 22}\n            y={height + 13}\n            fill=\"var(--muted-foreground)\"\n            fontSize={9}\n            fontFamily=\"var(--font-mono)\"\n          >\n            More\n          </text>\n        </svg>\n        {tip ? (\n          <div\n            className=\"pointer-events-none absolute z-10 rounded-[2px] border border-border bg-card px-2 py-1 font-mono text-[11px] shadow-sm\"\n            style={{ left: tip.x + 8, top: tip.y - 28 }}\n          >\n            {tip.text}\n          </div>\n        ) : null}\n      </div>\n      <p className=\"sr-only\">\n        {formatNumber(total)} plotted days, peak {peak.count} on {peakLabel}.\n      </p>\n    </ChartCard>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:block"
}