diff --git a/frontend/src/components/git/ForgejoHeatmap.tsx b/frontend/src/components/git/ForgejoHeatmap.tsx
index 910500e..bb2da9c 100644
--- a/frontend/src/components/git/ForgejoHeatmap.tsx
+++ b/frontend/src/components/git/ForgejoHeatmap.tsx
@@ -97,10 +97,11 @@ function toLevel(count: number): number {
}
// ── Line chart sub-component ───────────────────────────────────────────────
-function LineChart({ days, range, onRangeChange }: {
+function LineChart({ days, range, onRangeChange, lastPush }: {
days: ForgejoHeatmapDay[];
range: RangeKey;
onRangeChange: (r: RangeKey) => void;
+ lastPush: ForgejoLastPush | null;
}) {
const { points, xLabels, yLabels, linePath, areaPath } = useMemo(() => {
const lookup = new Map(days.map(d => [d.date, d.count]));
@@ -218,13 +219,37 @@ function LineChart({ days, range, onRangeChange }: {
))}
+
+ {/* Last push — centered at bottom of card */}
+ {lastPush && (
+
+
+ {lastPush.sha}
+
+
+
+ {lastPush.message}
+
+
+ {lastPush.author} pushed to{" "}
+ {lastPush.branch}
+ {" · "}{lastPush.repo}{" · "}{fmtRelative(lastPush.pushed_at)}
+
+
+
+ )}
);
}
// ── Heatmap grid sub-component ─────────────────────────────────────────────
-function HeatmapGrid({ days }: { days: ForgejoHeatmapDay[] }) {
- const { weeks, monthLabels } = useMemo(() => {
+function HeatmapGrid({ days, range, onRangeChange }: {
+ days: ForgejoHeatmapDay[];
+ range: RangeKey;
+ onRangeChange: (r: RangeKey) => void;
+}) {
+ const { weeks, monthLabels, totalEvents } = useMemo(() => {
const lookup = new Map(days.map(d => [d.date, d.count]));
const today = new Date(); today.setHours(0,0,0,0);
const start = new Date(today);
@@ -251,51 +276,72 @@ function HeatmapGrid({ days }: { days: ForgejoHeatmapDay[] }) {
}
builtWeeks.push(week);
}
- return { weeks: builtWeeks, monthLabels: monthLabelList };
- }, [days]);
+
+ // contributions count for selected range
+ const numDays = RANGE_DAYS[range];
+ const cutoff = new Date(today); cutoff.setDate(cutoff.getDate() - numDays);
+ const cutoffStr = isoDate(cutoff);
+ const totalEvents = days.filter(d => d.date >= cutoffStr).reduce((s,d) => s+d.count, 0);
+
+ return { weeks: builtWeeks, monthLabels: monthLabelList, totalEvents };
+ }, [days, range]);
return (
-
+
{/* Header */}
-
+
Activity Heatmap
-
- Last 12 months
-
+
+ {RANGE_LABELS.map(r => (
+
+ ))}
+
{/* SVG */}
+
+ {/* Contributions summary */}
+
+
+ {totalEvents.toLocaleString()}
+
+
+ contributions across all tracked repositories in the last {range}
+
+
+
);
}
@@ -309,15 +355,8 @@ export function ForgejoHeatmap({
lastPush = null,
isLoading = false,
}: ForgejoHeatmapProps) {
- const [lineRange, setLineRange] = useState
("30d");
-
- const totalEvents = useMemo(() => {
- const numDays = RANGE_DAYS[lineRange];
- const today = new Date(); today.setHours(0,0,0,0);
- const cutoff = new Date(today); cutoff.setDate(cutoff.getDate() - numDays);
- const cutoffStr = isoDate(cutoff);
- return days.filter(d => d.date >= cutoffStr).reduce((s,d) => s+d.count, 0);
- }, [days, lineRange]);
+ const [lineRange, setLineRange] = useState("7d");
+ const [heatRange, setHeatRange] = useState("7d");
if (isLoading) {
return (
@@ -341,43 +380,13 @@ export function ForgejoHeatmap({
{/* ── Two cards ───────────────────────────────────────────── */}
- {/* ── Contributions summary ────────────────────────────────── */}
-
-
- {totalEvents.toLocaleString()}
-
-
- contributions across all tracked repositories in the last {lineRange}
-
-
-
- {/* ── Last push — no box, plain inline ────────────────────── */}
- {lastPush && (
-
-
- {lastPush.sha}
-
-
-
- {lastPush.message}
-
-
- {lastPush.author} pushed to{" "}
- {lastPush.branch}
- {" · "}{lastPush.repo}{" · "}{fmtRelative(lastPush.pushed_at)}
-
-
-
- )}
-
{/* ── Line stats — boxed ──────────────────────────────────── */}
{hasLineStats ? (