@docubook/flame 1.5.2 → 1.5.3

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.
@@ -36,13 +36,39 @@ export default function Menu({ onNavigate, className = "", pathname, routes = []
36
36
  if (!currentPath.startsWith("/docs")) return null;
37
37
 
38
38
  const mode = docuConfig.sidebar?.context || "dropdown";
39
+ const navProps = {
40
+ "aria-label": "Documentation navigation" as const,
41
+ className: cn("transition-all duration-200", className),
42
+ };
39
43
 
40
- // Helper: check if a sublink under a given route matches the current path
41
- const isItemActive = (itemHref: string, parentRouteHref: string) => {
42
- const fullHref = `/docs${parentRouteHref}${itemHref}`;
43
- return currentPath === fullHref || currentPath === `${fullHref}.html`;
44
+ // Shared nav item with border-left overlap wrapper
45
+ const renderBorderItem = (item: DocuRoute, parentRouteHref: string, key: string) => {
46
+ const fullHref = `/docs${parentRouteHref}${item.href}`;
47
+ const isActive = currentPath === fullHref || currentPath === `${fullHref}.html`;
48
+ return (
49
+ <li key={key}>
50
+ <div
51
+ className={cn(
52
+ "-ml-[14px] border-l-2",
53
+ isActive ? "border-primary" : "border-transparent"
54
+ )}
55
+ >
56
+ <div className="pl-3">
57
+ <Sublink
58
+ {...item}
59
+ href={item.href}
60
+ level={0}
61
+ onNavigate={onNavigate}
62
+ parentHref={`/docs${parentRouteHref}`}
63
+ />
64
+ </div>
65
+ </div>
66
+ </li>
67
+ );
44
68
  };
45
69
 
70
+ const sharedUlClasses = "border-base-300 flex flex-col gap-0.5 border-l-2 pb-0.5 pl-3 pt-0.5";
71
+
46
72
  // Separator mode: render all context sections as group headers + nav items
47
73
  if (mode === "separator") {
48
74
  const contextRoutes = menuRoutes.filter((r) => r.context);
@@ -50,62 +76,24 @@ export default function Menu({ onNavigate, className = "", pathname, routes = []
50
76
  // No context routes defined — fall back to flat list of all routes
51
77
  if (contextRoutes.length === 0) {
52
78
  return (
53
- <nav
54
- aria-label="Documentation navigation"
55
- className={cn("transition-all duration-200", className)}
56
- >
57
- <ul className="flex flex-col gap-0.5 py-4">
58
- {menuRoutes.map((route) => (
59
- <li key={route.href}>
60
- <Sublink
61
- {...route}
62
- href={route.href}
63
- level={0}
64
- onNavigate={onNavigate}
65
- parentHref="/docs"
66
- />
67
- </li>
68
- ))}
79
+ <nav {...navProps}>
80
+ <ul className={sharedUlClasses}>
81
+ {menuRoutes.map((route) => renderBorderItem(route, "", route.href))}
69
82
  </ul>
70
83
  </nav>
71
84
  );
72
85
  }
73
86
 
74
87
  return (
75
- <nav
76
- aria-label="Documentation navigation"
77
- className={cn("transition-all duration-200", className)}
78
- >
88
+ <nav {...navProps}>
79
89
  {contextRoutes.map((route, i) => (
80
90
  <div key={route.href} className={i > 0 ? "mt-6 lg:mt-8" : ""}>
81
91
  <SidebarGroupHeader
82
92
  icon={route.context?.icon}
83
93
  title={route.context?.title || route.title}
84
94
  />
85
- <ul className="border-base-300 flex flex-col gap-0.5 border-l-2 pb-0.5 pl-3 pt-0.5">
86
- {route.items?.map((item) => {
87
- const isActive = isItemActive(item.href, route.href);
88
- return (
89
- <li key={item.href}>
90
- <div
91
- className={cn(
92
- "-ml-[14px] border-l-2",
93
- isActive ? "border-primary" : "border-transparent"
94
- )}
95
- >
96
- <div className="pl-3">
97
- <Sublink
98
- {...item}
99
- href={item.href}
100
- level={0}
101
- onNavigate={onNavigate}
102
- parentHref={`/docs${route.href}`}
103
- />
104
- </div>
105
- </div>
106
- </li>
107
- );
108
- })}
95
+ <ul className={sharedUlClasses}>
96
+ {route.items?.map((item) => renderBorderItem(item, route.href, item.href))}
109
97
  </ul>
110
98
  </div>
111
99
  ))}
@@ -131,10 +119,7 @@ export default function Menu({ onNavigate, className = "", pathname, routes = []
131
119
  if (!contextRoute) return null;
132
120
 
133
121
  return (
134
- <nav
135
- aria-label="Documentation navigation"
136
- className={cn("transition-all duration-200", className)}
137
- >
122
+ <nav {...navProps}>
138
123
  <ul className="flex flex-col gap-0.5 py-4">
139
124
  <li key={contextRoute.title}>
140
125
  <Sublink
@@ -2,6 +2,7 @@ import type { ReactNode } from "react";
2
2
  import { useState } from "react";
3
3
  import Anchor from "./Anchor";
4
4
  import { cn } from "../node/utils";
5
+ import { config as docuConfig } from "../node/client-routes";
5
6
  import {
6
7
  Navbar as BaseNavbar,
7
8
  Logo as BaseLogo,
@@ -172,7 +173,7 @@ export function NavbarBrand({
172
173
  }
173
174
 
174
175
  export function GitHubLink({ repoUrl }: { repoUrl?: string }) {
175
- if (!repoUrl) return null;
176
+ if (!docuConfig.repo?.edit || !repoUrl) return null;
176
177
 
177
178
  return (
178
179
  <a
@@ -5,6 +5,7 @@ import { ChevronDown } from "lucide-react";
5
5
  import Anchor from "./Anchor";
6
6
  import type { DocuRoute } from "../node/types";
7
7
  import { cn, docsHtmlHref } from "../node/utils";
8
+ import { config as docuConfig } from "../node/client-routes";
8
9
 
9
10
  interface SublinkProps extends DocuRoute {
10
11
  level: number;
@@ -34,7 +35,7 @@ export default function Sublink({
34
35
  });
35
36
 
36
37
  // Shared padding based on nesting level
37
- const levelPadding = cn(level === 1 && "pl-2", level === 2 && "pl-4", level >= 3 && "pl-6");
38
+ const levelPadding = cn(level === 1 && "pl-4", level === 2 && "pl-8", level >= 3 && "pl-12");
38
39
  const isActive = currentPathname === fullHref || currentPathname === `${fullHref}.html`;
39
40
  const activeRef = useRef<HTMLDivElement>(null);
40
41
 
@@ -58,16 +59,49 @@ export default function Sublink({
58
59
  </Anchor>
59
60
  );
60
61
 
62
+ // Level 0: border handled by Menu.tsx wrapper
63
+ // Level 1+: border at natural indented position, follows levelPadding
64
+ if (level >= 1) {
65
+ // Separator mode: active border overlaps at ul's edge
66
+ // Each parent section adds its levelPadding to the offset
67
+ if (docuConfig.sidebar?.context === "separator") {
68
+ // Calculate accumulated offset from ul's edge to this item's natural position
69
+ // Base: ul border(2px) + pl-3(12px) = 14px
70
+ // Each parent section adds: level 1→16px, level 2→32px, level 3+→48px
71
+ const sectionOffsets: Record<number, number> = { 1: 16, 2: 32 };
72
+ let overlap = 14;
73
+ for (let l = 1; l < level; l++) {
74
+ overlap += sectionOffsets[l] ?? 48;
75
+ }
76
+
77
+ return (
78
+ <div
79
+ ref={activeRef}
80
+ className={cn("border-l-2", isActive ? "border-primary" : "border-transparent")}
81
+ style={{ marginLeft: `-${overlap}px` }}
82
+ >
83
+ <div className={cn("py-1 pl-3", levelPadding)}>{link}</div>
84
+ </div>
85
+ );
86
+ }
87
+
88
+ return (
89
+ <div
90
+ ref={activeRef}
91
+ className={cn(
92
+ "py-1",
93
+ levelPadding,
94
+ "border-l-2",
95
+ isActive ? "border-primary" : "border-base-300"
96
+ )}
97
+ >
98
+ {link}
99
+ </div>
100
+ );
101
+ }
102
+
61
103
  return (
62
- <div
63
- ref={activeRef}
64
- className={cn(
65
- "py-1",
66
- levelPadding,
67
- level >= 2 && "border-l-2",
68
- level >= 2 && (isActive ? "border-primary" : "border-base-300")
69
- )}
70
- >
104
+ <div ref={activeRef} className={cn("py-1", levelPadding)}>
71
105
  {link}
72
106
  </div>
73
107
  );
@@ -2,7 +2,7 @@ import { PropsWithChildren } from "react";
2
2
 
3
3
  export function Typography({ children }: PropsWithChildren) {
4
4
  return (
5
- <div className="prose prose-zinc dark:prose-invert prose-code:font-code dark:prose-code:bg-stone-900/25 prose-code:bg-stone-50 prose-pre:bg-background max-lg:prose-headings:scroll-mt-54 prose-headings:scroll-mt-4 prose-code:text-sm prose-code:leading-6 dark:prose-code:text-white prose-code:text-stone-800 prose-code:p-1 prose-code:rounded-md prose-code:border prose-img:rounded-md prose-img:border prose-code:before:content-none prose-code:after:content-none prose-code:px-1.5 prose-code:overflow-x-auto prose-img:my-3 prose-h2:my-4 prose-h2:mt-8 w-[85vw] max-w-[500px]! min-w-full! pt-2 sm:mx-auto sm:w-full">
5
+ <div className="prose prose-zinc dark:prose-invert prose-code:font-code dark:prose-code:bg-stone-900/25 prose-code:bg-stone-50 prose-pre:bg-background max-lg:prose-headings:scroll-mt-54 prose-headings:scroll-mt-4 prose-code:text-sm prose-code:leading-6 dark:prose-code:text-white prose-code:text-stone-800 prose-code:p-1 prose-code:rounded-md prose-code:border prose-img:rounded-md prose-img:border prose-code:before:content-none prose-code:after:content-none prose-code:px-1.5 prose-code:overflow-x-auto prose-img:my-3 prose-h2:my-4 prose-h2:mt-8 max-w-full! w-full pt-2">
6
6
  {children}
7
7
  </div>
8
8
  );
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  runBuildCli
3
- } from "./chunk-7J3N2MCP.js";
4
- import "./chunk-QGEFJH47.js";
3
+ } from "./chunk-YENO4SVR.js";
4
+ import "./chunk-YI76L7LB.js";
5
5
  import "./chunk-EOK6KATZ.js";
6
- import "./chunk-GLOJMRT4.js";
6
+ import "./chunk-WCMRAAWH.js";
7
7
  import "./chunk-J5NMYSBJ.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-7J3N2MCP.js";
5
- import "./chunk-QGEFJH47.js";
4
+ } from "./chunk-YENO4SVR.js";
5
+ import "./chunk-YI76L7LB.js";
6
6
  import "./chunk-EOK6KATZ.js";
7
- import "./chunk-GLOJMRT4.js";
7
+ import "./chunk-WCMRAAWH.js";
8
8
  import "./chunk-J5NMYSBJ.js";
9
9
  export {
10
10
  runBuild,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  runBuildCli
3
- } from "./chunk-7J3N2MCP.js";
4
- import "./chunk-QGEFJH47.js";
3
+ } from "./chunk-YENO4SVR.js";
4
+ import "./chunk-YI76L7LB.js";
5
5
  import "./chunk-EOK6KATZ.js";
6
- import "./chunk-GLOJMRT4.js";
6
+ import "./chunk-WCMRAAWH.js";
7
7
  import "./chunk-J5NMYSBJ.js";
8
8
 
9
9
  // .docu/node/build.node.ts
@@ -12,7 +12,7 @@ var WORKFLOW_FILE = join(WORKFLOW_DIR, "deploy.yml");
12
12
  async function runDeploy() {
13
13
  console.log("\u{1F4E6} Building for production...\n");
14
14
  process.env.NODE_ENV = "production";
15
- const { runBuildCli } = await import("./build.impl-FA57P3VC.js");
15
+ const { runBuildCli } = await import("./build.impl-O3Z5XIGM.js");
16
16
  await runBuildCli();
17
17
  await writeFile(join(DIST_DIR, ".nojekyll"), "");
18
18
  if (!existsSync(WORKFLOW_FILE)) {
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-EOK6KATZ.js";
8
8
  import {
9
9
  logger
10
- } from "./chunk-GLOJMRT4.js";
10
+ } from "./chunk-WCMRAAWH.js";
11
11
  import {
12
12
  DIST_DIR
13
13
  } from "./chunk-J5NMYSBJ.js";
@@ -14,7 +14,7 @@ import {
14
14
  htmlShell,
15
15
  initSentry,
16
16
  loadPlugins
17
- } from "./chunk-QGEFJH47.js";
17
+ } from "./chunk-YI76L7LB.js";
18
18
  import {
19
19
  SECURITY_HEADERS,
20
20
  generateNonce,
@@ -27,7 +27,7 @@ import {
27
27
  } from "./chunk-EOK6KATZ.js";
28
28
  import {
29
29
  logger
30
- } from "./chunk-GLOJMRT4.js";
30
+ } from "./chunk-WCMRAAWH.js";
31
31
  import {
32
32
  DIST_DIR,
33
33
  DOCS_DIR,
@@ -5,7 +5,7 @@ import {
5
5
  // package.json
6
6
  var package_default = {
7
7
  name: "@docubook/flame",
8
- version: "1.5.2",
8
+ version: "1.5.3",
9
9
  description: "A blazing-fast React + MDX framework powered by Bun, built for modern documentation experiences.",
10
10
  type: "module",
11
11
  bin: {
@@ -13,14 +13,14 @@ import {
13
13
  htmlShell,
14
14
  initSentry,
15
15
  loadPlugins
16
- } from "./chunk-QGEFJH47.js";
16
+ } from "./chunk-YI76L7LB.js";
17
17
  import {
18
18
  generateNonce,
19
19
  scanMdxFiles
20
20
  } from "./chunk-EOK6KATZ.js";
21
21
  import {
22
22
  logger
23
- } from "./chunk-GLOJMRT4.js";
23
+ } from "./chunk-WCMRAAWH.js";
24
24
  import {
25
25
  ASSETS_DIR,
26
26
  CACHE_FILE,
@@ -1281,7 +1281,7 @@ function Pagination({
1281
1281
  // .docu/components/Typography.tsx
1282
1282
  import { jsx as jsx3 } from "react/jsx-runtime";
1283
1283
  function Typography({ children }) {
1284
- return /* @__PURE__ */ jsx3("div", { className: "prose prose-zinc dark:prose-invert prose-code:font-code dark:prose-code:bg-stone-900/25 prose-code:bg-stone-50 prose-pre:bg-background max-lg:prose-headings:scroll-mt-54 prose-headings:scroll-mt-4 prose-code:text-sm prose-code:leading-6 dark:prose-code:text-white prose-code:text-stone-800 prose-code:p-1 prose-code:rounded-md prose-code:border prose-img:rounded-md prose-img:border prose-code:before:content-none prose-code:after:content-none prose-code:px-1.5 prose-code:overflow-x-auto prose-img:my-3 prose-h2:my-4 prose-h2:mt-8 w-[85vw] max-w-[500px]! min-w-full! pt-2 sm:mx-auto sm:w-full", children });
1284
+ return /* @__PURE__ */ jsx3("div", { className: "prose prose-zinc dark:prose-invert prose-code:font-code dark:prose-code:bg-stone-900/25 prose-code:bg-stone-50 prose-pre:bg-background max-lg:prose-headings:scroll-mt-54 prose-headings:scroll-mt-4 prose-code:text-sm prose-code:leading-6 dark:prose-code:text-white prose-code:text-stone-800 prose-code:p-1 prose-code:rounded-md prose-code:border prose-img:rounded-md prose-img:border prose-code:before:content-none prose-code:after:content-none prose-code:px-1.5 prose-code:overflow-x-auto prose-img:my-3 prose-h2:my-4 prose-h2:mt-8 max-w-full! w-full pt-2", children });
1285
1285
  }
1286
1286
 
1287
1287
  // .docu/components/EditWith.tsx
@@ -1707,49 +1707,57 @@ function DocsPage({
1707
1707
  "data-repo": repoUrl || ""
1708
1708
  }
1709
1709
  ),
1710
- /* @__PURE__ */ jsxs6("div", { className: "w-full min-w-0 flex-[7] px-4 py-4 lg:px-8 lg:py-8", children: [
1711
- /* @__PURE__ */ jsx9(DocsBreadcrumb, { paths: slug }),
1712
- /* @__PURE__ */ jsxs6(Typography, { children: [
1713
- /* @__PURE__ */ jsx9("h1", { className: "-mt-0.5 text-3xl", children: title }),
1714
- description && /* @__PURE__ */ jsx9("p", { className: "text-muted-foreground -mt-4 text-[16.5px]", children: description }),
1715
- /* @__PURE__ */ jsx9("div", { id: "mdx-content-island", children: content }),
1716
- compiledSource && /* @__PURE__ */ jsx9(
1717
- "script",
1718
- {
1719
- id: "mdx-compiled-source",
1720
- type: "application/json",
1721
- dangerouslySetInnerHTML: {
1722
- __html: JSON.stringify(compiledSource).replace(/<\//g, "\\u003C/")
1723
- }
1724
- }
1725
- ),
1726
- /* @__PURE__ */ jsxs6("div", { className: "border-base-300 my-8 flex items-center border-b-2 border-dashed", children: [
1727
- /* @__PURE__ */ jsx9(EditWith, { className: "text-muted-foreground", filePath }),
1728
- date && /* @__PURE__ */ jsxs6("p", { className: "text-muted-foreground ml-auto text-[13px]", children: [
1729
- "Last updated ",
1730
- formatDate2(date)
1731
- ] })
1732
- ] }),
1733
- /* @__PURE__ */ jsx9(
1734
- Pagination,
1735
- {
1736
- pathname,
1737
- prevIcon: /* @__PURE__ */ jsx9(ChevronLeft, { className: "h-3 w-3" }),
1738
- nextIcon: /* @__PURE__ */ jsx9(ChevronRight, { className: "h-3 w-3" })
1739
- }
1740
- ),
1741
- /* @__PURE__ */ jsx9(Footer, {})
1742
- ] })
1743
- ] }),
1744
- tocs.length > 0 && /* @__PURE__ */ jsx9(
1745
- "div",
1746
- {
1747
- id: "toc-island",
1748
- "data-tocs": tocsJson,
1749
- className: "sticky top-4 hidden h-[calc(100vh-8rem)] min-w-[240px] flex-[3] self-start lg:flex lg:px-4 lg:py-6",
1750
- children: /* @__PURE__ */ jsx9(Toc, { tocs })
1751
- }
1752
- )
1710
+ /* @__PURE__ */ jsxs6("div", { className: "flex w-full flex-col lg:flex-row 2xl:mx-auto 2xl:max-w-[1300px]", children: [
1711
+ /* @__PURE__ */ jsxs6(
1712
+ "div",
1713
+ {
1714
+ 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`,
1715
+ children: [
1716
+ /* @__PURE__ */ jsx9(DocsBreadcrumb, { paths: slug }),
1717
+ /* @__PURE__ */ jsxs6(Typography, { children: [
1718
+ /* @__PURE__ */ jsx9("h1", { className: "-mt-0.5 text-3xl", children: title }),
1719
+ description && /* @__PURE__ */ jsx9("p", { className: "text-muted-foreground -mt-4 text-[16.5px]", children: description }),
1720
+ /* @__PURE__ */ jsx9("div", { id: "mdx-content-island", children: content }),
1721
+ compiledSource && /* @__PURE__ */ jsx9(
1722
+ "script",
1723
+ {
1724
+ id: "mdx-compiled-source",
1725
+ type: "application/json",
1726
+ dangerouslySetInnerHTML: {
1727
+ __html: JSON.stringify(compiledSource).replace(/<\//g, "\\u003C/")
1728
+ }
1729
+ }
1730
+ ),
1731
+ /* @__PURE__ */ jsxs6("div", { className: "border-base-300 my-8 flex items-center border-b-2 border-dashed", children: [
1732
+ /* @__PURE__ */ jsx9(EditWith, { className: "text-muted-foreground", filePath }),
1733
+ date && /* @__PURE__ */ jsxs6("p", { className: "text-muted-foreground ml-auto text-[13px]", children: [
1734
+ "Last updated ",
1735
+ formatDate2(date)
1736
+ ] })
1737
+ ] }),
1738
+ /* @__PURE__ */ jsx9(
1739
+ Pagination,
1740
+ {
1741
+ pathname,
1742
+ prevIcon: /* @__PURE__ */ jsx9(ChevronLeft, { className: "h-3 w-3" }),
1743
+ nextIcon: /* @__PURE__ */ jsx9(ChevronRight, { className: "h-3 w-3" })
1744
+ }
1745
+ ),
1746
+ /* @__PURE__ */ jsx9(Footer, {})
1747
+ ] })
1748
+ ]
1749
+ }
1750
+ ),
1751
+ tocs.length > 0 && /* @__PURE__ */ jsx9(
1752
+ "div",
1753
+ {
1754
+ id: "toc-island",
1755
+ "data-tocs": tocsJson,
1756
+ className: "sticky top-4 hidden h-[calc(100vh-8rem)] min-w-[240px] flex-[3] self-start lg:flex lg:px-4 lg:py-6",
1757
+ children: /* @__PURE__ */ jsx9(Toc, { tocs })
1758
+ }
1759
+ )
1760
+ ] })
1753
1761
  ]
1754
1762
  }
1755
1763
  ) });
@@ -1996,6 +2004,16 @@ function Anchor({
1996
2004
  return /* @__PURE__ */ jsx15("a", { href, className: baseClasses, ...props, children });
1997
2005
  }
1998
2006
 
2007
+ // docu-config-runtime:../../docu.json
2008
+ import { readFileSync as readFileSync2 } from "node:fs";
2009
+ import { join as join4 } from "node:path";
2010
+ var config = JSON.parse(readFileSync2(join4(process.cwd(), "docu.json"), "utf-8"));
2011
+ var docu_default = config;
2012
+
2013
+ // .docu/node/client-routes.ts
2014
+ var routes2 = docu_default.routes || [];
2015
+ var config2 = docu_default;
2016
+
1999
2017
  // .docu/components/Sublink.tsx
2000
2018
  import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
2001
2019
  function Sublink({
@@ -2015,7 +2033,7 @@ function Sublink({
2015
2033
  if (!items) return false;
2016
2034
  return currentPathname.startsWith(fullHref) && currentPathname !== fullHref;
2017
2035
  });
2018
- const levelPadding = cn(level === 1 && "pl-2", level === 2 && "pl-4", level >= 3 && "pl-6");
2036
+ const levelPadding = cn(level === 1 && "pl-4", level === 2 && "pl-8", level >= 3 && "pl-12");
2019
2037
  const isActive = currentPathname === fullHref || currentPathname === `${fullHref}.html`;
2020
2038
  const activeRef = useRef2(null);
2021
2039
  useEffect3(() => {
@@ -2035,19 +2053,38 @@ function Sublink({
2035
2053
  children: title
2036
2054
  }
2037
2055
  );
2038
- return /* @__PURE__ */ jsx16(
2039
- "div",
2040
- {
2041
- ref: activeRef,
2042
- className: cn(
2043
- "py-1",
2044
- levelPadding,
2045
- level >= 2 && "border-l-2",
2046
- level >= 2 && (isActive ? "border-primary" : "border-base-300")
2047
- ),
2048
- children: link
2056
+ if (level >= 1) {
2057
+ if (config2.sidebar?.context === "separator") {
2058
+ const sectionOffsets = { 1: 16, 2: 32 };
2059
+ let overlap = 14;
2060
+ for (let l = 1; l < level; l++) {
2061
+ overlap += sectionOffsets[l] ?? 48;
2062
+ }
2063
+ return /* @__PURE__ */ jsx16(
2064
+ "div",
2065
+ {
2066
+ ref: activeRef,
2067
+ className: cn("border-l-2", isActive ? "border-primary" : "border-transparent"),
2068
+ style: { marginLeft: `-${overlap}px` },
2069
+ children: /* @__PURE__ */ jsx16("div", { className: cn("py-1 pl-3", levelPadding), children: link })
2070
+ }
2071
+ );
2049
2072
  }
2050
- );
2073
+ return /* @__PURE__ */ jsx16(
2074
+ "div",
2075
+ {
2076
+ ref: activeRef,
2077
+ className: cn(
2078
+ "py-1",
2079
+ levelPadding,
2080
+ "border-l-2",
2081
+ isActive ? "border-primary" : "border-base-300"
2082
+ ),
2083
+ children: link
2084
+ }
2085
+ );
2086
+ }
2087
+ return /* @__PURE__ */ jsx16("div", { ref: activeRef, className: cn("py-1", levelPadding), children: link });
2051
2088
  }
2052
2089
  return /* @__PURE__ */ jsxs12("div", { ref: isActive ? activeRef : void 0, className: cn("flex flex-col", levelPadding), children: [
2053
2090
  /* @__PURE__ */ jsxs12(
@@ -2107,16 +2144,6 @@ function SidebarGroupHeader({ icon, title }) {
2107
2144
  ] });
2108
2145
  }
2109
2146
 
2110
- // docu-config-runtime:../../docu.json
2111
- import { readFileSync as readFileSync2 } from "node:fs";
2112
- import { join as join4 } from "node:path";
2113
- var config = JSON.parse(readFileSync2(join4(process.cwd(), "docu.json"), "utf-8"));
2114
- var docu_default = config;
2115
-
2116
- // .docu/node/client-routes.ts
2117
- var routes2 = docu_default.routes || [];
2118
- var config2 = docu_default;
2119
-
2120
2147
  // .docu/components/Menu.tsx
2121
2148
  import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
2122
2149
  function getCurrentContext(path) {
@@ -2137,91 +2164,64 @@ function Menu({ onNavigate, className = "", pathname, routes: routes3 = [] }) {
2137
2164
  );
2138
2165
  if (!currentPath.startsWith("/docs")) return null;
2139
2166
  const mode = config2.sidebar?.context || "dropdown";
2140
- const isItemActive = (itemHref, parentRouteHref) => {
2141
- const fullHref = `/docs${parentRouteHref}${itemHref}`;
2142
- return currentPath === fullHref || currentPath === `${fullHref}.html`;
2167
+ const navProps = {
2168
+ "aria-label": "Documentation navigation",
2169
+ className: cn("transition-all duration-200", className)
2170
+ };
2171
+ const renderBorderItem = (item, parentRouteHref, key) => {
2172
+ const fullHref = `/docs${parentRouteHref}${item.href}`;
2173
+ const isActive = currentPath === fullHref || currentPath === `${fullHref}.html`;
2174
+ return /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(
2175
+ "div",
2176
+ {
2177
+ className: cn(
2178
+ "-ml-[14px] border-l-2",
2179
+ isActive ? "border-primary" : "border-transparent"
2180
+ ),
2181
+ children: /* @__PURE__ */ jsx18("div", { className: "pl-3", children: /* @__PURE__ */ jsx18(
2182
+ Sublink,
2183
+ {
2184
+ ...item,
2185
+ href: item.href,
2186
+ level: 0,
2187
+ onNavigate,
2188
+ parentHref: `/docs${parentRouteHref}`
2189
+ }
2190
+ ) })
2191
+ }
2192
+ ) }, key);
2143
2193
  };
2194
+ const sharedUlClasses = "border-base-300 flex flex-col gap-0.5 border-l-2 pb-0.5 pl-3 pt-0.5";
2144
2195
  if (mode === "separator") {
2145
2196
  const contextRoutes = menuRoutes.filter((r) => r.context);
2146
2197
  if (contextRoutes.length === 0) {
2147
- return /* @__PURE__ */ jsx18(
2148
- "nav",
2198
+ return /* @__PURE__ */ jsx18("nav", { ...navProps, children: /* @__PURE__ */ jsx18("ul", { className: sharedUlClasses, children: menuRoutes.map((route) => renderBorderItem(route, "", route.href)) }) });
2199
+ }
2200
+ return /* @__PURE__ */ jsx18("nav", { ...navProps, children: contextRoutes.map((route, i) => /* @__PURE__ */ jsxs14("div", { className: i > 0 ? "mt-6 lg:mt-8" : "", children: [
2201
+ /* @__PURE__ */ jsx18(
2202
+ SidebarGroupHeader,
2149
2203
  {
2150
- "aria-label": "Documentation navigation",
2151
- className: cn("transition-all duration-200", className),
2152
- children: /* @__PURE__ */ jsx18("ul", { className: "flex flex-col gap-0.5 py-4", children: menuRoutes.map((route) => /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(
2153
- Sublink,
2154
- {
2155
- ...route,
2156
- href: route.href,
2157
- level: 0,
2158
- onNavigate,
2159
- parentHref: "/docs"
2160
- }
2161
- ) }, route.href)) })
2204
+ icon: route.context?.icon,
2205
+ title: route.context?.title || route.title
2162
2206
  }
2163
- );
2164
- }
2165
- return /* @__PURE__ */ jsx18(
2166
- "nav",
2167
- {
2168
- "aria-label": "Documentation navigation",
2169
- className: cn("transition-all duration-200", className),
2170
- children: contextRoutes.map((route, i) => /* @__PURE__ */ jsxs14("div", { className: i > 0 ? "mt-6 lg:mt-8" : "", children: [
2171
- /* @__PURE__ */ jsx18(
2172
- SidebarGroupHeader,
2173
- {
2174
- icon: route.context?.icon,
2175
- title: route.context?.title || route.title
2176
- }
2177
- ),
2178
- /* @__PURE__ */ jsx18("ul", { className: "border-base-300 flex flex-col gap-0.5 border-l-2 pb-0.5 pl-3 pt-0.5", children: route.items?.map((item) => {
2179
- const isActive = isItemActive(item.href, route.href);
2180
- return /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(
2181
- "div",
2182
- {
2183
- className: cn(
2184
- "-ml-[14px] border-l-2",
2185
- isActive ? "border-primary" : "border-transparent"
2186
- ),
2187
- children: /* @__PURE__ */ jsx18("div", { className: "pl-3", children: /* @__PURE__ */ jsx18(
2188
- Sublink,
2189
- {
2190
- ...item,
2191
- href: item.href,
2192
- level: 0,
2193
- onNavigate,
2194
- parentHref: `/docs${route.href}`
2195
- }
2196
- ) })
2197
- }
2198
- ) }, item.href);
2199
- }) })
2200
- ] }, route.href))
2201
- }
2202
- );
2207
+ ),
2208
+ /* @__PURE__ */ jsx18("ul", { className: sharedUlClasses, children: route.items?.map((item) => renderBorderItem(item, route.href, item.href)) })
2209
+ ] }, route.href)) });
2203
2210
  }
2204
2211
  const isDocsRoot = currentPath === "/docs" || currentPath === "/docs/";
2205
2212
  const currentContext = isDocsRoot ? menuRoutes[0]?.href.replace(/^\/+|\/+$/, "") : getCurrentContext(currentPath);
2206
2213
  const contextRoute = isDocsRoot && menuRoutes[0] ? currentContext ? getContextRoute(currentContext, menuRoutes) : menuRoutes[0] : currentContext ? getContextRoute(currentContext, menuRoutes) : void 0;
2207
2214
  if (!contextRoute) return null;
2208
- return /* @__PURE__ */ jsx18(
2209
- "nav",
2215
+ return /* @__PURE__ */ jsx18("nav", { ...navProps, children: /* @__PURE__ */ jsx18("ul", { className: "flex flex-col gap-0.5 py-4", children: /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(
2216
+ Sublink,
2210
2217
  {
2211
- "aria-label": "Documentation navigation",
2212
- className: cn("transition-all duration-200", className),
2213
- children: /* @__PURE__ */ jsx18("ul", { className: "flex flex-col gap-0.5 py-4", children: /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18(
2214
- Sublink,
2215
- {
2216
- ...contextRoute,
2217
- href: contextRoute.href,
2218
- level: 0,
2219
- onNavigate,
2220
- parentHref: "/docs"
2221
- }
2222
- ) }, contextRoute.title) })
2218
+ ...contextRoute,
2219
+ href: contextRoute.href,
2220
+ level: 0,
2221
+ onNavigate,
2222
+ parentHref: "/docs"
2223
2223
  }
2224
- );
2224
+ ) }, contextRoute.title) }) });
2225
2225
  }
2226
2226
 
2227
2227
  // .docu/components/DocsLayout.tsx
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-GLOJMRT4.js";
3
+ } from "./chunk-WCMRAAWH.js";
4
4
  import "./chunk-J5NMYSBJ.js";
5
5
 
6
6
  // .docu/node/clean.ts
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runDeploy
3
- } from "./chunk-NXO2BF64.js";
3
+ } from "./chunk-7VXEOH7X.js";
4
4
  import "./chunk-J5NMYSBJ.js";
5
5
 
6
6
  // .docu/node/deploy.deno.ts
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runDeploy
3
- } from "./chunk-NXO2BF64.js";
3
+ } from "./chunk-7VXEOH7X.js";
4
4
  import "./chunk-J5NMYSBJ.js";
5
5
 
6
6
  // .docu/node/deploy.node.ts
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  runPreview
3
- } from "./chunk-Q3AXTF2V.js";
3
+ } from "./chunk-EIKBL7SD.js";
4
4
  import "./chunk-EOK6KATZ.js";
5
- import "./chunk-GLOJMRT4.js";
5
+ import "./chunk-WCMRAAWH.js";
6
6
  import "./chunk-J5NMYSBJ.js";
7
7
 
8
8
  // .docu/node/preview.deno.ts
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  runPreview
3
- } from "./chunk-Q3AXTF2V.js";
3
+ } from "./chunk-EIKBL7SD.js";
4
4
  import "./chunk-EOK6KATZ.js";
5
- import "./chunk-GLOJMRT4.js";
5
+ import "./chunk-WCMRAAWH.js";
6
6
  import "./chunk-J5NMYSBJ.js";
7
7
 
8
8
  // .docu/node/preview.node.ts
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  runServer
3
- } from "./chunk-TEXSBNMR.js";
4
- import "./chunk-QGEFJH47.js";
3
+ } from "./chunk-VX4HLVHE.js";
4
+ import "./chunk-YI76L7LB.js";
5
5
  import "./chunk-EOK6KATZ.js";
6
- import "./chunk-GLOJMRT4.js";
6
+ import "./chunk-WCMRAAWH.js";
7
7
  import "./chunk-J5NMYSBJ.js";
8
8
 
9
9
  // .docu/node/server.deno.ts
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  runServer
3
- } from "./chunk-TEXSBNMR.js";
4
- import "./chunk-QGEFJH47.js";
3
+ } from "./chunk-VX4HLVHE.js";
4
+ import "./chunk-YI76L7LB.js";
5
5
  import "./chunk-EOK6KATZ.js";
6
- import "./chunk-GLOJMRT4.js";
6
+ import "./chunk-WCMRAAWH.js";
7
7
  import "./chunk-J5NMYSBJ.js";
8
8
 
9
9
  // .docu/node/server.node.ts
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docubook/flame",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "description": "A blazing-fast React + MDX framework powered by Bun, built for modern documentation experiences.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -54,11 +54,11 @@
54
54
  "react": "^19.2.7",
55
55
  "react-dom": "^19.2.7",
56
56
  "unified": "^11.0.0",
57
- "@docubook/core": "^1.8.2",
58
57
  "@docubook/mdx-content": "^3.4.3",
59
- "@docubook/themes-colors": "^1.0.1",
60
- "@docubook/runt": "^1.0.0",
61
- "@docubook/ui-react": "^1.0.0"
58
+ "@docubook/core": "^1.8.2",
59
+ "@docubook/themes-colors": "^1.0.2",
60
+ "@docubook/ui-react": "^1.0.0",
61
+ "@docubook/runt": "^1.0.0"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "@sentry/bun": "^10.0.0"
@@ -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