79 lines
2.3 KiB
JavaScript
79 lines
2.3 KiB
JavaScript
|
const sectionsContainer = document.querySelector('.page-sections');
|
||
|
const sections = document.querySelectorAll('.page-section');
|
||
|
const nav = document.querySelector('.nav-sections');
|
||
|
const menu = nav.querySelector('.menu');
|
||
|
const links = nav.querySelectorAll('.menu-item-link');
|
||
|
const activeLine = nav.querySelector('.active-line');
|
||
|
const sectionOffset = nav.offsetHeight + 24;
|
||
|
const activeClass = 'active';
|
||
|
let activeIndex = 0;
|
||
|
let isScrolling = true;
|
||
|
let userScroll = true;
|
||
|
|
||
|
const setActiveClass = () => {
|
||
|
links[activeIndex].classList.add(activeClass);
|
||
|
};
|
||
|
|
||
|
const removeActiveClass = () => {
|
||
|
links[activeIndex].classList.remove(activeClass);
|
||
|
};
|
||
|
|
||
|
const moveActiveLine = () => {
|
||
|
const link = links[activeIndex];
|
||
|
const linkX = link.getBoundingClientRect().x;
|
||
|
const menuX = menu.getBoundingClientRect().x;
|
||
|
|
||
|
activeLine.style.transform = `translateX(${menu.scrollLeft - menuX + linkX}px)`;
|
||
|
activeLine.style.width = `${link.offsetWidth}px`;
|
||
|
};
|
||
|
|
||
|
const setMenuLeftPosition = position => {
|
||
|
menu.scrollTo({
|
||
|
left: position,
|
||
|
behavior: 'smooth' });
|
||
|
|
||
|
};
|
||
|
|
||
|
const checkMenuOverflow = () => {
|
||
|
const activeLink = links[activeIndex].getBoundingClientRect();
|
||
|
const offset = 30;
|
||
|
|
||
|
if (Math.floor(activeLink.right) > window.innerWidth) {
|
||
|
setMenuLeftPosition(menu.scrollLeft + activeLink.right - window.innerWidth + offset);
|
||
|
} else if (activeLink.left < 0) {
|
||
|
setMenuLeftPosition(menu.scrollLeft + activeLink.left - offset);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const handleActiveLinkUpdate = current => {
|
||
|
removeActiveClass();
|
||
|
activeIndex = current;
|
||
|
checkMenuOverflow();
|
||
|
setActiveClass();
|
||
|
moveActiveLine();
|
||
|
};
|
||
|
|
||
|
const init = () => {
|
||
|
moveActiveLine(links[0]);
|
||
|
document.documentElement.style.setProperty('--section-offset', sectionOffset);
|
||
|
};
|
||
|
|
||
|
links.forEach((link, index) => link.addEventListener('click', () => {
|
||
|
userScroll = false;
|
||
|
handleActiveLinkUpdate(index);
|
||
|
}));
|
||
|
|
||
|
window.addEventListener("scroll", () => {
|
||
|
const currentIndex = sectionsContainer.getBoundingClientRect().top < 0 ?
|
||
|
sections.length - 1 - [...sections].reverse().findIndex(section => window.scrollY >= section.offsetTop - sectionOffset * 2) :
|
||
|
0;
|
||
|
|
||
|
if (userScroll && activeIndex !== currentIndex) {
|
||
|
handleActiveLinkUpdate(currentIndex);
|
||
|
} else {
|
||
|
window.clearTimeout(isScrolling);
|
||
|
isScrolling = setTimeout(() => userScroll = true, 100);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
init();
|