mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-27 06:44:07 -06:00
Canvas Rendering stub
This commit is contained in:
parent
6af17125f0
commit
1175c7af87
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"nodes":[
|
"nodes":[
|
||||||
{"id":"a85fff7a7493ef52","type":"group","x":-600,"y":-240,"width":1340,"height":980,"color":"4","label":"Canvas Group"},
|
{"id":"a85fff7a7493ef52","type":"group","x":-600,"y":-240,"width":1340,"height":980,"color":"4","label":"Canvas Group"},
|
||||||
{"id":"f5769d77556ecdca","type":"file","file":"features/Canvas.md","x":-200,"y":-200,"width":400,"height":400,"color":"1"},
|
|
||||||
{"id":"05e0c45c85417543","type":"link","url":"https://jsoncanvas.org/spec/1.0/","x":300,"y":300,"width":401,"height":400,"color":"3"},
|
{"id":"05e0c45c85417543","type":"link","url":"https://jsoncanvas.org/spec/1.0/","x":300,"y":300,"width":401,"height":400,"color":"3"},
|
||||||
{"id":"5997bc7558e18f0b","type":"text","text":"Plain text note","x":-560,"y":470,"width":250,"height":60,"color":"5"}
|
{"id":"5997bc7558e18f0b","type":"text","text":"Plain text note","x":-560,"y":470,"width":250,"height":60,"color":"5"},
|
||||||
|
{"id":"f583da2f9411eca1","x":-200,"y":-200,"width":400,"height":400,"color":"1","type":"file","file":"features/popover previews.md"}
|
||||||
],
|
],
|
||||||
"edges":[
|
"edges":[
|
||||||
{"id":"d63d107e865d06ec","fromNode":"f5769d77556ecdca","fromSide":"right","toNode":"05e0c45c85417543","toSide":"top","color":"2","label":"Specification"},
|
{"id":"185431e9b6c045dc","fromNode":"5997bc7558e18f0b","fromSide":"right","toNode":"05e0c45c85417543","toSide":"left","fromEnd":"arrow"},
|
||||||
{"id":"4dcf493fa007b200","fromNode":"f5769d77556ecdca","fromSide":"bottom","toNode":"5997bc7558e18f0b","toSide":"top","toEnd":"none","color":"6"},
|
{"id":"be55c44ecde61a30","fromNode":"f583da2f9411eca1","fromSide":"right","toNode":"05e0c45c85417543","toSide":"top","color":"2","label":"Specifications"},
|
||||||
{"id":"185431e9b6c045dc","fromNode":"5997bc7558e18f0b","fromSide":"right","toNode":"05e0c45c85417543","toSide":"left","fromEnd":"arrow"}
|
{"id":"1ff7941319ca11b8","fromNode":"f583da2f9411eca1","fromSide":"left","toNode":"5997bc7558e18f0b","toSide":"top","color":"6"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,7 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Canvas"
|
|
||||||
tags:
|
|
||||||
- component
|
|
||||||
---
|
|
||||||
|
|
||||||
Quartz supports Obsidian's [JSON Canvas](https://jsoncanvas.org/).
|
|
||||||
@ -81,6 +81,7 @@ const config: QuartzConfig = {
|
|||||||
Plugin.ContentPage(),
|
Plugin.ContentPage(),
|
||||||
Plugin.FolderPage(),
|
Plugin.FolderPage(),
|
||||||
Plugin.TagPage(),
|
Plugin.TagPage(),
|
||||||
|
Plugin.CanvasPage(),
|
||||||
Plugin.ContentIndex({
|
Plugin.ContentIndex({
|
||||||
enableSiteMap: true,
|
enableSiteMap: true,
|
||||||
enableRSS: true,
|
enableRSS: true,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { PageLayout, SharedLayout } from "./quartz/cfg"
|
import { PageLayout, SharedLayout, CanvasLayout } from "./quartz/cfg"
|
||||||
import * as Component from "./quartz/components"
|
import * as Component from "./quartz/components"
|
||||||
|
|
||||||
// components shared across all pages
|
// components shared across all pages
|
||||||
@ -48,3 +48,8 @@ export const defaultListPageLayout: PageLayout = {
|
|||||||
],
|
],
|
||||||
right: [],
|
right: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// components for canvas pages
|
||||||
|
export const defaultCanvasPageLayout: CanvasLayout = {
|
||||||
|
left: [Component.PageTitle(), Component.Search(), Component.Darkmode(), Component.Explorer()],
|
||||||
|
}
|
||||||
|
|||||||
@ -70,7 +70,7 @@ async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) {
|
|||||||
|
|
||||||
perf.addEvent("glob")
|
perf.addEvent("glob")
|
||||||
const allFiles = await glob("**/*.*", argv.directory, cfg.configuration.ignorePatterns)
|
const allFiles = await glob("**/*.*", argv.directory, cfg.configuration.ignorePatterns)
|
||||||
const fps = allFiles.filter((fp) => fp.endsWith(".md")).sort()
|
const fps = allFiles.filter((fp) => fp.endsWith(".md") || fp.endsWith(".canvas")).sort()
|
||||||
console.log(
|
console.log(
|
||||||
`Found ${fps.length} input files from \`${argv.directory}\` in ${perf.timeSince("glob")}`,
|
`Found ${fps.length} input files from \`${argv.directory}\` in ${perf.timeSince("glob")}`,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -95,3 +95,4 @@ export interface FullPageLayout {
|
|||||||
|
|
||||||
export type PageLayout = Pick<FullPageLayout, "beforeBody" | "left" | "right">
|
export type PageLayout = Pick<FullPageLayout, "beforeBody" | "left" | "right">
|
||||||
export type SharedLayout = Pick<FullPageLayout, "head" | "header" | "footer" | "afterBody">
|
export type SharedLayout = Pick<FullPageLayout, "head" | "header" | "footer" | "afterBody">
|
||||||
|
export type CanvasLayout = Pick<FullPageLayout, "left">
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import Content from "./pages/Content"
|
import Content from "./pages/Content"
|
||||||
import TagContent from "./pages/TagContent"
|
import TagContent from "./pages/TagContent"
|
||||||
import FolderContent from "./pages/FolderContent"
|
import FolderContent from "./pages/FolderContent"
|
||||||
|
import CanvasContent from "./pages/CanvasContent"
|
||||||
import NotFound from "./pages/404"
|
import NotFound from "./pages/404"
|
||||||
import ArticleTitle from "./ArticleTitle"
|
import ArticleTitle from "./ArticleTitle"
|
||||||
import Darkmode from "./Darkmode"
|
import Darkmode from "./Darkmode"
|
||||||
@ -26,6 +27,7 @@ export {
|
|||||||
Content,
|
Content,
|
||||||
TagContent,
|
TagContent,
|
||||||
FolderContent,
|
FolderContent,
|
||||||
|
CanvasContent,
|
||||||
Darkmode,
|
Darkmode,
|
||||||
Head,
|
Head,
|
||||||
PageTitle,
|
PageTitle,
|
||||||
|
|||||||
@ -1 +1,27 @@
|
|||||||
import { QuartzCanvasComponent } from "../types"
|
import { ComponentChildren } from "preact"
|
||||||
|
import { htmlToJsx } from "../../util/jsx"
|
||||||
|
import {
|
||||||
|
QuartzComponent,
|
||||||
|
QuartzComponentConstructor,
|
||||||
|
QuartzComponentProps,
|
||||||
|
QuartzCanvasComponent,
|
||||||
|
} from "../types"
|
||||||
|
import { type FilePath } from "../../util/path"
|
||||||
|
import fs from "fs"
|
||||||
|
|
||||||
|
function loadCanvas(file: FilePath): QuartzCanvasComponent {
|
||||||
|
const data = fs.readFileSync(file, "utf8") ?? "{}"
|
||||||
|
console.log(data)
|
||||||
|
return JSON.parse(data) as QuartzCanvasComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
const CanvasContent: QuartzComponent = ({ fileData, tree }: QuartzComponentProps) => {
|
||||||
|
//const content = htmlToJsx(fileData.filePath!, tree) as ComponentChildren
|
||||||
|
const content = loadCanvas(fileData.filePath!)
|
||||||
|
const classes: string[] = fileData.frontmatter?.cssclasses ?? []
|
||||||
|
const classString = ["popover-hint", ...classes].join(" ")
|
||||||
|
//TODO: Implement canvas rendering
|
||||||
|
return <article class={classString}>{content["nodes"]}</article>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (() => CanvasContent) satisfies QuartzComponentConstructor
|
||||||
|
|||||||
266
quartz/components/renderCanvas.tsx
Normal file
266
quartz/components/renderCanvas.tsx
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
import { render } from "preact-render-to-string"
|
||||||
|
import { QuartzComponent, QuartzComponentProps } from "./types"
|
||||||
|
import HeaderConstructor from "./Header"
|
||||||
|
import BodyConstructor from "./Body"
|
||||||
|
import { JSResourceToScriptElement, StaticResources } from "../util/resources"
|
||||||
|
import { clone, FullSlug, RelativeURL, joinSegments, normalizeHastElement } from "../util/path"
|
||||||
|
import { visit } from "unist-util-visit"
|
||||||
|
import { Root, Element, ElementContent } from "hast"
|
||||||
|
import { GlobalConfiguration } from "../cfg"
|
||||||
|
import { i18n } from "../i18n"
|
||||||
|
// @ts-ignore
|
||||||
|
import mermaidScript from "./scripts/mermaid.inline"
|
||||||
|
import mermaidStyle from "./styles/mermaid.inline.scss"
|
||||||
|
import { QuartzPluginData } from "../plugins/vfile"
|
||||||
|
|
||||||
|
interface RenderComponents {
|
||||||
|
head: QuartzComponent
|
||||||
|
header: QuartzComponent[]
|
||||||
|
beforeBody: QuartzComponent[]
|
||||||
|
pageBody: QuartzComponent
|
||||||
|
afterBody: QuartzComponent[]
|
||||||
|
left: QuartzComponent[]
|
||||||
|
right: QuartzComponent[]
|
||||||
|
footer: QuartzComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerRegex = new RegExp(/h[1-6]/)
|
||||||
|
export function pageResources(
|
||||||
|
baseDir: FullSlug | RelativeURL,
|
||||||
|
fileData: QuartzPluginData,
|
||||||
|
staticResources: StaticResources,
|
||||||
|
): StaticResources {
|
||||||
|
const contentIndexPath = joinSegments(baseDir, "static/contentIndex.json")
|
||||||
|
const contentIndexScript = `const fetchData = fetch("${contentIndexPath}").then(data => data.json())`
|
||||||
|
|
||||||
|
const resources: StaticResources = {
|
||||||
|
css: [
|
||||||
|
{
|
||||||
|
content: joinSegments(baseDir, "index.css"),
|
||||||
|
},
|
||||||
|
...staticResources.css,
|
||||||
|
],
|
||||||
|
js: [
|
||||||
|
{
|
||||||
|
src: joinSegments(baseDir, "prescript.js"),
|
||||||
|
loadTime: "beforeDOMReady",
|
||||||
|
contentType: "external",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loadTime: "beforeDOMReady",
|
||||||
|
contentType: "inline",
|
||||||
|
spaPreserve: true,
|
||||||
|
script: contentIndexScript,
|
||||||
|
},
|
||||||
|
...staticResources.js,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileData.hasMermaidDiagram) {
|
||||||
|
resources.js.push({
|
||||||
|
script: mermaidScript,
|
||||||
|
loadTime: "afterDOMReady",
|
||||||
|
moduleType: "module",
|
||||||
|
contentType: "inline",
|
||||||
|
})
|
||||||
|
resources.css.push({ content: mermaidStyle, inline: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: we have to put this last to make sure spa.inline.ts is the last item.
|
||||||
|
resources.js.push({
|
||||||
|
src: joinSegments(baseDir, "postscript.js"),
|
||||||
|
loadTime: "afterDOMReady",
|
||||||
|
moduleType: "module",
|
||||||
|
contentType: "external",
|
||||||
|
})
|
||||||
|
|
||||||
|
return resources
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderCanvas(
|
||||||
|
cfg: GlobalConfiguration,
|
||||||
|
slug: FullSlug,
|
||||||
|
componentData: QuartzComponentProps,
|
||||||
|
components: RenderComponents,
|
||||||
|
pageResources: StaticResources,
|
||||||
|
): string {
|
||||||
|
// make a deep copy of the tree so we don't remove the transclusion references
|
||||||
|
// for the file cached in contentMap in build.ts
|
||||||
|
const root = clone(componentData.tree) as Root
|
||||||
|
|
||||||
|
console.log(root)
|
||||||
|
|
||||||
|
// process transcludes in componentData
|
||||||
|
/*visit(root, "element", (node, _index, _parent) => {
|
||||||
|
if (node.tagName === "blockquote") {
|
||||||
|
const classNames = (node.properties?.className ?? []) as string[]
|
||||||
|
if (classNames.includes("transclude")) {
|
||||||
|
const inner = node.children[0] as Element
|
||||||
|
const transcludeTarget = inner.properties["data-slug"] as FullSlug
|
||||||
|
const page = componentData.allFiles.find((f) => f.slug === transcludeTarget)
|
||||||
|
if (!page) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let blockRef = node.properties.dataBlock as string | undefined
|
||||||
|
if (blockRef?.startsWith("#^")) {
|
||||||
|
// block transclude
|
||||||
|
blockRef = blockRef.slice("#^".length)
|
||||||
|
let blockNode = page.blocks?.[blockRef]
|
||||||
|
if (blockNode) {
|
||||||
|
if (blockNode.tagName === "li") {
|
||||||
|
blockNode = {
|
||||||
|
type: "element",
|
||||||
|
tagName: "ul",
|
||||||
|
properties: {},
|
||||||
|
children: [blockNode],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.children = [
|
||||||
|
normalizeHastElement(blockNode, slug, transcludeTarget),
|
||||||
|
{
|
||||||
|
type: "element",
|
||||||
|
tagName: "a",
|
||||||
|
properties: { href: inner.properties?.href, class: ["internal", "transclude-src"] },
|
||||||
|
children: [
|
||||||
|
{ type: "text", value: i18n(cfg.locale).components.transcludes.linkToOriginal },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (blockRef?.startsWith("#") && page.htmlAst) {
|
||||||
|
// header transclude
|
||||||
|
blockRef = blockRef.slice(1)
|
||||||
|
let startIdx = undefined
|
||||||
|
let startDepth = undefined
|
||||||
|
let endIdx = undefined
|
||||||
|
for (const [i, el] of page.htmlAst.children.entries()) {
|
||||||
|
// skip non-headers
|
||||||
|
if (!(el.type === "element" && el.tagName.match(headerRegex))) continue
|
||||||
|
const depth = Number(el.tagName.substring(1))
|
||||||
|
|
||||||
|
// lookin for our blockref
|
||||||
|
if (startIdx === undefined || startDepth === undefined) {
|
||||||
|
// skip until we find the blockref that matches
|
||||||
|
if (el.properties?.id === blockRef) {
|
||||||
|
startIdx = i
|
||||||
|
startDepth = depth
|
||||||
|
}
|
||||||
|
} else if (depth <= startDepth) {
|
||||||
|
// looking for new header that is same level or higher
|
||||||
|
endIdx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startIdx === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
node.children = [
|
||||||
|
...(page.htmlAst.children.slice(startIdx, endIdx) as ElementContent[]).map((child) =>
|
||||||
|
normalizeHastElement(child as Element, slug, transcludeTarget),
|
||||||
|
),
|
||||||
|
{
|
||||||
|
type: "element",
|
||||||
|
tagName: "a",
|
||||||
|
properties: { href: inner.properties?.href, class: ["internal", "transclude-src"] },
|
||||||
|
children: [
|
||||||
|
{ type: "text", value: i18n(cfg.locale).components.transcludes.linkToOriginal },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
} else if (page.htmlAst) {
|
||||||
|
// page transclude
|
||||||
|
node.children = [
|
||||||
|
{
|
||||||
|
type: "element",
|
||||||
|
tagName: "h1",
|
||||||
|
properties: {},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
value:
|
||||||
|
page.frontmatter?.title ??
|
||||||
|
i18n(cfg.locale).components.transcludes.transcludeOf({
|
||||||
|
targetSlug: page.slug!,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
...(page.htmlAst.children as ElementContent[]).map((child) =>
|
||||||
|
normalizeHastElement(child as Element, slug, transcludeTarget),
|
||||||
|
),
|
||||||
|
{
|
||||||
|
type: "element",
|
||||||
|
tagName: "a",
|
||||||
|
properties: { href: inner.properties?.href, class: ["internal", "transclude-src"] },
|
||||||
|
children: [
|
||||||
|
{ type: "text", value: i18n(cfg.locale).components.transcludes.linkToOriginal },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})*/
|
||||||
|
|
||||||
|
// set componentData.tree to the edited html that has transclusions rendered
|
||||||
|
componentData.tree = root
|
||||||
|
|
||||||
|
const {
|
||||||
|
head: Head,
|
||||||
|
header,
|
||||||
|
beforeBody,
|
||||||
|
pageBody: CanvasContent,
|
||||||
|
afterBody,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
footer: Footer,
|
||||||
|
} = components
|
||||||
|
const Header = HeaderConstructor()
|
||||||
|
const Body = BodyConstructor()
|
||||||
|
|
||||||
|
const LeftComponent = (
|
||||||
|
<div class="left sidebar">
|
||||||
|
{left.map((BodyComponent) => (
|
||||||
|
<BodyComponent {...componentData} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
const lang = componentData.fileData.frontmatter?.lang ?? cfg.locale?.split("-")[0] ?? "en"
|
||||||
|
const doc = (
|
||||||
|
<html lang={lang}>
|
||||||
|
<Head {...componentData} />
|
||||||
|
<body data-slug={slug}>
|
||||||
|
<div id="quartz-root" class="page canvas">
|
||||||
|
<Body {...componentData}>
|
||||||
|
{LeftComponent}
|
||||||
|
<div class="center">
|
||||||
|
<div class="page-header">
|
||||||
|
<Header {...componentData}>
|
||||||
|
{header.map((HeaderComponent) => (
|
||||||
|
<HeaderComponent {...componentData} />
|
||||||
|
))}
|
||||||
|
</Header>
|
||||||
|
<div class="popover-hint">
|
||||||
|
{beforeBody.map((BodyComponent) => (
|
||||||
|
<BodyComponent {...componentData} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<CanvasContent {...componentData} />
|
||||||
|
</div>
|
||||||
|
</Body>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
{pageResources.js
|
||||||
|
.filter((resource) => resource.loadTime === "afterDOMReady")
|
||||||
|
.map((res) => JSResourceToScriptElement(res))}
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
|
||||||
|
return "<!DOCTYPE html>\n" + render(doc)
|
||||||
|
}
|
||||||
141
quartz/plugins/emitters/canvasPage.tsx
Normal file
141
quartz/plugins/emitters/canvasPage.tsx
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
import path from "path"
|
||||||
|
import { visit } from "unist-util-visit"
|
||||||
|
import { Root } from "hast"
|
||||||
|
import { VFile } from "vfile"
|
||||||
|
import { QuartzEmitterPlugin } from "../types"
|
||||||
|
import { QuartzComponentProps } from "../../components/types"
|
||||||
|
import HeaderConstructor from "../../components/Header"
|
||||||
|
import BodyConstructor from "../../components/Body"
|
||||||
|
import { pageResources, renderCanvas } from "../../components/renderCanvas"
|
||||||
|
import { FullPageLayout } from "../../cfg"
|
||||||
|
import { Argv } from "../../util/ctx"
|
||||||
|
import { FilePath, isRelativeURL, joinSegments, pathToRoot } from "../../util/path"
|
||||||
|
import { defaultContentPageLayout, sharedPageComponents } from "../../../quartz.layout"
|
||||||
|
import { CanvasContent } from "../../components"
|
||||||
|
import chalk from "chalk"
|
||||||
|
import { write } from "./helpers"
|
||||||
|
import DepGraph from "../../depgraph"
|
||||||
|
|
||||||
|
// get all the dependencies for the markdown file
|
||||||
|
// eg. images, scripts, stylesheets, transclusions
|
||||||
|
const parseDependencies = (argv: Argv, hast: Root, file: VFile): string[] => {
|
||||||
|
const dependencies: string[] = []
|
||||||
|
|
||||||
|
visit(hast, "element", (elem): void => {
|
||||||
|
let ref: string | null = null
|
||||||
|
|
||||||
|
if (
|
||||||
|
["script", "img", "audio", "video", "source", "iframe"].includes(elem.tagName) &&
|
||||||
|
elem?.properties?.src
|
||||||
|
) {
|
||||||
|
ref = elem.properties.src.toString()
|
||||||
|
} else if (["a", "link"].includes(elem.tagName) && elem?.properties?.href) {
|
||||||
|
// transclusions will create a tags with relative hrefs
|
||||||
|
ref = elem.properties.href.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it is a relative url, its a local file and we need to add
|
||||||
|
// it to the dependency graph. otherwise, ignore
|
||||||
|
if (ref === null || !isRelativeURL(ref)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let fp = path.join(file.data.filePath!, path.relative(argv.directory, ref)).replace(/\\/g, "/")
|
||||||
|
// markdown files have the .md extension stripped in hrefs, add it back here
|
||||||
|
if (!fp.split("/").pop()?.includes(".")) {
|
||||||
|
fp += ".md"
|
||||||
|
}
|
||||||
|
dependencies.push(fp)
|
||||||
|
})
|
||||||
|
|
||||||
|
return dependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CanvasPage: QuartzEmitterPlugin<Partial<FullPageLayout>> = (userOpts) => {
|
||||||
|
const opts: FullPageLayout = {
|
||||||
|
...sharedPageComponents,
|
||||||
|
...defaultContentPageLayout,
|
||||||
|
pageBody: CanvasContent(),
|
||||||
|
...userOpts,
|
||||||
|
}
|
||||||
|
|
||||||
|
const { head: Head, header, beforeBody, pageBody, afterBody, left, right, footer: Footer } = opts
|
||||||
|
const Header = HeaderConstructor()
|
||||||
|
const Body = BodyConstructor()
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "CanvasPage",
|
||||||
|
getQuartzComponents() {
|
||||||
|
return [
|
||||||
|
Head,
|
||||||
|
Header,
|
||||||
|
Body,
|
||||||
|
...header,
|
||||||
|
...beforeBody,
|
||||||
|
pageBody,
|
||||||
|
...afterBody,
|
||||||
|
...left,
|
||||||
|
...right,
|
||||||
|
Footer,
|
||||||
|
]
|
||||||
|
},
|
||||||
|
async getDependencyGraph(ctx, content, _resources) {
|
||||||
|
const graph = new DepGraph<FilePath>()
|
||||||
|
|
||||||
|
for (const [tree, file] of content) {
|
||||||
|
const sourcePath = file.data.filePath!
|
||||||
|
const slug = file.data.slug!
|
||||||
|
graph.addEdge(sourcePath, joinSegments(ctx.argv.output, slug + ".html") as FilePath)
|
||||||
|
|
||||||
|
parseDependencies(ctx.argv, tree as Root, file).forEach((dep) => {
|
||||||
|
graph.addEdge(dep as FilePath, sourcePath)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return graph
|
||||||
|
},
|
||||||
|
async emit(ctx, content, resources): Promise<FilePath[]> {
|
||||||
|
const cfg = ctx.cfg.configuration
|
||||||
|
const fps: FilePath[] = []
|
||||||
|
const allFiles = content.map((c) => c[1].data)
|
||||||
|
|
||||||
|
let containsCanvas = false
|
||||||
|
for (const [tree, file] of content) {
|
||||||
|
if (!file.data.filePath?.endsWith(".canvas")) continue
|
||||||
|
const slug = file.data.slug!
|
||||||
|
containsCanvas = true
|
||||||
|
|
||||||
|
const externalResources = pageResources(pathToRoot(slug), file.data, resources)
|
||||||
|
const componentData: QuartzComponentProps = {
|
||||||
|
ctx,
|
||||||
|
fileData: file.data,
|
||||||
|
externalResources,
|
||||||
|
cfg,
|
||||||
|
children: [],
|
||||||
|
tree,
|
||||||
|
allFiles,
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = renderCanvas(cfg, slug, componentData, opts, externalResources)
|
||||||
|
const fp = await write({
|
||||||
|
ctx,
|
||||||
|
content,
|
||||||
|
slug,
|
||||||
|
ext: ".html",
|
||||||
|
})
|
||||||
|
|
||||||
|
fps.push(fp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!containsCanvas && !ctx.argv.fastRebuild) {
|
||||||
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
`\nWarning: No canvas files detected in \`${ctx.argv.directory}\`. Skipping.`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fps
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
export { ContentPage } from "./contentPage"
|
export { ContentPage } from "./contentPage"
|
||||||
export { TagPage } from "./tagPage"
|
export { TagPage } from "./tagPage"
|
||||||
export { FolderPage } from "./folderPage"
|
export { FolderPage } from "./folderPage"
|
||||||
|
export { CanvasPage } from "./canvasPage"
|
||||||
export { ContentIndex } from "./contentIndex"
|
export { ContentIndex } from "./contentIndex"
|
||||||
export { AliasRedirects } from "./aliases"
|
export { AliasRedirects } from "./aliases"
|
||||||
export { Assets } from "./assets"
|
export { Assets } from "./assets"
|
||||||
|
|||||||
@ -66,7 +66,7 @@ export function slugifyFilePath(fp: FilePath, excludeExt?: boolean): FullSlug {
|
|||||||
fp = stripSlashes(fp) as FilePath
|
fp = stripSlashes(fp) as FilePath
|
||||||
let ext = _getFileExtension(fp)
|
let ext = _getFileExtension(fp)
|
||||||
const withoutFileExt = fp.replace(new RegExp(ext + "$"), "")
|
const withoutFileExt = fp.replace(new RegExp(ext + "$"), "")
|
||||||
if (excludeExt || [".md", ".html", undefined].includes(ext)) {
|
if (excludeExt || [".md", ".html", ".canvas", undefined].includes(ext)) {
|
||||||
ext = ""
|
ext = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user