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)
|
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) {
|
if (!page) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,9 @@ import { ProcessedContent, defaultProcessedContent } from "../vfile"
|
|||||||
import { write } from "../emitters/helpers"
|
import { write } from "../emitters/helpers"
|
||||||
import { BuildCtx, trieFromAllFiles } from "../../util/ctx"
|
import { BuildCtx, trieFromAllFiles } from "../../util/ctx"
|
||||||
import { StaticResources } from "../../util/resources"
|
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[] {
|
function getPageTypes(ctx: BuildCtx): QuartzPageTypePluginInstance[] {
|
||||||
return (ctx.cfg.plugins.pageTypes ?? []) as unknown as 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) => {
|
export const PageTypeDispatcher: QuartzEmitterPlugin<Partial<DispatcherOptions>> = (userOpts) => {
|
||||||
const defaults = userOpts?.defaults ?? {}
|
const defaults = userOpts?.defaults ?? {}
|
||||||
const byPageType = userOpts?.byPageType ?? {}
|
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
|
// Merge virtual page data into allFiles so renderPage can resolve transcludes
|
||||||
const allFilesWithVirtual = [...allFiles, ...virtualEntries.map((ve) => ve.vfile.data)]
|
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
|
// Merge virtual page data into allFiles for transclude resolution
|
||||||
const allFilesWithVirtual = [...allFiles, ...virtualEntries.map((ve) => ve.vfile.data)]
|
const allFilesWithVirtual = [...allFiles, ...virtualEntries.map((ve) => ve.vfile.data)]
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user