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

174 lines
5.3 KiB
TypeScript

"use client";
import { useMemo } from "react";
import * as HeatGraph from "heat-graph";
import type { ActivityPoint } from "@/lib/traction";
const COMMIT_COLORS = [
"color-mix(in oklab, var(--color-muted-foreground) 14%, transparent)",
"color-mix(in oklab, var(--color-chart-1) 30%, transparent)",
"color-mix(in oklab, var(--color-chart-1) 55%, transparent)",
"color-mix(in oklab, var(--color-chart-1) 80%, transparent)",
"var(--color-chart-1)",
];
const RELEASE_RING = "inset 0 0 0 1.5px var(--color-chart-2)";
const formatDate = (date: Date) =>
date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
});
const localDateKey = (d: Date): string => {
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
};
export function ActivityHeatmap({
commits,
releases,
}: {
commits: ActivityPoint[];
releases: ActivityPoint[];
}) {
const releaseDays = useMemo(() => {
const set = new Set<string>();
for (const r of releases) {
if (r.count > 0) set.add(r.date);
}
return set;
}, [releases]);
if (commits.length === 0 && releases.length === 0) {
return (
<div className="border-border text-muted-foreground flex h-[220px] items-center justify-center rounded-lg border border-dashed text-sm">
Activity is currently unavailable.
</div>
);
}
return (
<div className="border-border rounded-lg border p-4 md:p-5">
<HeatGraph.Root
data={commits}
weekStart="sunday"
colorScale={COMMIT_COLORS}
className="flex flex-col"
>
<div
className="relative"
style={{ height: 14, marginLeft: 28, marginBottom: 6 }}
>
<HeatGraph.MonthLabels>
{({ label, totalWeeks }) => (
<span
className="text-muted-foreground absolute text-[11px] leading-[14px]"
style={{ left: `${(label.column / totalWeeks) * 100}%` }}
>
{HeatGraph.MONTH_SHORT[label.month]}
</span>
)}
</HeatGraph.MonthLabels>
</div>
<div className="flex" style={{ gap: 3 }}>
<div className="flex shrink-0 flex-col" style={{ width: 25, gap: 3 }}>
<HeatGraph.DayLabels>
{({ label }) => (
<span
className="text-muted-foreground relative text-[10px]"
style={{ height: 11 }}
>
{label.row % 2 === 1 ? (
<span className="absolute" style={{ bottom: -1 }}>
{HeatGraph.DAY_SHORT[label.dayOfWeek]?.charAt(0)}
</span>
) : null}
</span>
)}
</HeatGraph.DayLabels>
</div>
<HeatGraph.Grid
style={{
gap: 3,
gridTemplateRows: "repeat(7, 11px)",
flex: 1,
minWidth: 0,
}}
>
{({ cell }) => {
const released = releaseDays.has(localDateKey(cell.date));
return (
<HeatGraph.Cell
className="rounded-[2px]"
style={released ? { boxShadow: RELEASE_RING } : undefined}
/>
);
}}
</HeatGraph.Grid>
</div>
<div
className="text-muted-foreground flex flex-wrap items-center justify-end text-[11px]"
style={{ marginTop: 10, gap: 12 }}
>
<div className="flex items-center" style={{ gap: 4 }}>
<span>Less</span>
<HeatGraph.Legend>
{() => (
<HeatGraph.LegendLevel
className="rounded-[2px]"
style={{ width: 10, height: 10 }}
/>
)}
</HeatGraph.Legend>
<span>More</span>
</div>
<div className="flex items-center" style={{ gap: 6 }}>
<span
className="rounded-[2px]"
style={{
width: 10,
height: 10,
backgroundColor:
"color-mix(in oklab, var(--color-muted-foreground) 14%, transparent)",
boxShadow: RELEASE_RING,
}}
/>
<span>Released</span>
</div>
</div>
<HeatGraph.Tooltip className="border-border bg-popover text-popover-foreground pointer-events-none rounded-md border px-3 py-1.5 text-xs whitespace-nowrap shadow-md">
{({ cell }) => {
const released = releaseDays.has(localDateKey(cell.date));
const headline =
cell.count > 0
? `${cell.count} ${cell.count === 1 ? "commit" : "commits"}`
: released
? "Released"
: "No commits";
return (
<>
<strong>{headline}</strong>
{released && cell.count > 0 ? (
<span style={{ color: "var(--color-chart-2)" }}>
{" · released"}
</span>
) : null}
{" — "}
{formatDate(cell.date)}
</>
);
}}
</HeatGraph.Tooltip>
</HeatGraph.Root>
</div>
);
}