170 lines
5.0 KiB
JavaScript
170 lines
5.0 KiB
JavaScript
import gsap from "gsap";
|
|
|
|
// DOM elements
|
|
const DOM = {
|
|
frame: document.querySelector(".frame"),
|
|
overlayPath: document.querySelector(".overlay__path"),
|
|
menuWrap: document.querySelector(".menu-wrap"),
|
|
menuItems: document.querySelectorAll(".menu__item"),
|
|
openMenuCtrl: document.querySelector("button#navbutton"),
|
|
closeMenuCtrl: document.querySelector(".button#navbutton.open"),
|
|
menuToggle: document.querySelector("#navbutton"),
|
|
brand: document.querySelector("#brand"),
|
|
navLink: document.querySelectorAll("#nav-link"),
|
|
};
|
|
|
|
let isAnimating = false;
|
|
|
|
const openMenu = () => {
|
|
if (isAnimating) return;
|
|
isAnimating = true;
|
|
DOM.menuToggle.classList.add("open");
|
|
|
|
gsap.timeline({
|
|
onComplete: () => {
|
|
isAnimating = false;
|
|
},
|
|
})
|
|
.set(DOM.overlayPath, {
|
|
attr: { d: "M 0 100 V 100 Q 50 100 100 100 V 100 z" },
|
|
})
|
|
.to(
|
|
DOM.overlayPath,
|
|
{
|
|
duration: 0.8,
|
|
ease: "power4.in",
|
|
attr: { d: "M 0 100 V 50 Q 50 0 100 50 V 100 z" },
|
|
},
|
|
0
|
|
)
|
|
.to(DOM.overlayPath, {
|
|
duration: 0.3,
|
|
ease: "power2",
|
|
attr: { d: "M 0 100 V 0 Q 50 0 100 0 V 100 z" },
|
|
onComplete: () => {
|
|
DOM.frame.classList.add("frame--menu-open");
|
|
DOM.menuWrap.classList.add("menu-wrap--open");
|
|
},
|
|
})
|
|
.set(DOM.menuItems, { opacity: 0 })
|
|
.set(DOM.overlayPath, {
|
|
attr: { d: "M 0 0 V 100 Q 50 100 100 100 V 0 z" },
|
|
})
|
|
.to(DOM.overlayPath, {
|
|
duration: 0.3,
|
|
ease: "power2.in",
|
|
attr: { d: "M 0 0 V 50 Q 50 0 100 50 V 0 z" },
|
|
})
|
|
.to(DOM.overlayPath, {
|
|
duration: 0.8,
|
|
ease: "power4",
|
|
attr: { d: "M 0 0 V 0 Q 50 0 100 0 V 0 z" },
|
|
})
|
|
.to(
|
|
DOM.menuItems,
|
|
{
|
|
duration: 1.1,
|
|
ease: "power4",
|
|
startAt: { y: 150 },
|
|
y: 0,
|
|
opacity: 1,
|
|
stagger: 0.05,
|
|
},
|
|
">-=1.1"
|
|
);
|
|
};
|
|
|
|
const closeMenu = () => {
|
|
if (isAnimating) return;
|
|
isAnimating = true;
|
|
DOM.menuToggle.classList.remove("open");
|
|
|
|
gsap.timeline({
|
|
onComplete: () => {
|
|
isAnimating = false;
|
|
},
|
|
})
|
|
.set(DOM.overlayPath, { attr: { d: "M 0 0 V 0 Q 50 0 100 0 V 0 z" } })
|
|
.to(
|
|
DOM.overlayPath,
|
|
{
|
|
duration: 0.8,
|
|
ease: "power4.in",
|
|
attr: { d: "M 0 0 V 50 Q 50 100 100 50 V 0 z" },
|
|
},
|
|
0
|
|
)
|
|
.to(DOM.overlayPath, {
|
|
duration: 0.3,
|
|
ease: "power2",
|
|
attr: { d: "M 0 0 V 100 Q 50 100 100 100 V 0 z" },
|
|
onComplete: () => {
|
|
DOM.frame.classList.remove("frame--menu-open");
|
|
DOM.menuWrap.classList.remove("menu-wrap--open");
|
|
},
|
|
})
|
|
.set(DOM.overlayPath, {
|
|
attr: { d: "M 0 100 V 0 Q 50 0 100 0 V 100 z" },
|
|
})
|
|
.to(DOM.overlayPath, {
|
|
duration: 0.3,
|
|
ease: "power2.in",
|
|
attr: { d: "M 0 100 V 50 Q 50 100 100 50 V 100 z" },
|
|
})
|
|
.to(DOM.overlayPath, {
|
|
duration: 0.8,
|
|
ease: "power4",
|
|
attr: { d: "M 0 100 V 100 Q 50 100 100 100 V 100 z" },
|
|
})
|
|
.to(
|
|
DOM.menuItems,
|
|
{
|
|
duration: 0.8,
|
|
ease: "power2.in",
|
|
y: 100,
|
|
opacity: 0,
|
|
stagger: -0.05,
|
|
},
|
|
0
|
|
);
|
|
};
|
|
|
|
const handleScroll = () => {
|
|
const contentSection = document.querySelector("#content-report");
|
|
const isPendahuluan = window.location.hash === "#pendahuluan";
|
|
|
|
if (!contentSection) return;
|
|
const contentTop = contentSection.offsetTop;
|
|
const contentHeight = contentSection.offsetHeight;
|
|
const scrollPosition = window.scrollY;
|
|
const idInContent = scrollPosition >= contentTop && scrollPosition <= contentTop + contentHeight;
|
|
|
|
DOM.navLink.forEach((link) => {
|
|
link.classList.toggle("text-white", !idInContent && !isPendahuluan);
|
|
link.classList.toggle("text-neutral-950", idInContent || isPendahuluan);
|
|
});
|
|
|
|
DOM.brand.classList.toggle("text-white", !idInContent && !isPendahuluan);
|
|
DOM.brand.classList.toggle("text-neutral-950", idInContent || isPendahuluan);
|
|
};
|
|
|
|
const initScrollEvents = () => {
|
|
window.addEventListener("scroll", () => requestAnimationFrame(handleScroll));
|
|
window.addEventListener("hashchange", handleScroll);
|
|
handleScroll();
|
|
};
|
|
|
|
export function initNavigation() {
|
|
if (!DOM.menuToggle) return;
|
|
|
|
DOM.menuToggle.addEventListener("click", function () {
|
|
if (DOM.frame.classList.contains("frame--menu-open")) {
|
|
closeMenu();
|
|
} else {
|
|
openMenu();
|
|
}
|
|
});
|
|
|
|
initScrollEvents();
|
|
}
|