(function () { "use strict"; const ready = (callback) => { if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", callback, { once: true }); return; } callback(); }; ready(function () { const header = document.querySelector(".site-header"); const toggle = document.querySelector("[data-nav-toggle], .nav-toggle, .menu-toggle"); const navigation = document.querySelector("[data-primary-nav], .primary-nav, .primary-navigation"); const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)"); let lastFocusedElement = null; const updateHeader = () => { if (!header) { return; } header.classList.toggle("is-scrolled", window.scrollY > 24); }; updateHeader(); window.addEventListener("scroll", updateHeader, { passive: true }); if (toggle && navigation) { const drawerClose = navigation.querySelector("[data-nav-close]"); const navigationParent = navigation.parentNode; const navigationNextSibling = navigation.nextSibling; let navigationIsDrawer = false; const placeNavigation = (asDrawer) => { if (asDrawer && !navigationIsDrawer) { document.body.appendChild(navigation); navigationIsDrawer = true; } else if (!asDrawer && navigationIsDrawer) { navigationParent.insertBefore(navigation, navigationNextSibling); navigationIsDrawer = false; } }; if (!navigation.id) { navigation.id = "site-navigation"; } toggle.setAttribute("aria-controls", navigation.id); toggle.setAttribute("aria-expanded", "false"); navigation.setAttribute("aria-hidden", "true"); const focusableSelector = [ "a[href]", "button:not([disabled])", "input:not([disabled])", "select:not([disabled])", "textarea:not([disabled])", "[tabindex]:not([tabindex='-1'])", ].join(","); const closeMenu = (restoreFocus) => { toggle.setAttribute("aria-expanded", "false"); const toggleLabel = toggle.querySelector(".menu-toggle__label"); if (toggleLabel && window.gustavooPortfolioNavigation) { toggleLabel.textContent = window.gustavooPortfolioNavigation.expand; } navigation.setAttribute("aria-hidden", "true"); navigation.classList.remove("is-open"); navigation.classList.remove("has-more-content"); document.body.classList.remove("nav-open"); if (restoreFocus && lastFocusedElement) { lastFocusedElement.focus(); } }; const openMenu = () => { lastFocusedElement = document.activeElement; toggle.setAttribute("aria-expanded", "true"); const toggleLabel = toggle.querySelector(".menu-toggle__label"); if (toggleLabel && window.gustavooPortfolioNavigation) { toggleLabel.textContent = window.gustavooPortfolioNavigation.collapse; } navigation.setAttribute("aria-hidden", "false"); navigation.classList.add("is-open"); document.body.classList.add("nav-open"); window.requestAnimationFrame(function () { updateNavigationScrollHint(); }); const firstFocusable = navigation.querySelector(focusableSelector); if (firstFocusable) { window.requestAnimationFrame(() => firstFocusable.focus()); } }; const updateNavigationScrollHint = () => { const hasMoreContent = navigation.scrollHeight > navigation.clientHeight + 4 && navigation.scrollTop + navigation.clientHeight < navigation.scrollHeight - 4; navigation.classList.toggle("has-more-content", hasMoreContent); }; toggle.addEventListener("click", function () { if (toggle.getAttribute("aria-expanded") === "true") { closeMenu(false); } else { openMenu(); } }); if (drawerClose) { drawerClose.addEventListener("click", function () { closeMenu(true); }); } navigation.addEventListener("click", function (event) { if (event.target.closest("a")) { closeMenu(false); } }); navigation.addEventListener("scroll", updateNavigationScrollHint, { passive: true }); window.addEventListener("resize", updateNavigationScrollHint, { passive: true }); document.addEventListener("keydown", function (event) { if (toggle.getAttribute("aria-expanded") !== "true") { return; } if (event.key === "Escape") { event.preventDefault(); closeMenu(true); return; } if (event.key !== "Tab") { return; } const focusable = Array.from(navigation.querySelectorAll(focusableSelector)); focusable.push(toggle); if (!focusable.length) { return; } const first = focusable[0]; const last = focusable[focusable.length - 1]; if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); } else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); } }); const desktopQuery = window.matchMedia("(min-width: 921px)"); const handleDesktop = (event) => { placeNavigation(!event.matches); if (event.matches) { closeMenu(false); navigation.removeAttribute("aria-hidden"); } else if (toggle.getAttribute("aria-expanded") !== "true") { navigation.setAttribute("aria-hidden", "true"); } }; handleDesktop(desktopQuery); desktopQuery.addEventListener("change", handleDesktop); } if (window.location.hash.length > 1) { const hashId = decodeURIComponent(window.location.hash.slice(1)); const hashTarget = document.getElementById(hashId); if (hashTarget) { window.requestAnimationFrame(function () { window.setTimeout(function () { hashTarget.scrollIntoView({ behavior: "auto", block: "start" }); }, 120); }); } } document.querySelectorAll('a[href^="#"]:not([href="#"])').forEach(function (link) { link.addEventListener("click", function (event) { const id = link.getAttribute("href").slice(1); const target = document.getElementById(id); if (!target) { return; } event.preventDefault(); // The header becomes fixed after the page is scrolled, so // scrollIntoView() cannot scroll the document when targeting it. if (id === "masthead") { window.scrollTo({ top: 0, behavior: reduceMotion.matches ? "auto" : "smooth", }); } else { target.scrollIntoView({ behavior: reduceMotion.matches ? "auto" : "smooth", block: "start", }); } if (window.history && window.history.replaceState) { window.history.replaceState(null, "", `#${id}`); } }); }); const revealItems = Array.from(document.querySelectorAll("[data-reveal]")); if (revealItems.length && "IntersectionObserver" in window && !reduceMotion.matches) { document.documentElement.classList.add("has-reveal"); const revealObserver = new IntersectionObserver( function (entries, observer) { entries.forEach(function (entry) { if (!entry.isIntersecting) { return; } const delay = Number.parseInt(entry.target.dataset.revealDelay || "0", 10); if (delay > 0) { entry.target.style.transitionDelay = `${Math.min(delay, 500)}ms`; } entry.target.classList.add("is-visible"); observer.unobserve(entry.target); }); }, { rootMargin: "0px 0px -8%", threshold: 0.12 } ); revealItems.forEach((item) => revealObserver.observe(item)); } else { revealItems.forEach((item) => item.classList.add("is-visible")); } const progress = document.querySelector("[data-reading-progress]"); const article = document.querySelector(".entry-content"); if (progress && article) { const updateProgress = () => { const articleTop = article.getBoundingClientRect().top + window.scrollY; const articleHeight = article.offsetHeight; const viewportHeight = window.innerHeight; const distance = articleHeight - viewportHeight; const current = window.scrollY - articleTop; const percentage = distance > 0 ? Math.min(100, Math.max(0, (current / distance) * 100)) : 100; progress.style.setProperty("--reading-progress", `${percentage}%`); progress.setAttribute("aria-valuenow", String(Math.round(percentage))); }; updateProgress(); window.addEventListener("scroll", updateProgress, { passive: true }); window.addEventListener("resize", updateProgress, { passive: true }); } }); })();