Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 120 additions & 1 deletion changelog-toc.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,6 +33,7 @@

function collectPairs() {
syncCurrentPath();
syncDatePicker();

if (!isChangelogPage()) {
pairs = [];
Expand Down Expand Up @@ -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 <select> lets readers jump between dates.
function syncDatePicker() {
var updates = Array.prototype.slice.call(document.querySelectorAll(".update-container[id]"));

if (updates.length < 2) {
removeDatePicker();
return;
}

if (!datePicker || !datePicker.isConnected) {
datePicker = createDatePicker();
datePickerIds = "";
}

var ids = updates.map(function (update) {
return update.id;
}).join(",");

if (ids !== datePickerIds) {
var select = datePicker.querySelector("select");
select.textContent = "";
updates.forEach(function (update) {
var option = document.createElement("option");
option.value = update.id;
option.textContent = updateLabelText(update);
select.appendChild(option);
});
datePickerIds = ids;
}

updateDatePickerValue();
}

function createDatePicker() {
var picker = document.createElement("div");
picker.id = "changelog-date-picker";
picker.innerHTML =
'<span class="changelog-date-picker-value"></span>' +
'<svg aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" ' +
'stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg>' +
"<select></select>";

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;
Expand All @@ -177,6 +286,7 @@
window.requestAnimationFrame(function () {
scrollScheduled = false;
updateActiveState(false);
updateDatePickerValue();
});
}

Expand All @@ -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,
});
Expand Down
83 changes: 80 additions & 3 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 <select> covers the pill so phones open their own picker. */
#changelog-date-picker {
position: fixed;
left: 50%;
bottom: calc(16px + env(safe-area-inset-bottom));
z-index: 20;
display: flex;
align-items: center;
gap: 6px;
padding: 8px 14px;
transform: translateX(-50%);
border: 1px solid rgba(17, 17, 17, 0.18);
border-radius: 999px;
background: rgb(var(--background-light, 255 255 255));
box-shadow: 0 4px 16px rgba(17, 17, 17, 0.12);
color: #111111;
font-size: 14px;
font-weight: 500;
line-height: 20px;
white-space: nowrap;
}

#changelog-date-picker select {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
/* 16px keeps iOS Safari from zooming in when the picker opens */
font-size: 16px;
}

#changelog-date-picker:focus-within {
outline: 2px solid rgb(var(--primary));
outline-offset: 2px;
}

.dark #changelog-date-picker {
border-color: rgba(255, 255, 255, 0.25);
background: rgb(24, 24, 27);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
color: #f3f4f6;
}

@media (width >= 1280px) {
#changelog-date-picker {
display: none;
}
}

/* Hide sidebar collapse button */
Expand Down
Loading