From f346a01296e5bdbd19de38fa69968b42629b883d Mon Sep 17 00:00:00 2001
From: Emile Bangma <github@emilebangma.com>
Date: Thu, 08 Jan 2026 01:54:41 +0000
Subject: [PATCH] feat(explorer): Add active class to current folder in explorer (#2196)

---
 quartz/components/scripts/explorer.inline.ts |   60 +++++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 45 insertions(+), 15 deletions(-)

diff --git a/quartz/components/scripts/explorer.inline.ts b/quartz/components/scripts/explorer.inline.ts
index 7160492..3c6851c 100644
--- a/quartz/components/scripts/explorer.inline.ts
+++ b/quartz/components/scripts/explorer.inline.ts
@@ -23,11 +23,18 @@
 function toggleExplorer(this: HTMLElement) {
   const nearestExplorer = this.closest(".explorer") as HTMLElement
   if (!nearestExplorer) return
-  nearestExplorer.classList.toggle("collapsed")
+  const explorerCollapsed = nearestExplorer.classList.toggle("collapsed")
   nearestExplorer.setAttribute(
     "aria-expanded",
     nearestExplorer.getAttribute("aria-expanded") === "true" ? "false" : "true",
   )
+
+  if (!explorerCollapsed) {
+    // Stop <html> from being scrollable when mobile explorer is open
+    document.documentElement.classList.add("mobile-no-scroll")
+  } else {
+    document.documentElement.classList.remove("mobile-no-scroll")
+  }
 }
 
 function toggleFolder(evt: MouseEvent) {
@@ -104,6 +111,10 @@
   const folderPath = node.slug
   folderContainer.dataset.folderpath = folderPath
 
+  if (currentSlug === folderPath) {
+    folderContainer.classList.add("active")
+  }
+
   if (opts.folderClickBehavior === "link") {
     // Replace button with link for link behavior
     const button = titleContainer.querySelector(".folder-button") as HTMLElement
@@ -134,9 +145,9 @@
   }
 
   for (const child of node.children) {
-    const childNode = child.data
-      ? createFileNode(currentSlug, child)
-      : createFolderNode(currentSlug, child, opts)
+    const childNode = child.isFolder
+      ? createFolderNode(currentSlug, child, opts)
+      : createFileNode(currentSlug, child)
     ul.appendChild(childNode)
   }
 
@@ -161,7 +172,7 @@
     // Get folder state from local storage
     const storageTree = localStorage.getItem("fileTree")
     const serializedExplorerState = storageTree && opts.useSavedState ? JSON.parse(storageTree) : []
-    const oldIndex = new Map(
+    const oldIndex = new Map<string, boolean>(
       serializedExplorerState.map((entry: FolderState) => [entry.path, entry.collapsed]),
     )
 
@@ -186,10 +197,14 @@
 
     // Get folder paths for state management
     const folderPaths = trie.getFolderPaths()
-    currentExplorerState = folderPaths.map((path) => ({
-      path,
-      collapsed: oldIndex.get(path) === true,
-    }))
+    currentExplorerState = folderPaths.map((path) => {
+      const previousState = oldIndex.get(path)
+      return {
+        path,
+        collapsed:
+          previousState === undefined ? opts.folderDefaultState === "collapsed" : previousState,
+      }
+    })
 
     const explorerUl = explorer.querySelector(".explorer-ul")
     if (!explorerUl) continue
@@ -259,15 +274,30 @@
   await setupExplorer(currentSlug)
 
   // if mobile hamburger is visible, collapse by default
-  for (const explorer of document.getElementsByClassName("mobile-explorer")) {
-    if (explorer.checkVisibility()) {
+  for (const explorer of document.getElementsByClassName("explorer")) {
+    const mobileExplorer = explorer.querySelector(".mobile-explorer")
+    if (!mobileExplorer) return
+
+    if (mobileExplorer.checkVisibility()) {
       explorer.classList.add("collapsed")
       explorer.setAttribute("aria-expanded", "false")
-    }
-  }
 
-  const hiddenUntilDoneLoading = document.querySelector(".mobile-explorer")
-  hiddenUntilDoneLoading?.classList.remove("hide-until-loaded")
+      // Allow <html> to be scrollable when mobile explorer is collapsed
+      document.documentElement.classList.remove("mobile-no-scroll")
+    }
+
+    mobileExplorer.classList.remove("hide-until-loaded")
+  }
+})
+
+window.addEventListener("resize", function () {
+  // Desktop explorer opens by default, and it stays open when the window is resized
+  // to mobile screen size. Applies `no-scroll` to <html> in this edge case.
+  const explorer = document.querySelector(".explorer")
+  if (explorer && !explorer.classList.contains("collapsed")) {
+    document.documentElement.classList.add("mobile-no-scroll")
+    return
+  }
 })
 
 function setFolderState(folderElement: HTMLElement, collapsed: boolean) {

--
Gitblit v1.10.0