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
95 lines
2.3 KiB
TypeScript
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>
|
|
);
|
|
}
|