boltdocs 3.0.2 → 3.2.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.
Files changed (123) hide show
  1. package/README.md +2 -18
  2. package/dist/{adapters-DEXNIv3x.mjs → adapters-ByYY44Zy.mjs} +1 -1
  3. package/dist/{adapters-C5AWWGfb.cjs → adapters-DvmtpdSF.cjs} +1 -1
  4. package/dist/{banner-CfdalYLL.d.ts → banner-BMop1KLF.d.ts} +2 -2
  5. package/dist/{banner-DNSkgUsO.d.cts → banner-CVD0GugR.d.cts} +2 -2
  6. package/dist/cache-CO4Dy2uQ.cjs +6 -0
  7. package/dist/cache-Dk53iOo6.mjs +6 -0
  8. package/dist/chunk-BFSpntXv.mjs +6 -0
  9. package/dist/{chunk-Ds5LZdWN.cjs → chunk-D1Md3oWO.cjs} +1 -1
  10. package/dist/client/index.cjs +433 -272
  11. package/dist/client/index.d.cts +129 -18
  12. package/dist/client/index.d.ts +129 -18
  13. package/dist/client/index.js +337 -178
  14. package/dist/client/mdx.cjs +1 -1
  15. package/dist/client/mdx.d.cts +1 -1
  16. package/dist/client/mdx.d.ts +1 -1
  17. package/dist/client/mdx.js +1 -1
  18. package/dist/client/primitives.cjs +7 -7
  19. package/dist/client/primitives.d.cts +5 -22
  20. package/dist/client/primitives.d.ts +5 -22
  21. package/dist/client/primitives.js +4 -4
  22. package/dist/client/theme/neutral.css +1 -3
  23. package/dist/client/theme/reset.css +31 -4
  24. package/dist/config-BpzaPsJj.d.cts +781 -0
  25. package/dist/config-CCXp3aXO.mjs +7 -0
  26. package/dist/{config-JGkMJoJQ.cjs → config-CMd4XoFq.cjs} +1 -1
  27. package/dist/config-DlGoEM9D.cjs +7 -0
  28. package/dist/config-xtS0ZkMm.d.mts +781 -0
  29. package/dist/{csp-CBysWlAf.cjs → csp-CRp_3U7a.cjs} +1 -1
  30. package/dist/csp-oTC2ygvF.mjs +6 -0
  31. package/dist/{docs-layout-6FQ8__ok.js → docs-layout-BdtZ9z6s.js} +9 -28
  32. package/dist/{docs-layout-3TpAt6MB.cjs → docs-layout-CFWI15Id.cjs} +69 -88
  33. package/dist/{doctor-BR1B2Mkz.cjs → doctor-BBtmNJE0.cjs} +1 -1
  34. package/dist/doctor-Bv16QSrI.cjs +7 -0
  35. package/dist/doctor-DOAbSaiL.mjs +7 -0
  36. package/dist/{generator-DtUU3Cfk.cjs → generator-COepVWGi.cjs} +1 -1
  37. package/dist/{handler-Btd4t_67.mjs → handler-DzQae4eA.mjs} +1 -1
  38. package/dist/{handler-Dzf4dSnV.cjs → handler-XX7cLTqe.cjs} +1 -1
  39. package/dist/headers-Ddwek8K7.mjs +6 -0
  40. package/dist/{headers-BXKxiPUv.cjs → headers-dg4SDrjY.cjs} +1 -1
  41. package/dist/{image-C9md50h2.js → image-Bz87fCla.js} +2 -2
  42. package/dist/{image-CR6UlaI5.cjs → image-C4TlpMHn.cjs} +18 -18
  43. package/dist/link-2PzgTnaP.js +673 -0
  44. package/dist/{icons-dev-BryEFkJu.cjs → link-D1Gjkb-2.cjs} +8 -353
  45. package/dist/{mdx-DhyMkc35.js → mdx-BuO6a1f7.js} +199 -40
  46. package/dist/{mdx-DJBg5DuL.cjs → mdx-CD-tSjRG.cjs} +237 -72
  47. package/dist/{meta-loader-C9MKjAs0.cjs → meta-loader-Dq1zcFnh.cjs} +1 -1
  48. package/dist/node/cache.cjs +6 -0
  49. package/dist/node/cache.d.cts +84 -0
  50. package/dist/node/cache.d.mts +84 -0
  51. package/dist/node/cache.mjs +6 -0
  52. package/dist/node/cli-entry.cjs +6 -6
  53. package/dist/node/cli-entry.mjs +9 -9
  54. package/dist/node/index.cjs +1 -1
  55. package/dist/node/index.d.cts +27 -638
  56. package/dist/node/index.d.mts +27 -640
  57. package/dist/node/index.mjs +1 -1
  58. package/dist/node/mdx/shiki-adapter.cjs +6 -0
  59. package/dist/node/mdx/shiki-adapter.d.cts +51 -0
  60. package/dist/node/mdx/shiki-adapter.d.mts +51 -0
  61. package/dist/node/mdx/shiki-adapter.mjs +6 -0
  62. package/dist/node-BXtqM1uH.mjs +6 -0
  63. package/dist/node-BlVk4EVg.cjs +104 -0
  64. package/dist/node-DOf4zhWc.mjs +104 -0
  65. package/dist/node-aD1eisrR.cjs +6 -0
  66. package/dist/{package-CEDhVAfO.cjs → package-BcISI5-P.cjs} +1 -1
  67. package/dist/{package-_dCCKVvG.mjs → package-CCYEAYeA.mjs} +1 -1
  68. package/dist/{pages-external-CX2uyW95.cjs → pages-external-XkYIs-d5.cjs} +1 -1
  69. package/dist/parser-DCiEWkSk.cjs +8 -0
  70. package/dist/parser-qk9FIHJ7.mjs +8 -0
  71. package/dist/plugin-C95kvu6h.mjs +73 -0
  72. package/dist/plugin-DM3u2bVj.cjs +73 -0
  73. package/dist/routes-BW6zsk7Z.mjs +6 -0
  74. package/dist/routes-BgoIB5wb.cjs +6 -0
  75. package/dist/{routes-BajCwrvX.cjs → routes-CORVxc02.cjs} +1 -1
  76. package/dist/{search-dialog-D4rplZMv.cjs → search-dialog-B1NERUNx.cjs} +101 -55
  77. package/dist/{search-dialog-Cx7aGW3U.cjs → search-dialog-BRFno7HD.cjs} +8 -8
  78. package/dist/{search-dialog-DDopgbKM.js → search-dialog-BmxHiKwt.js} +2 -2
  79. package/dist/{search-dialog-BNdRV60O.js → search-dialog-D6TvjcuV.js} +1 -1
  80. package/dist/{search-dialog-DaeSPvEo.js → search-dialog-DFnlx8LO.js} +44 -4
  81. package/dist/{search-dialog-CW1f6dn6.cjs → search-dialog-DHqwjJuG.cjs} +1 -1
  82. package/dist/server/index.cjs +1 -1
  83. package/dist/server/index.d.mts +1 -1
  84. package/dist/server/index.mjs +1 -1
  85. package/dist/shiki-adapter-CoQ6jyJ4.cjs +6 -0
  86. package/dist/shiki-adapter-D-aKw7PP.mjs +6 -0
  87. package/dist/sidebar-COTaMHR-.d.ts +1100 -0
  88. package/dist/sidebar-CrEdJuHX.d.cts +1100 -0
  89. package/dist/{types-generator-CYcHkDzZ.cjs → types-generator-BXhv7Ill.cjs} +1 -1
  90. package/dist/types-generator-bDPvUztF.mjs +26 -0
  91. package/dist/utils-Crm9oPcV.mjs +7 -0
  92. package/dist/utils-D6Xtj0FZ.cjs +7 -0
  93. package/package.json +26 -12
  94. package/src/shared/types.ts +532 -23
  95. package/dist/cache-DETwlACe.cjs +0 -6
  96. package/dist/cache-SF59enb3.mjs +0 -6
  97. package/dist/config-B5uVv5q4.cjs +0 -7
  98. package/dist/config-D3_zDkHh.mjs +0 -7
  99. package/dist/csp-gaZ51xzq.mjs +0 -6
  100. package/dist/doctor-3MheVMwd.mjs +0 -7
  101. package/dist/doctor-DQxLM202.cjs +0 -7
  102. package/dist/headers-CXyf0auY.mjs +0 -6
  103. package/dist/icons-dev-kJyGWNeg.js +0 -916
  104. package/dist/node-B9JSyEIU.mjs +0 -105
  105. package/dist/node-Cedquois.cjs +0 -105
  106. package/dist/parser-CNIPHx4s.cjs +0 -8
  107. package/dist/parser-D0QHIQsi.mjs +0 -8
  108. package/dist/plugin-WYNORxp1.cjs +0 -68
  109. package/dist/plugin-YWNVRpws.mjs +0 -68
  110. package/dist/rolldown-runtime-fkIsjY3S.mjs +0 -6
  111. package/dist/routes-CyrnmVuG.mjs +0 -6
  112. package/dist/routes-D6Tuu7Fs.cjs +0 -6
  113. package/dist/shiki-adapter-CGTmrR6S.cjs +0 -6
  114. package/dist/shiki-adapter-CXEGRnjr.mjs +0 -6
  115. package/dist/shiki-adapter-Mr8_oT_9.cjs +0 -6
  116. package/dist/sidebar-7gIifpBX.d.cts +0 -615
  117. package/dist/sidebar-BAKgJ-Er.d.ts +0 -615
  118. package/dist/types-generator-DVOnRVKU.mjs +0 -26
  119. package/dist/utils-B3xYMrpK.mjs +0 -7
  120. package/dist/utils-Bz1tG9Dg.cjs +0 -7
  121. /package/dist/{errors-C0Hx15Ag.mjs → errors-0zGHRLue.mjs} +0 -0
  122. /package/dist/{errors-Dx6JHoKE.cjs → errors-vKw8CkiX.cjs} +0 -0
  123. /package/dist/{index-CdJv4ocW.d.mts → index-1KsTDq4o.d.mts} +0 -0
@@ -3,18 +3,18 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- import { $ as TextAlignStart, C as RoutesProvider, D as Check, E as ArrowLeft, F as FaceBad, I as FaceGood, J as Moon, K as Menu, L as FaceRegular, M as Copy, O as ChevronDown, P as ExternalLink, Q as Sun, S as normalizePath, U as Languages, V as Home, X as Pencil, _ as Link$1, at as useBoltdocsContext, b as useLocalizedTo, et as X, it as BoltdocsProvider, j as CircleHelp, nt as ConfigContext, q as Monitor, rt as useConfig, s as Github, tt as icons_exports, x as useRoutes, y as cn } from "../icons-dev-kJyGWNeg.js";
7
- import { c as ThemeProvider, l as useTheme } from "../image-C9md50h2.js";
8
- import { n as useCodeBlock, r as copyToClipboard, t as mdx_components_default } from "../mdx-DhyMkc35.js";
9
- import { A as useUI, C as useSidebar, D as ButtonGroup, O as Breadcrumbs$2, S as useLocation, T as Menu$1, f as PageNav$1, k as UIProvider, m as OnThisPage$1, n as Sidebar$1, t as DocsLayout$1, w as Tabs$1, x as useSearchHighlight } from "../docs-layout-6FQ8__ok.js";
10
- import { a as Button$1, n as Navbar$1, r as ErrorBoundary$1 } from "../search-dialog-DaeSPvEo.js";
11
- import { n as useSearch, r as InternalErrorBoundary, t as SearchDialog } from "../search-dialog-DDopgbKM.js";
6
+ import { A as Monitor, B as useConfig, E as Languages, F as Sun, H as useBoltdocsContext, I as TextAlignStart, L as X, N as Pencil, R as icons_exports, V as BoltdocsProvider, a as useRoutes, b as FaceGood, d as Check, f as ChevronDown, g as Copy, h as CircleHelp, i as useLocalizedTo, j as Moon, k as Menu, o as normalizePath, r as cn, s as RoutesProvider, t as Link$1, u as ArrowLeft, v as ExternalLink, w as Home, x as FaceRegular, y as FaceBad, z as ConfigContext } from "../link-2PzgTnaP.js";
7
+ import { c as ThemeProvider, l as useTheme } from "../image-Bz87fCla.js";
8
+ import { i as copyToClipboard, n as Timeline, r as useCodeBlock, t as mdx_components_default } from "../mdx-BuO6a1f7.js";
9
+ import { A as useUI, C as useSidebar, D as ButtonGroup, O as Breadcrumbs$2, S as useLocation, T as Menu$1, f as PageNav$1, k as UIProvider, m as OnThisPage$1, n as Sidebar$1, t as DocsLayout$1, w as Tabs$1, x as useSearchHighlight } from "../docs-layout-BdtZ9z6s.js";
10
+ import { i as ErrorBoundary$1, n as Navbar$1, o as Button$1, r as Github } from "../search-dialog-DFnlx8LO.js";
11
+ import { n as useSearch, r as InternalErrorBoundary, t as SearchDialog } from "../search-dialog-BmxHiKwt.js";
12
12
  import { ViteReactSSG } from "@bdocs/ssg";
13
13
  import { Suspense, createContext, isValidElement, lazy, use, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
14
14
  import { Link, Outlet, useLoaderData, useLocation as useLocation$1, useMatches, useNavigate } from "react-router-dom";
15
15
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
16
- import * as ReactHelmetAsync from "react-helmet-async";
17
16
  import { Button } from "react-aria-components";
17
+ import * as ReactHelmetAsync from "react-helmet-async";
18
18
  import virtualCustomComponents from "virtual:boltdocs-mdx-components";
19
19
  import virtualIcons from "virtual:boltdocs-icons";
20
20
  import DOMPurify from "isomorphic-dompurify";
@@ -49,20 +49,6 @@ function MdxComponentsProvider({ components, children }) {
49
49
  });
50
50
  }
51
51
 
52
- //#endregion
53
- //#region src/client/app/helmet-compat.tsx
54
- const mod = ReactHelmetAsync;
55
- /**
56
- * The `<Helmet>` component, resolved across CJS/ESM module shapes.
57
- * Falls back to a transparent fragment wrapper if the module cannot be resolved.
58
- */
59
- const Helmet = mod.Helmet || mod.default?.Helmet || (({ children }) => /* @__PURE__ */ jsx(Fragment, { children }));
60
- /**
61
- * The `<HelmetProvider>` component, resolved across CJS/ESM module shapes.
62
- * Falls back to a transparent fragment wrapper if the module cannot be resolved.
63
- */
64
- const HelmetProvider = mod.HelmetProvider || mod.default?.HelmetProvider || (({ children }) => /* @__PURE__ */ jsx(Fragment, { children }));
65
-
66
52
  //#endregion
67
53
  //#region src/client/app/scroll-handler.tsx
68
54
  /**
@@ -73,7 +59,7 @@ const HelmetProvider = mod.HelmetProvider || mod.default?.HelmetProvider || (({
73
59
  function ScrollHandler() {
74
60
  const { pathname, hash } = useLocation$1();
75
61
  const handleScroll = (behavior = "auto") => {
76
- const container = document.querySelector(".boltdocs-content") || window;
62
+ const container = document.querySelector(".boltdocs-content") || document.querySelector(".boltdocs-external-content") || document.querySelector(".boltdocs-shell-content") || window;
77
63
  const getScrollTop = () => {
78
64
  if (container === window) return window.scrollY;
79
65
  return container.scrollTop;
@@ -106,11 +92,6 @@ function ScrollHandler() {
106
92
  }, [pathname, hash]);
107
93
  useEffect(() => {
108
94
  handleScroll("auto");
109
- const rafId = requestAnimationFrame(() => {
110
- handleScroll("auto");
111
- window.dispatchEvent(new Event("resize"));
112
- });
113
- return () => cancelAnimationFrame(rafId);
114
95
  }, [pathname, hash]);
115
96
  return null;
116
97
  }
@@ -155,6 +136,28 @@ const mdxComponentsDefault = {
155
136
  "404": NotFound
156
137
  };
157
138
 
139
+ //#endregion
140
+ //#region src/client/app/helmet-compat.tsx
141
+ const mod = ReactHelmetAsync;
142
+ /**
143
+ * The `<Helmet>` component, resolved across CJS/ESM module shapes.
144
+ * Falls back to a transparent fragment wrapper if the module cannot be resolved.
145
+ */
146
+ const Helmet = mod.Helmet || mod.default?.Helmet || (({ children }) => /* @__PURE__ */ jsx(Fragment, { children }));
147
+ /**
148
+ * The `<HelmetProvider>` component, resolved across CJS/ESM module shapes.
149
+ * Falls back to a transparent fragment wrapper if the module cannot be resolved.
150
+ */
151
+ const HelmetProvider = mod.HelmetProvider || mod.default?.HelmetProvider || (({ children }) => /* @__PURE__ */ jsx(Fragment, { children }));
152
+ if (typeof globalThis !== "undefined" && globalThis.__BOLTDOCS_SSG_RENDERING__) {
153
+ const hp = HelmetProvider;
154
+ if (hp && typeof hp === "function" && hp.canUseDOM) hp.canUseDOM = false;
155
+ }
156
+ if (typeof globalThis !== "undefined") {
157
+ globalThis.__BOLTDOCS_HELMET_PROVIDER__ = HelmetProvider;
158
+ globalThis.__BOLTDOCS_HELMET__ = Helmet;
159
+ }
160
+
158
161
  //#endregion
159
162
  //#region src/client/utils/i18n.ts
160
163
  /**
@@ -272,12 +275,14 @@ function Head({ siteTitle, siteDescription, routes }) {
272
275
  content: config.seo.verification.facebook
273
276
  }),
274
277
  Object.entries(globalMetatags).map(([key, value]) => {
275
- return key.startsWith("og:") || key.startsWith("music:") || key.startsWith("video:") || key.startsWith("article:") || key.startsWith("book:") || key.startsWith("profile:") ? /* @__PURE__ */ jsx("meta", {
278
+ const isProperty = key.startsWith("og:") || key.startsWith("music:") || key.startsWith("video:") || key.startsWith("article:") || key.startsWith("book:") || key.startsWith("profile:");
279
+ const strVal = String(value ?? "");
280
+ return isProperty ? /* @__PURE__ */ jsx("meta", {
276
281
  property: key,
277
- content: value
282
+ content: strVal
278
283
  }, key) : /* @__PURE__ */ jsx("meta", {
279
284
  name: key,
280
- content: value
285
+ content: strVal
281
286
  }, key);
282
287
  }),
283
288
  Object.entries(seo).map(([key, value]) => {
@@ -287,15 +292,17 @@ function Head({ siteTitle, siteDescription, routes }) {
287
292
  }, "noindex");
288
293
  if (key === "robots") return /* @__PURE__ */ jsx("meta", {
289
294
  name: "robots",
290
- content: value
295
+ content: String(value)
291
296
  }, "robots");
292
297
  if (key === "canonical" || key === "og:url" || key === "og:image" || key === "twitter:image") return null;
293
- return key.startsWith("og:") || key.startsWith("music:") || key.startsWith("video:") || key.startsWith("article:") || key.startsWith("book:") || key.startsWith("profile:") ? /* @__PURE__ */ jsx("meta", {
298
+ const isProperty = key.startsWith("og:") || key.startsWith("music:") || key.startsWith("video:") || key.startsWith("article:") || key.startsWith("book:") || key.startsWith("profile:");
299
+ const strVal = String(value ?? "");
300
+ return isProperty ? /* @__PURE__ */ jsx("meta", {
294
301
  property: key,
295
- content: value
302
+ content: strVal
296
303
  }, key) : /* @__PURE__ */ jsx("meta", {
297
304
  name: key,
298
- content: value
305
+ content: strVal
299
306
  }, key);
300
307
  })
301
308
  ] });
@@ -307,6 +314,16 @@ const CollectionsContext = createContext({});
307
314
  function useCollectionsData() {
308
315
  return use(CollectionsContext);
309
316
  }
317
+ const CurrentPostContext = createContext(null);
318
+ function CurrentPostProvider({ value, children }) {
319
+ return /* @__PURE__ */ jsx(CurrentPostContext.Provider, {
320
+ value,
321
+ children
322
+ });
323
+ }
324
+ function useCurrentPostData() {
325
+ return use(CurrentPostContext);
326
+ }
310
327
 
311
328
  //#endregion
312
329
  //#region src/client/ssg/boltdocs-shell.tsx
@@ -376,7 +393,7 @@ function BoltdocsShell({ config, routes, components = {}, collectionsData }) {
376
393
  config,
377
394
  routeMap
378
395
  ]);
379
- return /* @__PURE__ */ jsx(HelmetProvider, { children: /* @__PURE__ */ jsx(RoutesProvider, {
396
+ return /* @__PURE__ */ jsx(RoutesProvider, {
380
397
  routes,
381
398
  children: /* @__PURE__ */ jsx(ThemeProvider, { children: /* @__PURE__ */ jsx(UIProvider, { children: /* @__PURE__ */ jsx(MdxComponentsProvider, {
382
399
  components: allComponents,
@@ -398,13 +415,16 @@ function BoltdocsShell({ config, routes, components = {}, collectionsData }) {
398
415
  siteDescription: config.theme?.description,
399
416
  routes
400
417
  }),
401
- /* @__PURE__ */ jsx(InternalErrorBoundary, { children: /* @__PURE__ */ jsx(Outlet, {}) })
418
+ /* @__PURE__ */ jsx(InternalErrorBoundary, { children: /* @__PURE__ */ jsx("div", {
419
+ className: "boltdocs-shell-content h-screen overflow-hidden",
420
+ children: /* @__PURE__ */ jsx(Outlet, {})
421
+ }) })
402
422
  ]
403
423
  })]
404
424
  })
405
425
  })
406
426
  }) }) })
407
- }) });
427
+ });
408
428
  }
409
429
 
410
430
  //#endregion
@@ -449,17 +469,43 @@ function DocPage({ route, content: Content, mdxComponents: propComponents }) {
449
469
  /**
450
470
  * Renders an MDX page by consuming pre-loaded route data.
451
471
  *
452
- * - If the route belongs to a collection (`data.collection` is set), renders
453
- * the custom post component if provided, else falls back to the standard DocPage.
472
+ * - If the route belongs to a collection (`data.collection` is set), wraps
473
+ * the content with `CurrentPostProvider` so that `usePost()` (called without
474
+ * a slug) can read the current post's data from context.
454
475
  * - Otherwise, renders the standard `DocPage` layout.
455
476
  */
456
477
  function MdxPage({ MDXComponent, mdxComponents: propComponents, collectionPostComponent: CollectionPost }) {
457
478
  const data = useLoaderData();
458
479
  if (!MDXComponent) return null;
459
- if (!!data?.collection && CollectionPost) return /* @__PURE__ */ jsx(CollectionPost, {
460
- MDXComponent,
461
- mdxComponents: propComponents
462
- });
480
+ const collectionData = data;
481
+ if (!!collectionData?.collection) {
482
+ const postElement = CollectionPost ? /* @__PURE__ */ jsx(CollectionPost, {
483
+ MDXComponent,
484
+ mdxComponents: propComponents
485
+ }) : /* @__PURE__ */ jsx(DocPage, {
486
+ route: {
487
+ path: collectionData.route.path,
488
+ filePath: collectionData.route.filePath,
489
+ title: collectionData.route.title,
490
+ description: collectionData.route.description,
491
+ headings: collectionData.headings,
492
+ locale: collectionData.route.locale,
493
+ version: collectionData.route.version,
494
+ lastUpdated: collectionData.route.lastUpdated,
495
+ frontmatter: collectionData.route.frontmatter
496
+ },
497
+ content: MDXComponent,
498
+ mdxComponents: propComponents
499
+ });
500
+ return /* @__PURE__ */ jsx(CurrentPostProvider, {
501
+ value: {
502
+ route: collectionData.route,
503
+ headings: collectionData.headings,
504
+ collection: collectionData.collection
505
+ },
506
+ children: postElement
507
+ });
508
+ }
463
509
  const docData = data;
464
510
  return /* @__PURE__ */ jsx(DocPage, {
465
511
  route: {
@@ -517,7 +563,7 @@ function Breadcrumbs() {
517
563
  return /* @__PURE__ */ jsxs(Breadcrumbs$2.Item, {
518
564
  className: "gap-2",
519
565
  children: [/* @__PURE__ */ jsx(Breadcrumbs$2.Separator, { className: "text-muted/40" }), /* @__PURE__ */ jsx(Breadcrumbs$2.Link, {
520
- href: crumb.href,
566
+ href: crumb.href ?? "",
521
567
  className: cn("transition-colors", isActive ? "text-body font-semibold cursor-default pointer-events-none" : "text-muted hover:text-body"),
522
568
  children: crumb.label
523
569
  })]
@@ -692,7 +738,7 @@ function useNavbar() {
692
738
  const cleanPathParts = (p) => {
693
739
  const parts = p.split("/").filter(Boolean);
694
740
  let i = 0;
695
- if (config.i18n?.locales && parts[i] && config.i18n.locales[parts[i]]) i++;
741
+ if (config.i18n?.locales && parts[i] && !Array.isArray(config.i18n.locales) && config.i18n.locales[parts[i]]) i++;
696
742
  if (config.versions?.versions && parts[i]) {
697
743
  if (config.versions.versions.some((v) => v.path === parts[i])) i++;
698
744
  }
@@ -1022,7 +1068,7 @@ function VersionSelector({ className }) {
1022
1068
  function useI18n() {
1023
1069
  const navigate = useNavigate();
1024
1070
  const config = useConfig();
1025
- const { allRoutes, currentRoute, currentLocale, currentVersion } = useRoutes();
1071
+ const { allRoutes, currentRoute, currentLocale, isCollectionPage } = useRoutes();
1026
1072
  const i18n = config.i18n;
1027
1073
  const { setLocale } = useBoltdocsContext();
1028
1074
  const handleLocaleChange = (locale) => {
@@ -1032,7 +1078,7 @@ function useI18n() {
1032
1078
  const safeBase = base === "/" ? "" : base.replace(/\/$/, "");
1033
1079
  const isDocRoute = !!currentRoute?.filePath;
1034
1080
  let targetPath = "";
1035
- if (currentRoute) if (isDocRoute) {
1081
+ if (currentRoute) if (isDocRoute && !currentRoute.collection && !isCollectionPage) {
1036
1082
  const baseFile = getBaseFilePath(currentRoute.filePath, currentRoute.version, currentRoute.locale);
1037
1083
  const targetRoute = allRoutes.find((r) => getBaseFilePath(r.filePath, r.version, r.locale) === baseFile && (r.locale || i18n.defaultLocale) === locale && r.version === currentRoute.version);
1038
1084
  if (targetRoute) targetPath = targetRoute.path;
@@ -1044,25 +1090,29 @@ function useI18n() {
1044
1090
  } else {
1045
1091
  let rawExternal = currentRoute.path;
1046
1092
  const parts = rawExternal.split("/").filter(Boolean);
1047
- if (parts.length > 0 && (Array.isArray(i18n.locales) ? i18n.locales.includes(parts[0]) : !!i18n.locales[parts[0]])) {
1048
- parts.shift();
1093
+ const localePosition = currentRoute.collection ? 1 : 0;
1094
+ if (parts.length > localePosition && (Array.isArray(i18n.locales) ? i18n.locales.includes(parts[localePosition]) : !!i18n.locales[parts[localePosition]])) {
1095
+ parts.splice(localePosition, 1);
1049
1096
  rawExternal = "/" + parts.join("/");
1050
1097
  }
1098
+ const cleanParts = rawExternal.split("/").filter(Boolean);
1051
1099
  if (locale === i18n.defaultLocale) targetPath = rawExternal === "" ? "/" : rawExternal;
1052
1100
  else {
1053
- const cleanExt = rawExternal.startsWith("/") ? rawExternal : `/${rawExternal}`;
1054
- targetPath = `/${locale}${cleanExt === "/" ? "" : cleanExt}`;
1101
+ cleanParts.splice(localePosition, 0, locale);
1102
+ targetPath = "/" + cleanParts.join("/") || "/";
1055
1103
  }
1056
1104
  }
1057
1105
  else {
1058
- const targetRoute = allRoutes.find((r) => (r.locale || i18n.defaultLocale) === locale && (r.version || config.versions?.defaultVersion) === (currentVersion || config.versions?.defaultVersion));
1059
- if (targetRoute) targetPath = targetRoute.path;
1106
+ const currentPath = location.pathname;
1107
+ if (isCollectionPage) targetPath = currentPath;
1060
1108
  else {
1061
- const vPath = currentVersion && currentVersion !== config.versions?.defaultVersion ? `/${currentVersion}` : "";
1062
- targetPath = locale === i18n.defaultLocale ? `${safeBase}${vPath}` : `${safeBase}${vPath}/${locale}`;
1109
+ const parts = currentPath.split("/").filter(Boolean);
1110
+ if (parts.length > 0 && (Array.isArray(i18n.locales) ? i18n.locales.includes(parts[0]) : !!i18n.locales[parts[0]])) parts.shift();
1111
+ if (locale !== i18n.defaultLocale) parts.unshift(locale);
1112
+ targetPath = "/" + parts.join("/");
1063
1113
  }
1064
1114
  }
1065
- if (!targetPath || targetPath === "") targetPath = "/";
1115
+ if (!targetPath || targetPath === "") targetPath = "/s";
1066
1116
  targetPath = targetPath.replace(/\/+/g, "/");
1067
1117
  navigate(targetPath);
1068
1118
  };
@@ -1146,10 +1196,42 @@ function usePageNav() {
1146
1196
  //#region src/client/hooks/use-analytics.ts
1147
1197
  function createAnalyticsInstance(config) {
1148
1198
  if (typeof window === "undefined") return createDisabledAnalytics();
1199
+ if (window.posthog) return createPostHogAnalytics(config);
1149
1200
  if (typeof window.gtag === "function") return createGtagAnalytics(config);
1150
1201
  if (window.dataLayer) return createDataLayerAnalytics(config);
1151
1202
  return createDisabledAnalytics();
1152
1203
  }
1204
+ function createPostHogAnalytics(_config) {
1205
+ return {
1206
+ trackPageView: (path) => {
1207
+ window.posthog?.capture("$pageview", { $current_url: path });
1208
+ },
1209
+ trackEvent: ({ action, category, label, value, params }) => {
1210
+ window.posthog?.capture(action, {
1211
+ event_category: category,
1212
+ event_label: label,
1213
+ value,
1214
+ ...params
1215
+ });
1216
+ },
1217
+ trackSearch: (query, resultsCount) => {
1218
+ window.posthog?.capture("search", {
1219
+ query,
1220
+ results_count: resultsCount
1221
+ });
1222
+ },
1223
+ trackDownload: (file, type) => {
1224
+ window.posthog?.capture("file_download", {
1225
+ file_name: file,
1226
+ file_type: type || file.split(".").pop()
1227
+ });
1228
+ },
1229
+ trackExternalLink: (url) => {
1230
+ window.posthog?.capture("external_link", { link_url: url });
1231
+ },
1232
+ isEnabled: true
1233
+ };
1234
+ }
1153
1235
  function createGtagAnalytics(config) {
1154
1236
  return {
1155
1237
  trackPageView: (path, title) => {
@@ -1433,7 +1515,7 @@ function I18nSelector({ className }) {
1433
1515
 
1434
1516
  //#endregion
1435
1517
  //#region src/client/components/ui-base/navbar.tsx
1436
- const SearchDialog$1 = lazy(() => import("../search-dialog-BNdRV60O.js").then((m) => ({ default: m.SearchDialog })));
1518
+ const SearchDialog$1 = lazy(() => import("../search-dialog-D6TvjcuV.js").then((m) => ({ default: m.SearchDialog })));
1437
1519
  function Navbar() {
1438
1520
  const { links, title, logo, logoProps, github, social, config } = useNavbar();
1439
1521
  const { routes, currentRoute, isCollectionPage, currentVersion, currentLocale } = useRoutes();
@@ -1464,6 +1546,10 @@ function Navbar() {
1464
1546
  href: "site:/",
1465
1547
  children: title
1466
1548
  }),
1549
+ currentRoute?.draft && /* @__PURE__ */ jsx("span", {
1550
+ className: "hidden sm:inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400 border border-yellow-200 dark:border-yellow-800",
1551
+ children: "Draft"
1552
+ }),
1467
1553
  /* @__PURE__ */ jsx("div", {
1468
1554
  className: "hidden sm:block",
1469
1555
  children: config.versions && currentVersion && /* @__PURE__ */ jsx(VersionSelector, {})
@@ -1600,13 +1686,19 @@ function NavbarMobileLinkItem({ link, onClose }) {
1600
1686
  //#endregion
1601
1687
  //#region src/client/components/ui-base/on-this-page.tsx
1602
1688
  function OnThisPage({ headings = [], editLink, communityHelp, filePath }) {
1603
- if (headings.length === 0) return null;
1689
+ if (headings.length === 0) return /* @__PURE__ */ jsx("nav", {
1690
+ className: "w-toc shrink-0 hidden xl:block",
1691
+ "aria-hidden": "true"
1692
+ });
1604
1693
  return /* @__PURE__ */ jsxs(OnThisPage$1.Root, { children: [
1605
1694
  /* @__PURE__ */ jsxs(OnThisPage$1.Header, {
1606
1695
  className: "flex flex-row gap-x-2",
1607
1696
  children: [/* @__PURE__ */ jsx(TextAlignStart, { size: 16 }), "On this page"]
1608
1697
  }),
1609
- /* @__PURE__ */ jsx(OnThisPage$1.Tree, { headings }),
1698
+ /* @__PURE__ */ jsx(OnThisPage$1.Tree, {
1699
+ className: "max-h-[300px]",
1700
+ headings
1701
+ }),
1610
1702
  (editLink || communityHelp) && /* @__PURE__ */ jsxs("div", {
1611
1703
  className: "mt-8 pt-8 border-t border-subtle space-y-4",
1612
1704
  children: [/* @__PURE__ */ jsx("p", {
@@ -1923,7 +2015,7 @@ const EagerMdxElement = ({ moduleLoader, moduleKey, route, components, collectio
1923
2015
  if (!MDXComponent) return /* @__PURE__ */ jsx(Loading, {});
1924
2016
  return /* @__PURE__ */ jsx(MdxPage, {
1925
2017
  MDXComponent,
1926
- mdxComponents: components,
2018
+ mdxComponents: components ?? {},
1927
2019
  collectionPostComponent
1928
2020
  });
1929
2021
  };
@@ -1932,14 +2024,36 @@ const NotFoundWrapper = () => {
1932
2024
  return /* @__PURE__ */ jsx(components.NotFound || components["404"] || NotFound, {});
1933
2025
  };
1934
2026
 
2027
+ //#endregion
2028
+ //#region src/client/app/doc-route-context.tsx
2029
+ /**
2030
+ * Context that exposes the currently active route to every primitive in the
2031
+ * tree. Slot renderers and other primitives consume it via `useDocRoute()`
2032
+ * instead of calling `useRoutes()` directly so a single computation is shared
2033
+ * across the whole layout.
2034
+ *
2035
+ * `undefined` means "no active route" (e.g. on a not-found page or before the
2036
+ * routes context has hydrated).
2037
+ */
2038
+ const DocRouteContext = createContext(void 0);
2039
+ function DocRouteProvider({ value, children }) {
2040
+ return /* @__PURE__ */ jsx(DocRouteContext.Provider, {
2041
+ value,
2042
+ children
2043
+ });
2044
+ }
2045
+
1935
2046
  //#endregion
1936
2047
  //#region src/client/app/docs-layout.tsx
1937
2048
  function DocsLayout({ collectionsData }) {
1938
2049
  const { currentRoute } = useRoutes();
1939
- const content = /* @__PURE__ */ jsx(InternalErrorBoundary, { children: /* @__PURE__ */ jsx(UserLayout, {
1940
- route: currentRoute,
1941
- children: /* @__PURE__ */ jsx(Outlet, {})
1942
- }) });
2050
+ const content = /* @__PURE__ */ jsx(DocRouteProvider, {
2051
+ value: currentRoute,
2052
+ children: /* @__PURE__ */ jsx(InternalErrorBoundary, { children: /* @__PURE__ */ jsx(UserLayout, {
2053
+ route: currentRoute,
2054
+ children: /* @__PURE__ */ jsx(Outlet, {})
2055
+ }) })
2056
+ });
1943
2057
  if (collectionsData) return /* @__PURE__ */ jsx(CollectionsContext.Provider, {
1944
2058
  value: collectionsData,
1945
2059
  children: content
@@ -2032,15 +2146,15 @@ function buildDocRoutes(options) {
2032
2146
  moduleKey,
2033
2147
  moduleLoader: mod,
2034
2148
  route,
2035
- components
2149
+ components: components ?? {}
2036
2150
  }, moduleKey || path);
2037
2151
  } };
2038
2152
  };
2039
2153
  else routeRecord.element = /* @__PURE__ */ jsx(EagerMdxElement, {
2040
2154
  moduleKey,
2041
- moduleLoader,
2155
+ moduleLoader: moduleLoader ?? {},
2042
2156
  route,
2043
- components
2157
+ components: components ?? {}
2044
2158
  }, moduleKey || path);
2045
2159
  return routeRecord;
2046
2160
  });
@@ -2139,6 +2253,15 @@ function buildDocRoutes(options) {
2139
2253
  };
2140
2254
  }
2141
2255
 
2256
+ //#endregion
2257
+ //#region src/client/ssg/external-page-wrapper.tsx
2258
+ function ExternalPageWrapper({ children }) {
2259
+ return /* @__PURE__ */ jsx("div", {
2260
+ className: "boltdocs-external-content h-screen overflow-y-auto",
2261
+ children
2262
+ });
2263
+ }
2264
+
2142
2265
  //#endregion
2143
2266
  //#region src/client/ssg/create-routes.external.tsx
2144
2267
  function buildExternalRoutes(options) {
@@ -2157,11 +2280,12 @@ function buildExternalRoutes(options) {
2157
2280
  locale: config.i18n?.defaultLocale,
2158
2281
  title: rawPath === "/" ? "Home" : rawPath.replace(/^\//, "").split("/").pop() || "Page",
2159
2282
  filePath: "",
2283
+ componentPath: "",
2160
2284
  headings: []
2161
2285
  });
2162
2286
  children.push({
2163
2287
  path,
2164
- element: /* @__PURE__ */ jsx(EffectiveExternalLayout, { children: /* @__PURE__ */ jsx(ExtComponent, {}) }),
2288
+ element: /* @__PURE__ */ jsx(ExternalPageWrapper, { children: /* @__PURE__ */ jsx(EffectiveExternalLayout, { children: /* @__PURE__ */ jsx(ExtComponent, {}) }) }),
2165
2289
  loader: async () => ({
2166
2290
  path,
2167
2291
  locale: config.i18n?.defaultLocale
@@ -2175,11 +2299,12 @@ function buildExternalRoutes(options) {
2175
2299
  locale,
2176
2300
  title: rawPath,
2177
2301
  filePath: "",
2302
+ componentPath: "",
2178
2303
  headings: []
2179
2304
  });
2180
2305
  children.push({
2181
2306
  path: localePath,
2182
- element: /* @__PURE__ */ jsx(EffectiveExternalLayout, { children: /* @__PURE__ */ jsx(ExtComponent, {}) }),
2307
+ element: /* @__PURE__ */ jsx(ExternalPageWrapper, { children: /* @__PURE__ */ jsx(EffectiveExternalLayout, { children: /* @__PURE__ */ jsx(ExtComponent, {}) }) }),
2183
2308
  loader: async () => ({
2184
2309
  path: localePath,
2185
2310
  locale
@@ -2194,21 +2319,107 @@ function buildExternalRoutes(options) {
2194
2319
  };
2195
2320
  }
2196
2321
 
2322
+ //#endregion
2323
+ //#region src/client/collections/hooks.ts
2324
+ const DEFAULT_COLLECTION = "blog";
2325
+ /**
2326
+ * Returns the posts of a collection, filtered by the current locale and version.
2327
+ * Defaults to "blog" if no collection is specified.
2328
+ * @param collection - The name of the collection. Defaults to "blog".
2329
+ * @param options - Options to customize the query.
2330
+ * @param options.includeDrafts - If true, includes draft posts in the results.
2331
+ * @returns The filtered posts of the collection.
2332
+ */
2333
+ function usePosts(collection = DEFAULT_COLLECTION, options) {
2334
+ const data = useCollectionsData();
2335
+ const { currentLocale, currentVersion } = useRoutes();
2336
+ const config = useConfig();
2337
+ const posts = data[collection] || [];
2338
+ const defaultLocale = config.i18n?.defaultLocale;
2339
+ const defaultVersion = config.versions?.defaultVersion;
2340
+ return useMemo(() => {
2341
+ return posts.filter((post) => {
2342
+ const postLocale = post.locale || defaultLocale;
2343
+ const postVersion = post.version || defaultVersion;
2344
+ const localeMatch = !currentLocale || postLocale === currentLocale;
2345
+ const versionMatch = !currentVersion || postVersion === currentVersion;
2346
+ const draftMatch = options?.includeDrafts || !post.draft;
2347
+ return localeMatch && versionMatch && draftMatch;
2348
+ });
2349
+ }, [
2350
+ posts,
2351
+ currentLocale,
2352
+ currentVersion,
2353
+ defaultLocale,
2354
+ defaultVersion,
2355
+ options?.includeDrafts
2356
+ ]);
2357
+ }
2358
+ function usePost(collection, slug) {
2359
+ const ctx = useCurrentPostData();
2360
+ const posts = usePosts(collection);
2361
+ if (ctx && !slug) {
2362
+ const { route } = ctx;
2363
+ return useMemo(() => ({
2364
+ path: route.path,
2365
+ title: route.title,
2366
+ date: route.date,
2367
+ excerpt: route.excerpt,
2368
+ tags: route.tags,
2369
+ author: route.author,
2370
+ coverImage: route.coverImage,
2371
+ filePath: route.filePath,
2372
+ locale: route.locale,
2373
+ version: route.version,
2374
+ frontmatter: route.frontmatter,
2375
+ lastUpdated: route.lastUpdated,
2376
+ headings: route.headings
2377
+ }), [route]);
2378
+ }
2379
+ if (!collection || !slug) return void 0;
2380
+ return useMemo(() => posts.find((p) => p.path === `/${collection}/${slug}` || p.path.endsWith(`/${slug}`) || p.path === slug), [
2381
+ posts,
2382
+ collection,
2383
+ slug
2384
+ ]);
2385
+ }
2386
+ /**
2387
+ * Returns the recent posts of a collection. Defaults to "blog".
2388
+ * @param collection - The name of the collection. Defaults to "blog".
2389
+ * @param count - The number of recent posts to return.
2390
+ * @returns The recent posts of the collection.
2391
+ */
2392
+ function useRecentPosts(collection = DEFAULT_COLLECTION, count = 5) {
2393
+ const posts = usePosts(collection);
2394
+ return useMemo(() => posts.slice(0, count), [posts, count]);
2395
+ }
2396
+
2197
2397
  //#endregion
2198
2398
  //#region src/client/ssg/create-routes.collection.tsx
2199
2399
  function DefaultCollectionList() {
2200
- const data = useLoaderData();
2201
- if (!data || !data.posts) return null;
2400
+ const location = useLocation$1();
2401
+ const config = useConfig();
2402
+ const postsPerPage = config.collections?.postsPerPage ?? 10;
2403
+ const segments = location.pathname.split("/").filter(Boolean);
2404
+ const isLocalePrefixed = config.i18n && segments[0] in (config.i18n.locales || {});
2405
+ const collection = isLocalePrefixed ? segments[1] : segments[0];
2406
+ const currentPage = (isLocalePrefixed ? segments[3] : segments[2]) === "page" ? Number(isLocalePrefixed ? segments[4] : segments[3]) || 1 : 1;
2407
+ const allPosts = usePosts(collection);
2408
+ const totalPages = Math.ceil(allPosts.length / postsPerPage);
2409
+ const start = (currentPage - 1) * postsPerPage;
2410
+ const posts = allPosts.slice(start, start + postsPerPage);
2411
+ if (!posts.length) return null;
2412
+ const basePath = isLocalePrefixed ? `/${segments[0]}/${segments[1]}` : `/${segments[0]}`;
2202
2413
  return /* @__PURE__ */ jsxs("div", {
2203
2414
  className: "py-8 max-w-2xl mx-auto px-4",
2204
2415
  children: [
2205
2416
  /* @__PURE__ */ jsx("h1", {
2206
2417
  className: "text-3xl font-bold mb-6 capitalize",
2207
- children: data.collection
2418
+ children: collection
2208
2419
  }),
2209
2420
  /* @__PURE__ */ jsx("div", {
2210
2421
  className: "space-y-6",
2211
- children: data.posts.map((post) => /* @__PURE__ */ jsxs("article", {
2422
+ children: posts.map((post) => /* @__PURE__ */ jsxs("article", {
2212
2423
  className: "border-b border-subtle pb-4",
2213
2424
  children: [
2214
2425
  /* @__PURE__ */ jsx("h2", {
@@ -2230,22 +2441,22 @@ function DefaultCollectionList() {
2230
2441
  ]
2231
2442
  }, post.path))
2232
2443
  }),
2233
- data.totalPages > 1 && /* @__PURE__ */ jsxs("div", {
2444
+ totalPages > 1 && /* @__PURE__ */ jsxs("div", {
2234
2445
  className: "mt-8 flex gap-4 text-sm",
2235
2446
  children: [
2236
- data.currentPage > 1 && /* @__PURE__ */ jsx(Link, {
2237
- to: data.currentPage === 2 ? `/${data.collection}` : `/${data.collection}/page/${data.currentPage - 1}`,
2447
+ currentPage > 1 && /* @__PURE__ */ jsx(Link, {
2448
+ to: currentPage === 2 ? basePath : `${basePath}/page/${currentPage - 1}`,
2238
2449
  className: "text-primary-600 hover:underline",
2239
2450
  children: "Previous"
2240
2451
  }),
2241
2452
  /* @__PURE__ */ jsxs("span", { children: [
2242
2453
  "Page ",
2243
- data.currentPage,
2454
+ currentPage,
2244
2455
  " of ",
2245
- data.totalPages
2456
+ totalPages
2246
2457
  ] }),
2247
- data.currentPage < data.totalPages && /* @__PURE__ */ jsx(Link, {
2248
- to: `/${data.collection}/page/${data.currentPage + 1}`,
2458
+ currentPage < totalPages && /* @__PURE__ */ jsx(Link, {
2459
+ to: `${basePath}/page/${currentPage + 1}`,
2249
2460
  className: "text-primary-600 hover:underline",
2250
2461
  children: "Next"
2251
2462
  })
@@ -2336,6 +2547,9 @@ function buildCollectionRoutes(options) {
2336
2547
  author: r.author,
2337
2548
  coverImage: r.coverImage,
2338
2549
  filePath: r.filePath,
2550
+ locale: r.locale,
2551
+ version: r.version,
2552
+ lastUpdated: r.lastUpdated,
2339
2553
  frontmatter: r.frontmatter
2340
2554
  }));
2341
2555
  const ListElement = collectionLists?.[colName] || DefaultCollectionList;
@@ -2393,7 +2607,7 @@ function createRoutes(options) {
2393
2607
  ...collectionRoutes.children,
2394
2608
  {
2395
2609
  path: "*",
2396
- element: /* @__PURE__ */ jsx(EffectiveExternalLayout, { children: /* @__PURE__ */ jsx(NotFoundWrapper, {}) })
2610
+ element: /* @__PURE__ */ jsx(ExternalPageWrapper, { children: /* @__PURE__ */ jsx(EffectiveExternalLayout, { children: /* @__PURE__ */ jsx(NotFoundWrapper, {}) }) })
2397
2611
  }
2398
2612
  ];
2399
2613
  return [{
@@ -2413,21 +2627,17 @@ function createRoutes(options) {
2413
2627
 
2414
2628
  //#endregion
2415
2629
  //#region src/client/components/docs-layout-default.tsx
2630
+ /**
2631
+ * Default docs layout — composes the visual primitives and delegates
2632
+ * sub-area routing to them. Slot rendering (plugin injections at
2633
+ * `navbar:end`, `sidebar:bottom`, `docs-content:top`, etc.) is handled
2634
+ * internally by each primitive so the layout itself does no slot "magic".
2635
+ *
2636
+ * A custom layout can reuse any primitive and the slot wiring just works.
2637
+ */
2416
2638
  function DocsLayoutComponent({ children }) {
2417
2639
  const { routes: filteredRoutes, currentRoute, isCollectionPage } = useRoutes();
2418
2640
  const config = useConfig();
2419
- const AskAiDialog = useMergedComponents().AskAiDialog;
2420
- const [isAskAiOpen, setIsAskAiOpen] = useState(false);
2421
- useEffect(() => {
2422
- const handleOpen = () => setIsAskAiOpen(true);
2423
- const handleClose = () => setIsAskAiOpen(false);
2424
- window.addEventListener("boltdocs:ask-ai:open", handleOpen);
2425
- window.addEventListener("boltdocs:ask-ai:close", handleClose);
2426
- return () => {
2427
- window.removeEventListener("boltdocs:ask-ai:open", handleOpen);
2428
- window.removeEventListener("boltdocs:ask-ai:close", handleClose);
2429
- };
2430
- }, []);
2431
2641
  return /* @__PURE__ */ jsxs(DocsLayout$1, {
2432
2642
  className: "selection:bg-primary-500/10 selection:text-primary-500",
2433
2643
  children: [/* @__PURE__ */ jsx(Navbar, {}), /* @__PURE__ */ jsxs(DocsLayout$1.Body, {
@@ -2437,97 +2647,46 @@ function DocsLayoutComponent({ children }) {
2437
2647
  routes: filteredRoutes || [],
2438
2648
  config
2439
2649
  }),
2440
- /* @__PURE__ */ jsx(DocsLayout$1.Content, {
2441
- className: "animate-in fade-in duration-500 scroll-smooth",
2442
- children: /* @__PURE__ */ jsxs(DocsLayout$1.ContentMdx, {
2443
- className: "max-w-3xl sm:max-w-4xl lg:max-w-5xl px-4 sm:px-6 pt-8 pb-24",
2444
- children: [
2445
- !isCollectionPage && /* @__PURE__ */ jsxs(DocsLayout$1.Header, { children: [
2446
- /* @__PURE__ */ jsxs("div", {
2447
- className: "mb-4 border-b border-subtle pb-4 flex flex-wrap items-center justify-between gap-3",
2448
- children: [/* @__PURE__ */ jsx(Breadcrumbs, {}), /* @__PURE__ */ jsx(CopyMarkdown, {
2449
- mdxRaw: currentRoute?._rawContent,
2450
- route: currentRoute
2451
- })]
2452
- }),
2453
- currentRoute?.title && /* @__PURE__ */ jsx("h1", {
2454
- className: "text-4xl font-bold tracking-tight text-default mb-3",
2455
- children: currentRoute.title
2456
- }),
2457
- currentRoute?.description && /* @__PURE__ */ jsx("p", {
2458
- className: "text-lg text-muted-foreground mb-6 leading-relaxed",
2459
- children: currentRoute.description
2460
- })
2461
- ] }),
2462
- /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx("div", {
2463
- className: "prose prose-neutral dark:prose-invert max-w-none",
2464
- children
2465
- }) }),
2466
- !isCollectionPage && /* @__PURE__ */ jsx(Feedback, {}),
2467
- !isCollectionPage && /* @__PURE__ */ jsx(Giscus, {}),
2468
- /* @__PURE__ */ jsx(DocsLayout$1.Footer, { children: !isCollectionPage && /* @__PURE__ */ jsx(PageNav, {}) })
2469
- ]
2650
+ /* @__PURE__ */ jsx(DocsLayout$1.Content, { children: /* @__PURE__ */ jsxs(DocsLayout$1.ContentMdx, { children: [
2651
+ !isCollectionPage && /* @__PURE__ */ jsxs(DocsLayout$1.Header, { children: [
2652
+ /* @__PURE__ */ jsxs("div", {
2653
+ className: "mb-4 border-b border-subtle pb-4 flex flex-wrap items-center justify-between gap-3",
2654
+ children: [/* @__PURE__ */ jsx(Breadcrumbs, {}), /* @__PURE__ */ jsx(CopyMarkdown, {
2655
+ mdxRaw: currentRoute?._rawContent,
2656
+ route: currentRoute
2657
+ })]
2658
+ }),
2659
+ currentRoute?.title && /* @__PURE__ */ jsx("h1", {
2660
+ className: "text-4xl font-bold tracking-tight text-default mb-3",
2661
+ children: currentRoute.title
2662
+ }),
2663
+ currentRoute?.description && /* @__PURE__ */ jsx("p", {
2664
+ className: "text-lg text-muted-foreground mb-6 leading-relaxed",
2665
+ children: currentRoute.description
2666
+ })
2667
+ ] }),
2668
+ /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx("div", {
2669
+ className: "prose prose-neutral dark:prose-invert max-w-none",
2670
+ children
2671
+ }) }),
2672
+ !isCollectionPage && /* @__PURE__ */ jsx(Feedback, {}),
2673
+ !isCollectionPage && /* @__PURE__ */ jsx(Giscus, {}),
2674
+ /* @__PURE__ */ jsx(DocsLayout$1.Footer, { children: !isCollectionPage && /* @__PURE__ */ jsx(PageNav, {}) })
2675
+ ] }) }),
2676
+ /* @__PURE__ */ jsx("div", {
2677
+ className: "overflow-y-auto sticky",
2678
+ children: /* @__PURE__ */ jsx(OnThisPage, {
2679
+ headings: currentRoute?.headings,
2680
+ filePath: currentRoute?.filePath,
2681
+ communityHelp: config.theme?.communityHelp,
2682
+ editLink: config.theme?.editLink
2470
2683
  })
2471
- }),
2472
- AskAiDialog && /* @__PURE__ */ jsx(AskAiDialog, {}),
2473
- !isCollectionPage && !isAskAiOpen && /* @__PURE__ */ jsx(OnThisPage, {
2474
- headings: currentRoute?.headings,
2475
- filePath: currentRoute?.filePath,
2476
- communityHelp: config.theme?.communityHelp,
2477
- editLink: config.theme?.editLink
2478
2684
  })
2479
2685
  ]
2480
2686
  })]
2481
2687
  });
2482
2688
  }
2483
2689
 
2484
- //#endregion
2485
- //#region src/client/collections/hooks.ts
2486
- /**
2487
- * Returns the posts of a collection.
2488
- * @param collection - The name of the collection.
2489
- * @returns The posts of the collection.
2490
- */
2491
- function usePosts(collection) {
2492
- const data = useCollectionsData();
2493
- const { currentLocale, currentVersion } = useRoutes();
2494
- const config = useConfig();
2495
- const posts = data[collection] || [];
2496
- const defaultLocale = config.i18n?.defaultLocale;
2497
- const defaultVersion = config.versions?.defaultVersion;
2498
- return useMemo(() => {
2499
- return posts.filter((post) => {
2500
- const postLocale = post.locale || defaultLocale;
2501
- const postVersion = post.version || defaultVersion;
2502
- return (!currentLocale || postLocale === currentLocale) && (!currentVersion || postVersion === currentVersion);
2503
- });
2504
- }, [
2505
- posts,
2506
- currentLocale,
2507
- currentVersion,
2508
- defaultLocale,
2509
- defaultVersion
2510
- ]);
2511
- }
2512
- function usePost(collection, slug) {
2513
- const posts = usePosts(collection);
2514
- return useMemo(() => posts.find((p) => p.path === `/${collection}/${slug}` || p.path.endsWith(`/${slug}`) || p.path === slug), [
2515
- posts,
2516
- collection,
2517
- slug
2518
- ]);
2519
- }
2520
- /**
2521
- * Returns the recent posts of a collection.
2522
- * @param collection - The name of the collection.
2523
- * @param count - The number of recent posts to return.
2524
- * @returns The recent posts of the collection.
2525
- */
2526
- function useRecentPosts(collection, count = 5) {
2527
- const posts = usePosts(collection);
2528
- return useMemo(() => posts.slice(0, count), [posts, count]);
2529
- }
2530
-
2531
2690
  //#endregion
2532
2691
  //#region src/client/utils/react-to-text.ts
2533
2692
  const reactToText = (node, resolvers) => {
@@ -2543,4 +2702,4 @@ const reactToText = (node, resolvers) => {
2543
2702
  };
2544
2703
 
2545
2704
  //#endregion
2546
- export { Banner, BoltdocsShell, Breadcrumbs, CollectionsContext, CopyMarkdown, DocsLayoutComponent as DocsLayout, ErrorBoundary, MdxPage, Navbar, NotFound, OnThisPage, PageNav, SearchDialog, Sidebar, ViteReactSSG, cn, copyToClipboard, createRoutes, getStarsRepo, getTranslated, reactToText, useAnalytics, useBreadcrumbs, useCodeBlock, useConfig, useFeedback, useHeadings, useI18n, useLocalizedTo, useLocation, useMdxComponents, useMergedComponents, useNavbar, usePageNav, usePost, usePosts, useRecentPosts, useRoutes, useSearch, useSearchHighlight, useSidebar, useTabs, useTheme, useTrackEvent, useTrackPageView, useUI, useVersion };
2705
+ export { Banner, BoltdocsShell, Breadcrumbs, CollectionsContext, CopyMarkdown, CurrentPostProvider, DocsLayoutComponent as DocsLayout, ErrorBoundary, MdxPage, Navbar, NotFound, OnThisPage, PageNav, SearchDialog, Sidebar, Timeline, ViteReactSSG, cn, copyToClipboard, createRoutes, getStarsRepo, getTranslated, reactToText, useAnalytics, useBreadcrumbs, useCodeBlock, useConfig, useFeedback, useHeadings, useI18n, useLocalizedTo, useLocation, useMdxComponents, useMergedComponents, useNavbar, usePageNav, usePost, usePosts, useRecentPosts, useRoutes, useSearch, useSearchHighlight, useSidebar, useTabs, useTheme, useTrackEvent, useTrackPageView, useUI, useVersion };