diff --git a/changelog-toc.js b/changelog-toc.js index db3e30b6..48e54a41 100644 --- a/changelog-toc.js +++ b/changelog-toc.js @@ -4,6 +4,10 @@ var scrollScheduled = false; var refreshTimer = null; var lazyVideoObserver = null; + var datePicker = null; + var datePickerIds = ""; + // Mintlify only shows the table of contents (the date list) at xl; keep in sync with style.css. + var tocHiddenQuery = window.matchMedia("(width < 1280px)"); function isChangelogPage() { var currentPath = document.documentElement.getAttribute("data-current-path") || window.location.pathname; @@ -29,6 +33,7 @@ function collectPairs() { syncCurrentPath(); + syncDatePicker(); if (!isChangelogPage()) { pairs = []; @@ -168,6 +173,110 @@ } } + function updateLabelText(update) { + var label = update.querySelector("[data-component-part='update-label']"); + return label ? label.textContent.trim() : update.id; + } + + // Below xl there is no table of contents, so a floating native "; + + var select = picker.querySelector("select"); + select.setAttribute("aria-label", /^\/zh(\/|$)/.test(window.location.pathname) ? "跳转到日期" : "Jump to date"); + select.addEventListener("change", function () { + var target = document.getElementById(select.value); + if (!target) { + return; + } + + target.scrollIntoView({ block: "start" }); + window.history.replaceState(window.history.state, "", "#" + target.id); + updateDatePickerValue(); + }); + + document.body.appendChild(picker); + return picker; + } + + function removeDatePicker() { + if (datePicker) { + datePicker.remove(); + datePicker = null; + datePickerIds = ""; + } + } + + function updateDatePickerValue() { + if (!datePicker || !tocHiddenQuery.matches) { + return; + } + + var updates = document.querySelectorAll(".update-container[id]"); + var anchor = Math.min(window.innerHeight * 0.35, 260); + var active = updates[0]; + + for (var index = 1; index < updates.length; index += 1) { + if (updates[index].getBoundingClientRect().top > anchor) { + break; + } + active = updates[index]; + } + + if (!active) { + return; + } + + var select = datePicker.querySelector("select"); + var value = datePicker.querySelector(".changelog-date-picker-value"); + var text = updateLabelText(active); + + if (select.value !== active.id) { + select.value = active.id; + } + if (value.textContent !== text) { + value.textContent = text; + } + } + function scheduleActiveStateUpdate() { if (scrollScheduled) { return; @@ -177,6 +286,7 @@ window.requestAnimationFrame(function () { scrollScheduled = false; updateActiveState(false); + updateDatePickerValue(); }); } @@ -185,7 +295,16 @@ window.addEventListener("hashchange", scheduleCollectPairs); window.addEventListener("DOMContentLoaded", collectPairs); - new MutationObserver(scheduleCollectPairs).observe(document.documentElement, { + // Ignore the date picker's own updates so refreshing it does not schedule another refresh. + new MutationObserver(function (records) { + var external = records.some(function (record) { + return !datePicker || !datePicker.contains(record.target); + }); + + if (external) { + scheduleCollectPairs(); + } + }).observe(document.documentElement, { childList: true, subtree: true, }); diff --git a/style.css b/style.css index 5b62e810..e27e602a 100644 --- a/style.css +++ b/style.css @@ -7,9 +7,86 @@ object-fit: contain; } -/* Hide changelog left date column, expand content */ -.update-container > div:first-child { - display: none !important; +/* Changelog dates: Mintlify only shows the right-side table of contents (which lists + the dates) at width >= 1280px. Hide the left date column there to expand content; + below that, stack the date above each entry so it stays visible. The breakpoints + mirror Mintlify's `xl` range queries so fractional widths from zoom/OS scaling + always match exactly one rule. */ +@media (width >= 1280px) { + .update-container > div:first-child { + display: none !important; + } +} + +@media (width < 1280px) { + .update-container { + flex-direction: column !important; + } + + .update-container > div:first-child { + position: static !important; + width: auto !important; + } +} + +/* Mintlify's scroll offset below lg ignores the announcement banner, so anchor jumps + (e.g. the banner's own changelog link) land with the date under the navbar. */ +@media (width < 1024px) { + html[data-banner-state="visible"] .update-container { + scroll-margin-top: calc(var(--scroll-mt) - 2rem + var(--banner-height, 2.5rem)); + } +} + +/* Changelog date picker (changelog-toc.js): stands in for the table of contents below 1280px. + The native