@docubook/flame 1.5.2 → 1.5.4

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.
@@ -8,6 +8,8 @@
8
8
 
9
9
  import { escapeHtml } from "./escapeHtml";
10
10
 
11
+ import type { SeoMeta } from "./seo";
12
+
11
13
  export interface HtmlShellOptions {
12
14
  title: string;
13
15
  description: string;
@@ -30,6 +32,8 @@ export interface HtmlShellOptions {
30
32
  headExtra?: string[];
31
33
  /** HTML strings to inject before `</body>`, after the main script (from plugin `injectBody` hooks). */
32
34
  bodyExtra?: string[];
35
+ /** SEO meta tags derived from config + frontmatter */
36
+ seo?: SeoMeta;
33
37
  }
34
38
 
35
39
  export function htmlShell(opts: HtmlShellOptions): string {
@@ -55,6 +59,18 @@ export function htmlShell(opts: HtmlShellOptions): string {
55
59
  const depthPrefix = depth === 0 ? "" : "../".repeat(depth);
56
60
  const assetPrefix = depthPrefix + "assets/";
57
61
  const resolvePath = (path: string) => (path.startsWith("/") ? depthPrefix + path.slice(1) : path);
62
+
63
+ // Build SEO meta tags (OG, Twitter, canonical)
64
+ let seoTags = "";
65
+ if (opts.seo) {
66
+ const s = opts.seo;
67
+ const e = escapeHtml;
68
+ seoTags = `\n <meta property="og:title" content="${e(title)}" />\n <meta property="og:description" content="${e(description)}" />\n <meta property="og:url" content="${e(s.url)}" />\n <meta property="og:type" content="website" />\n <meta property="og:site_name" content="${e(s.siteName)}" />\n <meta name="twitter:card" content="summary_large_image" />\n <link rel="canonical" href="${e(s.url)}" />`;
69
+ if (s.image) {
70
+ seoTags += `\n <meta property="og:image" content="${e(s.image)}" />`;
71
+ }
72
+ }
73
+
58
74
  return `<!DOCTYPE html>
59
75
  <html lang="en">
60
76
  <head>
@@ -65,6 +81,7 @@ export function htmlShell(opts: HtmlShellOptions): string {
65
81
  ${favicon ? `<link rel="icon" type="image/x-icon" href="${escapeHtml(resolvePath(favicon))}">` : ""}${themeStyle}
66
82
  <link rel="stylesheet" href="${escapeHtml(assetPrefix + css)}">
67
83
  ${csp ? `<meta http-equiv="Content-Security-Policy" content="${escapeHtml(csp)}">` : ""}
84
+ ${seoTags}
68
85
  <script${nonceAttr}>try{if(localStorage.getItem("theme")==="dark")document.documentElement.classList.add("dark")}catch(e){}</script>${headInjection}
69
86
  </head>
70
87
  <body>
@@ -1,3 +1,5 @@
1
+ import type { SeoMeta } from "./seo";
2
+
1
3
  export interface HtmlShellOptions {
2
4
  title: string;
3
5
  description: string;
@@ -20,6 +22,8 @@ export interface HtmlShellOptions {
20
22
  headExtra?: string[];
21
23
  /** HTML strings to inject before `</body>`, after the main script (from plugin `injectBody` hooks). */
22
24
  bodyExtra?: string[];
25
+ /** SEO meta tags derived from config + frontmatter */
26
+ seo?: SeoMeta;
23
27
  }
24
28
 
25
29
  export function htmlShell(opts: HtmlShellOptions): string {
@@ -45,6 +49,18 @@ export function htmlShell(opts: HtmlShellOptions): string {
45
49
  const depthPrefix = depth === 0 ? "" : "../".repeat(depth);
46
50
  const assetPrefix = depthPrefix + "assets/";
47
51
  const resolvePath = (path: string) => (path.startsWith("/") ? depthPrefix + path.slice(1) : path);
52
+
53
+ // Build SEO meta tags (OG, Twitter, canonical)
54
+ let seoTags = "";
55
+ if (opts.seo) {
56
+ const s = opts.seo;
57
+ const e = Bun.escapeHTML;
58
+ seoTags = `\n <meta property="og:title" content="${e(title)}" />\n <meta property="og:description" content="${e(description)}" />\n <meta property="og:url" content="${e(s.url)}" />\n <meta property="og:type" content="website" />\n <meta property="og:site_name" content="${e(s.siteName)}" />\n <meta name="twitter:card" content="summary_large_image" />\n <link rel="canonical" href="${e(s.url)}" />`;
59
+ if (s.image) {
60
+ seoTags += `\n <meta property="og:image" content="${e(s.image)}" />`;
61
+ }
62
+ }
63
+
48
64
  return `<!DOCTYPE html>
49
65
  <html lang="en">
50
66
  <head>
@@ -55,6 +71,7 @@ export function htmlShell(opts: HtmlShellOptions): string {
55
71
  ${favicon ? `<link rel="icon" type="image/x-icon" href="${Bun.escapeHTML(resolvePath(favicon))}">` : ""}${themeStyle}
56
72
  <link rel="stylesheet" href="${Bun.escapeHTML(assetPrefix + css)}">
57
73
  ${csp ? `<meta http-equiv="Content-Security-Policy" content="${Bun.escapeHTML(csp)}">` : ""}
74
+ ${seoTags}
58
75
  <script${nonceAttr}>try{if(localStorage.getItem("theme")==="dark")document.documentElement.classList.add("dark")}catch(e){}</script>${headInjection}
59
76
  </head>
60
77
  <body>
@@ -0,0 +1,42 @@
1
+ import type { DocuConfig } from "./types";
2
+
3
+ export interface SeoMeta {
4
+ /** Absolute canonical URL */
5
+ url: string;
6
+ /** Site name for og:site_name */
7
+ siteName: string;
8
+ /** Absolute OG image URL (from frontmatter.image, if set) */
9
+ image?: string;
10
+ }
11
+
12
+ /**
13
+ * Build SEO metadata from config and per-page frontmatter.
14
+ * All fields are derived from existing data — no extra config required.
15
+ */
16
+ export function buildSeoMeta(
17
+ config: DocuConfig,
18
+ frontmatter: Record<string, unknown>,
19
+ slug: string
20
+ ): SeoMeta {
21
+ const baseURL = config.meta?.baseURL?.replace(/\/+$/, "") || "";
22
+ const url = slug ? `${baseURL}/docs/${slug}` : `${baseURL}/`;
23
+
24
+ const result: SeoMeta = {
25
+ url,
26
+ siteName: config.meta?.title || "",
27
+ };
28
+
29
+ // Per-page image from frontmatter, fallback to global default from config
30
+ const image =
31
+ (typeof frontmatter.image === "string" && frontmatter.image) || config.meta?.ogImage;
32
+ if (image) {
33
+ // Resolve using URL constructor — handles absolute, root-relative, and relative paths
34
+ try {
35
+ result.image = new URL(image, image.startsWith("/") ? baseURL : `${baseURL}/docs/`).href;
36
+ } catch {
37
+ result.image = image;
38
+ }
39
+ }
40
+
41
+ return result;
42
+ }
@@ -20,6 +20,8 @@ export interface DocuMeta {
20
20
  description: string;
21
21
  baseURL: string;
22
22
  favicon?: string;
23
+ /** Default OG image path (e.g. /docs/assets/images/og.png). Used when page frontmatter has no image. */
24
+ ogImage?: string;
23
25
  }
24
26
 
25
27
  export interface SocialLink {
@@ -50,50 +50,54 @@ export default function DocsPage({
50
50
  data-repo={repoUrl || ""}
51
51
  />
52
52
 
53
- <div className="w-full min-w-0 flex-[7] px-4 py-4 lg:px-8 lg:py-8">
54
- <DocsBreadcrumb paths={slug} />
55
- <Typography>
56
- <h1 className="-mt-0.5 text-3xl">{title}</h1>
57
- {description && (
58
- <p className="text-muted-foreground -mt-4 text-[16.5px]">{description}</p>
59
- )}
60
- <div id="mdx-content-island">{content}</div>
61
- {compiledSource && (
62
- <script
63
- id="mdx-compiled-source"
64
- type="application/json"
65
- dangerouslySetInnerHTML={{
66
- __html: JSON.stringify(compiledSource).replace(/<\//g, "\\u003C/"),
67
- }}
68
- />
69
- )}
70
- <div className="border-base-300 my-8 flex items-center border-b-2 border-dashed">
71
- <EditWith className="text-muted-foreground" filePath={filePath} />
72
- {date && (
73
- <p className="text-muted-foreground ml-auto text-[13px]">
74
- Last updated {formatDate2(date)}
75
- </p>
76
- )}
77
- </div>
78
- <Pagination
79
- pathname={pathname}
80
- prevIcon={<ChevronLeft className="h-3 w-3" />}
81
- nextIcon={<ChevronRight className="h-3 w-3" />}
82
- />
83
- <Footer />
84
- </Typography>
85
- </div>
86
-
87
- {/* Desktop TOC - SSR rendered */}
88
- {tocs.length > 0 && (
53
+ <div className="flex w-full flex-col lg:flex-row 2xl:mx-auto 2xl:max-w-[1300px]">
89
54
  <div
90
- id="toc-island"
91
- data-tocs={tocsJson}
92
- className="sticky top-4 hidden h-[calc(100vh-8rem)] min-w-[240px] flex-[3] self-start lg:flex lg:px-4 lg:py-6"
55
+ className={`w-full min-w-0 ${tocs.length > 0 ? "flex-[7]" : "mx-auto max-w-[820px]"} px-4 py-6 lg:px-12 lg:py-10`}
93
56
  >
94
- <Toc tocs={tocs} />
57
+ <DocsBreadcrumb paths={slug} />
58
+ <Typography>
59
+ <h1 className="-mt-0.5 text-3xl">{title}</h1>
60
+ {description && (
61
+ <p className="text-muted-foreground -mt-4 text-[16.5px]">{description}</p>
62
+ )}
63
+ <div id="mdx-content-island">{content}</div>
64
+ {compiledSource && (
65
+ <script
66
+ id="mdx-compiled-source"
67
+ type="application/json"
68
+ dangerouslySetInnerHTML={{
69
+ __html: JSON.stringify(compiledSource).replace(/<\//g, "\\u003C/"),
70
+ }}
71
+ />
72
+ )}
73
+ <div className="border-base-300 my-8 flex items-center border-b-2 border-dashed">
74
+ <EditWith className="text-muted-foreground" filePath={filePath} />
75
+ {date && (
76
+ <p className="text-muted-foreground ml-auto text-[13px]">
77
+ Last updated {formatDate2(date)}
78
+ </p>
79
+ )}
80
+ </div>
81
+ <Pagination
82
+ pathname={pathname}
83
+ prevIcon={<ChevronLeft className="h-3 w-3" />}
84
+ nextIcon={<ChevronRight className="h-3 w-3" />}
85
+ />
86
+ <Footer />
87
+ </Typography>
95
88
  </div>
96
- )}
89
+
90
+ {/* Desktop TOC - SSR rendered */}
91
+ {tocs.length > 0 && (
92
+ <div
93
+ id="toc-island"
94
+ data-tocs={tocsJson}
95
+ className="sticky top-4 hidden h-[calc(100vh-8rem)] min-w-[240px] flex-[3] self-start lg:flex lg:px-4 lg:py-6"
96
+ >
97
+ <Toc tocs={tocs} />
98
+ </div>
99
+ )}
100
+ </div>
97
101
  </div>
98
102
  </div>
99
103
  );
package/docu.schema.json CHANGED
@@ -15,7 +15,11 @@
15
15
  "title": { "type": "string", "description": "Site title" },
16
16
  "description": { "type": "string", "description": "Site description" },
17
17
  "baseURL": { "type": "string", "description": "Base URL for the site" },
18
- "favicon": { "type": "string", "description": "Path to favicon" }
18
+ "favicon": { "type": "string", "description": "Path to favicon" },
19
+ "ogImage": {
20
+ "type": "string",
21
+ "description": "Default OG image path (e.g. /docs/assets/images/og.png)"
22
+ }
19
23
  },
20
24
  "required": ["title"]
21
25
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docubook/flame",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "A blazing-fast React + MDX framework powered by Bun, built for modern documentation experiences.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -55,9 +55,9 @@
55
55
  "react-dom": "^19.2.7",
56
56
  "unified": "^11.0.0",
57
57
  "@docubook/core": "^1.8.2",
58
- "@docubook/mdx-content": "^3.4.3",
59
- "@docubook/themes-colors": "^1.0.1",
58
+ "@docubook/mdx-content": "^3.4.4",
60
59
  "@docubook/runt": "^1.0.0",
60
+ "@docubook/themes-colors": "^1.0.2",
61
61
  "@docubook/ui-react": "^1.0.0"
62
62
  },
63
63
  "peerDependencies": {
@@ -0,0 +1,92 @@
1
+ <h1 align="center" style="font-size: 32px;">
2
+ DocuBook Flame 🔥
3
+ </h1>
4
+ <h3 align="center" style="font-size: 20px;">
5
+ Fast as flame — a Bun-native framework for modern documentation experiences.
6
+ </h3>
7
+
8
+ <p align="center">
9
+ <strong>@docubook/flame</strong> is a lightweight runtime for building documentation websites using React, MDX, and filesystem-based routing — running on Bun, Node.js, and Deno.
10
+ </p>
11
+
12
+ ---
13
+
14
+ > **Lightweight** — 📦 ~132 kB packed. No bloat, just fire.
15
+
16
+ ---
17
+ ## Quick Start
18
+
19
+ **Bun**
20
+ ```bash
21
+ mkdir my-docs && cd my-docs
22
+ bun add @docubook/flame
23
+ bunx flame init
24
+ bun run dev
25
+ ```
26
+
27
+ **Node.js**
28
+ ```bash
29
+ mkdir my-docs && cd my-docs
30
+ npm install @docubook/flame
31
+ npx flame init
32
+ npm run dev
33
+ ```
34
+
35
+ **Deno**
36
+ ```bash
37
+ mkdir my-docs && cd my-docs
38
+ deno run -A npm:@docubook/flame init
39
+ deno task dev
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Documentation
45
+
46
+ For the full documentation, please visit **[packages/flame/docs](https://github.com/DocuBook/docubook/tree/main/packages/flame/docs)** or read the individual pages below:
47
+
48
+ ### Getting Started
49
+
50
+ | Page | Description |
51
+ | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
52
+ | [Welcome](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/index.mdx) | Overview and welcome to `@docubook/flame`. |
53
+ | [Introduction](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/getting-started/introduction.mdx) | Overview of the framework. |
54
+ | [Installation](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/getting-started/installation.mdx) | Install and scaffold your first site. |
55
+ | [Quick Start Guide](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/getting-started/quick-start-guide.mdx) | Get up and running in minutes. |
56
+ | [Format text](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/getting-started/format-text.mdx) | Markdown and inline styling in MDX. |
57
+ | [Frontmatter](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/getting-started/frontmatter.mdx) | Page metadata via frontmatter. |
58
+ | [Themes](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/getting-started/themes.mdx) | Color system, presets, and custom hex. |
59
+ | [Plugins](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/getting-started/plugins.mdx) | Extend the build and dev pipeline. |
60
+ | [Deployment](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/getting-started/deployment.mdx) | Deploy to static hosting with clean URLs. |
61
+ | [Search — Built-in](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/getting-started/search/built-in.mdx) | Build-time full-text search. |
62
+ | [Search — Algolia](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/getting-started/search/algolia.mdx) | Algolia DocSearch integration. |
63
+
64
+ ### Components
65
+
66
+ | Page | Description |
67
+ | ------------------------------------------------------------------------------------------------- | ---------------------------------------- |
68
+ | [Accordion](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/accordion.mdx) | Collapsible content sections. |
69
+ | [Accordion Group](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/accordion-group.mdx) | Group multiple accordions. |
70
+ | [Button](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/button.mdx) | Action and navigation buttons. |
71
+ | [Card](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/card.mdx) | Compact content cards. |
72
+ | [Card Group](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/card-group.mdx) | Display multiple cards together. |
73
+ | [Code Block](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/code-block.mdx) | Code snippets with line highlighting. |
74
+ | [Custom Components](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/custom.mdx) | Register your own MDX components. |
75
+ | [File Tree](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/file-tree.mdx) | Hierarchical file structures. |
76
+ | [Image](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/image.mdx) | Display images in Markdown. |
77
+ | [Keyboard](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/keyboard.mdx) | Keyboard keys with platform styling. |
78
+ | [Link](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/link.mdx) | Navigation links. |
79
+ | [Mermaid](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/mermaid.mdx) | Mermaid.js diagrams in MDX. |
80
+ | [Note](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/note.mdx) | Notes, warnings, and success messages. |
81
+ | [Release Note](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/release-note.mdx) | Per-version update notes. |
82
+ | [Stepper](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/stepper.mdx) | Step-by-step instructions. |
83
+ | [Tables](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/tables.mdx) | GitHub-flavored tables. |
84
+ | [Tabs](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/tabs.mdx) | Switchable content sections. |
85
+ | [Tooltips](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/tooltips.mdx) | Hover info tooltips. |
86
+ | [Youtube](https://github.com/DocuBook/docubook/blob/main/packages/flame/docs/components/youtube.mdx) | Embed YouTube videos. |
87
+
88
+ ---
89
+
90
+ ## License
91
+
92
+ MIT
@@ -4,7 +4,8 @@
4
4
  "title": "My Docs",
5
5
  "description": "Documentation powered by DocuBook Flame",
6
6
  "baseURL": "http://localhost:3000",
7
- "favicon": "/docs/assets/images/favicon.ico"
7
+ "favicon": "/docs/assets/images/favicon.ico",
8
+ "ogImage": "/docs/assets/images/og.png"
8
9
  },
9
10
  "themes": {
10
11
  "colors": "default"