fix(card): heatmap month labels skip leading zero-pad cell

The first cell of week 0 can be a zero-time padding slot when
start_of_week differs from the data's first weekday. Zero time
(0001-01-01) reports Day=1, Month=January, leaking a bogus "Jan"
label that overlaps the next real month label.
This commit is contained in:
tiennm99 committed 2026-05-09 09:02:16 +07:00
1 parent d21e65d401
commit 85461bd8c8
2 files changed
+30 -1

No files matched your search

+1 -1
View File
@@ -103,7 +103,7 @@ func renderHeatmapHalf(b *strings.Builder, cells []github.DailyContribution, sta
lastMonth := time.Month(0) lastMonth := time.Month(0)
for w := startWeek; w < endWeek; w++ { for w := startWeek; w < endWeek; w++ {
first := cells[w*7].Date first := cells[w*7].Date
if first.Day() > 7 || first.Month() == lastMonth { if first.IsZero() || first.Day() > 7 || first.Month() == lastMonth {
continue continue
} }
lastMonth = first.Month() lastMonth = first.Month()
+29
View File
@@ -107,6 +107,35 @@ func TestRenderHeatmapLabelsRespectWeekStart(t *testing.T) {
} }
} }
// TestRenderHeatmapMonthLabelsSkipPaddedCells guards against the leading
// zero-pad cell at week 0 leaking a bogus "Jan" label (zero time = 0001-01-01,
// Day=1 ≤ 7, Month=Jan). When weekStart=Monday and data starts mid-week, the
// pad cell would otherwise render an out-of-range month above the first column.
func TestRenderHeatmapMonthLabelsSkipPaddedCells(t *testing.T) {
th, _ := theme.Lookup("dracula")
// Sunday 2025-04-27 — with weekStart=Monday this needs 6 leading zero pads,
// putting the bogus "Jan" label at week 0 in the buggy version.
start := time.Date(2025, 4, 27, 0, 0, 0, 0, time.UTC)
var days []github.DailyContribution
for i := 0; i < 200; i++ {
days = append(days, github.DailyContribution{Date: start.AddDate(0, 0, i), Count: i % 5})
}
svg := string(renderHeatmap("t", days, time.Monday, th))
// The data range is 2025-04-27 .. 2025-11-12 — none of which is January.
// Any "Jan" label is the leaked zero-time month from the leading pad.
if strings.Contains(svg, ">Jan</text>") {
t.Error("month-label loop leaked a Jan label from the leading zero-pad cell")
}
// Sanity: months actually in range should still appear.
for _, m := range []string{"May", "Jun", "Jul"} {
if !strings.Contains(svg, ">"+m+"</text>") {
t.Errorf("expected month label %q in heatmap, missing", m)
}
}
}
// extractWeekdayLabels pulls weekday 3-letter names out of <text …>…</text> // extractWeekdayLabels pulls weekday 3-letter names out of <text …>…</text>
// blocks in the order they appear. Good enough for bar-chart cards that emit // blocks in the order they appear. Good enough for bar-chart cards that emit
// exactly 7 weekday labels and no colliding strings. // exactly 7 weekday labels and no colliding strings.