From 673d1b7c29f5306f22b0f41e745a49dca8a51a42 Mon Sep 17 00:00:00 2001 From: Richard Bergsma Date: Fri, 6 Jun 2025 22:14:49 +0200 Subject: [PATCH] Enhance ContributionCalendar component and update development.astro for better contribution visualization - Modify getCalendarDays function to start the week on Monday and improve date calculations. - Add getMonthLabels function to generate month labels for the contribution calendar. - Update styling and structure of the ContributionCalendar for improved layout and responsiveness. - Integrate ContributionCalendar into development.astro to visually represent code contributions over the past year, enhancing project transparency. --- src/components/ContributionCalendar.jsx | 148 +++++++++++++++++++----- src/pages/development.astro | 27 ++++- 2 files changed, 143 insertions(+), 32 deletions(-) diff --git a/src/components/ContributionCalendar.jsx b/src/components/ContributionCalendar.jsx index 77180ce..604bb6e 100644 --- a/src/components/ContributionCalendar.jsx +++ b/src/components/ContributionCalendar.jsx @@ -1,13 +1,17 @@ import React from 'react'; -// Helper to get all days in the last 52 weeks +// Helper to get all days in the last 52 weeks, starting on Monday function getCalendarDays() { const days = []; const today = new Date(); today.setHours(0, 0, 0, 0); - // Go back 51 weeks (to get 52 weeks total) + // Find the most recent Monday const start = new Date(today); - start.setDate(start.getDate() - (7 * 51 + today.getDay())); + const dayOfWeek = start.getDay(); + // getDay(): 0=Sunday, 1=Monday, ..., 6=Saturday + // If today is not Monday, go back to the previous Monday + const offset = (dayOfWeek === 0 ? -6 : 1 - dayOfWeek); // If Sunday, go back 6 days; else, go back to Monday + start.setDate(start.getDate() - (7 * 51) + offset); for (let i = 0; i < 7 * 52; i++) { const d = new Date(start); d.setDate(start.getDate() + i); @@ -16,6 +20,24 @@ function getCalendarDays() { return days; } +// Get month labels for the top +function getMonthLabels(days) { + const labels = []; + let lastMonth = null; + for (let week = 0; week < 52; week++) { + const day = days[week * 7]; + const month = day.toLocaleString('default', { month: 'short' }); + if (month !== lastMonth) { + labels.push({ week, month }); + lastMonth = month; + } + } + return labels; +} + +// Day labels for rows (Monday to Sunday) +const DAY_LABELS = ['Mon', '', 'Wed', '', 'Fri', '', 'Sun']; + // Color scale (GitHub-like) const COLORS = [ '#ebedf0', // 0 @@ -32,38 +54,104 @@ function getColor(count) { export default function ContributionCalendar({ data }) { const days = getCalendarDays(); + const monthLabels = getMonthLabels(days); // Get max count for scaling (optional, for more dynamic color) // const max = Math.max(...Object.values(data)); return ( -
-
- {/* Weeks (columns) */} - {Array.from({ length: 52 }).map((_, weekIdx) => ( -
- {/* Days (rows) */} - {Array.from({ length: 7 }).map((_, dayIdx) => { - const day = days[weekIdx * 7 + dayIdx]; - const dateStr = day.toISOString().slice(0, 10); - const count = data[dateStr] || 0; - return ( -
- ); - })} -
- ))} +
+ {/* Month labels */} +
+
+ {Array.from({ length: 52 }).map((_, weekIdx) => { + const label = monthLabels.find((l) => l.week === weekIdx); + return ( +
+ {label ? label.month : ''} +
+ ); + })}
-
+
+ {/* Day labels */} +
+ {DAY_LABELS.map((label, i) => ( +
+ {label} +
+ ))} +
+ {/* Weeks (columns) */} +
+ {Array.from({ length: 52 }).map((_, weekIdx) => ( +
+ {/* Days (rows) */} + {Array.from({ length: 7 }).map((_, dayIdx) => { + // Shift the dayIdx so that Monday is the first row and Sunday is the last + const shiftedDayIdx = (dayIdx + 1) % 7; + const day = days[weekIdx * 7 + shiftedDayIdx]; + const dateStr = day.toISOString().slice(0, 10); + const count = data[dateStr] || 0; + return ( +
+ ); + })} +
+ ))} +
+
+
Less {COLORS.map((color, i) => ( diff --git a/src/pages/development.astro b/src/pages/development.astro index 7e50591..27e7042 100644 --- a/src/pages/development.astro +++ b/src/pages/development.astro @@ -2,6 +2,9 @@ import Layout from '../layouts/Layout.astro'; import { getPermalink } from '../utils/permalinks'; import { getTranslation } from '../i18n/translations'; +import React, { useMemo } from 'react'; +import dynamic from 'astro/dynamic'; +import ContributionCalendar from '../components/ContributionCalendar.jsx'; const lang = Astro.params.lang || 'en'; const t = getTranslation(lang); @@ -40,12 +43,32 @@ const formatDate = (dateString: string) => { day: 'numeric', }); }; + +// Helper: Group commits by date (YYYY-MM-DD) +function getContributionData(commits) { + const contributions = {}; + for (const commit of commits) { + const date = commit.commit?.author?.date?.slice(0, 10); + if (date) { + contributions[date] = (contributions[date] || 0) + 1; + } + } + return contributions; +} + +const contributionData = getContributionData(commits); ---
-

{t.development.title || 'Development Progress'}

- +

{t.development.title || 'Development Progress'}

+

+ This page provides a transparent overview of the ongoing development activity for the 365DevNet project. The contribution calendar below visually represents code contributions (commits) made over the past year, with darker squares indicating more active days. Below the calendar, you'll find a list of the most recent commits, including details about each change. This helps users, contributors, and stakeholders track project progress and stay up to date with the latest updates. +

+ {/* Contribution Calendar */} +
+ +

{t.development.latestCommits || 'Latest Commits'}