mirror of
https://github.com/jackyzha0/quartz.git
synced 2026-03-21 21:45:42 -05:00
fix(links): virtual page transclusion
This commit is contained in:
parent
ed3ff89568
commit
f4f64e121c
@ -102,7 +102,19 @@ function renderTranscludes(
|
||||
}
|
||||
visited.add(transcludeTarget)
|
||||
|
||||
const page = componentData.allFiles.find((f) => f.slug === transcludeTarget)
|
||||
let page = componentData.allFiles.find((f) => f.slug === transcludeTarget)
|
||||
if (!page) {
|
||||
// Virtual pages from PageType plugins have slugs without extensions
|
||||
// (e.g. "plugins/CanvasPage") but CrawlLinks resolves wikilinks like
|
||||
// ![[CanvasPage.canvas]] to "plugins/CanvasPage.canvas". Fall back to
|
||||
// stripping the extension from the transclude target.
|
||||
const dotIdx = transcludeTarget.lastIndexOf(".")
|
||||
const slashIdx = transcludeTarget.lastIndexOf("/")
|
||||
if (dotIdx > slashIdx + 1) {
|
||||
const stripped = transcludeTarget.slice(0, dotIdx) as FullSlug
|
||||
page = componentData.allFiles.findLast((f) => f.slug === stripped)
|
||||
}
|
||||
}
|
||||
if (!page) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -7,6 +7,9 @@ import { ProcessedContent, defaultProcessedContent } from "../vfile"
|
||||
import { write } from "../emitters/helpers"
|
||||
import { BuildCtx, trieFromAllFiles } from "../../util/ctx"
|
||||
import { StaticResources } from "../../util/resources"
|
||||
import { render } from "preact-render-to-string"
|
||||
import { fromHtml } from "hast-util-from-html"
|
||||
import { Root as HtmlRoot } from "hast"
|
||||
|
||||
function getPageTypes(ctx: BuildCtx): QuartzPageTypePluginInstance[] {
|
||||
return (ctx.cfg.plugins.pageTypes ?? []) as unknown as QuartzPageTypePluginInstance[]
|
||||
@ -89,6 +92,47 @@ async function emitPage(
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Render each virtual page's Body component to HTML and parse it to a hast tree,
|
||||
* populating both the ProcessedContent tree and vfile.data.htmlAst so that
|
||||
* transclusion (e.g. ![[file.canvas]]) can inline the virtual page's content.
|
||||
*/
|
||||
function populateVirtualPageHtmlAst(
|
||||
virtualEntries: Array<{
|
||||
tree: ProcessedContent[0]
|
||||
vfile: ProcessedContent[1]
|
||||
layout: FullPageLayout
|
||||
vpSlug: FullSlug
|
||||
}>,
|
||||
ctx: BuildCtx,
|
||||
allFiles: ProcessedContent[1]["data"][],
|
||||
resources: StaticResources,
|
||||
) {
|
||||
const cfg = ctx.cfg.configuration
|
||||
for (const ve of virtualEntries) {
|
||||
const BodyComponent = ve.layout.pageBody
|
||||
const externalResources = pageResources(pathToRoot(ve.vpSlug), resources)
|
||||
const componentData: QuartzComponentProps = {
|
||||
ctx,
|
||||
fileData: ve.vfile.data,
|
||||
externalResources,
|
||||
cfg,
|
||||
children: [],
|
||||
tree: ve.tree,
|
||||
allFiles,
|
||||
}
|
||||
try {
|
||||
const htmlString = render(BodyComponent(componentData))
|
||||
const htmlAst = fromHtml(htmlString, { fragment: true }) as HtmlRoot
|
||||
ve.tree.children = htmlAst.children
|
||||
ve.vfile.data.htmlAst = htmlAst
|
||||
} catch {
|
||||
// Body rendering failed — leave htmlAst empty so transclusion falls
|
||||
// back to the default title-only display.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const PageTypeDispatcher: QuartzEmitterPlugin<Partial<DispatcherOptions>> = (userOpts) => {
|
||||
const defaults = userOpts?.defaults ?? {}
|
||||
const byPageType = userOpts?.byPageType ?? {}
|
||||
@ -135,6 +179,9 @@ export const PageTypeDispatcher: QuartzEmitterPlugin<Partial<DispatcherOptions>>
|
||||
}
|
||||
}
|
||||
|
||||
// Render Body components to populate htmlAst for transclusion
|
||||
populateVirtualPageHtmlAst(virtualEntries, ctx, allFiles, resources)
|
||||
|
||||
// Merge virtual page data into allFiles so renderPage can resolve transcludes
|
||||
const allFilesWithVirtual = [...allFiles, ...virtualEntries.map((ve) => ve.vfile.data)]
|
||||
|
||||
@ -207,6 +254,9 @@ export const PageTypeDispatcher: QuartzEmitterPlugin<Partial<DispatcherOptions>>
|
||||
}
|
||||
}
|
||||
|
||||
// Render Body components to populate htmlAst for transclusion
|
||||
populateVirtualPageHtmlAst(virtualEntries, ctx, allFiles, resources)
|
||||
|
||||
// Merge virtual page data into allFiles for transclude resolution
|
||||
const allFilesWithVirtual = [...allFiles, ...virtualEntries.map((ve) => ve.vfile.data)]
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user