diff --git a/docs/features/breadcrumbs.md b/docs/features/breadcrumbs.md index 94db66a..20c3b8d 100644 --- a/docs/features/breadcrumbs.md +++ b/docs/features/breadcrumbs.md @@ -16,10 +16,10 @@ For example, here's what the default configuration looks like: ```typescript title="quartz.layout.ts" Component.Breadcrumbs({ - spacerSymbol: ">", // symbol between crumbs + spacerSymbol: "❯", // symbol between crumbs rootName: "Home", // name of first/root element - resolveFrontmatterTitle: false, // wether to resolve folder names through frontmatter titles (more computationally expensive) - hideOnRoot: true, // wether to hide breadcrumbs on root `index.md` page + resolveFrontmatterTitle: true, // whether to resolve folder names through frontmatter titles + hideOnRoot: true, // whether to hide breadcrumbs on root `index.md` page }) ``` diff --git a/quartz/components/Breadcrumbs.tsx b/quartz/components/Breadcrumbs.tsx index f35f876..29c73a8 100644 --- a/quartz/components/Breadcrumbs.tsx +++ b/quartz/components/Breadcrumbs.tsx @@ -41,25 +41,13 @@ function formatCrumb(displayName: string, baseSlug: FullSlug, currentSlug: Simpl } } -// given a folderName (e.g. "features"), search for the corresponding `index.md` file -function findCurrentFile(allFiles: QuartzPluginData[], folderName: string) { - return allFiles.find((file) => { - if (file.slug?.endsWith("index")) { - const folderParts = file.filePath?.split("/") - if (folderParts) { - const name = folderParts[folderParts?.length - 2] - if (name === folderName) { - return true - } - } - } - }) -} - export default ((opts?: Partial) => { // Merge options with defaults const options: BreadcrumbOptions = { ...defaultOptions, ...opts } + // computed index of folder name to its associated file data + let folderIndex: Map | undefined + function Breadcrumbs({ fileData, allFiles, displayClass }: QuartzComponentProps) { // Hide crumbs on root if enabled if (options.hideOnRoot && fileData.slug === "index") { @@ -70,28 +58,39 @@ export default ((opts?: Partial) => { const firstEntry = formatCrumb(options.rootName, fileData.slug!, "/" as SimpleSlug) const crumbs: CrumbData[] = [firstEntry] + if (!folderIndex && options.resolveFrontmatterTitle) { + folderIndex = new Map() + // construct the index for the first time + for (const file of allFiles) { + if (file.slug?.endsWith("index")) { + const folderParts = file.filePath?.split("/") + if (folderParts) { + const folderName = folderParts[folderParts?.length - 2] + folderIndex.set(folderName, file) + } + } + } + } + // Split slug into hierarchy/parts const slugParts = fileData.slug?.split("/") if (slugParts) { // full path until current part let currentPath = "" for (let i = 0; i < slugParts.length - 1; i++) { - let currentTitle = slugParts[i] + let curPathSegment = slugParts[i] - // TODO: performance optimizations/memoizing // Try to resolve frontmatter folder title - if (options?.resolveFrontmatterTitle) { - // try to find file for current path - const currentFile = findCurrentFile(allFiles, currentTitle) - if (currentFile) { - currentTitle = currentFile.frontmatter!.title - } + const currentFile = folderIndex?.get(curPathSegment) + if (currentFile) { + curPathSegment = currentFile.frontmatter!.title } + // Add current slug to full path currentPath += slugParts[i] + "/" // Format and add current crumb - const crumb = formatCrumb(currentTitle, fileData.slug!, currentPath as SimpleSlug) + const crumb = formatCrumb(curPathSegment, fileData.slug!, currentPath as SimpleSlug) crumbs.push(crumb) }