Skip to content

Commit

Permalink
🔄 synced local 'quartz/' with remote 'quartz/'
Browse files Browse the repository at this point in the history
  • Loading branch information
Mara-Li committed Feb 25, 2024
1 parent 119b584 commit 518932d
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 32 deletions.
33 changes: 21 additions & 12 deletions quartz/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,14 @@ async function partialRebuildFromEntrypoint(
const emitterGraph =
(await emitter.getDependencyGraph?.(ctx, processedFiles, staticResources)) ?? null

// emmiter may not define a dependency graph. nothing to update if so
if (emitterGraph) {
dependencies[emitter.name]?.updateIncomingEdgesForNode(emitterGraph, fp)
const existingGraph = dependencies[emitter.name]
if (existingGraph !== null) {
existingGraph.mergeGraph(emitterGraph)
} else {
// might be the first time we're adding a mardown file
dependencies[emitter.name] = emitterGraph
}
}
}
break
Expand Down Expand Up @@ -224,7 +229,6 @@ async function partialRebuildFromEntrypoint(
// EMIT
perf.addEvent("rebuild")
let emittedFiles = 0
const destinationsToDelete = new Set<FilePath>()

for (const emitter of cfg.plugins.emitters) {
const depGraph = dependencies[emitter.name]
Expand Down Expand Up @@ -264,11 +268,6 @@ async function partialRebuildFromEntrypoint(
// and supply [a.md, b.md] to the emitter
const upstreams = [...depGraph.getLeafNodeAncestors(fp)] as FilePath[]

if (action === "delete" && upstreams.length === 1) {
// if there's only one upstream, the destination is solely dependent on this file
destinationsToDelete.add(upstreams[0])
}

const upstreamContent = upstreams
// filter out non-markdown files
.filter((file) => contentMap.has(file))
Expand All @@ -291,14 +290,24 @@ async function partialRebuildFromEntrypoint(
console.log(`Emitted ${emittedFiles} files to \`${argv.output}\` in ${perf.timeSince("rebuild")}`)

// CLEANUP
// delete files that are solely dependent on this file
await rimraf([...destinationsToDelete])
const destinationsToDelete = new Set<FilePath>()
for (const file of toRemove) {
// remove from cache
contentMap.delete(file)
// remove the node from dependency graphs
Object.values(dependencies).forEach((depGraph) => depGraph?.removeNode(file))
Object.values(dependencies).forEach((depGraph) => {
// remove the node from dependency graphs
depGraph?.removeNode(file)
// remove any orphan nodes. eg if a.md is deleted, a.html is orphaned and should be removed
const orphanNodes = depGraph?.removeOrphanNodes()
orphanNodes?.forEach((node) => {
// only delete files that are in the output directory
if (node.startsWith(argv.output)) {
destinationsToDelete.add(node)
}
})
})
}
await rimraf([...destinationsToDelete])

toRemove.clear()
release()
Expand Down
22 changes: 15 additions & 7 deletions quartz/components/scripts/popover.inline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,28 +47,36 @@ async function mouseEnterHandler(
}

if (!response) return
const contentType = response.headers.get("Content-Type")
const contentTypeCategory = contentType?.split("/")[0] ?? "text"
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 = contentTypeCategory
popoverInner.dataset.contentType = contentType ?? undefined

switch (contentTypeCategory) {
case "image":
const img = document.createElement("img")

response.blob().then((blob) => {
img.src = URL.createObjectURL(blob)
})
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")
Expand Down
25 changes: 18 additions & 7 deletions quartz/components/styles/popover.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,25 @@
white-space: normal;
}

& > .popover-inner[data-content-type="image"] {
padding: 0;
max-height: 100%;
& > .popover-inner[data-content-type] {
&[data-content-type*="pdf"],
&[data-content-type*="image"] {
padding: 0;
max-height: 100%;
}

&[data-content-type*="image"] {
img {
margin: 0;
border-radius: 0;
display: block;
}
}

img {
margin: 0;
border-radius: 0;
display: block;
&[data-content-type*="pdf"] {
iframe {
width: 100%;
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions quartz/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { StaticResources } from "../util/resources"
import { QuartzPluginData } from "../plugins/vfile"
import { GlobalConfiguration } from "../cfg"
import { Node } from "hast"
import { BuildCtx } from "../util/ctx"

export type QuartzComponentProps = {
ctx: BuildCtx
externalResources: StaticResources
fileData: QuartzPluginData
cfg: GlobalConfiguration
Expand Down
22 changes: 22 additions & 0 deletions quartz/depgraph.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,28 @@ describe("DepGraph", () => {
})
})

describe("mergeGraph", () => {
test("merges two graphs", () => {
const graph = new DepGraph<string>()
graph.addEdge("A.md", "A.html")

const other = new DepGraph<string>()
other.addEdge("B.md", "B.html")

graph.mergeGraph(other)

const expected = {
nodes: ["A.md", "A.html", "B.md", "B.html"],
edges: [
["A.md", "A.html"],
["B.md", "B.html"],
],
}

assert.deepStrictEqual(graph.export(), expected)
})
})

describe("updateIncomingEdgesForNode", () => {
test("merges when node exists", () => {
// A.md -> B.md -> B.html
Expand Down
41 changes: 41 additions & 0 deletions quartz/depgraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,26 @@ export default class DepGraph<T> {
}
}

// Remove node and all edges connected to it
removeNode(node: T): void {
if (this._graph.has(node)) {
// first remove all edges so other nodes don't have references to this node
for (const target of this._graph.get(node)!.outgoing) {
this.removeEdge(node, target)
}
for (const source of this._graph.get(node)!.incoming) {
this.removeEdge(source, node)
}
this._graph.delete(node)
}
}

forEachNode(callback: (node: T) => void): void {
for (const node of this._graph.keys()) {
callback(node)
}
}

hasEdge(from: T, to: T): boolean {
return Boolean(this._graph.get(from)?.outgoing.has(to))
}
Expand Down Expand Up @@ -92,6 +106,15 @@ export default class DepGraph<T> {

// DEPENDENCY ALGORITHMS

// Add all nodes and edges from other graph to this graph
mergeGraph(other: DepGraph<T>): void {
other.forEachEdge(([source, target]) => {
this.addNode(source)
this.addNode(target)
this.addEdge(source, target)
})
}

// For the node provided:
// If node does not exist, add it
// If an incoming edge was added in other, it is added in this graph
Expand All @@ -112,6 +135,24 @@ export default class DepGraph<T> {
})
}

// Remove all nodes that do not have any incoming or outgoing edges
// A node may be orphaned if the only node pointing to it was removed
removeOrphanNodes(): Set<T> {
let orphanNodes = new Set<T>()

this.forEachNode((node) => {
if (this.inDegree(node) === 0 && this.outDegree(node) === 0) {
orphanNodes.add(node)
}
})

orphanNodes.forEach((node) => {
this.removeNode(node)
})

return orphanNodes
}

// Get all leaf nodes (i.e. destination paths) reachable from the node provided
// Eg. if the graph is A -> B -> C
// D ---^
Expand Down
1 change: 1 addition & 0 deletions quartz/plugins/emitters/404.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const NotFoundPage: QuartzEmitterPlugin = () => {
frontmatter: { title: notFound, tags: [] },
})
const componentData: QuartzComponentProps = {
ctx,
fileData: vfile.data,
externalResources,
cfg,
Expand Down
1 change: 1 addition & 0 deletions quartz/plugins/emitters/contentPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export const ContentPage: QuartzEmitterPlugin<Partial<FullPageLayout>> = (userOp

const externalResources = pageResources(pathToRoot(slug), resources)
const componentData: QuartzComponentProps = {
ctx,
fileData: file.data,
externalResources,
cfg,
Expand Down
1 change: 1 addition & 0 deletions quartz/plugins/emitters/folderPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export const FolderPage: QuartzEmitterPlugin<Partial<FullPageLayout>> = (userOpt
const externalResources = pageResources(pathToRoot(slug), resources)
const [tree, file] = folderDescriptions[folder]
const componentData: QuartzComponentProps = {
ctx,
fileData: file.data,
externalResources,
cfg,
Expand Down
1 change: 1 addition & 0 deletions quartz/plugins/emitters/tagPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export const TagPage: QuartzEmitterPlugin<Partial<FullPageLayout>> = (userOpts)
const externalResources = pageResources(pathToRoot(slug), resources)
const [tree, file] = tagDescriptions[tag]
const componentData: QuartzComponentProps = {
ctx,
fileData: file.data,
externalResources,
cfg,
Expand Down
7 changes: 1 addition & 6 deletions quartz/plugins/transformers/ofm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,12 +412,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
children: [
{
type: "text",
value: useDefaultTitle
? capitalize(
i18n(cfg.locale).components.callout[calloutType as ValidCallout] ??
calloutType,
)
: titleContent + " ",
value: useDefaultTitle ? capitalize(typeString) : titleContent + " ",
},
...restOfTitle,
],
Expand Down

0 comments on commit 518932d

Please sign in to comment.