import { useState } from "react"; import { cn } from "~/utils/cn"; import type { ContributionDay } from "~/server/profiles"; const WEEK = 7; const LEVELS = ["bg-gray-900", "bg-orange-950", "bg-orange-800", "bg-orange-600", "bg-orange-400"]; const LEVEL_STEPS = [0, 1, 3, 6, 10]; const TOOLTIP_OFFSET_PX = 8; const BREAKDOWN_LABELS = [ { key: "commits", singular: "commit", plural: "commits" }, { key: "pulls", singular: "pull request event", plural: "pull request events" }, { key: "issues", singular: "issue opened", plural: "issues opened" }, { key: "reviews", singular: "comment or review", plural: "comments and reviews" }, { key: "other", singular: "other event", plural: "other events" }, ] as const; const DATE_FORMAT = new Intl.DateTimeFormat(undefined, { weekday: "short", month: "short", day: "numeric", year: "numeric", timeZone: "UTC", }); type Hover = { day: ContributionDay; left: number; top: number }; function level(count: number): string { let index = 0; for (const [step, threshold] of LEVEL_STEPS.entries()) if (count >= threshold) index = step; return LEVELS[index]; } function formatDay(date: string): string { return DATE_FORMAT.format(new Date(`${date}T00:00:00Z`)); } function DayCard({ hover }: { hover: Hover }) { const { day } = hover; const lines = day.breakdown ? BREAKDOWN_LABELS.flatMap((label) => { const value = day.breakdown?.[label.key] ?? 0; return value > 0 ? [`${value} ${value === 1 ? label.singular : label.plural}`] : []; }) : []; return (
{day.count === 0 ? "No contributions" : `${day.count} contribution${day.count === 1 ? "" : "s"}`}
{formatDay(day.date)}
{lines.length > 0 && ( )} {day.repos.length > 0 && (
{day.repos.map((repo) => (
{repo}
))}
)}
); } export function ContributionGraph({ days }: { days: ContributionDay[] }) { const [hover, setHover] = useState(null); if (days.length === 0) return null; const weeks: ContributionDay[][] = []; for (let index = 0; index < days.length; index += WEEK) weeks.push(days.slice(index, index + WEEK)); const total = days.reduce((sum, day) => sum + day.count, 0); function show(day: ContributionDay, target: HTMLElement) { const container = target.closest("[data-contribution-grid]"); if (!(container instanceof HTMLElement)) return; const box = target.getBoundingClientRect(); const frame = container.getBoundingClientRect(); setHover({ day, left: box.left - frame.left + box.width / 2, top: box.top - frame.top }); } return (

{total} contribution{total === 1 ? "" : "s"} in the last year

setHover(null)}> {weeks.map((week) => (
{week.map((day) => (
))}
{hover && }
); }