// Custom tooltip demo
import {
ContributionGraph,
ContributionGraphGrid,
ContributionGraphTooltip,
ContributionGraphLegend,
type ContributionData,
} from "@/components/ui/contribution-graph";
function generateSampleData(): ContributionData[] {
const data: ContributionData[] = [];
const endDate = new Date();
const startDate = new Date();
startDate.setFullYear(startDate.getFullYear() - 1);
const current = new Date(startDate);
while (current <= endDate) {
const dayOfWeek = current.getDay();
const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
const baseChance = isWeekend ? 0.3 : 0.6;
if (Math.random() < baseChance) {
data.push({
date: current.toISOString().split("T")[0],
count: Math.floor(Math.random() * 12) + 1,
});
}
current.setDate(current.getDate() + 1);
}
return data;
}
const sampleData = generateSampleData();
const endDate = new Date();
const startDate = new Date();
startDate.setFullYear(startDate.getFullYear() - 1);
startDate.setDate(startDate.getDate() + 1);
// Calculate stats for tooltip
const totalContributions = sampleData.reduce((sum, d) => sum + d.count, 0);
const avgPerDay = (totalContributions / 365).toFixed(1);
function getActivityLevel(count: number): { label: string; color: string } {
if (count === 0) return { label: "No activity", color: "text-muted-foreground" };
if (count <= 2) return { label: "Light", color: "text-blue-500" };
if (count <= 5) return { label: "Moderate", color: "text-green-500" };
if (count <= 8) return { label: "Active", color: "text-orange-500" };
return { label: "Very Active", color: "text-red-500" };
}
function getRelativeDate(dateStr: string): string {
const date = new Date(dateStr);
const now = new Date();
const diffDays = Math.floor((now.getTime() - date.getTime()) / (1000 * 60 * 60 * 24));
if (diffDays === 0) return "Today";
if (diffDays === 1) return "Yesterday";
if (diffDays < 7) return `${diffDays} days ago`;
if (diffDays < 30) return `${Math.floor(diffDays / 7)} weeks ago`;
if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago`;
return `${Math.floor(diffDays / 365)} years ago`;
}
export default function DemoCustomTooltip() {
return (
<div className="w-full max-w-4xl p-6">
<ContributionGraph
data={sampleData}
startDate={startDate.toISOString().split("T")[0]}
endDate={endDate.toISOString().split("T")[0]}
>
<ContributionGraphGrid />
<ContributionGraphTooltip className="min-w-[180px] p-0 overflow-hidden">
{({ date, count }) => {
const activity = getActivityLevel(count);
const dayOfWeek = new Date(date).toLocaleDateString("en-US", { weekday: "long" });
return (
<div className="divide-y divide-border">
{/* Header */}
<div className="px-3 py-2 bg-muted/50">
<div className="flex items-center justify-between gap-3">
<span className="text-[10px] uppercase tracking-wider text-muted-foreground">
{dayOfWeek}
</span>
<span className={`text-[10px] font-medium ${activity.color}`}>
{activity.label}
</span>
</div>
<div className="text-xs text-muted-foreground mt-0.5">
{getRelativeDate(date)}
</div>
</div>
{/* Stats */}
<div className="px-3 py-2 space-y-1.5">
<div className="flex items-baseline justify-between">
<span className="text-2xl font-bold text-popover-foreground tabular-nums">
{count}
</span>
<span className="text-[10px] text-muted-foreground">
contribution{count !== 1 ? "s" : ""}
</span>
</div>
{/* Progress bar */}
<div className="space-y-1">
<div className="h-1.5 w-full bg-muted rounded-full overflow-hidden">
<div
className="h-full bg-primary transition-all duration-300"
style={{ width: `${Math.min(100, (count / 12) * 100)}%` }}
/>
</div>
<div className="flex justify-between text-[9px] text-muted-foreground">
<span>0</span>
<span>Daily avg: {avgPerDay}</span>
<span>12+</span>
</div>
</div>
</div>
{/* Footer */}
<div className="px-3 py-1.5 bg-muted/30">
<div className="text-[10px] text-muted-foreground">
{new Date(date).toLocaleDateString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
})}
</div>
</div>
</div>
);
}}
</ContributionGraphTooltip>
<ContributionGraphLegend className="mt-3" />
</ContributionGraph>
</div>
);
}