init from template

This commit is contained in:
2026-08-03 15:47:35 -04:00
commit 32ef7db900
279 changed files with 44706 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
import { PageFrame, PageFrameProps } from "./types"
import HeaderConstructor from "../Header"
const Header = HeaderConstructor()
/**
* The default page frame — three-column layout with left sidebar, center
* content (header + body + afterBody), and right sidebar, followed by a footer.
*
* This is the original Quartz layout, extracted from renderPage.tsx.
*/
export const DefaultFrame: PageFrame = {
name: "default",
render({
componentData,
header,
beforeBody,
pageBody: Content,
afterBody,
left,
right,
footer,
}: PageFrameProps) {
return (
<>
<div class="left sidebar">
{left.map((BodyComponent) => (
<BodyComponent {...componentData} />
))}
</div>
<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>
<Content {...componentData} />
<hr />
<div class="page-footer">
{afterBody.map((BodyComponent) => (
<BodyComponent {...componentData} />
))}
</div>
</div>
<div class="right sidebar">
{right.map((BodyComponent) => (
<BodyComponent {...componentData} />
))}
</div>
{footer.map((FooterComponent) => (
<FooterComponent {...componentData} />
))}
</>
)
},
}
@@ -0,0 +1,53 @@
import { PageFrame, PageFrameProps } from "./types"
import HeaderConstructor from "../Header"
const Header = HeaderConstructor()
/**
* Full-width page frame — no sidebars. The center content area spans the
* full width of the page. Header, beforeBody, body, afterBody, and footer
* are all rendered in a single column.
*
* Useful for page types like Canvas, presentations, or dashboards that
* need maximum horizontal space.
*/
export const FullWidthFrame: PageFrame = {
name: "full-width",
render({
componentData,
header,
beforeBody,
pageBody: Content,
afterBody,
footer,
}: PageFrameProps) {
return (
<>
<div class="center full-width">
<div class="page-header">
<Header {...componentData}>
{header.map((HeaderComponent) => (
<HeaderComponent {...componentData} />
))}
</Header>
<div class="popover-hint">
{beforeBody.map((BodyComponent) => (
<BodyComponent {...componentData} />
))}
</div>
</div>
<Content {...componentData} />
<hr />
<div class="page-footer">
{afterBody.map((BodyComponent) => (
<BodyComponent {...componentData} />
))}
</div>
</div>
{footer.map((FooterComponent) => (
<FooterComponent {...componentData} />
))}
</>
)
},
}
+25
View File
@@ -0,0 +1,25 @@
import { PageFrame, PageFrameProps } from "./types"
/**
* Minimal page frame — no sidebars, no header/footer chrome. Only the
* page body is rendered with a thin wrapper, plus the footer for legal/link
* obligations.
*
* Useful for immersive page types like full-screen canvases, kiosks,
* or custom landing pages that want complete control of the viewport.
*/
export const MinimalFrame: PageFrame = {
name: "minimal",
render({ componentData, pageBody: Content, footer }: PageFrameProps) {
return (
<>
<div class="center minimal">
<Content {...componentData} />
</div>
{footer.map((FooterComponent) => (
<FooterComponent {...componentData} />
))}
</>
)
},
}
+41
View File
@@ -0,0 +1,41 @@
import test, { describe } from "node:test"
import assert from "node:assert"
import { resolveFrame, frameRegistry } from "./index"
import { DefaultFrame } from "./DefaultFrame"
import { FullWidthFrame } from "./FullWidthFrame"
import type { PageFrame } from "./types"
const customFrame: PageFrame = {
name: "custom-test-frame",
render: () => null as any,
}
describe("resolveFrame", () => {
test("returns DefaultFrame for undefined", () => {
assert.strictEqual(resolveFrame(undefined), DefaultFrame)
})
test("returns DefaultFrame for 'default'", () => {
assert.strictEqual(resolveFrame("default"), DefaultFrame)
})
test("returns named built-in frame", () => {
assert.strictEqual(resolveFrame("full-width"), FullWidthFrame)
})
test("returns DefaultFrame for unknown frame name", () => {
assert.strictEqual(resolveFrame("nonexistent"), DefaultFrame)
})
test("plugin-registered frame takes priority", () => {
frameRegistry.register("custom-test-frame", customFrame, "test-plugin")
const result = resolveFrame("custom-test-frame")
assert.strictEqual(result, customFrame)
})
test("returns DefaultFrame for unknown name even with plugin frames registered", () => {
frameRegistry.register("custom-test-frame", customFrame, "test-plugin")
const result = resolveFrame("totally-unknown")
assert.strictEqual(result, DefaultFrame)
})
})
+52
View File
@@ -0,0 +1,52 @@
import { PageFrame } from "./types"
import { DefaultFrame } from "./DefaultFrame"
import { FullWidthFrame } from "./FullWidthFrame"
import { MinimalFrame } from "./MinimalFrame"
import { frameRegistry } from "./registry"
export type { PageFrame, PageFrameProps } from "./types"
export { DefaultFrame } from "./DefaultFrame"
export { FullWidthFrame } from "./FullWidthFrame"
export { MinimalFrame } from "./MinimalFrame"
export { frameRegistry } from "./registry"
export type { RegisteredFrame } from "./registry"
/**
* Registry of built-in page frames. Page types can reference these by name
* via their `frame` property, and YAML config can override via
* `layout.byPageType.<name>.template`.
*
* The "default" frame reproduces the original three-column Quartz layout.
*/
const builtinFrames: Record<string, PageFrame> = {
default: DefaultFrame,
"full-width": FullWidthFrame,
minimal: MinimalFrame,
}
/**
* Resolve a frame by name. Checks plugin-registered frames first,
* then built-in frames, then falls back to DefaultFrame.
*/
export function resolveFrame(name: string | undefined): PageFrame {
if (!name || name === "default") {
return DefaultFrame
}
// Check plugin-registered frames first
const registered = frameRegistry.get(name)
if (registered) {
return registered.frame
}
// Fall back to built-in frames
const frame = builtinFrames[name]
if (!frame) {
const allFrameNames = [...Object.keys(builtinFrames), ...[...frameRegistry.getAll().keys()]]
console.warn(
`Unknown page frame "${name}", falling back to "default". Available frames: ${allFrameNames.join(", ")}`,
)
return DefaultFrame
}
return frame
}
+34
View File
@@ -0,0 +1,34 @@
import { PageFrame } from "./types"
export interface RegisteredFrame {
frame: PageFrame
source: string
}
class FrameRegistry {
private frames = new Map<string, RegisteredFrame>()
register(name: string, frame: PageFrame, source: string): void {
const existing = this.frames.get(name)
if (existing && existing.source !== source) {
console.warn(
`Page frame "${name}" from ${source} is overwriting frame from ${existing.source}`,
)
}
this.frames.set(name, { frame, source })
}
get(name: string): RegisteredFrame | undefined {
return this.frames.get(name)
}
getAll(): Map<string, RegisteredFrame> {
return new Map(this.frames)
}
has(name: string): boolean {
return this.frames.has(name)
}
}
export const frameRegistry = new FrameRegistry()
+43
View File
@@ -0,0 +1,43 @@
import { JSX } from "preact"
import { QuartzComponent, QuartzComponentProps } from "../types"
/**
* Props passed to a PageFrame's render function.
* Contains the resolved layout components and the shared component data.
*/
export interface PageFrameProps {
/** Component data shared across all components on the page */
componentData: QuartzComponentProps
/** The Head component (rendered in <head>) — NOT used by frames, included for completeness */
head: QuartzComponent
/** Header slot components (rendered inside <header>) */
header: QuartzComponent[]
/** Components rendered before the page body */
beforeBody: QuartzComponent[]
/** The page body component (Content) */
pageBody: QuartzComponent
/** Components rendered after the page body */
afterBody: QuartzComponent[]
/** Left sidebar components */
left: QuartzComponent[]
/** Right sidebar components */
right: QuartzComponent[]
/** Footer components */
footer: QuartzComponent[]
}
/**
* A PageFrame defines the inner HTML structure of a page inside the
* `<div id="quartz-root">` shell. Different frames can produce completely
* different layouts (e.g. with/without sidebars, horizontal scroll, etc.)
* while the outer shell (html, head, body, quartz-root) remains stable
* for SPA navigation.
*/
export interface PageFrame {
/** Unique name for this frame (e.g. "default", "full-width", "minimal") */
name: string
/** Render the inner page structure. Returns a JSX tree to be placed inside Body > #quartz-body. */
render: (props: PageFrameProps) => JSX.Element
/** Optional CSS string to include when this frame is active */
css?: string
}