From 1d2dc167f4397e230092cc867889a86734343cfc Mon Sep 17 00:00:00 2001 From: Thomas Hack <39602241+tha00@users.noreply.github.com> Date: Fri, 25 Oct 2024 18:52:33 +0200 Subject: [PATCH] feat(folder): add intermediate folders pages (#1295) Co-authored-by: Aaron Pham Co-authored-by: Aaron Pham --- quartz/components/pages/FolderContent.tsx | 46 ++++++++++++++++++++--- quartz/plugins/emitters/folderPage.tsx | 22 ++++++++--- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/quartz/components/pages/FolderContent.tsx b/quartz/components/pages/FolderContent.tsx index dc216cd..7a49d49 100644 --- a/quartz/components/pages/FolderContent.tsx +++ b/quartz/components/pages/FolderContent.tsx @@ -2,22 +2,25 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } fro import path from "path" import style from "../styles/listPage.scss" -import { PageList, SortFn } from "../PageList" -import { stripSlashes, simplifySlug } from "../../util/path" +import { byDateAndAlphabetical, PageList, SortFn } from "../PageList" +import { stripSlashes, simplifySlug, joinSegments, FullSlug } from "../../util/path" import { Root } from "hast" import { htmlToJsx } from "../../util/jsx" import { i18n } from "../../i18n" +import { QuartzPluginData } from "../../plugins/vfile" interface FolderContentOptions { /** * Whether to display number of folders */ showFolderCount: boolean + showSubfolders: boolean sort?: SortFn } const defaultOptions: FolderContentOptions = { showFolderCount: true, + showSubfolders: true, } export default ((opts?: Partial) => { @@ -26,14 +29,47 @@ export default ((opts?: Partial) => { const FolderContent: QuartzComponent = (props: QuartzComponentProps) => { const { tree, fileData, allFiles, cfg } = props const folderSlug = stripSlashes(simplifySlug(fileData.slug!)) - const allPagesInFolder = allFiles.filter((file) => { + const folderParts = folderSlug.split(path.posix.sep) + + const allPagesInFolder: QuartzPluginData[] = [] + const allPagesInSubfolders: Map = new Map() + + allFiles.forEach((file) => { const fileSlug = stripSlashes(simplifySlug(file.slug!)) const prefixed = fileSlug.startsWith(folderSlug) && fileSlug !== folderSlug - const folderParts = folderSlug.split(path.posix.sep) const fileParts = fileSlug.split(path.posix.sep) const isDirectChild = fileParts.length === folderParts.length + 1 - return prefixed && isDirectChild + + if (!prefixed) { + return + } + + if (isDirectChild) { + allPagesInFolder.push(file) + } else if (options.showSubfolders) { + const subfolderSlug = joinSegments( + ...fileParts.slice(0, folderParts.length + 1), + ) as FullSlug + const pagesInFolder = allPagesInSubfolders.get(subfolderSlug) || [] + allPagesInSubfolders.set(subfolderSlug, [...pagesInFolder, file]) + } }) + + allPagesInSubfolders.forEach((files, subfolderSlug) => { + const hasIndex = allPagesInFolder.some( + (file) => subfolderSlug === stripSlashes(simplifySlug(file.slug!)), + ) + if (!hasIndex) { + const subfolderDates = files.sort(byDateAndAlphabetical(cfg))[0].dates + const subfolderTitle = subfolderSlug.split(path.posix.sep).at(-1)! + allPagesInFolder.push({ + slug: subfolderSlug, + dates: subfolderDates, + frontmatter: { title: subfolderTitle, tags: ["folder"] }, + }) + } + }) + const cssClasses: string[] = fileData.frontmatter?.cssclasses ?? [] const classes = ["popover-hint", ...cssClasses].join(" ") const listProps = { diff --git a/quartz/plugins/emitters/folderPage.tsx b/quartz/plugins/emitters/folderPage.tsx index 7eebb21..b6d8602 100644 --- a/quartz/plugins/emitters/folderPage.tsx +++ b/quartz/plugins/emitters/folderPage.tsx @@ -76,12 +76,11 @@ export const FolderPage: QuartzEmitterPlugin> = (user const folders: Set = new Set( allFiles.flatMap((data) => { - const slug = data.slug - const folderName = path.dirname(slug ?? "") as SimpleSlug - if (slug && folderName !== "." && folderName !== "tags") { - return [folderName] - } - return [] + return data.slug + ? _getFolders(data.slug).filter( + (folderName) => folderName !== "." && folderName !== "tags", + ) + : [] }), ) @@ -133,3 +132,14 @@ export const FolderPage: QuartzEmitterPlugin> = (user }, } } + +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 +}