@docubook/flame 2.0.0-alpha.0 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docu/components/Pagination.tsx +9 -1
- package/.docu/components/Toc.tsx +3 -3
- package/.docu/lib/build.deno.js +3 -3
- package/.docu/lib/{build.impl-WR24HDUT.js → build.impl-VXB4KL4D.js} +3 -3
- package/.docu/lib/build.node.js +3 -3
- package/.docu/lib/{chunk-X7KPVCDN.js → chunk-7PRQ3RQB.js} +1 -1
- package/.docu/lib/{chunk-VPV7KP7K.js → chunk-A6FIEG3H.js} +7 -3
- package/.docu/lib/{chunk-AJV2GEDF.js → chunk-JRERMREW.js} +1 -1
- package/.docu/lib/{chunk-KEWRVASF.js → chunk-LZDEWK25.js} +1 -1
- package/.docu/lib/{chunk-2EYRWRDP.js → chunk-MQWWCO6O.js} +6 -3
- package/.docu/lib/{chunk-QPF4DPZQ.js → chunk-TRT6WQZG.js} +54 -8
- package/.docu/lib/clean.js +1 -1
- package/.docu/lib/deploy.deno.js +1 -1
- package/.docu/lib/deploy.node.js +1 -1
- package/.docu/lib/preview.deno.js +2 -2
- package/.docu/lib/preview.node.js +2 -2
- package/.docu/lib/server.deno.js +3 -3
- package/.docu/lib/server.node.js +3 -3
- package/.docu/node/build.impl.ts +3 -0
- package/.docu/node/build.ts +3 -0
- package/.docu/node/html.shared.ts +7 -2
- package/.docu/node/html.ts +4 -2
- package/.docu/node/route.ts +57 -1
- package/.docu/node/server-routes.ts +4 -0
- package/.docu/styles/globals.css +9 -0
- package/package.json +5 -5
- package/template/README.md +1 -1
- package/template/docs/getting-started/configuration.mdx +16 -4
- package/template/docs/getting-started/overview.mdx +34 -42
- package/template/docs/guide/components.mdx +46 -228
- package/template/docs/guide/routing.mdx +8 -6
- package/template/docs/index.mdx +9 -8
- package/template/docu.json +4 -4
|
@@ -29,7 +29,15 @@ export default function Pagination({
|
|
|
29
29
|
return (
|
|
30
30
|
<PaginationDocs
|
|
31
31
|
prev={prev ? { href: docsHtmlHref(`/docs${prev.href}`), title: prev.title } : undefined}
|
|
32
|
-
next={
|
|
32
|
+
next={
|
|
33
|
+
next
|
|
34
|
+
? {
|
|
35
|
+
href: docsHtmlHref(`/docs${next.href}`),
|
|
36
|
+
title: next.title,
|
|
37
|
+
description: next.description,
|
|
38
|
+
}
|
|
39
|
+
: undefined
|
|
40
|
+
}
|
|
33
41
|
className={className}
|
|
34
42
|
prevIcon={prevIcon}
|
|
35
43
|
nextIcon={nextIcon}
|
package/.docu/components/Toc.tsx
CHANGED
|
@@ -25,12 +25,12 @@ export default function Toc({ tocs }: TocProps) {
|
|
|
25
25
|
// CSS scroll-margin-top (prose-headings:scroll-mt-4 desktop /
|
|
26
26
|
// scroll-mt-16 mobile) so a change in one place updates both, and the
|
|
27
27
|
// heading lands exactly where the browser would put a native anchor jump.
|
|
28
|
-
|
|
28
|
+
const getAnchorOffset = useCallback((): number => {
|
|
29
29
|
if (typeof window === "undefined") return 100;
|
|
30
30
|
const first = tocs[0] ? document.getElementById(tocs[0].href.slice(1)) : null;
|
|
31
31
|
const margin = first ? parseFloat(getComputedStyle(first).scrollMarginTop) : 0;
|
|
32
32
|
return margin || 100;
|
|
33
|
-
}
|
|
33
|
+
}, [tocs]);
|
|
34
34
|
|
|
35
35
|
useEffect(() => {
|
|
36
36
|
// Desktop-only TOC — on mobile this island is display:none but still
|
|
@@ -88,7 +88,7 @@ export default function Toc({ tocs }: TocProps) {
|
|
|
88
88
|
scrollTarget.removeEventListener("scroll", listener);
|
|
89
89
|
if (throttleTimer) clearTimeout(throttleTimer);
|
|
90
90
|
};
|
|
91
|
-
}, [tocs]);
|
|
91
|
+
}, [tocs, getAnchorOffset]);
|
|
92
92
|
|
|
93
93
|
const handleLinkClick = useCallback((id: string) => {
|
|
94
94
|
clickedIdRef.current = id;
|
package/.docu/lib/build.deno.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runBuildCli
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-MQWWCO6O.js";
|
|
4
|
+
import "./chunk-TRT6WQZG.js";
|
|
5
5
|
import "./chunk-EOK6KATZ.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-JRERMREW.js";
|
|
7
7
|
import "./chunk-4IQXHHPF.js";
|
|
8
8
|
|
|
9
9
|
// .docu/node/build.deno.ts
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runBuild,
|
|
3
3
|
runBuildCli
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-MQWWCO6O.js";
|
|
5
|
+
import "./chunk-TRT6WQZG.js";
|
|
6
6
|
import "./chunk-EOK6KATZ.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-JRERMREW.js";
|
|
8
8
|
import "./chunk-4IQXHHPF.js";
|
|
9
9
|
export {
|
|
10
10
|
runBuild,
|
package/.docu/lib/build.node.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runBuildCli
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-MQWWCO6O.js";
|
|
4
|
+
import "./chunk-TRT6WQZG.js";
|
|
5
5
|
import "./chunk-EOK6KATZ.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-JRERMREW.js";
|
|
7
7
|
import "./chunk-4IQXHHPF.js";
|
|
8
8
|
|
|
9
9
|
// .docu/node/build.node.ts
|
|
@@ -137,7 +137,7 @@ async function runBuild() {
|
|
|
137
137
|
process.env.FLAME_BUILD_SILENT = "1";
|
|
138
138
|
process.env.LOG_LEVEL = "error";
|
|
139
139
|
}
|
|
140
|
-
const { runBuildCli } = await import("./build.impl-
|
|
140
|
+
const { runBuildCli } = await import("./build.impl-VXB4KL4D.js");
|
|
141
141
|
await runBuildCli();
|
|
142
142
|
}
|
|
143
143
|
async function writeDockerFiles() {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
htmlShell,
|
|
16
16
|
initSentry,
|
|
17
17
|
loadPlugins
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-TRT6WQZG.js";
|
|
19
19
|
import {
|
|
20
20
|
SECURITY_HEADERS,
|
|
21
21
|
generateNonce,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
} from "./chunk-EOK6KATZ.js";
|
|
29
29
|
import {
|
|
30
30
|
logger
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-JRERMREW.js";
|
|
32
32
|
import {
|
|
33
33
|
DIST_DIR,
|
|
34
34
|
DOCS_DIR,
|
|
@@ -60,7 +60,11 @@ function createHtmlResponse(title, description, body, status, state, depth = 0)
|
|
|
60
60
|
nonce,
|
|
61
61
|
extraScripts: hmrScript(nonce),
|
|
62
62
|
themeCss: state.inlineThemeCss,
|
|
63
|
-
depth
|
|
63
|
+
depth,
|
|
64
|
+
// 404 pages can be requested at arbitrary depths (e.g. a noLink section
|
|
65
|
+
// path typed in the address bar) — relative asset paths would resolve
|
|
66
|
+
// against the wrong directory and break CSS/JS.
|
|
67
|
+
absoluteAssets: status === 404
|
|
64
68
|
});
|
|
65
69
|
return htmlResponse(html, nonce, status, true);
|
|
66
70
|
}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
// package.json
|
|
6
6
|
var package_default = {
|
|
7
7
|
name: "@docubook/flame",
|
|
8
|
-
version: "2.0.0-alpha.
|
|
8
|
+
version: "2.0.0-alpha.1",
|
|
9
9
|
description: "A blazing-fast React + MDX framework powered by Bun, built for modern documentation experiences.",
|
|
10
10
|
type: "module",
|
|
11
11
|
bin: {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
htmlShell,
|
|
16
16
|
initSentry,
|
|
17
17
|
loadPlugins
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-TRT6WQZG.js";
|
|
19
19
|
import {
|
|
20
20
|
cspHeader,
|
|
21
21
|
generateNonce,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "./chunk-EOK6KATZ.js";
|
|
24
24
|
import {
|
|
25
25
|
logger
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-JRERMREW.js";
|
|
27
27
|
import {
|
|
28
28
|
ASSETS_DIR,
|
|
29
29
|
CACHE_FILE,
|
|
@@ -398,7 +398,10 @@ async function runBuild() {
|
|
|
398
398
|
css: assetManifest.css,
|
|
399
399
|
js: assetManifest.js,
|
|
400
400
|
nonce: notFoundNonce,
|
|
401
|
-
themeCss: inlineThemeCss
|
|
401
|
+
themeCss: inlineThemeCss,
|
|
402
|
+
// Served as the static-host fallback at ANY requested path — relative
|
|
403
|
+
// depth can never be right there, so use root-absolute asset URLs.
|
|
404
|
+
absoluteAssets: true
|
|
402
405
|
});
|
|
403
406
|
await writeFile(join(DIST_DIR, "404.html"), notFoundHtml);
|
|
404
407
|
logger.spinner.stop(
|
|
@@ -1333,6 +1333,9 @@ function DocsBreadcrumb({ paths }) {
|
|
|
1333
1333
|
}
|
|
1334
1334
|
|
|
1335
1335
|
// .docu/node/route.ts
|
|
1336
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
1337
|
+
import { join as join4 } from "node:path";
|
|
1338
|
+
import { extractFrontmatter } from "@docubook/core";
|
|
1336
1339
|
var docuConfig2 = loadDocuConfig();
|
|
1337
1340
|
var routes = resolveRoutes(docuConfig2.routes);
|
|
1338
1341
|
function flattenRoutes() {
|
|
@@ -1361,8 +1364,42 @@ function getRouteMap() {
|
|
|
1361
1364
|
routes.forEach((route) => traverse(route));
|
|
1362
1365
|
return map;
|
|
1363
1366
|
}
|
|
1367
|
+
var descriptionCache = /* @__PURE__ */ new Map();
|
|
1368
|
+
function readDescription(href) {
|
|
1369
|
+
const cached = descriptionCache.get(href);
|
|
1370
|
+
if (cached !== void 0) return cached;
|
|
1371
|
+
let description = "";
|
|
1372
|
+
const rel = href.replace(/^\/|$/g, "");
|
|
1373
|
+
for (const ext of [".mdx", ".md"]) {
|
|
1374
|
+
for (const file of [join4(DOCS_DIR, `${rel}${ext}`), join4(DOCS_DIR, `${rel}/index${ext}`)]) {
|
|
1375
|
+
try {
|
|
1376
|
+
const fm = extractFrontmatter(readFileSync2(file, "utf-8"));
|
|
1377
|
+
description = typeof fm.description === "string" ? fm.description : "";
|
|
1378
|
+
if (description) break;
|
|
1379
|
+
} catch {
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
if (description) break;
|
|
1383
|
+
}
|
|
1384
|
+
descriptionCache.set(href, description);
|
|
1385
|
+
return description;
|
|
1386
|
+
}
|
|
1364
1387
|
function getPreviousNext(pathname) {
|
|
1365
1388
|
const normalizedPath = pathname.replace(/^\/|$/g, "");
|
|
1389
|
+
if (normalizedPath === "docs" || normalizedPath === "") {
|
|
1390
|
+
const paths2 = flattenRoutes();
|
|
1391
|
+
const routeMap2 = getRouteMap();
|
|
1392
|
+
const first = paths2[0];
|
|
1393
|
+
if (!first) return { prev: null, next: null };
|
|
1394
|
+
return {
|
|
1395
|
+
prev: null,
|
|
1396
|
+
next: {
|
|
1397
|
+
href: first,
|
|
1398
|
+
title: routeMap2.get(first) || "",
|
|
1399
|
+
description: readDescription(first)
|
|
1400
|
+
}
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1366
1403
|
const paths = flattenRoutes();
|
|
1367
1404
|
const index = paths.findIndex((href) => href === `/${normalizedPath}` || href === normalizedPath);
|
|
1368
1405
|
if (index === -1) {
|
|
@@ -1373,7 +1410,11 @@ function getPreviousNext(pathname) {
|
|
|
1373
1410
|
const nextHref = index < paths.length - 1 ? paths[index + 1] : null;
|
|
1374
1411
|
return {
|
|
1375
1412
|
prev: prevHref ? { href: prevHref, title: routeMap.get(prevHref) || "" } : null,
|
|
1376
|
-
next: nextHref ? {
|
|
1413
|
+
next: nextHref ? {
|
|
1414
|
+
href: nextHref,
|
|
1415
|
+
title: routeMap.get(nextHref) || "",
|
|
1416
|
+
description: readDescription(nextHref)
|
|
1417
|
+
} : null
|
|
1377
1418
|
};
|
|
1378
1419
|
}
|
|
1379
1420
|
|
|
@@ -1395,7 +1436,11 @@ function Pagination({
|
|
|
1395
1436
|
PaginationDocs,
|
|
1396
1437
|
{
|
|
1397
1438
|
prev: prev ? { href: docsHtmlHref(`/docs${prev.href}`), title: prev.title } : void 0,
|
|
1398
|
-
next: next ? {
|
|
1439
|
+
next: next ? {
|
|
1440
|
+
href: docsHtmlHref(`/docs${next.href}`),
|
|
1441
|
+
title: next.title,
|
|
1442
|
+
description: next.description
|
|
1443
|
+
} : void 0,
|
|
1399
1444
|
className,
|
|
1400
1445
|
prevIcon,
|
|
1401
1446
|
nextIcon,
|
|
@@ -1671,12 +1716,12 @@ function Toc({ tocs }) {
|
|
|
1671
1716
|
useEffect2(() => {
|
|
1672
1717
|
activeIdRef.current = activeId;
|
|
1673
1718
|
}, [activeId]);
|
|
1674
|
-
|
|
1719
|
+
const getAnchorOffset = useCallback2(() => {
|
|
1675
1720
|
if (typeof window === "undefined") return 100;
|
|
1676
1721
|
const first = tocs[0] ? document.getElementById(tocs[0].href.slice(1)) : null;
|
|
1677
1722
|
const margin = first ? parseFloat(getComputedStyle(first).scrollMarginTop) : 0;
|
|
1678
1723
|
return margin || 100;
|
|
1679
|
-
}
|
|
1724
|
+
}, [tocs]);
|
|
1680
1725
|
useEffect2(() => {
|
|
1681
1726
|
if (typeof window === "undefined" || window.innerWidth < 1024) return;
|
|
1682
1727
|
if (!tocs.length) return;
|
|
@@ -1717,7 +1762,7 @@ function Toc({ tocs }) {
|
|
|
1717
1762
|
scrollTarget.removeEventListener("scroll", listener);
|
|
1718
1763
|
if (throttleTimer) clearTimeout(throttleTimer);
|
|
1719
1764
|
};
|
|
1720
|
-
}, [tocs]);
|
|
1765
|
+
}, [tocs, getAnchorOffset]);
|
|
1721
1766
|
const handleLinkClick = useCallback2((id) => {
|
|
1722
1767
|
clickedIdRef.current = id;
|
|
1723
1768
|
setActiveId(id);
|
|
@@ -2475,7 +2520,8 @@ function htmlShell(opts) {
|
|
|
2475
2520
|
themeCss,
|
|
2476
2521
|
depth = 0,
|
|
2477
2522
|
headExtra,
|
|
2478
|
-
bodyExtra
|
|
2523
|
+
bodyExtra,
|
|
2524
|
+
absoluteAssets = false
|
|
2479
2525
|
} = opts;
|
|
2480
2526
|
const nonceAttr = nonce ? ` nonce="${escapeHtml(nonce)}"` : "";
|
|
2481
2527
|
const themeStyle = themeCss ? `
|
|
@@ -2485,8 +2531,8 @@ function htmlShell(opts) {
|
|
|
2485
2531
|
const bodyInjection = bodyExtra?.length ? `
|
|
2486
2532
|
${bodyExtra.join("\n ")}` : "";
|
|
2487
2533
|
const depthPrefix = depth === 0 ? "" : "../".repeat(depth);
|
|
2488
|
-
const assetPrefix = depthPrefix + "assets/";
|
|
2489
|
-
const resolvePath = (path) => path.startsWith("/") ? depthPrefix + path.slice(1) : path;
|
|
2534
|
+
const assetPrefix = absoluteAssets ? "/assets/" : depthPrefix + "assets/";
|
|
2535
|
+
const resolvePath = (path) => absoluteAssets ? path : path.startsWith("/") ? depthPrefix + path.slice(1) : path;
|
|
2490
2536
|
let seoTags = "";
|
|
2491
2537
|
if (opts.seo) {
|
|
2492
2538
|
const s = opts.seo;
|
package/.docu/lib/clean.js
CHANGED
package/.docu/lib/deploy.deno.js
CHANGED
package/.docu/lib/deploy.node.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runPreview
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LZDEWK25.js";
|
|
4
4
|
import {
|
|
5
5
|
denoAdapter
|
|
6
6
|
} from "./chunk-UISOJ4RW.js";
|
|
7
7
|
import "./chunk-EOK6KATZ.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-JRERMREW.js";
|
|
9
9
|
import "./chunk-4IQXHHPF.js";
|
|
10
10
|
|
|
11
11
|
// .docu/node/preview.deno.ts
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runPreview
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LZDEWK25.js";
|
|
4
4
|
import {
|
|
5
5
|
nodeAdapter
|
|
6
6
|
} from "./chunk-UISOJ4RW.js";
|
|
7
7
|
import "./chunk-EOK6KATZ.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-JRERMREW.js";
|
|
9
9
|
import "./chunk-4IQXHHPF.js";
|
|
10
10
|
|
|
11
11
|
// .docu/node/preview.node.ts
|
package/.docu/lib/server.deno.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runServer
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-A6FIEG3H.js";
|
|
4
|
+
import "./chunk-TRT6WQZG.js";
|
|
5
5
|
import {
|
|
6
6
|
denoAdapter
|
|
7
7
|
} from "./chunk-UISOJ4RW.js";
|
|
8
8
|
import "./chunk-EOK6KATZ.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-JRERMREW.js";
|
|
10
10
|
import "./chunk-4IQXHHPF.js";
|
|
11
11
|
|
|
12
12
|
// .docu/node/server.deno.ts
|
package/.docu/lib/server.node.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runServer
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-A6FIEG3H.js";
|
|
4
|
+
import "./chunk-TRT6WQZG.js";
|
|
5
5
|
import {
|
|
6
6
|
nodeAdapter
|
|
7
7
|
} from "./chunk-UISOJ4RW.js";
|
|
8
8
|
import "./chunk-EOK6KATZ.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-JRERMREW.js";
|
|
10
10
|
import "./chunk-4IQXHHPF.js";
|
|
11
11
|
|
|
12
12
|
// .docu/node/server.node.ts
|
package/.docu/node/build.impl.ts
CHANGED
|
@@ -436,6 +436,9 @@ export async function runBuild(): Promise<void> {
|
|
|
436
436
|
js: assetManifest.js,
|
|
437
437
|
nonce: notFoundNonce,
|
|
438
438
|
themeCss: inlineThemeCss,
|
|
439
|
+
// Served as the static-host fallback at ANY requested path — relative
|
|
440
|
+
// depth can never be right there, so use root-absolute asset URLs.
|
|
441
|
+
absoluteAssets: true,
|
|
439
442
|
});
|
|
440
443
|
await writeFile(join(DIST_DIR, "404.html"), notFoundHtml);
|
|
441
444
|
|
package/.docu/node/build.ts
CHANGED
|
@@ -418,6 +418,9 @@ async function build() {
|
|
|
418
418
|
js: assetManifest.js,
|
|
419
419
|
nonce: generateNonce(),
|
|
420
420
|
themeCss: inlineThemeCss,
|
|
421
|
+
// Served as the static-host fallback at ANY requested path — relative
|
|
422
|
+
// depth can never be right there, so use root-absolute asset URLs.
|
|
423
|
+
absoluteAssets: true,
|
|
421
424
|
});
|
|
422
425
|
await writeFile(join(DIST_DIR, "404.html"), notFoundHtml);
|
|
423
426
|
|
|
@@ -34,6 +34,9 @@ export interface HtmlShellOptions {
|
|
|
34
34
|
bodyExtra?: string[];
|
|
35
35
|
/** SEO meta tags derived from config + frontmatter */
|
|
36
36
|
seo?: SeoMeta;
|
|
37
|
+
/** Root-absolute asset URLs (`/assets/...`). Required for pages served at
|
|
38
|
+
* arbitrary paths (404 fallback) — relative depth is wrong there. */
|
|
39
|
+
absoluteAssets?: boolean;
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
export function htmlShell(opts: HtmlShellOptions): string {
|
|
@@ -51,14 +54,16 @@ export function htmlShell(opts: HtmlShellOptions): string {
|
|
|
51
54
|
depth = 0,
|
|
52
55
|
headExtra,
|
|
53
56
|
bodyExtra,
|
|
57
|
+
absoluteAssets = false,
|
|
54
58
|
} = opts;
|
|
55
59
|
const nonceAttr = nonce ? ` nonce="${escapeHtml(nonce)}"` : "";
|
|
56
60
|
const themeStyle = themeCss ? `\n <style${nonceAttr}>${escapeHtml(themeCss)}</style>` : "";
|
|
57
61
|
const headInjection = headExtra?.length ? `\n ${headExtra.join("\n ")}` : "";
|
|
58
62
|
const bodyInjection = bodyExtra?.length ? `\n ${bodyExtra.join("\n ")}` : "";
|
|
59
63
|
const depthPrefix = depth === 0 ? "" : "../".repeat(depth);
|
|
60
|
-
const assetPrefix = depthPrefix + "assets/";
|
|
61
|
-
const resolvePath = (path: string) =>
|
|
64
|
+
const assetPrefix = absoluteAssets ? "/assets/" : depthPrefix + "assets/";
|
|
65
|
+
const resolvePath = (path: string) =>
|
|
66
|
+
absoluteAssets ? path : path.startsWith("/") ? depthPrefix + path.slice(1) : path;
|
|
62
67
|
|
|
63
68
|
// Build SEO meta tags (OG, Twitter, canonical)
|
|
64
69
|
let seoTags = "";
|
package/.docu/node/html.ts
CHANGED
|
@@ -16,14 +16,16 @@ export function htmlShell(opts: HtmlShellOptions): string {
|
|
|
16
16
|
depth = 0,
|
|
17
17
|
headExtra,
|
|
18
18
|
bodyExtra,
|
|
19
|
+
absoluteAssets = false,
|
|
19
20
|
} = opts;
|
|
20
21
|
const nonceAttr = nonce ? ` nonce="${Bun.escapeHTML(nonce)}"` : "";
|
|
21
22
|
const themeStyle = themeCss ? `\n <style${nonceAttr}>${Bun.escapeHTML(themeCss)}</style>` : "";
|
|
22
23
|
const headInjection = headExtra?.length ? `\n ${headExtra.join("\n ")}` : "";
|
|
23
24
|
const bodyInjection = bodyExtra?.length ? `\n ${bodyExtra.join("\n ")}` : "";
|
|
24
25
|
const depthPrefix = depth === 0 ? "" : "../".repeat(depth);
|
|
25
|
-
const assetPrefix = depthPrefix + "assets/";
|
|
26
|
-
const resolvePath = (path: string) =>
|
|
26
|
+
const assetPrefix = absoluteAssets ? "/assets/" : depthPrefix + "assets/";
|
|
27
|
+
const resolvePath = (path: string) =>
|
|
28
|
+
absoluteAssets ? path : path.startsWith("/") ? depthPrefix + path.slice(1) : path;
|
|
27
29
|
|
|
28
30
|
// Build SEO meta tags (OG, Twitter, canonical)
|
|
29
31
|
let seoTags = "";
|
package/.docu/node/route.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { loadDocuConfig } from "./paths";
|
|
2
2
|
import type { DocuRoute } from "./types";
|
|
3
3
|
import { resolveRoutes } from "./fs-scanner";
|
|
4
|
+
import { DOCS_DIR } from "./paths";
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { extractFrontmatter } from "@docubook/core";
|
|
8
|
+
import type { Frontmatter } from "./mdx";
|
|
4
9
|
|
|
5
10
|
const docuConfig = loadDocuConfig();
|
|
6
11
|
export const routes: DocuRoute[] = resolveRoutes(docuConfig.routes);
|
|
@@ -41,8 +46,53 @@ export function getRouteMap(): Map<string, string> {
|
|
|
41
46
|
return map;
|
|
42
47
|
}
|
|
43
48
|
|
|
49
|
+
/** Build-time cache of href → frontmatter description (docs content is static). */
|
|
50
|
+
const descriptionCache = new Map<string, string>();
|
|
51
|
+
|
|
52
|
+
function readDescription(href: string): string {
|
|
53
|
+
const cached = descriptionCache.get(href);
|
|
54
|
+
if (cached !== undefined) return cached;
|
|
55
|
+
|
|
56
|
+
let description = "";
|
|
57
|
+
const rel = href.replace(/^\/|$/g, "");
|
|
58
|
+
for (const ext of [".mdx", ".md"]) {
|
|
59
|
+
for (const file of [join(DOCS_DIR, `${rel}${ext}`), join(DOCS_DIR, `${rel}/index${ext}`)]) {
|
|
60
|
+
try {
|
|
61
|
+
const fm = extractFrontmatter<Frontmatter>(readFileSync(file, "utf-8"));
|
|
62
|
+
description = typeof fm.description === "string" ? fm.description : "";
|
|
63
|
+
if (description) break;
|
|
64
|
+
} catch {
|
|
65
|
+
// not this file — try the next candidate
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (description) break;
|
|
69
|
+
}
|
|
70
|
+
descriptionCache.set(href, description);
|
|
71
|
+
return description;
|
|
72
|
+
}
|
|
73
|
+
|
|
44
74
|
export function getPreviousNext(pathname: string) {
|
|
45
75
|
const normalizedPath = pathname.replace(/^\/|$/g, "");
|
|
76
|
+
|
|
77
|
+
// Docs index (/docs — DocsPage renders with pathname "" from slug []):
|
|
78
|
+
// next-only navigation into the first docs page — never read the route
|
|
79
|
+
// backward from the index, so prev stays null even if a page sits before
|
|
80
|
+
// it in the route list.
|
|
81
|
+
if (normalizedPath === "docs" || normalizedPath === "") {
|
|
82
|
+
const paths = flattenRoutes();
|
|
83
|
+
const routeMap = getRouteMap();
|
|
84
|
+
const first = paths[0];
|
|
85
|
+
if (!first) return { prev: null, next: null };
|
|
86
|
+
return {
|
|
87
|
+
prev: null,
|
|
88
|
+
next: {
|
|
89
|
+
href: first,
|
|
90
|
+
title: routeMap.get(first) || "",
|
|
91
|
+
description: readDescription(first),
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
46
96
|
const paths = flattenRoutes();
|
|
47
97
|
|
|
48
98
|
const index = paths.findIndex((href) => href === `/${normalizedPath}` || href === normalizedPath);
|
|
@@ -57,7 +107,13 @@ export function getPreviousNext(pathname: string) {
|
|
|
57
107
|
|
|
58
108
|
return {
|
|
59
109
|
prev: prevHref ? { href: prevHref, title: routeMap.get(prevHref) || "" } : null,
|
|
60
|
-
next: nextHref
|
|
110
|
+
next: nextHref
|
|
111
|
+
? {
|
|
112
|
+
href: nextHref,
|
|
113
|
+
title: routeMap.get(nextHref) || "",
|
|
114
|
+
description: readDescription(nextHref),
|
|
115
|
+
}
|
|
116
|
+
: null,
|
|
61
117
|
};
|
|
62
118
|
}
|
|
63
119
|
|
|
@@ -44,6 +44,10 @@ function createHtmlResponse(
|
|
|
44
44
|
extraScripts: hmrScript(nonce),
|
|
45
45
|
themeCss: state.inlineThemeCss,
|
|
46
46
|
depth,
|
|
47
|
+
// 404 pages can be requested at arbitrary depths (e.g. a noLink section
|
|
48
|
+
// path typed in the address bar) — relative asset paths would resolve
|
|
49
|
+
// against the wrong directory and break CSS/JS.
|
|
50
|
+
absoluteAssets: status === 404,
|
|
47
51
|
});
|
|
48
52
|
/** Dev-only: serves compiledSource → MDXRemote eval path (no CSP in production). */
|
|
49
53
|
return htmlResponse(html, nonce, status, true);
|
package/.docu/styles/globals.css
CHANGED
|
@@ -9,6 +9,15 @@
|
|
|
9
9
|
@plugin "@tailwindcss/typography";
|
|
10
10
|
@source "../../.docu/components";
|
|
11
11
|
@source "../../.docu/pages";
|
|
12
|
+
@source "../../../ui-react/src";
|
|
13
|
+
|
|
14
|
+
/* daisyUI breadcrumbs underline every li child on hover (including plain
|
|
15
|
+
spans) — crumbs are not links, so strip the underline (and pointer cursor)
|
|
16
|
+
for non-anchor items; real anchors keep daisyUI's hover feedback. */
|
|
17
|
+
.breadcrumbs > ul > li > :not(a):hover {
|
|
18
|
+
text-decoration-line: none;
|
|
19
|
+
cursor: default;
|
|
20
|
+
}
|
|
12
21
|
@source inline(
|
|
13
22
|
"breadcrumbs collapse collapse-open collapse-close collapse-arrow collapse-plus collapse-title collapse-content"
|
|
14
23
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docubook/flame",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.1",
|
|
4
4
|
"description": "A blazing-fast React + MDX framework powered by Bun, built for modern documentation experiences.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -56,10 +56,10 @@
|
|
|
56
56
|
"react-dom": "^19.2.7",
|
|
57
57
|
"unified": "^11.0.0",
|
|
58
58
|
"zod": "^4.4.3",
|
|
59
|
-
"@docubook/core": "^2.0.0-alpha.
|
|
60
|
-
"@docubook/
|
|
61
|
-
"@docubook/
|
|
62
|
-
"@docubook/
|
|
59
|
+
"@docubook/core": "^2.0.0-alpha.1",
|
|
60
|
+
"@docubook/markdown": "^2.0.0-alpha.1",
|
|
61
|
+
"@docubook/themes-colors": "^2.0.0-alpha.1",
|
|
62
|
+
"@docubook/ui-react": "^2.0.0-alpha.1"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"@sentry/bun": "^10.0.0"
|
package/template/README.md
CHANGED
|
@@ -42,7 +42,7 @@ deno task dev
|
|
|
42
42
|
|
|
43
43
|
## Documentation
|
|
44
44
|
|
|
45
|
-
For the full documentation,
|
|
45
|
+
For the full documentation, visit **[www.docubook.pro](https://www.docubook.pro/)**
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
@@ -3,16 +3,28 @@ title: Configuration
|
|
|
3
3
|
description: docu.json reference — meta, navbar, themes, routes, and plugins.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
`docu.json` in
|
|
6
|
+
`docu.json` in the project root controls the whole site. It is validated against `docu.schema.json`.
|
|
7
|
+
|
|
8
|
+
## First edits
|
|
9
|
+
|
|
10
|
+
| What | Where |
|
|
11
|
+
|---|---|
|
|
12
|
+
| Site name & tagline | `meta.title`, `meta.description` |
|
|
13
|
+
| Brand in the header | `navbar.logoText` |
|
|
14
|
+
| Landing copy | `home.hero` — headline, description, actions |
|
|
15
|
+
| Colour preset | `themes.colors` — `default`, `freshlime`, `coffee` |
|
|
16
|
+
| Footer links | `footer.social` |
|
|
17
|
+
|
|
18
|
+
## Reference
|
|
7
19
|
|
|
8
20
|
| Field | Description |
|
|
9
21
|
|---|---|
|
|
10
22
|
| `meta` | Site title, description, favicon, base URL |
|
|
11
23
|
| `navbar` | Logo, navigation menu links |
|
|
12
|
-
| `home.hero` | Landing page hero
|
|
13
|
-
| `home.features` | Feature cards
|
|
24
|
+
| `home.hero` | Landing page hero — tagline, headline, actions |
|
|
25
|
+
| `home.features` | Feature cards — icon, title, description |
|
|
14
26
|
| `routes` | Sidebar navigation (auto-detected from `docs/` when empty) |
|
|
15
27
|
| `themes` | Colour preset or custom palette |
|
|
16
28
|
| `plugins` | Build/dev pipeline extensions |
|
|
17
29
|
|
|
18
|
-
|
|
30
|
+
This project's `docu.json` is a complete working example — edit it and the dev server applies the changes live.
|
|
@@ -1,50 +1,42 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Quick Start
|
|
3
|
-
description:
|
|
3
|
+
description: The Flame workflow — dev server, first edit, authoring, and build.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
deno task dev
|
|
38
|
-
```
|
|
39
|
-
</Tab>
|
|
40
|
-
</Tabs>
|
|
41
|
-
|
|
42
|
-
Open http://localhost:3000 — changes to `docs/` or `docu.json` hot-reload.
|
|
43
|
-
|
|
44
|
-
## Build for production
|
|
6
|
+
Your Flame project is ready — this is the workflow to make it yours.
|
|
7
|
+
|
|
8
|
+
## 1. Run the dev server
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
bun run dev # or: npm run dev / deno task dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Open http://localhost:3000 — edits to `docs/` and `docu.json` hot-reload instantly.
|
|
15
|
+
|
|
16
|
+
## 2. Make your first edit
|
|
17
|
+
|
|
18
|
+
Open `docs/getting-started/overview.mdx` (this file):
|
|
19
|
+
|
|
20
|
+
1. Change `title` and `description` in the frontmatter — the browser updates live
|
|
21
|
+
2. Add a heading below and save
|
|
22
|
+
3. New pages appear in the sidebar and search automatically
|
|
23
|
+
|
|
24
|
+
## 3. Author with directives
|
|
25
|
+
|
|
26
|
+
Content is plain markdown — components are directives, no JSX:
|
|
27
|
+
|
|
28
|
+
```md
|
|
29
|
+
:::tip
|
|
30
|
+
A callout — no JSX needed.
|
|
31
|
+
:::
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
See [Components](/docs/guide/components) for the full directive set.
|
|
35
|
+
|
|
36
|
+
## 4. Build for production
|
|
45
37
|
|
|
46
38
|
```bash
|
|
47
|
-
|
|
39
|
+
bun run build # or: npm run build / deno task build
|
|
48
40
|
```
|
|
49
41
|
|
|
50
|
-
|
|
42
|
+
Flat static HTML lands in `.docu/dist/` — deploy anywhere ([Deployment](/docs/guide/deployment)).
|
|
@@ -1,256 +1,74 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Components
|
|
3
|
-
description:
|
|
4
|
-
date: 2026-05-25
|
|
3
|
+
description: The directive syntax for built-in components — callouts, tabs, cards, code blocks, and more.
|
|
5
4
|
---
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
Components are **directives**, not JSX — content stays plain markdown. A few to get you started; the full reference lives at [docubook.pro/docs/components](https://www.docubook.pro/docs/components/accordion).
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
## Callout
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```jsx:filename.mdx
|
|
16
|
-
<Note type="tip" title="Tip">
|
|
17
|
-
This is a tip to suggests a helpful.
|
|
18
|
-
</Note>
|
|
19
|
-
<Note type="info" title="Info">
|
|
20
|
-
This is a general note to convey information to the user.
|
|
21
|
-
</Note>
|
|
22
|
-
<Note type="danger" title="Danger">
|
|
23
|
-
This is a danger alert to notify the user of a critical issue.
|
|
24
|
-
</Note>
|
|
25
|
-
<Note type="warning">
|
|
26
|
-
This note uses default title and default icon from its type.
|
|
27
|
-
</Note>
|
|
28
|
-
<Note type="success" title="Success">
|
|
29
|
-
This is a success message to inform the user of successful actions.
|
|
30
|
-
</Note>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Tabs
|
|
34
|
-
|
|
35
|
-
Organize content into switchable sections.
|
|
36
|
-
|
|
37
|
-
````jsx:filename.mdx
|
|
38
|
-
<Tabs className="pt-5 pb-1">
|
|
39
|
-
<Tab title="Java">
|
|
40
|
-
```java:HelloWorld.java
|
|
41
|
-
// HelloWorld.java
|
|
42
|
-
public class HelloWorld {
|
|
43
|
-
public static void main(String[] args) {
|
|
44
|
-
System.out.println("Hello, World!");
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
</Tab>
|
|
49
|
-
<Tab title="TypeScript">
|
|
50
|
-
```typescript:helloWorld.ts
|
|
51
|
-
// helloWorld.ts
|
|
52
|
-
function helloWorld(): void {
|
|
53
|
-
console.log("Hello, World!");
|
|
54
|
-
}
|
|
55
|
-
helloWorld();
|
|
56
|
-
```
|
|
57
|
-
</Tab>
|
|
58
|
-
</Tabs>
|
|
59
|
-
````
|
|
60
|
-
|
|
61
|
-
## Card
|
|
62
|
-
|
|
63
|
-
Display content in a compact card layout.
|
|
64
|
-
|
|
65
|
-
```jsx:filename.mdx
|
|
66
|
-
<Card title="Card with Link and icon" icon="Link" href="/docs/components/card-group">
|
|
67
|
-
This is how you use a card with an icon and a link. Clicking on this card
|
|
68
|
-
brings you to the Card Group page.
|
|
69
|
-
</Card>
|
|
10
|
+
```md
|
|
11
|
+
:::tip{title="Optional title"}
|
|
12
|
+
Callout content.
|
|
13
|
+
:::
|
|
70
14
|
```
|
|
71
15
|
|
|
72
|
-
|
|
16
|
+
Variants: `tip`, `info`, `warning`, `danger`, `success`.
|
|
73
17
|
|
|
74
|
-
|
|
18
|
+
## Code block with title
|
|
75
19
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
</Card>
|
|
81
|
-
<Card title="Heading 2" icon="Heading2">
|
|
82
|
-
This is an example of card content with columns.
|
|
83
|
-
</Card>
|
|
84
|
-
<Card title="Grid Card" icon="Grid" horizontal>
|
|
85
|
-
This is a horizontal card layout.
|
|
86
|
-
</Card>
|
|
87
|
-
<Card title="Horizontal Card" icon="Layout" horizontal>
|
|
88
|
-
This is a horizontal card layout.
|
|
89
|
-
</Card>
|
|
90
|
-
</Cards>
|
|
20
|
+
````md
|
|
21
|
+
```javascript:app.js showLineNumbers {2-3}
|
|
22
|
+
const docs = "markdown";
|
|
23
|
+
console.log(docs);
|
|
91
24
|
```
|
|
92
|
-
|
|
93
|
-
## Accordion
|
|
94
|
-
|
|
95
|
-
````markdown:filename.mdx
|
|
96
|
-
<Accordions>
|
|
97
|
-
<Accordion title="Basic Usage">
|
|
98
|
-
This accordion includes a [Lucide Icon](https://lucide.dev/icons/) because the `icon` prop is provided.
|
|
99
|
-
</Accordion>
|
|
100
|
-
|
|
101
|
-
<Accordion title="With icon props" icon="MousePointerClick">
|
|
102
|
-
This accordion includes a Lucide icon because the `icon` prop is provided.
|
|
103
|
-
</Accordion>
|
|
104
|
-
|
|
105
|
-
<Accordion title="With Code Block">
|
|
106
|
-
You can put other components inside Accordions.
|
|
107
|
-
```jsx:helloword.jsx
|
|
108
|
-
class HelloWorld {
|
|
109
|
-
public static void main(String[] args) {
|
|
110
|
-
System.out.println("Hello, World!");
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
</Accordion>
|
|
115
|
-
</Accordions>
|
|
116
25
|
````
|
|
117
26
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
Display step-by-step instructions.
|
|
121
|
-
|
|
122
|
-
````jsx:filename.mdx
|
|
123
|
-
<Steps>
|
|
124
|
-
<Step title="Step 1: Clone the DocuBook Repository">
|
|
125
|
-
```bash
|
|
126
|
-
git clone https://github.com/DocuBook/docubook.git
|
|
127
|
-
```
|
|
128
|
-
</Step>
|
|
129
|
-
<Step title="Step 2: Access the Project Directory">
|
|
130
|
-
```bash
|
|
131
|
-
cd docubook
|
|
132
|
-
```
|
|
133
|
-
</Step>
|
|
134
|
-
<Step title="Step 3: Install Required Dependencies">
|
|
135
|
-
```bash
|
|
136
|
-
pnpm install
|
|
137
|
-
```
|
|
138
|
-
</Step>
|
|
139
|
-
</Steps>
|
|
140
|
-
````
|
|
141
|
-
|
|
142
|
-
## Button
|
|
143
|
-
|
|
144
|
-
Styled buttons with icons.
|
|
145
|
-
|
|
146
|
-
```jsx
|
|
147
|
-
<Button
|
|
148
|
-
text="Learn More"
|
|
149
|
-
href="https://example.com"
|
|
150
|
-
icon="MoveUpRight"
|
|
151
|
-
size="md"
|
|
152
|
-
variant="secondary"
|
|
153
|
-
target="_blank"
|
|
154
|
-
/>
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## File Tree
|
|
158
|
-
|
|
159
|
-
Display hierarchical file structures.
|
|
160
|
-
|
|
161
|
-
```jsx
|
|
162
|
-
<Files>
|
|
163
|
-
<Folder name="src">
|
|
164
|
-
<File name="App.tsx" />
|
|
165
|
-
<File name="index.tsx" />
|
|
166
|
-
<Folder name="components">
|
|
167
|
-
<File name="Button.tsx" />
|
|
168
|
-
</Folder>
|
|
169
|
-
</Folder>
|
|
170
|
-
<File name="package.json" />
|
|
171
|
-
</Files>
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
## Code Block
|
|
175
|
-
|
|
176
|
-
Syntax-highlighted code with title and line highlighting.
|
|
27
|
+
The `:filename` suffix adds a title bar; `showLineNumbers` and `{2-3}` enable line numbers and highlighting.
|
|
177
28
|
|
|
178
|
-
|
|
179
|
-
```ts:server.ts {3-5}
|
|
180
|
-
import { serve } from "bun";
|
|
29
|
+
## Tabs
|
|
181
30
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
31
|
+
````md
|
|
32
|
+
::::tabs
|
|
33
|
+
:::tab{title="Bun"}
|
|
34
|
+
bun run dev
|
|
35
|
+
:::
|
|
36
|
+
:::tab{title="Node"}
|
|
37
|
+
npm run dev
|
|
38
|
+
:::
|
|
39
|
+
::::
|
|
187
40
|
````
|
|
188
41
|
|
|
189
|
-
##
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
42
|
+
## Card group
|
|
43
|
+
|
|
44
|
+
```md
|
|
45
|
+
::::cards{cols="2"}
|
|
46
|
+
:::card{title="First" icon="Heading1"}
|
|
47
|
+
Card content.
|
|
48
|
+
:::
|
|
49
|
+
:::card{title="Second" icon="Heading2"}
|
|
50
|
+
Card content.
|
|
51
|
+
:::
|
|
52
|
+
::::
|
|
195
53
|
```
|
|
196
54
|
|
|
197
|
-
##
|
|
198
|
-
|
|
199
|
-
Styled links with external indicator.
|
|
55
|
+
## Mermaid
|
|
200
56
|
|
|
201
|
-
```
|
|
202
|
-
|
|
57
|
+
```mermaid
|
|
58
|
+
flowchart LR
|
|
59
|
+
A --> B
|
|
203
60
|
```
|
|
204
61
|
|
|
205
|
-
##
|
|
206
|
-
|
|
207
|
-
Display keyboard shortcuts.
|
|
62
|
+
## Tooltip
|
|
208
63
|
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
<Kbd show="ctrl" /> + <Kbd show="v" />
|
|
212
|
-
|
|
213
|
-
{/* Mac style */}
|
|
214
|
-
<Kbd show="cmd" type="mac" /> + <Kbd show="v" type="mac" />
|
|
64
|
+
```md
|
|
65
|
+
Inline :tooltip[hover me]{tip="Extra details"}.
|
|
215
66
|
```
|
|
216
67
|
|
|
217
|
-
|
|
218
|
-
- Windows: <Kbd show="ctrl" type="window" /> + <Kbd show="v" type="window" />
|
|
219
|
-
- Mac: <Kbd show="cmd" type="mac" /> + <Kbd show="v" type="mac" />
|
|
220
|
-
|
|
221
|
-
## Tooltips
|
|
222
|
-
|
|
223
|
-
Hover tooltips for inline content.
|
|
68
|
+
## Youtube
|
|
224
69
|
|
|
225
|
-
```
|
|
226
|
-
|
|
70
|
+
```md
|
|
71
|
+
::youtube{videoId="OPM2t54T-Vo"}
|
|
227
72
|
```
|
|
228
73
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
Embed YouTube videos.
|
|
232
|
-
|
|
233
|
-
```markdown:filename.mdx
|
|
234
|
-
<Youtube videoId="OPM2t54T-Vo" />
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
> Usage
|
|
238
|
-
> for example the youtube URL show this https://www.youtube.com/watch?v=OPM2t54T-Vo
|
|
239
|
-
> the ID is `OPM2t54T-Vo`
|
|
240
|
-
|
|
241
|
-
## Release Note
|
|
242
|
-
|
|
243
|
-
Display changelog entries.
|
|
244
|
-
|
|
245
|
-
```markdown:filename.mdx
|
|
246
|
-
<Release version="1.10.1" date="2025-05-24" title="Accessibility Improvements and Bug Fixes">
|
|
247
|
-
<Changes type="added">
|
|
248
|
-
- New feature to improve accessibility
|
|
249
|
-
- Keyboard navigation support for dialog components
|
|
250
|
-
</Changes>
|
|
251
|
-
<Changes type="fixed">
|
|
252
|
-
- Bug fix for mobile menu
|
|
253
|
-
- Fixed loading issues on documentation pages
|
|
254
|
-
</Changes>
|
|
255
|
-
</Release>
|
|
256
|
-
```
|
|
74
|
+
> All directives render server-side to static HTML — no runtime JavaScript unless the component needs it.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Routing
|
|
3
|
-
description: How Flame maps
|
|
3
|
+
description: How Flame maps markdown files to static pages.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Flame uses **filesystem-based routing** — every
|
|
6
|
+
Flame uses **filesystem-based routing** — every markdown file in `docs/` compiles to a matching `.html` path:
|
|
7
7
|
|
|
8
8
|
```
|
|
9
9
|
docs/
|
|
@@ -16,10 +16,12 @@ docs/
|
|
|
16
16
|
└── routing.mdx → /docs/guide/routing.html
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Add a page
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
1. Create `docs/guide/faq.mdx`
|
|
22
|
+
2. Add frontmatter: `title` and `description`
|
|
23
|
+
3. Write markdown — the page appears in the sidebar and search automatically
|
|
22
24
|
|
|
23
|
-
##
|
|
25
|
+
## Sidebar order
|
|
24
26
|
|
|
25
|
-
Define `routes` in `docu.json` for a custom
|
|
27
|
+
When `routes: []`, Flame scans `docs/` and builds the sidebar from the directory structure. Define `routes` in `docu.json` for a custom order and grouped sections — see this project's `docu.json` for a working example.
|
package/template/docs/index.mdx
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
3
|
-
description:
|
|
2
|
+
title: My Docs
|
|
3
|
+
description: Documentation powered by DocuBook Flame.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Welcome to **My Docs** — a static documentation site built with [DocuBook Flame](https://www.docubook.pro/).
|
|
7
|
+
|
|
8
|
+
Flame compiles the markdown in `docs/` into flat static HTML. No server, no database, no runtime — deploy anywhere.
|
|
7
9
|
|
|
8
10
|
```mermaid
|
|
9
|
-
flowchart
|
|
10
|
-
A[
|
|
11
|
-
B --> C[Static HTML + assets]
|
|
12
|
-
C --> D[Vercel
|
|
11
|
+
flowchart TD
|
|
12
|
+
A["docs/*.md"] --> B["flame build"]
|
|
13
|
+
B --> C["Static HTML + assets"]
|
|
14
|
+
C --> D["Vercel · Netlify · GitHub Pages · S3"]
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
Check the sidebar for guides on getting started, configuration, components, routing, and deployment.
|
package/template/docu.json
CHANGED
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
"favicon": "/docs/assets/images/favicon.ico",
|
|
8
8
|
"ogImage": "/docs/assets/images/og.png"
|
|
9
9
|
},
|
|
10
|
+
"sidebar": {
|
|
11
|
+
"context": "separator"
|
|
12
|
+
},
|
|
10
13
|
"themes": {
|
|
11
14
|
"colors": "default"
|
|
12
15
|
},
|
|
@@ -71,13 +74,10 @@
|
|
|
71
74
|
"social": []
|
|
72
75
|
},
|
|
73
76
|
"repo": {
|
|
74
|
-
"url": "",
|
|
77
|
+
"url": "https://github.com/DocuBook/docubook",
|
|
75
78
|
"path": "blob/main/{filePath}",
|
|
76
79
|
"edit": false
|
|
77
80
|
},
|
|
78
|
-
"sidebar": {
|
|
79
|
-
"context": "dropdown"
|
|
80
|
-
},
|
|
81
81
|
"routes": [
|
|
82
82
|
{
|
|
83
83
|
"title": "Getting Started",
|