mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-05-18 22:44:14 +02:00
Compare commits
3 Commits
4c8e6d5711
...
99027dad59
Author | SHA1 | Date | |
---|---|---|---|
![]() |
99027dad59 | ||
![]() |
7be47742a6 | ||
![]() |
0bafa4c94a |
27
package-lock.json
generated
27
package-lock.json
generated
@ -34,7 +34,7 @@
|
||||
"mdast-util-to-hast": "^13.2.0",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"micromorph": "^0.4.5",
|
||||
"pixi.js": "^8.6.6",
|
||||
"pixi.js": "^8.7.3",
|
||||
"preact": "^10.25.4",
|
||||
"preact-render-to-string": "^6.5.13",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
@ -79,10 +79,10 @@
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/hast": "^3.0.4",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^22.10.6",
|
||||
"@types/node": "^22.12.0",
|
||||
"@types/pretty-time": "^1.1.5",
|
||||
"@types/source-map-support": "^0.5.10",
|
||||
"@types/ws": "^8.5.13",
|
||||
"@types/ws": "^8.5.14",
|
||||
"@types/yargs": "^17.0.33",
|
||||
"esbuild": "^0.24.2",
|
||||
"prettier": "^3.4.2",
|
||||
@ -1914,10 +1914,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.10.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.6.tgz",
|
||||
"integrity": "sha512-qNiuwC4ZDAUNcY47xgaSuS92cjf8JbSUoaKS77bmLG1rU7MlATVSiw/IlrjtIyyskXBZ8KkNfjK/P5na7rgXbQ==",
|
||||
"version": "22.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.12.0.tgz",
|
||||
"integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.20.0"
|
||||
}
|
||||
@ -1943,10 +1944,11 @@
|
||||
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ=="
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.5.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz",
|
||||
"integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==",
|
||||
"version": "8.5.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz",
|
||||
"integrity": "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@ -5583,9 +5585,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pixi.js": {
|
||||
"version": "8.6.6",
|
||||
"resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-8.6.6.tgz",
|
||||
"integrity": "sha512-o5pw7G2yuIrnBx0G4npBlmFp+XGNcapI/Ufs62rRj/4XKxc1Zo74YJr/BtEXcXTraTKd+pQvYOLvnfxRjxBMvQ==",
|
||||
"version": "8.7.3",
|
||||
"resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-8.7.3.tgz",
|
||||
"integrity": "sha512-wfWlhJYnGx1s4f2yoouevQjaeacbJ12LTkJGa+n9AIYNIjOnmJylBtZ2mARX7iFk3mr2xv0wuo//XPe2hk5OBw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@pixi/colord": "^2.9.6",
|
||||
"@types/css-font-loading-module": "^0.0.12",
|
||||
|
@ -60,7 +60,7 @@
|
||||
"mdast-util-to-hast": "^13.2.0",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"micromorph": "^0.4.5",
|
||||
"pixi.js": "^8.6.6",
|
||||
"pixi.js": "^8.7.3",
|
||||
"preact": "^10.25.4",
|
||||
"preact-render-to-string": "^6.5.13",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
@ -102,10 +102,10 @@
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/hast": "^3.0.4",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^22.10.6",
|
||||
"@types/node": "^22.12.0",
|
||||
"@types/pretty-time": "^1.1.5",
|
||||
"@types/source-map-support": "^0.5.10",
|
||||
"@types/ws": "^8.5.13",
|
||||
"@types/ws": "^8.5.14",
|
||||
"@types/yargs": "^17.0.33",
|
||||
"esbuild": "^0.24.2",
|
||||
"prettier": "^3.4.2",
|
||||
|
@ -40,11 +40,8 @@ const defaultOptions: BreadcrumbOptions = {
|
||||
showCurrentPage: true,
|
||||
}
|
||||
|
||||
function formatCrumb(displayName: string, baseSlug: FullSlug, currentSlug: SimpleSlug): CrumbData {
|
||||
return {
|
||||
displayName: displayName.replaceAll("-", " "),
|
||||
path: resolveRelative(baseSlug, currentSlug),
|
||||
}
|
||||
function newCrumb(displayName: string, baseSlug: FullSlug, currentSlug: SimpleSlug): CrumbData {
|
||||
return { displayName, path: resolveRelative(baseSlug, currentSlug) }
|
||||
}
|
||||
|
||||
export default ((opts?: Partial<BreadcrumbOptions>) => {
|
||||
@ -65,7 +62,7 @@ export default ((opts?: Partial<BreadcrumbOptions>) => {
|
||||
}
|
||||
|
||||
// Format entry for root element
|
||||
const firstEntry = formatCrumb(options.rootName, fileData.slug!, "/" as SimpleSlug)
|
||||
const firstEntry = newCrumb(options.rootName, fileData.slug!, "/" as SimpleSlug)
|
||||
const crumbs: CrumbData[] = [firstEntry]
|
||||
|
||||
if (!folderIndex && options.resolveFrontmatterTitle) {
|
||||
@ -81,6 +78,7 @@ export default ((opts?: Partial<BreadcrumbOptions>) => {
|
||||
|
||||
// Split slug into hierarchy/parts
|
||||
const slugParts = fileData.slug?.split("/")
|
||||
const pathParts = fileData.relativePath?.split("/")
|
||||
if (slugParts) {
|
||||
// is tag breadcrumb?
|
||||
const isTagPath = slugParts[0] === "tags"
|
||||
@ -89,7 +87,7 @@ export default ((opts?: Partial<BreadcrumbOptions>) => {
|
||||
let currentPath = ""
|
||||
|
||||
for (let i = 0; i < slugParts.length - 1; i++) {
|
||||
let curPathSegment = slugParts[i]
|
||||
let curPathSegment = pathParts?.[i] ?? slugParts[i]
|
||||
|
||||
// Try to resolve frontmatter folder title
|
||||
const currentFile = folderIndex?.get(slugParts.slice(0, i + 1).join("/"))
|
||||
@ -105,7 +103,7 @@ export default ((opts?: Partial<BreadcrumbOptions>) => {
|
||||
const includeTrailingSlash = !isTagPath || i < 1
|
||||
|
||||
// Format and add current crumb
|
||||
const crumb = formatCrumb(
|
||||
const crumb = newCrumb(
|
||||
curPathSegment,
|
||||
fileData.slug!,
|
||||
(currentPath + (includeTrailingSlash ? "/" : "")) as SimpleSlug,
|
||||
|
@ -23,6 +23,11 @@ const defaultOptions: FolderContentOptions = {
|
||||
showSubfolders: true,
|
||||
}
|
||||
|
||||
type Subfolder = {
|
||||
name: string
|
||||
contents: QuartzPluginData[]
|
||||
}
|
||||
|
||||
export default ((opts?: Partial<FolderContentOptions>) => {
|
||||
const options: FolderContentOptions = { ...defaultOptions, ...opts }
|
||||
|
||||
@ -31,51 +36,56 @@ export default ((opts?: Partial<FolderContentOptions>) => {
|
||||
const folderSlug = stripSlashes(simplifySlug(fileData.slug!))
|
||||
const folderParts = folderSlug.split(path.posix.sep)
|
||||
|
||||
const allPagesInFolder: QuartzPluginData[] = []
|
||||
const allPagesInSubfolders: Map<FullSlug, QuartzPluginData[]> = new Map()
|
||||
const shownPages: QuartzPluginData[] = []
|
||||
const subfolders: Map<FullSlug, Subfolder> = new Map()
|
||||
|
||||
allFiles.forEach((file) => {
|
||||
for (const file of allFiles) {
|
||||
const fileSlug = stripSlashes(simplifySlug(file.slug!))
|
||||
const prefixed = fileSlug.startsWith(folderSlug) && fileSlug !== folderSlug
|
||||
const fileParts = fileSlug.split(path.posix.sep)
|
||||
const isDirectChild = fileParts.length === folderParts.length + 1
|
||||
|
||||
if (!prefixed) {
|
||||
return
|
||||
// check only files in our folder or nested folders
|
||||
if (!fileSlug.startsWith(folderSlug) || fileSlug === folderSlug) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (isDirectChild) {
|
||||
allPagesInFolder.push(file)
|
||||
} else if (options.showSubfolders) {
|
||||
const fileParts = fileSlug.split(path.posix.sep)
|
||||
|
||||
// If the file is directly in the folder we just show it
|
||||
if (fileParts.length === folderParts.length + 1) {
|
||||
shownPages.push(file)
|
||||
continue
|
||||
}
|
||||
|
||||
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!)),
|
||||
)
|
||||
let subfolder = subfolders.get(subfolderSlug)
|
||||
if (!subfolder) {
|
||||
const subfolderName = file.relativePath!.split(path.posix.sep).at(folderParts.length)!
|
||||
subfolders.set(subfolderSlug, (subfolder = { name: subfolderName, contents: [] }))
|
||||
}
|
||||
subfolder.contents.push(file)
|
||||
}
|
||||
}
|
||||
|
||||
for (const [slug, subfolder] of subfolders.entries()) {
|
||||
const hasIndex = shownPages.some((file) => slug === 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,
|
||||
const subfolderDates = subfolder.contents.sort(byDateAndAlphabetical(cfg))[0].dates
|
||||
shownPages.push({
|
||||
slug: slug,
|
||||
dates: subfolderDates,
|
||||
frontmatter: { title: subfolderTitle, tags: ["folder"] },
|
||||
frontmatter: { title: subfolder.name, tags: ["folder"] },
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const cssClasses: string[] = fileData.frontmatter?.cssclasses ?? []
|
||||
const classes = cssClasses.join(" ")
|
||||
const listProps = {
|
||||
...props,
|
||||
sort: options.sort,
|
||||
allFiles: allPagesInFolder,
|
||||
allFiles: shownPages,
|
||||
}
|
||||
|
||||
const content =
|
||||
@ -90,7 +100,7 @@ export default ((opts?: Partial<FolderContentOptions>) => {
|
||||
{options.showFolderCount && (
|
||||
<p>
|
||||
{i18n(cfg.locale).pages.folderContent.itemsUnderFolder({
|
||||
count: allPagesInFolder.length,
|
||||
count: shownPages.length,
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
|
@ -74,13 +74,27 @@ export const FolderPage: QuartzEmitterPlugin<Partial<FolderPageOptions>> = (user
|
||||
const allFiles = content.map((c) => c[1].data)
|
||||
const cfg = ctx.cfg.configuration
|
||||
|
||||
const folderNames: Record<SimpleSlug, string> = {}
|
||||
|
||||
const folders: Set<SimpleSlug> = new Set(
|
||||
allFiles.flatMap((data) => {
|
||||
return data.slug
|
||||
? _getFolders(data.slug).filter(
|
||||
(folderName) => folderName !== "." && folderName !== "tags",
|
||||
)
|
||||
: []
|
||||
if (!data.slug || !data.relativePath) {
|
||||
return []
|
||||
}
|
||||
let folderSlug = path.dirname(data.slug) as SimpleSlug
|
||||
let folderFs = path.dirname(data.relativePath) as SimpleSlug
|
||||
folderNames[folderSlug] = folderFs
|
||||
|
||||
const folders = [folderSlug]
|
||||
while (folderSlug !== ".") {
|
||||
folderSlug = path.dirname(folderSlug) as SimpleSlug
|
||||
folders.push(folderSlug)
|
||||
|
||||
folderFs = path.dirname(folderFs) as SimpleSlug
|
||||
folderNames[folderSlug] = folderFs
|
||||
}
|
||||
|
||||
return folders.filter((f) => f !== "." && f !== "tags")
|
||||
}),
|
||||
)
|
||||
|
||||
@ -89,8 +103,9 @@ export const FolderPage: QuartzEmitterPlugin<Partial<FolderPageOptions>> = (user
|
||||
folder,
|
||||
defaultProcessedContent({
|
||||
slug: joinSegments(folder, "index") as FullSlug,
|
||||
relativePath: joinSegments(folderNames[folder], "index.html") as FilePath, // this is used by breadcrumbs
|
||||
frontmatter: {
|
||||
title: `${i18n(cfg.locale).pages.folderContent.folder}: ${folder}`,
|
||||
title: `${i18n(cfg.locale).pages.folderContent.folder}: ${folderNames[folder]}`,
|
||||
tags: [],
|
||||
},
|
||||
}),
|
||||
@ -100,7 +115,14 @@ export const FolderPage: QuartzEmitterPlugin<Partial<FolderPageOptions>> = (user
|
||||
for (const [tree, file] of content) {
|
||||
const slug = stripSlashes(simplifySlug(file.data.slug!)) as SimpleSlug
|
||||
if (folders.has(slug)) {
|
||||
folderDescriptions[slug] = [tree, file]
|
||||
if (file.data.frontmatter?.title === "index") {
|
||||
// sadly we need to avoid changing the original file title for things like explorer to work
|
||||
const clonedFile = structuredClone(file)
|
||||
clonedFile.data.frontmatter!.title = `${i18n(cfg.locale).pages.folderContent.folder}: ${folderNames[slug]}`
|
||||
folderDescriptions[slug] = [tree, clonedFile]
|
||||
} else {
|
||||
folderDescriptions[slug] = [tree, file]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,14 +154,3 @@ export const FolderPage: QuartzEmitterPlugin<Partial<FolderPageOptions>> = (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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user