From b6f86c4bdf249ca4c013b66ca707500dae8d0511 Mon Sep 17 00:00:00 2001 From: Eszter Schuffert Date: Sun, 8 Nov 2026 22:57:51 +0100 Subject: [PATCH] fix(app): keep year calendar days on their weekday rows Month labels in row 8 span four weeks, so a five-week month left a gap that grid auto-placement filled with the next Monday, shifting every later day down a row. Place each day cell and weekday label explicitly. Fixes #81 --- app/src/Stats.jsx | 14 +++++++------- app/src/Stats.test.jsx | 9 +++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/src/Stats.jsx b/app/src/Stats.jsx index 24e39ab..2ddb2e4 100644 --- a/app/src/Stats.jsx +++ b/app/src/Stats.jsx @@ -398,11 +398,11 @@ function ReadingCalendar({ summary, activity, books = [] }) { setScale(v) setBack(0) } - const cell = (d, round) => { - if (!shown(d)) return
+ const cell = (d, round, style) => { + if (!shown(d)) return
const key = localDay(d) const tip = `${fmt(d, { weekday: 'short', month: 'short', day: 'numeric' })}: ${byDay.has(key) ? tipFor(key) : 'no reading'}` - return
+ return
} // Share the visible period, reading days, available page/time totals and longest streak. const share = () => { @@ -538,14 +538,14 @@ function ReadingCalendar({ summary, activity, books = [] }) { }} > {WEEKDAYS.map((w, r) => ( -

+

{!year || r % 2 === 0 ? w[0] : ''}

))} - - {weeks.map((monday) => ( + {/* Explicit cells: month labels leave gaps in row 8 that auto-placement would fill with days. */} + {weeks.map((monday, i) => ( - {WEEKDAYS.map((w, r) => cell(new Date(monday.getTime() + r * DAY_MS), 'rounded-[2px]'))} + {WEEKDAYS.map((w, r) => cell(new Date(monday.getTime() + r * DAY_MS), 'rounded-[2px]', { gridRow: r + 1, gridColumn: i + 2 }))} ))} {/* Labels span weeks so their text fits; keep the last month inside the grid. */} diff --git a/app/src/Stats.test.jsx b/app/src/Stats.test.jsx index b4ec3ab..375f7e7 100644 --- a/app/src/Stats.test.jsx +++ b/app/src/Stats.test.jsx @@ -487,3 +487,12 @@ describe('BookOrbit stats', () => { expect(queryByText(/Duplicate BookOrbit session records are counted once/)).toBeNull() }) }) + +it('pins every year-calendar day to its weekday row', () => { + const { container, getByText } = render() + fireEvent.click(getByText('Year')) + const cells = [...container.querySelectorAll('[data-tip]')] + expect(cells.length).toBeGreaterThan(300) + const rows = { Mon: '1', Tue: '2', Wed: '3', Thu: '4', Fri: '5', Sat: '6', Sun: '7' } + for (const el of cells) expect(el.style.gridRow).toBe(rows[el.dataset.tip.slice(0, 3)]) +})