Skip to content

feat(folder): add intermediate folders pages (#1295) #110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 41 additions & 6 deletions quartz/components/pages/FolderContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } fro
import path from "path"

import style from "../styles/listPage.scss"
import { PageList } 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"
Expand All @@ -14,11 +14,13 @@ interface FolderContentOptions {
* Whether to display number of folders
*/
showFolderCount: boolean
sort?: (f1: QuartzPluginData, f2: QuartzPluginData) => number
showSubfolders: boolean
sort?: SortFn
}

const defaultOptions: FolderContentOptions = {
showFolderCount: true,
showSubfolders: true,
}

export default ((opts?: Partial<FolderContentOptions>) => {
Expand All @@ -27,14 +29,47 @@ export default ((opts?: Partial<FolderContentOptions>) => {
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<FullSlug, QuartzPluginData[]> = 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 = {
Expand Down
22 changes: 16 additions & 6 deletions quartz/plugins/emitters/folderPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,11 @@ export const FolderPage: QuartzEmitterPlugin<

const folders: Set<SimpleSlug> = 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",
)
: []
}),
)

Expand Down Expand Up @@ -131,3 +130,14 @@ export const FolderPage: QuartzEmitterPlugin<
},
}
}

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
}