feat(notes): render macroplan code blocks as a delivery plan grid
All checks were successful
CI / verify (push) Successful in 2m9s
All checks were successful
CI / verify (push) Successful in 2m9s
Follows the tikz pattern: the fence emits a base64 placeholder, then the post-render hook lazily imports the parser and grid (separate chunks) and mounts the grid only when a placeholder exists. Mono font forced on the block because the flag-stacking math assumes Fira Code.
This commit is contained in:
40
src/modules/macroplan/runMacroplan.spec.ts
Normal file
40
src/modules/macroplan/runMacroplan.spec.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { describe, expect, it } from "vitest"
|
||||
|
||||
import { encodeUTF8ToBase64 } from "@/utils/decodeBase64ToUTF8"
|
||||
|
||||
import { runMacroplan } from "./runMacroplan"
|
||||
|
||||
const placeholder = (source: string): HTMLElement => {
|
||||
const el = document.createElement("div")
|
||||
el.className = "macroplan-block"
|
||||
el.dataset.macroplanSource = encodeUTF8ToBase64(source)
|
||||
document.body.appendChild(el)
|
||||
return el
|
||||
}
|
||||
|
||||
describe("runMacroplan", () => {
|
||||
it("mounts the grid onto a valid placeholder", async () => {
|
||||
const el = placeholder(
|
||||
'title = "Plan"\n\n[[feature]]\nname = "Auth"\nstart = 2026-06-01\noriginal = 2026-06-15\n'
|
||||
)
|
||||
|
||||
await runMacroplan(".macroplan-block")
|
||||
|
||||
expect(el.dataset.macroplanRendered).toBe("true")
|
||||
expect(el.querySelector(".macroplan")).not.toBeNull()
|
||||
expect(el.textContent).toContain("Auth")
|
||||
el.remove()
|
||||
})
|
||||
|
||||
it("renders the parse error inline for malformed sources", async () => {
|
||||
const el = placeholder('[[feature]]\nname = "No dates"')
|
||||
|
||||
await runMacroplan(".macroplan-block")
|
||||
|
||||
expect(el.dataset.macroplanRendered).toBe("error")
|
||||
expect(el.querySelector(".macroplan-error")?.textContent).toContain(
|
||||
"missing `start`"
|
||||
)
|
||||
el.remove()
|
||||
})
|
||||
})
|
||||
55
src/modules/macroplan/runMacroplan.ts
Normal file
55
src/modules/macroplan/runMacroplan.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { createApp } from "vue"
|
||||
|
||||
import { decodeBase64ToUTF8 } from "@/utils/decodeBase64ToUTF8"
|
||||
|
||||
const renderMacroplanError = (el: HTMLElement, err: unknown): void => {
|
||||
const msg = err instanceof Error ? err.message : String(err)
|
||||
el.textContent = ""
|
||||
const box = document.createElement("div")
|
||||
box.className = "macroplan-error"
|
||||
const title = document.createElement("strong")
|
||||
title.textContent = "Macroplan error"
|
||||
const detail = document.createElement("pre")
|
||||
detail.textContent = msg
|
||||
box.append(title, detail)
|
||||
el.appendChild(box)
|
||||
}
|
||||
|
||||
/**
|
||||
* Mount a MacroplanGrid onto every ```macroplan placeholder in scope.
|
||||
* The parser (smol-toml + valibot) and the grid component only load
|
||||
* when a placeholder actually exists, so notes without a plan pay nothing.
|
||||
*/
|
||||
export const runMacroplan = async (querySelector: string): Promise<void> => {
|
||||
const elements = Array.from(
|
||||
document.querySelectorAll<HTMLElement>(querySelector)
|
||||
).filter((el) => !el.dataset.macroplanRendered)
|
||||
if (elements.length === 0) return
|
||||
|
||||
const [{ parseMacroplan }, { buildPlan }, { default: MacroplanGrid }] =
|
||||
await Promise.all([
|
||||
import("./model/parse"),
|
||||
import("./model/plan"),
|
||||
import("./components/MacroplanGrid.vue")
|
||||
])
|
||||
|
||||
for (const el of elements) {
|
||||
el.dataset.macroplanRendered = "pending"
|
||||
|
||||
const encoded = el.dataset.macroplanSource
|
||||
if (!encoded) {
|
||||
el.dataset.macroplanRendered = "error"
|
||||
continue
|
||||
}
|
||||
|
||||
try {
|
||||
const plan = buildPlan(parseMacroplan(decodeBase64ToUTF8(encoded)))
|
||||
el.textContent = ""
|
||||
createApp(MacroplanGrid, { plan }).mount(el)
|
||||
el.dataset.macroplanRendered = "true"
|
||||
} catch (err) {
|
||||
renderMacroplanError(el, err)
|
||||
el.dataset.macroplanRendered = "error"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user