import { Component, For, createMemo, Show } from "solid-js"; import { SkeletonBox } from "./SkeletonLoader"; interface ContributionDay { date: string; count: number; } export const ActivityHeatmap: Component<{ contributions: ContributionDay[] | undefined; title: string; }> = (props) => { // Generate last 12 weeks of days const weeks = createMemo(() => { const today = new Date(); const weeksData: { date: string; count: number }[][] = []; // Start from 12 weeks ago const startDate = new Date(today); startDate.setDate(startDate.getDate() - 84); // 12 weeks // Create a map for quick lookup const contributionMap = new Map(); props.contributions?.forEach((c) => { contributionMap.set(c.date, c.count); }); // Generate weeks for (let week = 0; week < 12; week++) { const weekData: { date: string; count: number }[] = []; for (let day = 0; day < 7; day++) { const date = new Date(startDate); date.setDate(startDate.getDate() + week * 7 + day); const dateStr = date.toISOString().split("T")[0]; const count = contributionMap.get(dateStr) || 0; weekData.push({ date: dateStr, count }); } weeksData.push(weekData); } return weeksData; }); const getColor = (count: number) => { if (count === 0) return "var(--color-surface0)"; if (count <= 2) return "var(--color-green)"; if (count <= 5) return "var(--color-teal)"; if (count <= 10) return "var(--color-blue)"; return "var(--color-mauve)"; }; const getOpacity = (count: number) => { if (count === 0) return 0.3; if (count <= 2) return 0.4; if (count <= 5) return 0.6; if (count <= 10) return 0.8; return 1; }; return (

{props.title}

0} fallback={
{/* Skeleton grid matching heatmap dimensions */}
{() => (
{() =>
}
)}
{/* Centered spinner overlay */}
} >
{(week) => (
{(day) => (
)}
)}
Less
{(count) => (
)}
More
); };