diff --git a/docs/advanced/creating components.md b/docs/advanced/creating components.md index 628d5aa29..3384834d3 100644 --- a/docs/advanced/creating components.md +++ b/docs/advanced/creating components.md @@ -161,6 +161,15 @@ document.addEventListener("nav", () => { }) ``` +You can also add the equivalent of a `beforeunload` event for [[SPA Routing]] via the `prenav` event. + +```ts +document.addEventListener("prenav", () => { + // executed after an SPA navigation is triggered but + // before the page is replaced +}) +``` + It is best practice to track any event handlers via `window.addCleanup` to prevent memory leaks. This will get called on page navigation. diff --git a/index.d.ts b/index.d.ts index a6c594fff..8e524af03 100644 --- a/index.d.ts +++ b/index.d.ts @@ -5,6 +5,7 @@ declare module "*.scss" { // dom custom event interface CustomEventMap { + prenav: CustomEvent<{}> nav: CustomEvent<{ url: FullSlug }> themechange: CustomEvent<{ theme: "light" | "dark" }> } diff --git a/quartz/components/OverflowList.tsx b/quartz/components/OverflowList.tsx index 2d32ec3a9..d74c5c255 100644 --- a/quartz/components/OverflowList.tsx +++ b/quartz/components/OverflowList.tsx @@ -17,7 +17,6 @@ document.addEventListener("nav", (e) => { const observer = new IntersectionObserver((entries) => { for (const entry of entries) { const parentUl = entry.target.parentElement - console.log(parentUl) if (entry.isIntersecting) { parentUl.classList.remove("gradient-active") } else { diff --git a/quartz/components/scripts/explorer.inline.ts b/quartz/components/scripts/explorer.inline.ts index 2a8a0cc91..c1e72cd66 100644 --- a/quartz/components/scripts/explorer.inline.ts +++ b/quartz/components/scripts/explorer.inline.ts @@ -193,6 +193,12 @@ async function setupExplorer(currentSlug: FullSlug) { } explorerUl.insertBefore(fragment, explorerUl.firstChild) + // restore explorer scrollTop position if it exists + const scrollTop = sessionStorage.getItem("explorerScrollTop") + if (scrollTop) { + explorerUl.scrollTop = parseInt(scrollTop) + } + // Set up event handlers const explorerButtons = explorer.querySelectorAll( "button.explorer-toggle", @@ -225,6 +231,13 @@ async function setupExplorer(currentSlug: FullSlug) { } } +document.addEventListener("prenav", async (e: CustomEventMap["prenav"]) => { + // save explorer scrollTop position + const explorer = document.getElementById("explorer-ul") + if (!explorer) return + sessionStorage.setItem("explorerScrollTop", explorer.scrollTop.toString()) +}) + document.addEventListener("nav", async (e: CustomEventMap["nav"]) => { const currentSlug = e.detail.url const mobileExplorer = document.querySelector("#mobile-explorer") diff --git a/quartz/components/scripts/spa.inline.ts b/quartz/components/scripts/spa.inline.ts index df48f0403..77900a639 100644 --- a/quartz/components/scripts/spa.inline.ts +++ b/quartz/components/scripts/spa.inline.ts @@ -75,6 +75,10 @@ async function navigate(url: URL, isBack: boolean = false) { if (!contents) return + // notify about to nav + const event: CustomEventMap["prenav"] = new CustomEvent("prenav", { detail: {} }) + document.dispatchEvent(event) + // cleanup old cleanupFns.forEach((fn) => fn()) cleanupFns.clear() @@ -108,7 +112,7 @@ async function navigate(url: URL, isBack: boolean = false) { } } - // now, patch head + // now, patch head, re-executing scripts const elementsToRemove = document.head.querySelectorAll(":not([spa-preserve])") elementsToRemove.forEach((el) => el.remove()) const elementsToAdd = html.head.querySelectorAll(":not([spa-preserve])")