Added definition list block and code block

This commit is contained in:
2026-09-30 11:00:47 +02:00
parent e40463dfd3
commit 9aa43737d2
24 changed files with 492 additions and 53 deletions

View File

@@ -0,0 +1,11 @@
export const TERM_KINDS = [
{ label: 'Entry', value: 'entry' },
{ label: 'Prime', value: 'prime' },
{ label: 'Essence', value: 'essence' },
{ label: 'Element', value: 'element' },
{ label: 'Stage', value: 'stage' },
{ label: 'Tier', value: 'tier' },
{ label: 'Premise', value: 'premise' },
] as const
export type TermKind = (typeof TERM_KINDS)[number]['value']

View File

@@ -0,0 +1,38 @@
import { createHighlighter, type Highlighter } from 'shiki'
const THEMES = { light: 'github-light', dark: 'github-dark' } as const
const LANGS = [
'astro',
'bash',
'css',
'diff',
'html',
'ini',
'js',
'json',
'jsonc',
'jsx',
'md',
'python',
'sql',
'ts',
'tsx',
'xml',
'yaml',
]
export type Highlight = (code: string, lang: string) => string | null
let ready: Promise<Highlighter> | null = null
export async function createHighlight(): Promise<Highlight> {
ready ??= createHighlighter({ themes: Object.values(THEMES), langs: LANGS })
const highlighter = await ready
const loaded = new Set(highlighter.getLoadedLanguages())
return (code, lang) =>
loaded.has(lang)
? highlighter.codeToHtml(code, { lang, themes: THEMES, defaultColor: false })
: null
}

View File

@@ -1,6 +1,7 @@
import Markdoc from '@markdoc/markdoc'
import { createDiagnostics } from '../diagnostics'
import { createHighlight } from './highlight'
import { createNodes } from './nodes'
import { createTags } from './tags'
import type { NodeState, Renderable, Rendered, ResolveLink } from './types'
@@ -21,11 +22,13 @@ export async function render(
ids: new Set(),
footnotes: [],
sidenoteCount: 0,
spoilerCount: 0,
markers: new Set(),
problems: [],
}
const highlight = await createHighlight()
const config = {
nodes: createNodes(state),
nodes: createNodes(state, highlight),
tags: createTags(state, resolveLink),
}
const problems = createDiagnostics()

View File

@@ -1,6 +1,7 @@
import Markdoc, { type Node, type Schema } from '@markdoc/markdoc'
import { slugify } from '../content/slug'
import type { Highlight } from './highlight'
import type { NodeState } from './types'
const { Tag } = Markdoc
@@ -18,8 +19,27 @@ function uniqueId(text: string, ids: Set<string>): string {
return id
}
export function createNodes(state: NodeState): Record<string, Schema> {
export function createNodes(state: NodeState, highlight: Highlight): Record<string, Schema> {
return {
fence: {
...Markdoc.nodes.fence,
transform(node) {
/* transformAttributes renames `language` to `data-language`, so the
raw attribute is the honest source. The content carries a trailing
newline that would render as a blank last line. */
const lang = String(node.attributes.language ?? '').trim()
const code = String(node.attributes.content ?? '').replace(/\n$/, '')
const html = lang ? highlight(code, lang) : null
if (lang && !html)
state.problems.push({
level: 'warning',
message: `No highlighting for language "${lang}" — add it to LANGS in highlight.ts.`,
})
return new Tag('Code', { code, lang: lang || undefined, html: html ?? undefined }, [])
},
},
document: {
...Markdoc.nodes.document,
transform: (node, config) => node.transformChildren(config),

View File

@@ -60,6 +60,8 @@ const generated =
components: generalBlocks(ARTICLES),
render: {
tags: {
definitions: 'DefinitionList',
definition: 'Definition',
callout: 'Callout',
figure: 'Figure',
tableWrapper: 'TableWrapper',
@@ -84,6 +86,16 @@ export function createTags(state: NodeState, resolveLink: ResolveLink): Record<s
])
},
},
spoiler: {
...generated.spoiler,
transform(node, config) {
const id = `spoiler-${(state.spoilerCount += 1)}`
return new Tag('span', { class: 'spoiler' }, [
new Tag('input', { id, class: 'spoiler__toggle', type: 'checkbox' }, []),
new Tag('label', { class: 'spoiler__text', for: id }, node.transformChildren(config)),
])
},
},
sidenote: {
...generated.sidenote,
transform(node, config) {

View File

@@ -23,6 +23,7 @@ export type NodeState = {
ids: Set<string>
footnotes: Footnote[]
sidenoteCount: number
spoilerCount: number
markers: Set<string>
problems: Problem[]
}