diff --git a/docs/app/components/ActivityHeatmap.tsx b/docs/app/components/ActivityHeatmap.tsx index d8d17e9..a14f64c 100644 --- a/docs/app/components/ActivityHeatmap.tsx +++ b/docs/app/components/ActivityHeatmap.tsx @@ -21,7 +21,11 @@ const CELL_GAP = 3; /** Width of the day-label column including right padding. */ const LABEL_WIDTH = 32; /** Minimum cell size to prevent cells from becoming invisible. */ -const MIN_CELL_SIZE = 6; +const MIN_CELL_SIZE = 8; +/** Fixed cell size for mobile (scroll mode). */ +const MOBILE_CELL_SIZE = 10; +/** Container width threshold below which we switch to scroll mode. */ +const SCROLL_MODE_THRESHOLD = 600; /** A full year of weekly data. */ const WEEKS_PER_YEAR = 52; /** Seconds in one week. */ @@ -121,6 +125,7 @@ function computeCellSize(containerWidth: number, colCount: number): number { export default function ActivityHeatmap({ weeks, loading = false }: ActivityHeatmapProps) { const containerRef = useRef(null); const [cellSize, setCellSize] = useState(0); + const [scrollMode, setScrollMode] = useState(false); const { hover, popover, show: showPopover, hide: hidePopover, cancelHide } = useHoverPopover(); const fullYear = padToFullYear(weeks); @@ -132,13 +137,29 @@ export default function ActivityHeatmap({ weeks, loading = false }: ActivityHeat const observer = new ResizeObserver((entries) => { for (const entry of entries) { - setCellSize(computeCellSize(entry.contentRect.width, colCount)); + const width = entry.contentRect.width; + if (width < SCROLL_MODE_THRESHOLD) { + // Mobile: fixed cell size, horizontal scroll + setScrollMode(true); + setCellSize(MOBILE_CELL_SIZE); + } else { + // Desktop: compute cell size to fill available space + setScrollMode(false); + setCellSize(computeCellSize(width, colCount)); + } } }); observer.observe(container); // Initial measurement - setCellSize(computeCellSize(container.clientWidth, colCount)); + const width = container.clientWidth; + if (width < SCROLL_MODE_THRESHOLD) { + setScrollMode(true); + setCellSize(MOBILE_CELL_SIZE); + } else { + setScrollMode(false); + setCellSize(computeCellSize(width, colCount)); + } return () => observer.disconnect(); }, [colCount, loading]); @@ -186,65 +207,68 @@ export default function ActivityHeatmap({ weeks, loading = false }: ActivityHeat {cellSize > 0 && (
- {/* Month labels — absolutely positioned above the cell grid */} -
- {monthLabels.map(({ label, offset }) => ( - - {label} - - ))} -
- - {/* Day labels (left) + Cell grid (right) */} -
- {/* Day labels */} -
- {DAY_LABELS.map((day) => ( + {/* Scrollable wrapper for mobile */} +
+ {/* Month labels — absolutely positioned above the cell grid */} +
+ {monthLabels.map(({ label, offset }) => ( - {day} + {label} ))}
- {/* Cell grid — column-flow: 7 rows, columns auto-created per week */} -
- {fullYear.map((week) => - week.days.map((count, dayIdx) => { - const level = intensityLevel(count, maxCommits); - return ( -
count > 0 && handleMouseEnter(event, week.week, dayIdx, count)} - onMouseLeave={hidePopover} - /> - ); - }) - )} + {/* Day labels (left) + Cell grid (right) */} +
+ {/* Day labels */} +
+ {DAY_LABELS.map((day) => ( + + {day} + + ))} +
+ + {/* Cell grid — column-flow: 7 rows, columns auto-created per week */} +
+ {fullYear.map((week) => + week.days.map((count, dayIdx) => { + const level = intensityLevel(count, maxCommits); + return ( +
count > 0 && handleMouseEnter(event, week.week, dayIdx, count)} + onMouseLeave={hidePopover} + /> + ); + }) + )} +