Data Display dataheatmapactivitygithubmatrix

Activity Heatmap Grid

GitHub-styled commit/activity frequency matrix visualizing contribution density across days and weeks.

Preview

Contribution Activity
1,428 events in the last 4 months
JulAugSepOct

Usage

Copy the full block below to use this component with its imports.

astro
---
import { ActivityHeatmapGrid } from 'astro-component-kit';
---

<ActivityHeatmapGrid title="Contribution Activity" weeks={16} />
--- import { ActivityHeatmapGrid } from 'astro-component-kit'; --- <ActivityHeatmapGrid title="Contribution Activity" weeks={16} />

Manual Installation

If you are not using the npm package, create a new file src/components/lib/ActivityHeatmapGrid.astro and paste the following code:

astro
---
/**
 * ActivityHeatmapGrid — GitHub-style activity contribution matrix with intensity color levels and month labels.
 * 
 * @param {string} title - Section header label. Default is 'Commit Activity'.
 * @param {number} totalCount - Total activity events recorded. Default is 1428.
 */
interface Props {
  title?: string;
  totalCount?: number;
}

const {
  title = 'Contribution Activity',
  totalCount = 1428,
} = Astro.props;

// Mock 16 weeks of 7 days
const weeks = Array.from({ length: 16 }, (_, w) =>
  Array.from({ length: 7 }, (_, d) => {
    // Generate pseudo-random intensity 0 to 4
    const seed = (w * 7 + d * 13 + 5) % 17;
    if (seed < 4) return 0;
    if (seed < 8) return 1;
    if (seed < 12) return 2;
    if (seed < 15) return 3;
    return 4;
  })
);

const months = ['Jul', 'Aug', 'Sep', 'Oct'];
---

<div class="heatmap-card">
  <div class="heatmap-card__head">
    <div class="heatmap-card__title-wrap">
      <h5 class="heatmap-card__title">{title}</h5>
      <span class="heatmap-card__total">{totalCount.toLocaleString()} events in the last 4 months</span>
    </div>

    <div class="heatmap-card__legend" aria-hidden="true">
      <span class="legend-text">Less</span>
      <span class="cell cell--0"></span>
      <span class="cell cell--1"></span>
      <span class="cell cell--2"></span>
      <span class="cell cell--3"></span>
      <span class="cell cell--4"></span>
      <span class="legend-text">More</span>
    </div>
  </div>

  <div class="heatmap-card__matrix">
    <div class="heatmap-card__months">
      {months.map((m) => (
        <span class="month-label">{m}</span>
      ))}
    </div>

    <div class="heatmap-card__grid">
      {weeks.map((week) => (
        <div class="heatmap-col">
          {week.map((level) => (
            <span class:list={['cell', `cell--${level}`]}></span>
          ))}
        </div>
      ))}
    </div>
  </div>
</div>

<style>
  .heatmap-card {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: var(--sp-6, 1.5rem);
    background: rgba(255, 255, 255, 0.02);
    backdrop-filter: blur(16px);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--r-xl, 20px);
    width: 100%;
    max-width: 480px;
    font-family: var(--font-sans, system-ui, sans-serif);
  }

  .heatmap-card__head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
  }

  .heatmap-card__title {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--c-text-1, #ffffff);
    margin: 0 0 2px 0;
  }

  .heatmap-card__total {
    font-size: 0.75rem;
    color: var(--c-text-3, #737373);
  }

  .heatmap-card__legend {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 0.7rem;
    color: var(--c-text-3, #737373);
  }

  .heatmap-card__matrix {
    display: flex;
    flex-direction: column;
    gap: 6px;
    overflow-x: auto;
    padding-bottom: 4px;
  }

  .heatmap-card__months {
    display: flex;
    justify-content: space-between;
    padding: 0 4px;
    font-size: 0.68rem;
    color: var(--c-text-3, #737373);
    font-weight: 600;
  }

  .heatmap-card__grid {
    display: flex;
    gap: 4px;
  }

  .heatmap-col {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }

  .cell {
    width: 12px;
    height: 12px;
    border-radius: 3px;
    transition: transform 0.15s ease;
  }

  .heatmap-card__grid .cell:hover {
    transform: scale(1.3);
  }

  .cell--0 { background: rgba(255, 255, 255, 0.05); }
  .cell--1 { background: rgba(184, 134, 11, 0.25); }
  .cell--2 { background: rgba(184, 134, 11, 0.55); }
  .cell--3 { background: rgba(212, 160, 23, 0.85); }
  .cell--4 { background: #fef3c7; box-shadow: 0 0 6px rgba(254, 243, 199, 0.6); }
</style>
--- /** * ActivityHeatmapGrid — GitHub-style activity contribution matrix with intensity color levels and month labels. * * @param {string} title - Section header label. Default is 'Commit Activity'. * @param {number} totalCount - Total activity events recorded. Default is 1428. */ interface Props { title?: string; totalCount?: number; } const { title = 'Contribution Activity', totalCount = 1428, } = Astro.props; // Mock 16 weeks of 7 days const weeks = Array.from({ length: 16 }, (_, w) => Array.from({ length: 7 }, (_, d) => { // Generate pseudo-random intensity 0 to 4 const seed = (w * 7 + d * 13 + 5) % 17; if (seed < 4) return 0; if (seed < 8) return 1; if (seed < 12) return 2; if (seed < 15) return 3; return 4; }) ); const months = ['Jul', 'Aug', 'Sep', 'Oct']; --- <div class="heatmap-card"> <div class="heatmap-card__head"> <div class="heatmap-card__title-wrap"> <h5 class="heatmap-card__title">{title}</h5> <span class="heatmap-card__total">{totalCount.toLocaleString()} events in the last 4 months</span> </div> <div class="heatmap-card__legend" aria-hidden="true"> <span class="legend-text">Less</span> <span class="cell cell--0"></span> <span class="cell cell--1"></span> <span class="cell cell--2"></span> <span class="cell cell--3"></span> <span class="cell cell--4"></span> <span class="legend-text">More</span> </div> </div> <div class="heatmap-card__matrix"> <div class="heatmap-card__months"> {months.map((m) => ( <span class="month-label">{m}</span> ))} </div> <div class="heatmap-card__grid"> {weeks.map((week) => ( <div class="heatmap-col"> {week.map((level) => ( <span class:list={['cell', `cell--${level}`]}></span> ))} </div> ))} </div> </div> </div> <style> .heatmap-card { display: flex; flex-direction: column; gap: 12px; padding: var(--sp-6, 1.5rem); background: rgba(255, 255, 255, 0.02); backdrop-filter: blur(16px); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: var(--r-xl, 20px); width: 100%; max-width: 480px; font-family: var(--font-sans, system-ui, sans-serif); } .heatmap-card__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; } .heatmap-card__title { font-size: 0.95rem; font-weight: 700; color: var(--c-text-1, #ffffff); margin: 0 0 2px 0; } .heatmap-card__total { font-size: 0.75rem; color: var(--c-text-3, #737373); } .heatmap-card__legend { display: flex; align-items: center; gap: 4px; font-size: 0.7rem; color: var(--c-text-3, #737373); } .heatmap-card__matrix { display: flex; flex-direction: column; gap: 6px; overflow-x: auto; padding-bottom: 4px; } .heatmap-card__months { display: flex; justify-content: space-between; padding: 0 4px; font-size: 0.68rem; color: var(--c-text-3, #737373); font-weight: 600; } .heatmap-card__grid { display: flex; gap: 4px; } .heatmap-col { display: flex; flex-direction: column; gap: 4px; } .cell { width: 12px; height: 12px; border-radius: 3px; transition: transform 0.15s ease; } .heatmap-card__grid .cell:hover { transform: scale(1.3); } .cell--0 { background: rgba(255, 255, 255, 0.05); } .cell--1 { background: rgba(184, 134, 11, 0.25); } .cell--2 { background: rgba(184, 134, 11, 0.55); } .cell--3 { background: rgba(212, 160, 23, 0.85); } .cell--4 { background: #fef3c7; box-shadow: 0 0 6px rgba(254, 243, 199, 0.6); } </style>

Quick Info

Category
Data Display
Filename
ActivityHeatmapGrid.astro
Dependencies
None — pure Astro + CSS
Tags
dataheatmapactivitygithubmatrix