mirror of
https://github.com/jackyzha0/quartz.git
synced 2026-03-24 15:05:42 -05:00
feat: add subfolders to folder page
This commit is contained in:
parent
e26448eaf3
commit
405f6f5103
38
quartz/components/FolderList.tsx
Normal file
38
quartz/components/FolderList.tsx
Normal file
@ -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 (
|
||||||
|
<ul>
|
||||||
|
{list.map((folderSlug) => {
|
||||||
|
const title = _getTitle(folderSlug)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<a href={resolveRelative(fileData.slug!, folderSlug!)}>{title}</a>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)!
|
||||||
|
}
|
||||||
@ -3,21 +3,25 @@ import path from "path"
|
|||||||
|
|
||||||
import style from "../styles/listPage.scss"
|
import style from "../styles/listPage.scss"
|
||||||
import { PageList, SortFn } from "../PageList"
|
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 { Root } from "hast"
|
||||||
import { htmlToJsx } from "../../util/jsx"
|
import { htmlToJsx } from "../../util/jsx"
|
||||||
import { i18n } from "../../i18n"
|
import { i18n } from "../../i18n"
|
||||||
|
import { QuartzPluginData } from "../../plugins/vfile"
|
||||||
|
|
||||||
interface FolderContentOptions {
|
interface FolderContentOptions {
|
||||||
/**
|
/**
|
||||||
* Whether to display number of folders
|
* Whether to display number of folders
|
||||||
*/
|
*/
|
||||||
showFolderCount: boolean
|
showFolderCount: boolean
|
||||||
|
showSubfolders: boolean
|
||||||
sort?: SortFn
|
sort?: SortFn
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultOptions: FolderContentOptions = {
|
const defaultOptions: FolderContentOptions = {
|
||||||
showFolderCount: true,
|
showFolderCount: true,
|
||||||
|
showSubfolders: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ((opts?: Partial<FolderContentOptions>) => {
|
export default ((opts?: Partial<FolderContentOptions>) => {
|
||||||
@ -26,21 +30,40 @@ export default ((opts?: Partial<FolderContentOptions>) => {
|
|||||||
const FolderContent: QuartzComponent = (props: QuartzComponentProps) => {
|
const FolderContent: QuartzComponent = (props: QuartzComponentProps) => {
|
||||||
const { tree, fileData, allFiles, cfg } = props
|
const { tree, fileData, allFiles, cfg } = props
|
||||||
const folderSlug = stripSlashes(simplifySlug(fileData.slug!))
|
const folderSlug = stripSlashes(simplifySlug(fileData.slug!))
|
||||||
const allPagesInFolder = allFiles.filter((file) => {
|
|
||||||
|
const allPagesInFolder: QuartzPluginData[] = []
|
||||||
|
const allSubfolders: Set<SimpleSlug> = new Set()
|
||||||
|
|
||||||
|
allFiles.forEach((file) => {
|
||||||
const fileSlug = stripSlashes(simplifySlug(file.slug!))
|
const fileSlug = stripSlashes(simplifySlug(file.slug!))
|
||||||
const prefixed = fileSlug.startsWith(folderSlug) && fileSlug !== folderSlug
|
const prefixed = fileSlug.startsWith(folderSlug) && fileSlug !== folderSlug
|
||||||
const folderParts = folderSlug.split(path.posix.sep)
|
const folderParts = folderSlug.split(path.posix.sep)
|
||||||
const fileParts = fileSlug.split(path.posix.sep)
|
const fileParts = fileSlug.split(path.posix.sep)
|
||||||
const isDirectChild = fileParts.length === folderParts.length + 1
|
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 cssClasses: string[] = fileData.frontmatter?.cssclasses ?? []
|
||||||
const classes = ["popover-hint", ...cssClasses].join(" ")
|
const classes = ["popover-hint", ...cssClasses].join(" ")
|
||||||
const listProps = {
|
const pageListProps = {
|
||||||
...props,
|
...props,
|
||||||
sort: options.sort,
|
sort: options.sort,
|
||||||
allFiles: allPagesInFolder,
|
allFiles: allPagesInFolder,
|
||||||
}
|
}
|
||||||
|
const folderListProps = {
|
||||||
|
...props,
|
||||||
|
allFolders: Array.from(allSubfolders.values()),
|
||||||
|
}
|
||||||
|
|
||||||
const content =
|
const content =
|
||||||
(tree as Root).children.length === 0
|
(tree as Root).children.length === 0
|
||||||
@ -59,7 +82,15 @@ export default ((opts?: Partial<FolderContentOptions>) => {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
<PageList {...listProps} />
|
<PageList {...pageListProps} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-listing">
|
||||||
|
{options.showSubfolders && (
|
||||||
|
<p>{allSubfolders.size === 1 ? "1 subfolder." : `${allSubfolders.size} subfolders.`}</p>
|
||||||
|
)}
|
||||||
|
<div>
|
||||||
|
<FolderList {...folderListProps} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user