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 (
+
+ {list.map((folderSlug) => {
+ const title = _getTitle(folderSlug)
+
+ return (
+ -
+ {title}
+
+ )
+ })}
+
+ )
+}
+
+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.`}
+ )}
+
+