diff --git a/apps/docs/scripts/build.ts b/apps/docs/scripts/build.ts
index f8d510e..4ddc19e 100644
--- a/apps/docs/scripts/build.ts
+++ b/apps/docs/scripts/build.ts
@@ -3,6 +3,7 @@ import { join } from "node:path"
import { $ } from "bun"
import { appRoot, loadPages } from "./content"
+import { appRoot, loadPages, slugifyHeading } from "./content"
await $`bun run ${join(appRoot, "scripts/check-content.ts")}`
await $`bun run ${join(appRoot, "scripts/check-links.ts")}`
@@ -37,15 +38,22 @@ function render(body: string) {
const blocks = body.split(/\n\n+/)
return blocks
.map((block) => {
- const heading = block.match(/^## (.+?)(?: \{#([a-z0-9-]+)\})?$/)
+ const heading = block.match(/^(#{2,6}) (.+?)(?: \{#([a-z0-9-]+)\})?$/)
if (heading) {
- const id =
- heading[2] ??
- heading[1]
- .toLowerCase()
- .replace(/[^a-z0-9]+/g, "-")
- .replace(/(^-|-$)/g, "")
- return `
${escape(heading[1])}
`
+ const level = heading[1].length
+ const title = heading[2]
+ const id = heading[3] ?? slugifyHeading(title)
+ return `#${escape(title)}`
+ }
+ if (block.startsWith("") && block.endsWith("")) {
+ const items = block
+ .slice("".length, -"".length)
+ .trim()
+ .split("\n")
+ .filter((line) => /^\d+\. /.test(line))
+ .map((line) => `${renderInline(line.replace(/^\d+\. /, ""))}`)
+ .join("")
+ return `${items}
`
}
if (block.startsWith("> "))
return ``
@@ -60,6 +68,10 @@ function render(body: string) {
}
await rm(outputRoot, { recursive: true, force: true })
+const themeBootstrap = ``
+const pageScript = ``
+await rm(outputRoot, { recursive: true, force: true })
+ const html = `${themeBootstrap}${escape(page.frontmatter.title)} ยท SO4 docs${escape(page.frontmatter.title)}
${render(page.body)}${pageScript}`
for (const page of pages) {
const directory = join(outputRoot, page.route.slice(1))
await mkdir(directory, { recursive: true })
diff --git a/apps/docs/scripts/content.ts b/apps/docs/scripts/content.ts
index c8a1357..cb4f0e5 100644
--- a/apps/docs/scripts/content.ts
+++ b/apps/docs/scripts/content.ts
@@ -80,9 +80,21 @@ export async function loadPages(): Promise> {
export function headingEntries(body: string) {
return [
...body.matchAll(
- /^## (.+?) \{#([a-z0-9-]+)\}\n\n([\s\S]*?)(?=\n\n## |$)/gm,
+ /^(#{2,6}) (.+?)(?: \{#([a-z0-9-]+)\})?$/gm,
),
- ].map(([, title, id, answer]) => ({ title, id, answer: answer.trim() }))
+ ].map(([, , title, explicitId]) => ({
+ title,
+ id: explicitId ?? slugifyHeading(title),
+ }))
+}
+
+export function slugifyHeading(title: string): string {
+ return title
+ .toLocaleLowerCase()
+ .normalize("NFKD")
+ .replace(/[\u0300-\u036f]/g, "")
+ .replace(/[^a-z0-9]+/g, "-")
+ .replace(/(^-|-$)/g, "")
}
export function internalLinks(body: string) {