MicProtocol / apps /web /src /components /ui /ActivityHeatmap.tsx
Benaah's picture
Upload folder using huggingface_hub
fb12607 verified
Raw History Blame Contribute Delete
4.35 kB
"use client";
import React from "react";
import { Activity, Flame, Calendar } from "lucide-react";
interface ActivityHeatmapProps {
title?: string;
subtitle?: string;
data?: Array<{ date?: string; month?: string; count: number; level?: number }>;
className?: string;
}
// Generate 12 months of activity data
const generateMonthlyData = () => {
const months = [
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
];
return months.map((month, i) => ({
month,
count: Math.floor(Math.random() * 100) + 20,
level: Math.floor(Math.random() * 4), // 0-3 intensity
}));
};
const LEVEL_COLORS = [
"var(--border-color-subtle)", // level 0 - no activity
"rgba(255, 159, 10, 0.15)", // level 1 - light
"rgba(255, 159, 10, 0.4)", // level 2 - medium
"var(--color-primary)", // level 3 - heavy
];
export function ActivityHeatmap({
title = "Activity Overview",
subtitle = "Activity over the last 12 months",
data,
className,
}: ActivityHeatmapProps) {
const heatmapData = data || generateMonthlyData();
const maxCount = Math.max(...heatmapData.map((d) => d.count), 1);
return (
<div
className={[
"rounded-xl border border-border-color bg-bg-elevated p-6",
className,
].filter(Boolean).join(" ")}
style={{ borderColor: "var(--border-color)" }}
>
<div className="flex items-center justify-between mb-6">
<div>
<p className="text-text-tertiary text-xs uppercase tracking-wider font-medium">
{title}
</p>
<p className="text-text-secondary text-sm">{subtitle}</p>
</div>
<div className="w-10 h-10 rounded-md bg-bg-tertiary flex items-center justify-center border border-border-color-subtle">
<Activity size={16} className="text-text-tertiary" />
</div>
</div>
{/* Heatmap grid */}
<div className="grid grid-cols-12 gap-2 mb-6">
{heatmapData.map((item, i) => (
<div
key={i}
className="flex flex-col items-center gap-2"
>
<div
className="h-8 rounded-sm transition-colors"
style={{
backgroundColor: LEVEL_COLORS[item.level ?? 0],
}}
title={`${(item as { month?: string; date?: string }).month ?? (item as { month?: string; date?: string }).date ?? ""}: ${item.count} activities`}
/>
<span className="text-text-tertiary text-xs">
{(item as { month?: string; date?: string }).month ?? (item as { month?: string; date?: string }).date ?? ""}
</span>
</div>
))}
</div>
{/* Legend */}
<div className="flex items-center gap-2 text-text-tertiary text-xs">
<div className="w-2 h-2 rounded-sm" style={{ backgroundColor: LEVEL_COLORS[0] }} />
<span>Low</span>
<span className="mx-2">•</span>
<div className="w-2 h-2 rounded-sm" style={{ backgroundColor: LEVEL_COLORS[2] }} />
<span>High</span>
</div>
{/* Stats summary */}
<div className="mt-6 pt-6 border-t border-border-color-subtle grid grid-cols-3 gap-4">
<div className="text-center">
<div className="text-2xl font-display font-bold text-text-primary">
{heatmapData.reduce((sum, d) => sum + d.count, 0)}
</div>
<div className="text-text-tertiary text-xs uppercase tracking-wider">
Total Activities
</div>
</div>
<div className="text-center">
<div className="text-2xl font-display font-bold text-text-primary">
{Math.round(
heatmapData.reduce((sum, d) => sum + d.count, 0) /
heatmapData.length
)}
</div>
<div className="text-text-tertiary text-xs uppercase tracking-wider">
Avg per Month
</div>
</div>
<div className="text-center">
<div className="text-2xl font-display font-bold text-text-primary">
{heatmapData[heatmapData.length - 1]?.count}
</div>
<div className="text-text-tertiary text-xs uppercase tracking-wider">
This Month
</div>
</div>
</div>
</div>
);
}