From ec00a40aefca73596ab76e3ebe3a8e1129b43688 Mon Sep 17 00:00:00 2001
From: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 27 Jan 2026 18:27:17 +0000
Subject: [PATCH] chore(deps): bump the production-dependencies group with 4 updates (#2289)

---
 quartz/plugins/emitters/folderPage.tsx |  200 ++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 146 insertions(+), 54 deletions(-)

diff --git a/quartz/plugins/emitters/folderPage.tsx b/quartz/plugins/emitters/folderPage.tsx
index 1eed30d..f9b181d 100644
--- a/quartz/plugins/emitters/folderPage.tsx
+++ b/quartz/plugins/emitters/folderPage.tsx
@@ -3,76 +3,168 @@
 import HeaderConstructor from "../../components/Header"
 import BodyConstructor from "../../components/Body"
 import { pageResources, renderPage } from "../../components/renderPage"
-import { ProcessedContent, defaultProcessedContent } from "../vfile"
+import { ProcessedContent, QuartzPluginData, defaultProcessedContent } from "../vfile"
 import { FullPageLayout } from "../../cfg"
 import path from "path"
-import { clientSideSlug } from "../../path"
+import {
+  FullSlug,
+  SimpleSlug,
+  stripSlashes,
+  joinSegments,
+  pathToRoot,
+  simplifySlug,
+} from "../../util/path"
+import { defaultListPageLayout, sharedPageComponents } from "../../../quartz.layout"
+import { FolderContent } from "../../components"
+import { write } from "./helpers"
+import { i18n, TRANSLATIONS } from "../../i18n"
+import { BuildCtx } from "../../util/ctx"
+import { StaticResources } from "../../util/resources"
+interface FolderPageOptions extends FullPageLayout {
+  sort?: (f1: QuartzPluginData, f2: QuartzPluginData) => number
+}
 
-export const FolderPage: QuartzEmitterPlugin<FullPageLayout> = (opts) => {
-  if (!opts) {
-    throw new Error("ErrorPage must be initialized with options specifiying the components to use")
+async function* processFolderInfo(
+  ctx: BuildCtx,
+  folderInfo: Record<SimpleSlug, ProcessedContent>,
+  allFiles: QuartzPluginData[],
+  opts: FullPageLayout,
+  resources: StaticResources,
+) {
+  for (const [folder, folderContent] of Object.entries(folderInfo) as [
+    SimpleSlug,
+    ProcessedContent,
+  ][]) {
+    const slug = joinSegments(folder, "index") as FullSlug
+    const [tree, file] = folderContent
+    const cfg = ctx.cfg.configuration
+    const externalResources = pageResources(pathToRoot(slug), resources)
+    const componentData: QuartzComponentProps = {
+      ctx,
+      fileData: file.data,
+      externalResources,
+      cfg,
+      children: [],
+      tree,
+      allFiles,
+    }
+
+    const content = renderPage(cfg, slug, componentData, opts, externalResources)
+    yield write({
+      ctx,
+      content,
+      slug,
+      ext: ".html",
+    })
+  }
+}
+
+function computeFolderInfo(
+  folders: Set<SimpleSlug>,
+  content: ProcessedContent[],
+  locale: keyof typeof TRANSLATIONS,
+): Record<SimpleSlug, ProcessedContent> {
+  // Create default folder descriptions
+  const folderInfo: Record<SimpleSlug, ProcessedContent> = Object.fromEntries(
+    [...folders].map((folder) => [
+      folder,
+      defaultProcessedContent({
+        slug: joinSegments(folder, "index") as FullSlug,
+        frontmatter: {
+          title: `${i18n(locale).pages.folderContent.folder}: ${folder}`,
+          tags: [],
+        },
+      }),
+    ]),
+  )
+
+  // Update with actual content if available
+  for (const [tree, file] of content) {
+    const slug = stripSlashes(simplifySlug(file.data.slug!)) as SimpleSlug
+    if (folders.has(slug)) {
+      folderInfo[slug] = [tree, file]
+    }
   }
 
-  const { head: Head, header, beforeBody, pageBody: Content, left, right, footer: Footer } = opts
+  return folderInfo
+}
+
+function _getFolders(slug: FullSlug): SimpleSlug[] {
+  var folderName = path.dirname(slug ?? "") as SimpleSlug
+  const parentFolderNames = [folderName]
+
+  while (folderName !== ".") {
+    folderName = path.dirname(folderName ?? "") as SimpleSlug
+    parentFolderNames.push(folderName)
+  }
+  return parentFolderNames
+}
+
+export const FolderPage: QuartzEmitterPlugin<Partial<FolderPageOptions>> = (userOpts) => {
+  const opts: FullPageLayout = {
+    ...sharedPageComponents,
+    ...defaultListPageLayout,
+    pageBody: FolderContent({ sort: userOpts?.sort }),
+    ...userOpts,
+  }
+
+  const { head: Head, header, beforeBody, pageBody, afterBody, left, right, footer: Footer } = opts
   const Header = HeaderConstructor()
   const Body = BodyConstructor()
 
   return {
     name: "FolderPage",
     getQuartzComponents() {
-      return [Head, Header, Body, ...header, ...beforeBody, Content, ...left, ...right, Footer]
+      return [
+        Head,
+        Header,
+        Body,
+        ...header,
+        ...beforeBody,
+        pageBody,
+        ...afterBody,
+        ...left,
+        ...right,
+        Footer,
+      ]
     },
-    async emit(_contentDir, cfg, content, resources, emit): Promise<string[]> {
-      const fps: string[] = []
-      const allFiles = content.map(c => c[1].data)
+    async *emit(ctx, content, resources) {
+      const allFiles = content.map((c) => c[1].data)
+      const cfg = ctx.cfg.configuration
 
-      const folders: Set<string> = new Set(allFiles.flatMap(data => data.slug ? [path.dirname(data.slug)] : []))
+      const folders: Set<SimpleSlug> = new Set(
+        allFiles.flatMap((data) => {
+          return data.slug
+            ? _getFolders(data.slug).filter(
+                (folderName) => folderName !== "." && folderName !== "tags",
+              )
+            : []
+        }),
+      )
 
-      // remove special prefixes
-      folders.delete(".")
-      folders.delete("tags")
+      const folderInfo = computeFolderInfo(folders, content, cfg.locale)
+      yield* processFolderInfo(ctx, folderInfo, allFiles, opts, resources)
+    },
+    async *partialEmit(ctx, content, resources, changeEvents) {
+      const allFiles = content.map((c) => c[1].data)
+      const cfg = ctx.cfg.configuration
 
-      const folderDescriptions: Record<string, ProcessedContent> = Object.fromEntries([...folders].map(folder => ([
-        folder, defaultProcessedContent({ slug: folder, frontmatter: { title: `Folder: ${folder}`, tags: [] } })
-      ])))
-
-      for (const [tree, file] of content) {
-        const slug = clientSideSlug(file.data.slug!)
-        if (folders.has(slug)) {
-          folderDescriptions[slug] = [tree, file]
-        }
-      }
-
-      for (const folder of folders) {
-        const slug = folder 
-        const externalResources = pageResources(slug, resources)
-        const [tree, file] = folderDescriptions[folder]
-        const componentData: QuartzComponentProps = {
-          fileData: file.data,
-          externalResources,
-          cfg,
-          children: [],
-          tree,
-          allFiles
-        }
-
-        const content = renderPage(
-          slug,
-          componentData,
-          opts,
-          externalResources
+      // Find all folders that need to be updated based on changed files
+      const affectedFolders: Set<SimpleSlug> = new Set()
+      for (const changeEvent of changeEvents) {
+        if (!changeEvent.file) continue
+        const slug = changeEvent.file.data.slug!
+        const folders = _getFolders(slug).filter(
+          (folderName) => folderName !== "." && folderName !== "tags",
         )
-
-        const fp = file.data.slug + ".html"
-        await emit({
-          content,
-          slug: file.data.slug!,
-          ext: ".html",
-        })
-
-        fps.push(fp)
+        folders.forEach((folder) => affectedFolders.add(folder))
       }
-      return fps
-    }
+
+      // If there are affected folders, rebuild their pages
+      if (affectedFolders.size > 0) {
+        const folderInfo = computeFolderInfo(affectedFolders, content, cfg.locale)
+        yield* processFolderInfo(ctx, folderInfo, allFiles, opts, resources)
+      }
+    },
   }
 }

--
Gitblit v1.10.0