Skip to content

Commit 25332b7

Browse files
committed
dynamic menu
1 parent 4392882 commit 25332b7

2 files changed

Lines changed: 185 additions & 14 deletions

File tree

assets/css/documentation.css

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,44 @@ html, body {
8181
#documenter .docs-main header.docs-navbar .docs-sidebar-button {
8282
display: block!important;
8383
}
84+
85+
/* Align Documenter header (burger) behavior with custom topbar on small screens */
86+
@media screen and (max-width: 1055px) {
87+
/* When JS adds these classes, they override Headroom positioning */
88+
#documenter .docs-main header.docs-navbar.ct-header-visible {
89+
top: var(--navbar-height) !important;
90+
}
91+
#documenter .docs-main header.docs-navbar.ct-header-hidden {
92+
top: -100vh !important;
93+
}
94+
95+
/* Staggered transitions: topbar first, then header (burger) */
96+
#multi-page-nav.smooth-show-hide {
97+
transition-property: transform !important;
98+
transition-duration: 0.25s !important; /* faster */
99+
transition-timing-function: ease-in-out !important;
100+
transition-delay: 0s !important; /* no delay for topbar */
101+
will-change: transform;
102+
}
103+
104+
#documenter .docs-main header.docs-navbar {
105+
transition-property: top, box-shadow !important;
106+
transition-duration: 0.35s !important; /* slightly slower */
107+
transition-timing-function: ease-in-out !important;
108+
transition-delay: 0.08s !important; /* delay so it follows topbar */
109+
will-change: top;
110+
}
111+
}
112+
113+
/* Fine-tune when the appearance originates from bottom of page */
114+
@media screen and (max-width: 1055px) {
115+
html.ct-appear-bottom #multi-page-nav.smooth-show-hide {
116+
transition-duration: 0.30s !important; /* slightly longer */
117+
transition-delay: 0s !important; /* keep topbar immediate */
118+
}
119+
120+
html.ct-appear-bottom #documenter .docs-main header.docs-navbar {
121+
transition-duration: 0.50s !important; /* slightly longer */
122+
transition-delay: 0.0s !important; /* less pronounced delay */
123+
}
124+
}

assets/js/documentation.js

Lines changed: 144 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,6 @@ function showTopBar() {
7676
topbar.classList.add("show-top-menu");
7777
}
7878

79-
// update sidebar
80-
var sidebar = document.getElementsByClassName("docs-sidebar");
81-
if (sidebar.length > 0) {
82-
sidebar[0].classList.remove("hide-top-menu");
83-
sidebar[0].classList.add("show-top-menu");
84-
}
85-
8679
}
8780

8881
// Function to hide the top bar menu
@@ -95,13 +88,6 @@ function hideTopBar() {
9588
topbar.classList.add("hide-top-menu");
9689
}
9790

98-
// update sidebar
99-
var sidebar = document.getElementsByClassName("docs-sidebar");
100-
if (sidebar.length > 0) {
101-
sidebar[0].classList.remove("show-top-menu");
102-
sidebar[0].classList.add("hide-top-menu");
103-
}
104-
10591
}
10692

10793
// ajoute un event listener sur les touches du clavier
@@ -198,10 +184,12 @@ if (
198184
setTimeout(topbarInjector, 1);
199185
setTimeout(addEventListenerToShowHideTopbar, 1);
200186
setTimeout(addSidebarToggleButton, 1);
187+
setTimeout(addScrollTopBehavior, 1);
201188
} else {
202189
document.addEventListener("DOMContentLoaded", topbarInjector);
203190
document.addEventListener("DOMContentLoaded", addEventListenerToShowHideTopbar);
204191
document.addEventListener("DOMContentLoaded", addSidebarToggleButton);
192+
document.addEventListener("DOMContentLoaded", addScrollTopBehavior);
205193
}
206194

207195
//
@@ -235,3 +223,145 @@ window.onload = function() {
235223
}
236224

237225
};
226+
227+
// Add scroll behavior to hide topbar when scrolled down beyond a threshold
228+
function addScrollTopBehavior() {
229+
var ticking = false;
230+
var threshold = 20; // px tolerance; adjustable (top and bottom)
231+
232+
// Cache last states to avoid redundant DOM writes
233+
var lastTopbarVisible = null;
234+
var lastHeaderVisible = null;
235+
var lastScrollY = window.scrollY || window.pageYOffset || 0;
236+
var minDelta = 6; // px minimal upward movement to trigger show mid-page
237+
var lastVisible = null; // persistent desired visibility state
238+
239+
function isTopbarMenuOpen() {
240+
var navItems = document.getElementById("nav-items");
241+
if (!navItems) return false;
242+
// On mobile, nav is open when it does NOT have 'hidden-on-mobile'
243+
return !navItems.classList.contains("hidden-on-mobile");
244+
}
245+
246+
function isDocSidebarVisible() {
247+
var sidebar = document.querySelector('.docs-sidebar');
248+
if (!sidebar) return false;
249+
return sidebar.classList.contains('visible');
250+
}
251+
252+
function getHeaderEl() {
253+
return document.querySelector('#documenter .docs-main header.docs-navbar');
254+
}
255+
256+
function atTopOrBottom(tol) {
257+
var y = window.scrollY || window.pageYOffset || 0;
258+
var atTop = y <= tol;
259+
var atBottom = (window.innerHeight + y) >= ((document.documentElement && document.documentElement.scrollHeight) || document.body.offsetHeight) - tol;
260+
return { atTop: atTop, atBottom: atBottom, y: y };
261+
}
262+
263+
function setHeaderVisible(visible) {
264+
var header = getHeaderEl();
265+
if (!header) return;
266+
if (visible === lastHeaderVisible) return;
267+
header.classList.toggle('ct-header-visible', !!visible);
268+
header.classList.toggle('ct-header-hidden', !visible);
269+
lastHeaderVisible = visible;
270+
}
271+
272+
function setTopbarVisible(visible) {
273+
if (visible === lastTopbarVisible) return;
274+
if (visible) {
275+
showTopBar();
276+
} else {
277+
hideTopBar();
278+
}
279+
lastTopbarVisible = visible;
280+
}
281+
282+
function computeDesiredVisibility() {
283+
var pos = atTopOrBottom(threshold);
284+
var dy = lastScrollY - pos.y;
285+
var directionUp = dy > minDelta;
286+
var directionDown = dy < -minDelta;
287+
288+
// If menus are open, always visible
289+
if (isTopbarMenuOpen() || isDocSidebarVisible()) {
290+
return { visible: true, atBottom: false, atTop: pos.atTop, y: pos.y };
291+
}
292+
293+
// At top or bottom within threshold => visible
294+
if (pos.atTop || pos.atBottom) {
295+
return { visible: true, atBottom: pos.atBottom, atTop: pos.atTop, y: pos.y };
296+
}
297+
298+
// Mid-page behavior: show on upward scroll, hide on downward scroll
299+
if (directionUp) {
300+
return { visible: true, atBottom: false, atTop: false, y: pos.y };
301+
}
302+
if (directionDown) {
303+
return { visible: false, atBottom: false, atTop: false, y: pos.y };
304+
}
305+
306+
// No significant movement: keep previous state
307+
return { visible: (lastVisible !== null ? lastVisible : false), atBottom: false, atTop: false, y: pos.y };
308+
}
309+
310+
function update() {
311+
ticking = false;
312+
var res = computeDesiredVisibility();
313+
var visible = res.visible;
314+
// Toggle a root class to signal that appearance originates from bottom
315+
// Only set when not forced by menus
316+
var fromBottom = res.atBottom && !(isTopbarMenuOpen() || isDocSidebarVisible());
317+
try {
318+
document.documentElement.classList.toggle('ct-appear-bottom', !!fromBottom);
319+
} catch (e) { /* no-op */ }
320+
setTopbarVisible(visible);
321+
setHeaderVisible(visible);
322+
// update last scroll position after applying visibility
323+
lastScrollY = res.y;
324+
lastVisible = visible;
325+
}
326+
327+
// Initial state: compute once based on current position
328+
update();
329+
330+
// Scroll listener
331+
window.addEventListener("scroll", function () {
332+
if (!ticking) {
333+
window.requestAnimationFrame(update);
334+
ticking = true;
335+
}
336+
}, { passive: true });
337+
338+
// Resize listener (in case layout switches around 1055px)
339+
window.addEventListener('resize', function () {
340+
if (!ticking) {
341+
window.requestAnimationFrame(update);
342+
ticking = true;
343+
}
344+
});
345+
346+
// Click on Documenter burger button: force reevaluation
347+
var docBurger = document.getElementById('documenter-sidebar-button');
348+
if (docBurger) {
349+
docBurger.addEventListener('click', function () {
350+
// Wait a tick so classes update
351+
setTimeout(update, 0);
352+
});
353+
}
354+
355+
// Observe sidebar visibility class changes
356+
var sidebar = document.querySelector('.docs-sidebar');
357+
if (sidebar && 'MutationObserver' in window) {
358+
try {
359+
var observer = new MutationObserver(function () {
360+
update();
361+
});
362+
observer.observe(sidebar, { attributes: true, attributeFilter: ['class'] });
363+
} catch (e) {
364+
// no-op
365+
}
366+
}
367+
}

0 commit comments

Comments
 (0)