Added layouts + routes

This commit is contained in:
2026-09-22 15:21:19 +02:00
parent 5cad56000c
commit 3f9574dce6
15 changed files with 331 additions and 23 deletions

View File

@@ -21,3 +21,6 @@ export function assertNoErrors(list: Diagnostic[]): void {
const errors = list.filter((d) => d.level === 'error').length
if (errors) throw new Error(`Content has ${errors} error(s):\n${formatDiagnostics(list)}`)
}
export const forEntry = (list: Diagnostic[], collection: string, id: string) =>
list.filter((d) => d.collection === collection && d.id === id)

33
src/lib/markdoc/index.ts Normal file
View File

@@ -0,0 +1,33 @@
import Markdoc from '@markdoc/markdoc'
import { createDiagnostics } from '../diagnostics'
import { createNodes } from './nodes'
import type { NodeState, Renderable, Rendered } from './types'
const LEVEL = {
critical: 'error',
error: 'error',
warning: 'warning',
} as const
export async function render({ collection, id, content }: Renderable): Promise<Rendered> {
const { node } = await content()
const state: NodeState = {
headings: [],
ids: new Set(),
}
const config = {
nodes: createNodes(state),
}
const problems = createDiagnostics()
for (const { lines, error } of Markdoc.validate(node, config)) {
const level = LEVEL[error.level as keyof typeof LEVEL]
if (level) problems[level](collection, id, `Line ${lines[0] + 1} : ${error.message}`)
}
return {
tree: Markdoc.transform(node, config),
headings: state.headings,
diagnostics: problems.list,
}
}

49
src/lib/markdoc/nodes.ts Normal file
View File

@@ -0,0 +1,49 @@
import Markdoc, { type Node, type Schema } from '@markdoc/markdoc'
import { slugify } from '../content/slug'
import type { NodeState } from './types'
const { Tag } = Markdoc
const textOf = (node: Node): string =>
node.type === 'text' || node.type === 'code'
? String(node.attributes.content ?? '')
: node.children.map(textOf).join('')
function uniqueId(text: string, ids: Set<string>): string {
const base = slugify(text) || 'section'
let id = base
for (let n = 2; ids.has(id); n++) id = `${base}-${n}`
ids.add(id)
return id
}
export function createNodes(state: NodeState): Record<string, Schema> {
return {
document: {
...Markdoc.nodes.document,
transform: (node, config) => node.transformChildren(config),
},
heading: {
...Markdoc.nodes.heading,
transform(node, config) {
const level = Number(node.attributes.level)
const text = textOf(node)
const id = uniqueId(text, state.ids)
state.headings.push({ id, level, text })
return new Tag(`h${level}`, { id }, node.transformChildren(config))
},
},
table: {
...Markdoc.nodes.table,
transform(node, config) {
const table = new Tag(
'table',
node.transformAttributes(config),
node.transformChildren(config),
)
return new Tag('div', { class: 'table-scroll', tabindex: 0 }, [table])
},
},
}
}

26
src/lib/markdoc/types.ts Normal file
View File

@@ -0,0 +1,26 @@
import type { Node, RenderableTreeNode } from '@markdoc/markdoc'
import type { Diagnostic } from '../diagnostics/types'
export type Heading = {
id: string
level: number
text: string
}
export type NodeState = {
headings: Heading[]
ids: Set<string>
}
export type Rendered = {
tree: RenderableTreeNode
headings: Heading[]
diagnostics: Diagnostic[]
}
export type Renderable = {
collection: string
id: string
content: () => Promise<{ node: Node }>
}