Skip to content
Closed
Changes from 1 commit
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
79 changes: 79 additions & 0 deletions sidebar-scroll.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
(function () {
if (typeof window === "undefined") return;

// Mintlify's DOM is not a stable contract, so selection is defensive:
// pick the first sidebar-ish element that is actually scrollable.
function findSidebar() {
var candidates = document.querySelectorAll(
"aside, nav[aria-label='Sidebar'], aside[aria-label='Sidebar'], #sidebar"
);
for (var i = 0; i < candidates.length; i++) {
var el = candidates[i];
if (el.scrollHeight > el.clientHeight + 1) return el;
}
return null;
}

function findActiveLink(sb) {
return sb.querySelector(
"a[aria-current='page'], a[aria-current='true'], a[data-active='true']"
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use Mintlify's active sidebar selector

On Mintlify pages that use the documented sidebar active state (#sidebar-content li[data-active]), this lookup returns null because it only checks attributes on the <a> and requires data-active='true'. In that case showActive() never runs past the active-link check, so the new sidebar-scroll behavior silently no-ops on the pages it was added to fix; include the li[data-active]/presence selector and resolve its contained link or element.

Useful? React with 👍 / 👎.

}

// Scroll the sidebar the minimum amount needed to bring the current page's
// link into view. No-op if it's already visible. Anchored to the active
// item (semantic) rather than a remembered pixel offset, so it stays correct
// even when the sidebar's contents differ between pages.
function showActive() {
var sb = findSidebar();
if (!sb) return false;
var link = findActiveLink(sb);
if (!link) return false;

var sbRect = sb.getBoundingClientRect();
var linkRect = link.getBoundingClientRect();
var margin = 24; // breathing room so the item isn't flush against an edge

if (linkRect.top < sbRect.top + margin) {
sb.scrollTop -= sbRect.top + margin - linkRect.top;
} else if (linkRect.bottom > sbRect.bottom - margin) {
sb.scrollTop += linkRect.bottom - (sbRect.bottom - margin);
}
return true;
}

// After a route change the sidebar may not exist yet; poll until it does.
// On success, re-apply once more to survive a late re-render that resets it.
function pollShow() {
var attempts = 0;
var iv = setInterval(function () {
attempts++;
if (showActive()) {
clearInterval(iv);
setTimeout(showActive, 150);
} else if (attempts > 30) {
clearInterval(iv);
}
}, 50);
}

var origPush = history.pushState;
history.pushState = function () {
var r = origPush.apply(this, arguments);
pollShow();
return r;
};
var origReplace = history.replaceState;
history.replaceState = function () {
var r = origReplace.apply(this, arguments);
pollShow();
return r;
};
window.addEventListener("popstate", pollShow);

if (document.readyState === "complete") {
pollShow();
} else {
window.addEventListener("load", pollShow);
}
})();
Loading