Files
wehub-resource-sync e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:40:13 +08:00

95 lines
2.3 KiB
TypeScript

"use client";
import * as HeatGraph from "heat-graph";
const COLORS = ["#ebedf0", "#c6d7f9", "#8fb0f3", "#5888e8", "#2563eb"];
export function ActivityGraph({ data }: { data: HeatGraph.DataPoint[] }) {
return (
<HeatGraph.Root
data={data}
weekStart="monday"
colorScale={COLORS}
className="flex flex-col gap-2"
>
<MonthLabels />
<div className="flex gap-2">
<DayLabels />
<CellGrid />
</div>
<GraphLegend />
<CellTooltip />
</HeatGraph.Root>
);
}
function MonthLabels() {
return (
<div className="relative ml-10 h-5">
<HeatGraph.MonthLabels>
{({ label, totalWeeks }) => (
<span
className="absolute text-xs text-gray-500"
style={{ left: `${(label.column / totalWeeks) * 100}%` }}
>
{HeatGraph.MONTH_SHORT[label.month]}
</span>
)}
</HeatGraph.MonthLabels>
</div>
);
}
function DayLabels() {
return (
<div className="flex w-8 shrink-0 flex-col justify-between py-[2px]">
<HeatGraph.DayLabels>
{({ label }) => (
<span className="flex h-[13px] items-center text-xs text-gray-500">
{label.row % 2 === 0 ? HeatGraph.DAY_SHORT[label.dayOfWeek] : ""}
</span>
)}
</HeatGraph.DayLabels>
</div>
);
}
function CellGrid() {
return (
<HeatGraph.Grid className="flex-1 gap-[3px]">
{() => <HeatGraph.Cell className="aspect-square w-full rounded-sm" />}
</HeatGraph.Grid>
);
}
function CellTooltip() {
return (
<HeatGraph.Tooltip className="pointer-events-none rounded-md bg-gray-900 px-3 py-1.5 text-xs whitespace-nowrap text-white shadow-lg">
{({ cell }) => (
<>
<strong>{cell.count} contributions</strong> on{" "}
{cell.date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
})}
</>
)}
</HeatGraph.Tooltip>
);
}
function GraphLegend() {
return (
<div className="ml-auto flex items-center gap-1 text-xs text-gray-500">
<span>Less</span>
<HeatGraph.Legend>
{() => (
<HeatGraph.LegendLevel className="h-[13px] w-[13px] rounded-sm" />
)}
</HeatGraph.Legend>
<span>More</span>
</div>
);
}