mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-24 21:34:06 -06:00
Canvas stub
This commit is contained in:
parent
1175c7af87
commit
2fb4b7474d
@ -1,12 +1,19 @@
|
||||
import { ComponentChildren } from "preact"
|
||||
import { htmlToJsx } from "../../util/jsx"
|
||||
import d3 from "d3"
|
||||
import {
|
||||
QuartzComponent,
|
||||
QuartzComponentConstructor,
|
||||
QuartzComponentProps,
|
||||
QuartzCanvasComponent,
|
||||
CanvasNode,
|
||||
CanvasEdge,
|
||||
CanvasTextNode,
|
||||
CanvasFileNode,
|
||||
CanvasLinkNode,
|
||||
CanvasGroupNode,
|
||||
} from "../types"
|
||||
import { type FilePath } from "../../util/path"
|
||||
import { type FilePath, slugifyFilePath } from "../../util/path"
|
||||
import fs from "fs"
|
||||
|
||||
function loadCanvas(file: FilePath): QuartzCanvasComponent {
|
||||
@ -15,13 +22,84 @@ function loadCanvas(file: FilePath): QuartzCanvasComponent {
|
||||
return JSON.parse(data) as QuartzCanvasComponent
|
||||
}
|
||||
|
||||
function renderTextNodes(nodes: CanvasTextNode[]): ComponentChildren {
|
||||
return nodes.map((node) => (
|
||||
<div
|
||||
class="canvas canvas-node canvas-text-node"
|
||||
style={{
|
||||
position: "fixed",
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
left: node.x,
|
||||
top: node.y,
|
||||
}}
|
||||
>
|
||||
{node["text"]}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
|
||||
function renderFileNodes(nodes: CanvasFileNode[]): ComponentChildren {
|
||||
return nodes.map((node) => (
|
||||
<div
|
||||
class="internal alias internal-canvas"
|
||||
data-slug={slugifyFilePath(node.file as FilePath)}
|
||||
data-x={node.x}
|
||||
data-y={node.y}
|
||||
style={{
|
||||
position: "fixed",
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
left: node.x,
|
||||
top: node.y,
|
||||
}}
|
||||
></div>
|
||||
))
|
||||
}
|
||||
|
||||
function renderLinkNodes(nodes: CanvasLinkNode[]): ComponentChildren {
|
||||
return nodes.map((node) => (
|
||||
<iframe
|
||||
src={node["url"]}
|
||||
style={{
|
||||
position: "fixed",
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
left: node.x,
|
||||
top: node.y,
|
||||
}}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
||||
const CanvasContent: QuartzComponent = ({ fileData, tree }: QuartzComponentProps) => {
|
||||
//const content = htmlToJsx(fileData.filePath!, tree) as ComponentChildren
|
||||
const content = loadCanvas(fileData.filePath!)
|
||||
const canvas = loadCanvas(fileData.filePath!)
|
||||
const canvasNodes = (canvas["nodes"] ?? []) as CanvasNode[]
|
||||
const canvasEdges = (canvas["edges"] ?? []) as CanvasEdge[]
|
||||
const classes: string[] = fileData.frontmatter?.cssclasses ?? []
|
||||
const classString = ["popover-hint", ...classes].join(" ")
|
||||
|
||||
// Canvas parts
|
||||
const textNodes = (canvasNodes.filter((node) => node["type"] === "text") ??
|
||||
[]) as CanvasTextNode[]
|
||||
const fileNodes = (canvasNodes.filter((node) => node["type"] === "file") ??
|
||||
[]) as CanvasFileNode[]
|
||||
const linkNodes = (canvasNodes.filter((node) => node["type"] === "link") ??
|
||||
[]) as CanvasLinkNode[]
|
||||
const groupNodes = (canvasNodes.filter((node) => node["type"] === "group") ??
|
||||
[]) as CanvasGroupNode[]
|
||||
|
||||
const result = (
|
||||
<article class={classString}>
|
||||
{renderTextNodes(textNodes)}
|
||||
{renderFileNodes(fileNodes)}
|
||||
{renderLinkNodes(linkNodes)}
|
||||
</article>
|
||||
)
|
||||
|
||||
//TODO: Implement canvas rendering
|
||||
return <article class={classString}>{content["nodes"]}</article>
|
||||
return <article class={classString}>{result}</article>
|
||||
}
|
||||
|
||||
export default (() => CanvasContent) satisfies QuartzComponentConstructor
|
||||
|
||||
@ -91,7 +91,7 @@ export function renderCanvas(
|
||||
console.log(root)
|
||||
|
||||
// process transcludes in componentData
|
||||
/*visit(root, "element", (node, _index, _parent) => {
|
||||
visit(root, "element", (node, _index, _parent) => {
|
||||
if (node.tagName === "blockquote") {
|
||||
const classNames = (node.properties?.className ?? []) as string[]
|
||||
if (classNames.includes("transclude")) {
|
||||
@ -204,7 +204,7 @@ export function renderCanvas(
|
||||
}
|
||||
}
|
||||
}
|
||||
})*/
|
||||
})
|
||||
|
||||
// set componentData.tree to the edited html that has transclusions rendered
|
||||
componentData.tree = root
|
||||
|
||||
@ -100,10 +100,121 @@ async function mouseEnterHandler(
|
||||
}
|
||||
}
|
||||
|
||||
async function navigationHandler(this: HTMLAnchorElement) {
|
||||
const link = this
|
||||
if (link.dataset.noPopover === "true") {
|
||||
return
|
||||
}
|
||||
|
||||
const canvasX = Number(link.getAttribute("data-x") ?? "0")
|
||||
const canvasY = Number(link.getAttribute("data-y") ?? "0")
|
||||
|
||||
async function setPosition(popoverElement: HTMLElement) {
|
||||
const { x, y } = await computePosition(link, popoverElement, {
|
||||
middleware: [inline({ x: canvasX, y: canvasY }), shift(), flip()],
|
||||
})
|
||||
Object.assign(popoverElement.style, {
|
||||
left: `${x}px`,
|
||||
top: `${y}px`,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
})
|
||||
}
|
||||
|
||||
const hasAlreadyBeenFetched = () =>
|
||||
[...link.children].some((child) => child.classList.contains("popover"))
|
||||
|
||||
// dont refetch if there's already a popover
|
||||
if (hasAlreadyBeenFetched()) {
|
||||
return setPosition(link.lastChild as HTMLElement)
|
||||
}
|
||||
|
||||
const thisUrl = new URL(document.location.href)
|
||||
thisUrl.hash = ""
|
||||
thisUrl.search = ""
|
||||
const targetUrl = new URL(link.href)
|
||||
const hash = decodeURIComponent(targetUrl.hash)
|
||||
targetUrl.hash = ""
|
||||
targetUrl.search = ""
|
||||
|
||||
const response = await fetchCanonical(targetUrl).catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
|
||||
// bailout if another popover exists
|
||||
if (hasAlreadyBeenFetched()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!response) return
|
||||
const [contentType] = response.headers.get("Content-Type")!.split(";")
|
||||
const [contentTypeCategory, typeInfo] = contentType.split("/")
|
||||
|
||||
const popoverElement = document.createElement("div")
|
||||
popoverElement.classList.add("popover")
|
||||
const popoverInner = document.createElement("div")
|
||||
popoverInner.classList.add("popover-inner")
|
||||
popoverElement.appendChild(popoverInner)
|
||||
|
||||
popoverInner.dataset.contentType = contentType ?? undefined
|
||||
|
||||
switch (contentTypeCategory) {
|
||||
case "image":
|
||||
const img = document.createElement("img")
|
||||
img.src = targetUrl.toString()
|
||||
img.alt = targetUrl.pathname
|
||||
|
||||
popoverInner.appendChild(img)
|
||||
break
|
||||
case "application":
|
||||
switch (typeInfo) {
|
||||
case "pdf":
|
||||
const pdf = document.createElement("iframe")
|
||||
pdf.src = targetUrl.toString()
|
||||
popoverInner.appendChild(pdf)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
break
|
||||
default:
|
||||
const contents = await response.text()
|
||||
const html = p.parseFromString(contents, "text/html")
|
||||
normalizeRelativeURLs(html, targetUrl)
|
||||
const elts = [...html.getElementsByClassName("popover-hint")]
|
||||
if (elts.length === 0) return
|
||||
|
||||
elts.forEach((elt) => popoverInner.appendChild(elt))
|
||||
}
|
||||
|
||||
setPosition(popoverElement)
|
||||
link.appendChild(popoverElement)
|
||||
|
||||
if (hash !== "") {
|
||||
const heading = popoverInner.querySelector(hash) as HTMLElement | null
|
||||
if (heading) {
|
||||
// leave ~12px of buffer when scrolling to a heading
|
||||
popoverInner.scroll({ top: heading.offsetTop - 12, behavior: "instant" })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("nav", () => {
|
||||
const links = [...document.getElementsByClassName("internal")] as HTMLAnchorElement[]
|
||||
for (const link of links) {
|
||||
console.log(links)
|
||||
const pageLinks = links.filter((link) =>
|
||||
link.classList.contains("internal-canvas"),
|
||||
) as HTMLAnchorElement[]
|
||||
const canvasLinks = links.filter(
|
||||
(link) => !link.classList.contains("internal-canvas"),
|
||||
) as HTMLAnchorElement[]
|
||||
for (const link of pageLinks) {
|
||||
link.addEventListener("mouseenter", mouseEnterHandler)
|
||||
window.addCleanup(() => link.removeEventListener("mouseenter", mouseEnterHandler))
|
||||
}
|
||||
//TODO: Fix canvas loading of popovers
|
||||
for (const link of canvasLinks) {
|
||||
link.addEventListener("load", navigationHandler)
|
||||
window.addCleanup(() => link.removeEventListener("load", navigationHandler))
|
||||
}
|
||||
})
|
||||
|
||||
Loading…
Reference in New Issue
Block a user