From 405f6f510386825040a6f50526aaf9b026a2dd74 Mon Sep 17 00:00:00 2001 From: Thomas Hack Date: Thu, 15 Aug 2024 15:48:14 +0200 Subject: [PATCH] feat: add subfolders to folder page --- quartz/components/FolderList.tsx | 38 +++++++++++++++++++++ quartz/components/pages/FolderContent.tsx | 41 ++++++++++++++++++++--- 2 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 quartz/components/FolderList.tsx diff --git a/quartz/components/FolderList.tsx b/quartz/components/FolderList.tsx new file mode 100644 index 000000000..7a81e2600 --- /dev/null +++ b/quartz/components/FolderList.tsx @@ -0,0 +1,38 @@ +import path from "path" +import { resolveRelative, SimpleSlug } from "../util/path" +import { QuartzComponent, QuartzComponentProps } from "./types" + +type Props = { + limit?: number +} & QuartzComponentProps + +export const FolderList: QuartzComponent = ({ cfg, fileData, allFolders, limit }: Props) => { + let list: SimpleSlug[] = allFolders.sort(_alphabetical) + if (limit) { + list = list.slice(0, limit) + } + + return ( + + ) +} + +function _alphabetical(f1: SimpleSlug, f2: SimpleSlug): number { + const f1Title = _getTitle(f1) + const f2Title = _getTitle(f2) + return f1Title.localeCompare(f2Title) +} + +function _getTitle(folderSlug: SimpleSlug): string { + return folderSlug.split(path.posix.sep).at(-1)! +} diff --git a/quartz/components/pages/FolderContent.tsx b/quartz/components/pages/FolderContent.tsx index dc216cde7..90f981f1e 100644 --- a/quartz/components/pages/FolderContent.tsx +++ b/quartz/components/pages/FolderContent.tsx @@ -3,21 +3,25 @@ import path from "path" import style from "../styles/listPage.scss" import { PageList, SortFn } from "../PageList" -import { stripSlashes, simplifySlug } from "../../util/path" +import { FolderList } from "../FolderList" +import { stripSlashes, simplifySlug, SimpleSlug, joinSegments } 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,21 +30,40 @@ 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 allPagesInFolder: QuartzPluginData[] = [] + const allSubfolders: Set = new Set() + + 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 { + const folderSlug = joinSegments(...fileParts.slice(0, folderParts.length + 1)) + allSubfolders.add(folderSlug as SimpleSlug) + } }) + const cssClasses: string[] = fileData.frontmatter?.cssclasses ?? [] const classes = ["popover-hint", ...cssClasses].join(" ") - const listProps = { + const pageListProps = { ...props, sort: options.sort, allFiles: allPagesInFolder, } + const folderListProps = { + ...props, + allFolders: Array.from(allSubfolders.values()), + } const content = (tree as Root).children.length === 0 @@ -59,7 +82,15 @@ export default ((opts?: Partial) => {

)}
- + +
+ +
+ {options.showSubfolders && ( +

{allSubfolders.size === 1 ? "1 subfolder." : `${allSubfolders.size} subfolders.`}

+ )} +
+