import { ACTIVITY_WEEKS, WEEK_MS } from '#/lib/activity.js'; import { cn } from '#/lib/utils.js'; /** * How often this ref was committed to, week by week, as a row of ticks read * like a gauge. The dates come from the walk the page already made for its * latest commit, so this costs no read of its own. * * A week with no commits keeps a floor tick, so the row reads as a scale * rather than as gaps. Heights are against the busiest week in view, which * makes the shape of the work legible whatever the repository's volume. */ export function ActivityTicks({ dates, className }) { const now = Date.now(); /** @type {{start: number, count: number}[]} oldest first */ const weeks = Array.from({ length: ACTIVITY_WEEKS }, (_, index) => ({ start: now - (ACTIVITY_WEEKS - index) * WEEK_MS, count: 0, })); for (const at of dates) { const week = Math.floor((now - at) / WEEK_MS); if (week >= 0 && week < ACTIVITY_WEEKS) { weeks[ACTIVITY_WEEKS - 1 - week].count += 1; } } const busiest = Math.max(...weeks.map((week) => week.count)); if (busiest === 0) return null; const total = weeks.reduce((sum, week) => sum + week.count, 0); const words = `${total} ${total === 1 ? 'commit' : 'commits'} in the last ${ACTIVITY_WEEKS} weeks`; return ( // The ticks spread across the whole row, as the language gauge's do, so // the two read against one scale rather than as a long bar beside a // short one. Each tick takes an equal share of whatever room the row // has, so the gauge draws the same shape in a sidebar and in a card.
{weeks.map((week) => ( 0 ? 'bg-key' : 'h-[2px] bg-border', )} style={ week.count > 0 ? { height: `${Math.max(20, (week.count / busiest) * 100)}%` } : undefined } /> ))}
); }