From 8c9b448bdc1c14cec92bc8aa988de6a653cdaad5 Mon Sep 17 00:00:00 2001 From: luxick Date: Wed, 1 Jul 2026 11:00:41 +0200 Subject: [PATCH] Render all months in sidebar --- assets/diary/calendar.html | 21 +++++-------- assets/diary/calendar.js | 64 ++++++++++++++++++-------------------- assets/style.css | 24 ++++++-------- diary.go | 28 +++++++---------- 4 files changed, 59 insertions(+), 78 deletions(-) diff --git a/assets/diary/calendar.html b/assets/diary/calendar.html index 86a1c16..4510a6d 100644 --- a/assets/diary/calendar.html +++ b/assets/diary/calendar.html @@ -1,29 +1,24 @@
- -
+
+ Chronological - {{.DisplayYear}} -
- {{range .Months}} - + {{range $i, $m := .Months}} + {{if $i}}
{{end}} + +
- {{range .Weeks}}{{range .}}{{end}} + {{range $m.Weeks}}{{range .}}{{end}} {{end}}
MoDiMiDoFrSaSo
{{if .Num}}{{.Num}}{{end}}
{{if .Num}}{{.Num}}{{end}}
diff --git a/assets/diary/calendar.js b/assets/diary/calendar.js index fa87767..f4872e0 100644 --- a/assets/diary/calendar.js +++ b/assets/diary/calendar.js @@ -3,47 +3,43 @@ if (!cal) return; cal.querySelectorAll(".dropdown > button").forEach(wireDropdown); - var displayYear = parseInt(cal.dataset.displayYear, 10); - var current = parseInt(cal.dataset.displayMonth, 10); - var monthLabel = cal.querySelector("[data-cal-month-link]"); + var displayMonth = parseInt(cal.dataset.displayMonth, 10); var months = {}; cal.querySelectorAll("[data-cal-month]").forEach(function (t) { months[parseInt(t.dataset.calMonth, 10)] = t; }); - var jumpLinks = {}; - cal.querySelectorAll("[data-cal-month-jump]").forEach(function (a) { - jumpLinks[parseInt(a.dataset.calMonthJump, 10)] = a; - }); - function show(m) { - if (m === current) return; - if (!months[m]) return; - months[current].hidden = true; - months[m].hidden = false; - current = m; - if (monthLabel) { - var label = jumpLinks[m]; - if (label) monthLabel.textContent = " " + label.textContent + " "; + // Centering only applies inside the persistent desktop rail (.sidebar). On + // mobile the widget is re-parented into .overlay-body, where we leave the + // grids stacked from January and do not scroll (design decision). + function railContainer() { + var el = cal.parentElement; + while (el) { + if (el.classList) { + if (el.classList.contains("overlay-body")) return null; + if (el.classList.contains("sidebar")) return el; + } + el = el.parentElement; } + return null; } - // Dropdown month picks scroll via the href anchor; we also swap the grid - // so the calendar reflects what the user just navigated to. - Object.keys(jumpLinks).forEach(function (key) { - var a = jumpLinks[key]; - a.addEventListener("click", function () { show(parseInt(key, 10)); }); - }); - - // Any in-page anchor click (#YYYY-MM or #YYYY-MM-DD) updates the calendar - // so it tracks the user's focus through the year page. - function syncFromHash() { - var h = window.location.hash; - if (!h) return; - var m = h.match(/^#(\d{4})-(\d{2})(?:-\d{2})?$/); - if (!m) return; - if (parseInt(m[1], 10) !== displayYear) return; - show(parseInt(m[2], 10)); + // Scroll only the rail so the given month grid sits in its vertical center; + // the main document/window position is untouched (priority: don't disturb + // the reading position). + function centerMonth(m) { + var grid = months[m]; + if (!grid) return; + var container = railContainer(); + if (!container) return; + var offset = grid.getBoundingClientRect().top - + container.getBoundingClientRect().top + container.scrollTop; + container.scrollTop = offset - (container.clientHeight - grid.clientHeight) / 2; } - window.addEventListener("hashchange", syncFromHash); - syncFromHash(); + + // Center the current month once, on initial render. Anchor navigation + // (#YYYY-MM / #YYYY-MM-DD) deliberately does NOT re-center the rail — + // re-scrolling on every hop is disorienting; the today/current cell + // highlighting is enough to keep bearings. + centerMonth(displayMonth); })(); diff --git a/assets/style.css b/assets/style.css index c1ab60f..bf44622 100644 --- a/assets/style.css +++ b/assets/style.css @@ -757,23 +757,17 @@ aside.tree-sidebar:empty { display: none; } } /* === Diary calendar === */ -.diary-cal-nav { - display: flex; - align-items: center; - justify-content: center; - gap: 0.2rem; - margin-bottom: 0.4rem; +/* Header row: "Chronological" on the left, the [year ▾] dropdown pushed to the + right. Composes with .row (flex + centering); space-between splits the two. */ +.diary-cal .panel-header { justify-content: space-between; } +.diary-cal-drop .dropdown-menu { min-width: 0; } +/* Per-month caption above each grid, linking to that month's anchor. */ +.diary-cal-month { font-size: var(--font-sm); + margin: var(--space-3) 0 0.2rem; } -.diary-cal-nav .diary-cal-drop + .diary-cal-heading { margin-left: var(--space-3); } -/* Anchor the month/year dropdowns to the nav row instead of the ▾ button so - the menu spans the full panel width rather than overflowing the 14rem - sidebar with its default min-width: 9rem. */ -.diary-cal-nav { position: relative; } -.diary-cal-nav .diary-cal-drop { position: static; } -.diary-cal-nav .dropdown-menu { left: 0; right: 0; min-width: 0; } -.diary-cal-heading { color: var(--link); } -.diary-cal-heading:hover { color: var(--link-hover); } +.diary-cal-month a { color: var(--link); } +.diary-cal-month a:hover { color: var(--link-hover); } .diary-cal-grid { width: 100%; border-collapse: collapse; diff --git a/diary.go b/diary.go index b7921b7..4a63c8a 100644 --- a/diary.go +++ b/diary.go @@ -343,8 +343,8 @@ type calYear struct { } // calMonthGrid carries everything the template needs to render one month's -// grid plus the dropdown / heading entry that targets it. The calendar -// widget ships all 12 in the initial HTML; JS swaps which one is visible. +// grid plus the caption that links to it. The calendar widget renders all 12 +// stacked vertically; JS centers the current month in the rail on load. type calMonthGrid struct { Num int Name string @@ -353,13 +353,11 @@ type calMonthGrid struct { } type calendarData struct { - DisplayYear int - DisplayMonth int - DisplayMonthName string // pre-resolved so the template doesn't need arithmetic - DiaryURL string - YearURL string - Months []calMonthGrid - Years []calYear + DisplayYear int + DisplayMonth int + DiaryURL string + Months []calMonthGrid + Years []calYear } var diaryCalTmpl = template.Must(template.ParseFS(assets, "assets/diary/calendar.html")) @@ -489,13 +487,11 @@ func computeCalendarWidget(diaryRootFS, diaryRootURL, fsPath string, depth int) sort.Slice(years, func(i, j int) bool { return years[i].Num > years[j].Num }) data := calendarData{ - DisplayYear: displayYear, - DisplayMonth: displayMonth, - DisplayMonthName: months[displayMonth-1].Name, - DiaryURL: diaryRootURL, - YearURL: yearURL, - Months: months, - Years: years, + DisplayYear: displayYear, + DisplayMonth: displayMonth, + DiaryURL: diaryRootURL, + Months: months, + Years: years, } var buf bytes.Buffer