boltdocs 2.7.11 → 2.8.0

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 (84) hide show
  1. package/README.md +2 -2
  2. package/dist/banner-3N4Jd_L9.d.ts +100 -0
  3. package/dist/banner-MynZD_Ox.d.cts +100 -0
  4. package/dist/cache-BMUyNiiA.mjs +6 -0
  5. package/dist/cache-CKm45d2w.cjs +6 -0
  6. package/dist/client/index.cjs +782 -443
  7. package/dist/client/index.d.cts +86 -110
  8. package/dist/client/index.d.ts +87 -111
  9. package/dist/client/index.js +773 -439
  10. package/dist/client/mdx.cjs +8 -3
  11. package/dist/client/mdx.d.cts +39 -93
  12. package/dist/client/mdx.d.ts +38 -93
  13. package/dist/client/mdx.js +3 -3
  14. package/dist/client/primitives.cjs +7 -7
  15. package/dist/client/primitives.d.cts +411 -347
  16. package/dist/client/primitives.d.ts +411 -347
  17. package/dist/client/primitives.js +4 -4
  18. package/dist/{docs-layout-BXHV0xw_.cjs → docs-layout-CwCq42Zt.cjs} +95 -178
  19. package/dist/{docs-layout-DwFndmj5.js → docs-layout-Dn6S5g59.js} +99 -163
  20. package/dist/doctor-BArviV8X.cjs +28 -0
  21. package/dist/doctor-CgLA7_Uv.mjs +28 -0
  22. package/dist/{doctor-CrytFkqW.cjs → doctor-DyNUVe96.cjs} +1 -1
  23. package/dist/{routes-DP1vmWRj.cjs → doctor-aN_leTbh.mjs} +1 -1
  24. package/dist/{generator-ClVanhvi.mjs → generator-BHCrLU6h.mjs} +2 -2
  25. package/dist/{generator-CHqxiQhF.cjs → generator-CC2yHzhZ.cjs} +2 -2
  26. package/dist/{icons-dev-3cZMyt8r.cjs → icons-dev-DvJ-hh9x.cjs} +116 -111
  27. package/dist/{icons-dev-Df8OQ481.js → icons-dev-Oju24Wjp.js} +120 -114
  28. package/dist/{image-DtrI2cw3.cjs → image-Ch4-GxdO.cjs} +13 -13
  29. package/dist/{image-jxPb-2iV.js → image-Do8V9PCW.js} +13 -13
  30. package/dist/{mdx-UTTLFWJq.js → mdx-D3A2_l7P.js} +106 -80
  31. package/dist/{mdx-BdWkJTeB.cjs → mdx-PLhhPJRS.cjs} +104 -96
  32. package/dist/node/cli-entry.cjs +3 -1
  33. package/dist/node/cli-entry.mjs +3 -1
  34. package/dist/node/index.cjs +1 -1
  35. package/dist/node/index.d.cts +258 -152
  36. package/dist/node/index.d.mts +258 -150
  37. package/dist/node/index.mjs +1 -1
  38. package/dist/node/routes/worker.cjs +1 -1
  39. package/dist/node/routes/worker.mjs +1 -1
  40. package/dist/node-BmlP0eBP.cjs +159 -0
  41. package/dist/node-Y8_4ayje.mjs +159 -0
  42. package/dist/package-2nFy_NsW.cjs +6 -0
  43. package/dist/{package-K0zsjGIz.mjs → package-DAbtltXX.mjs} +1 -1
  44. package/dist/parser-B7-6PyQz.cjs +6 -0
  45. package/dist/{parser-Aq8LoH-0.cjs → parser-BzB-zCkF.cjs} +1 -1
  46. package/dist/parser-WGZdWs0X.mjs +6 -0
  47. package/dist/routes-BDDSxAl0.mjs +6 -0
  48. package/dist/routes-DJNJ-rTt.cjs +6 -0
  49. package/dist/routes-DiYC4nD2.cjs +6 -0
  50. package/dist/routes-_Bb2f4eI.mjs +6 -0
  51. package/dist/{search-dialog-C7xuvyNk.cjs → search-dialog-BXVoecTx.cjs} +175 -78
  52. package/dist/{search-dialog-BwkDuI9R.cjs → search-dialog-BYhOov4S.cjs} +118 -7
  53. package/dist/{search-dialog-D-DDN7zJ.js → search-dialog-C09riYmx.js} +113 -8
  54. package/dist/{search-dialog-CIQg6k8c.cjs → search-dialog-CUeAfy-8.cjs} +1 -1
  55. package/dist/{search-dialog-BNF10tDl.js → search-dialog-D8gLkhUV.js} +158 -80
  56. package/dist/{search-dialog-BHuIiUC6.js → search-dialog-DHc_8FFX.js} +1 -1
  57. package/dist/{sidebar-CyZS9YOm.d.ts → sidebar-DNq4_ZAa.d.ts} +117 -51
  58. package/dist/{sidebar-CcBkrm06.d.cts → sidebar-Dlkgbxs6.d.cts} +117 -51
  59. package/dist/utils-BYITg7T5.mjs +7 -0
  60. package/dist/utils-Cjmx1hhk.cjs +7 -0
  61. package/dist/worker-pool-CtqklOXq.cjs +6 -0
  62. package/dist/worker-pool-k0DY6k8T.mjs +6 -0
  63. package/package.json +3 -3
  64. package/src/shared/config-utils.ts +4 -0
  65. package/src/shared/types.ts +52 -6
  66. package/dist/cache-Ba-DZQNH.cjs +0 -6
  67. package/dist/cache-BuMZ58L5.mjs +0 -6
  68. package/dist/cards-BakZPTz9.d.ts +0 -30
  69. package/dist/cards-CQn9mXZS.d.cts +0 -30
  70. package/dist/doctor-Be7Ly1oM.mjs +0 -21
  71. package/dist/doctor-jMxWZyLJ.cjs +0 -21
  72. package/dist/node-BSM4qcDK.cjs +0 -111
  73. package/dist/node-BspZN3R2.mjs +0 -111
  74. package/dist/package-DIIrjuWI.cjs +0 -6
  75. package/dist/parser-CdNbqN5y.cjs +0 -6
  76. package/dist/parser-nE792MLO.mjs +0 -6
  77. package/dist/rolldown-runtime-fkIsjY3S.mjs +0 -6
  78. package/dist/routes-2k3tbUmC.cjs +0 -6
  79. package/dist/routes-CpxZIsMM.mjs +0 -6
  80. package/dist/utils-CG65J0Sc.mjs +0 -7
  81. package/dist/utils-CKunkU96.cjs +0 -7
  82. package/dist/worker-pool-CGn7DrLb.mjs +0 -6
  83. package/dist/worker-pool-Crbqgw5R.cjs +0 -6
  84. /package/dist/{meta-loader-CWg2gnbY.mjs → meta-loader-DzwDFtdT.mjs} +0 -0
@@ -4,55 +4,325 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
7
- const require_icons_dev = require('../icons-dev-3cZMyt8r.cjs');
8
- const require_docs_layout = require('../docs-layout-BXHV0xw_.cjs');
9
- const require_image = require('../image-DtrI2cw3.cjs');
10
- const require_search_dialog = require('../search-dialog-C7xuvyNk.cjs');
11
- const require_search_dialog$1 = require('../search-dialog-BwkDuI9R.cjs');
12
- const require_mdx = require('../mdx-BdWkJTeB.cjs');
13
- let react_router_dom = require("react-router-dom");
7
+ const require_icons_dev = require('../icons-dev-DvJ-hh9x.cjs');
8
+ const require_image = require('../image-Ch4-GxdO.cjs');
9
+ const require_mdx = require('../mdx-PLhhPJRS.cjs');
10
+ const require_docs_layout = require('../docs-layout-CwCq42Zt.cjs');
11
+ const require_search_dialog = require('../search-dialog-BXVoecTx.cjs');
12
+ const require_search_dialog$1 = require('../search-dialog-BYhOov4S.cjs');
14
13
  let react = require("react");
14
+ let react_router_dom = require("react-router-dom");
15
15
  let react_jsx_runtime = require("react/jsx-runtime");
16
- let react_aria_components = require("react-aria-components");
17
- let virtual_boltdocs_icons = require("virtual:boltdocs-icons");
18
- virtual_boltdocs_icons = require_icons_dev.__toESM(virtual_boltdocs_icons);
19
16
  let react_helmet_async = require("react-helmet-async");
20
17
  react_helmet_async = require_icons_dev.__toESM(react_helmet_async);
18
+ let react_aria_components = require("react-aria-components");
21
19
  let virtual_boltdocs_mdx_components = require("virtual:boltdocs-mdx-components");
22
20
  virtual_boltdocs_mdx_components = require_icons_dev.__toESM(virtual_boltdocs_mdx_components);
21
+ let virtual_boltdocs_icons = require("virtual:boltdocs-icons");
22
+ virtual_boltdocs_icons = require_icons_dev.__toESM(virtual_boltdocs_icons);
23
23
  let virtual_boltdocs_layout = require("virtual:boltdocs-layout");
24
24
  virtual_boltdocs_layout = require_icons_dev.__toESM(virtual_boltdocs_layout);
25
25
  let _bdocs_ssg = require("@bdocs/ssg");
26
26
 
27
27
  //#region src/client/app/mdx-components-context.tsx
28
28
  const MDX_COMPONENTS_CONTEXT_SYMBOL = Symbol.for("__BDOCS_MDX_COMPONENTS_CONTEXT__");
29
- const MDX_COMPONENTS_INSTANCE_SYMBOL = Symbol.for("__BDOCS_MDX_COMPONENTS_INSTANCE__");
30
- const MdxComponentsContext = globalThis[MDX_COMPONENTS_CONTEXT_SYMBOL] || (globalThis[MDX_COMPONENTS_CONTEXT_SYMBOL] = (0, react.createContext)({}));
29
+ const registry = globalThis;
30
+ if (!registry[MDX_COMPONENTS_CONTEXT_SYMBOL]) registry[MDX_COMPONENTS_CONTEXT_SYMBOL] = (0, react.createContext)({});
31
+ const MdxComponentsContext = registry[MDX_COMPONENTS_CONTEXT_SYMBOL];
31
32
  function useMdxComponents() {
32
- const context = (0, react.use)(MdxComponentsContext);
33
- if ((!context || Object.keys(context).length === 0) && globalThis[MDX_COMPONENTS_INSTANCE_SYMBOL]) return globalThis[MDX_COMPONENTS_INSTANCE_SYMBOL];
34
- return context;
33
+ return (0, react.use)(MdxComponentsContext);
35
34
  }
36
35
  function MdxComponentsProvider({ components, children }) {
37
36
  const processedComponents = (0, react.useMemo)(() => {
38
37
  const processed = {};
39
38
  const frontmatter = {};
39
+ let hasFrontmatter = false;
40
40
  Object.entries(components).forEach(([key, value]) => {
41
41
  if (key.startsWith("Frontmatter_")) {
42
42
  const cleanKey = key.slice(12);
43
43
  frontmatter[cleanKey] = value;
44
+ hasFrontmatter = true;
44
45
  } else processed[key] = value;
45
46
  });
46
- processed.Frontmatter = frontmatter;
47
+ if (hasFrontmatter) processed.Frontmatter = frontmatter;
47
48
  return processed;
48
49
  }, [components]);
49
- if (typeof globalThis !== "undefined") globalThis[MDX_COMPONENTS_INSTANCE_SYMBOL] = processedComponents;
50
50
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MdxComponentsContext.Provider, {
51
51
  value: processedComponents,
52
52
  children
53
53
  });
54
54
  }
55
55
 
56
+ //#endregion
57
+ //#region src/client/app/helmet-compat.tsx
58
+ const mod = react_helmet_async;
59
+ /**
60
+ * The `<Helmet>` component, resolved across CJS/ESM module shapes.
61
+ * Falls back to a transparent fragment wrapper if the module cannot be resolved.
62
+ */
63
+ const Helmet = mod.Helmet || mod.default?.Helmet || (({ children }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children }));
64
+ /**
65
+ * The `<HelmetProvider>` component, resolved across CJS/ESM module shapes.
66
+ * Falls back to a transparent fragment wrapper if the module cannot be resolved.
67
+ */
68
+ const HelmetProvider = mod.HelmetProvider || mod.default?.HelmetProvider || (({ children }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children }));
69
+
70
+ //#endregion
71
+ //#region src/client/app/scroll-handler.tsx
72
+ /**
73
+ * Handles scroll restoration and hash scrolling on navigation.
74
+ * It ensures the page scrolls to top on pathname changes,
75
+ * or specifically to an anchor element if a hash is present.
76
+ */
77
+ function ScrollHandler() {
78
+ const { pathname, hash } = (0, react_router_dom.useLocation)();
79
+ const handleScroll = (behavior = "auto") => {
80
+ const container = document.querySelector(".boltdocs-content") || window;
81
+ const getScrollTop = () => {
82
+ if (container === window) return window.scrollY;
83
+ return container.scrollTop;
84
+ };
85
+ const scrollTo = (top, scrollBehavior) => {
86
+ if (container === window) window.scrollTo({
87
+ top,
88
+ behavior: scrollBehavior
89
+ });
90
+ else container.scrollTo({
91
+ top,
92
+ behavior: scrollBehavior
93
+ });
94
+ };
95
+ if (hash) {
96
+ const id = hash.replace("#", "");
97
+ const element = document.getElementById(id);
98
+ if (element) {
99
+ const offset = 80;
100
+ const containerTop = container === window ? 0 : container.getBoundingClientRect().top;
101
+ scrollTo(element.getBoundingClientRect().top - containerTop - offset + getScrollTop(), behavior);
102
+ return true;
103
+ }
104
+ }
105
+ scrollTo(0, behavior);
106
+ return false;
107
+ };
108
+ (0, react.useLayoutEffect)(() => {
109
+ handleScroll("auto");
110
+ }, [pathname, hash]);
111
+ (0, react.useEffect)(() => {
112
+ handleScroll("auto");
113
+ const rafId = requestAnimationFrame(() => {
114
+ handleScroll("auto");
115
+ window.dispatchEvent(new Event("resize"));
116
+ });
117
+ return () => cancelAnimationFrame(rafId);
118
+ }, [pathname, hash]);
119
+ return null;
120
+ }
121
+
122
+ //#endregion
123
+ //#region src/client/components/ui-base/not-found.tsx
124
+ function NotFound() {
125
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
126
+ className: "flex items-center justify-center min-h-[65vh] text-center px-4",
127
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
128
+ className: "space-y-6 max-w-md mx-auto p-8 border border-subtle bg-surface rounded-2xl shadow-xs",
129
+ children: [
130
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
131
+ className: "block text-7xl font-extrabold tracking-tight text-primary-500",
132
+ children: "404"
133
+ }),
134
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
135
+ className: "space-y-2",
136
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
137
+ className: "text-xl font-bold text-body",
138
+ children: "Page Not Found"
139
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
140
+ className: "text-sm text-muted leading-relaxed",
141
+ children: "The page you're looking for doesn't exist or has been moved."
142
+ })]
143
+ }),
144
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_icons_dev.Link, {
145
+ href: "/",
146
+ className: "inline-flex items-center gap-2 rounded-xl border border-subtle bg-main px-6 py-2.5 text-xs font-semibold text-body hover:bg-primary-50/50 hover:border-primary-500/50 transition-all duration-300 outline-none select-none",
147
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.ArrowLeft, { size: 14 }), " Go to Home"]
148
+ })
149
+ ]
150
+ })
151
+ });
152
+ }
153
+
154
+ //#endregion
155
+ //#region src/client/app/mdx-component.tsx
156
+ const mdxComponentsDefault = {
157
+ ...require_mdx.mdx_components_default,
158
+ NotFound,
159
+ "404": NotFound
160
+ };
161
+
162
+ //#endregion
163
+ //#region src/client/ssg/boltdocs-shell.tsx
164
+ /**
165
+ * Updates the HTML lang and dir attributes based on the current locale configuration.
166
+ */
167
+ function I18nUpdater({ config }) {
168
+ const { currentLocale } = require_icons_dev.useBoltdocsContext();
169
+ (0, react.useEffect)(() => {
170
+ if (!config.i18n || typeof document === "undefined") return;
171
+ const locale = currentLocale || config.i18n.defaultLocale;
172
+ const localeConfig = config.i18n.localeConfigs?.[locale];
173
+ document.documentElement.lang = localeConfig?.htmlLang || locale || "en";
174
+ document.documentElement.dir = localeConfig?.direction || "ltr";
175
+ }, [currentLocale, config.i18n]);
176
+ return null;
177
+ }
178
+ function StoreSync({ config, routeMap }) {
179
+ const location = (0, react_router_dom.useLocation)();
180
+ const { setLocale, setVersion } = require_icons_dev.useBoltdocsContext();
181
+ (0, react.useEffect)(() => {
182
+ const currentPath = require_icons_dev.normalizePath(location.pathname);
183
+ const matchedRoute = routeMap.get(currentPath);
184
+ if (matchedRoute) {
185
+ if (config.i18n) setLocale(matchedRoute.locale || config.i18n.defaultLocale);
186
+ if (config.versions) setVersion(matchedRoute.version || config.versions.defaultVersion);
187
+ }
188
+ }, [
189
+ location.pathname,
190
+ config,
191
+ routeMap,
192
+ setLocale,
193
+ setVersion
194
+ ]);
195
+ return null;
196
+ }
197
+ function BoltdocsShell({ config, routes, components = {} }) {
198
+ const allComponents = (0, react.useMemo)(() => ({
199
+ ...mdxComponentsDefault,
200
+ ...virtual_boltdocs_mdx_components.default,
201
+ ...components
202
+ }), [components]);
203
+ const { pathname } = (0, react_router_dom.useLocation)();
204
+ const currentPath = (0, react.useMemo)(() => require_icons_dev.normalizePath(pathname || "/"), [pathname]);
205
+ const routeMap = (0, react.useMemo)(() => {
206
+ const map = /* @__PURE__ */ new Map();
207
+ for (const r of routes) {
208
+ const key = require_icons_dev.normalizePath(r.path === "" ? "/" : r.path);
209
+ map.set(key, r);
210
+ }
211
+ return map;
212
+ }, [routes]);
213
+ const initialData = (0, react.useMemo)(() => {
214
+ const matched = routeMap.get(currentPath);
215
+ let initLocale;
216
+ let initVersion;
217
+ if (matched) {
218
+ if (config.i18n) initLocale = matched.locale || config.i18n.defaultLocale;
219
+ if (config.versions) initVersion = matched.version || config.versions.defaultVersion;
220
+ }
221
+ return {
222
+ initLocale,
223
+ initVersion
224
+ };
225
+ }, [
226
+ currentPath,
227
+ config,
228
+ routeMap
229
+ ]);
230
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HelmetProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.RoutesProvider, {
231
+ routes,
232
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_image.ThemeProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.UIProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MdxComponentsProvider, {
233
+ components: allComponents,
234
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_icons_dev.ConfigContext.Provider, {
235
+ value: config,
236
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollHandler, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_icons_dev.BoltdocsProvider, {
237
+ initialLocale: initialData.initLocale,
238
+ initialVersion: initialData.initVersion,
239
+ children: [
240
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StoreSync, {
241
+ config,
242
+ routeMap
243
+ }),
244
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(I18nUpdater, { config }),
245
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog$1.InternalErrorBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_router_dom.Outlet, {}) })
246
+ ]
247
+ })]
248
+ })
249
+ }) }) })
250
+ }) });
251
+ }
252
+
253
+ //#endregion
254
+ //#region src/client/hooks/use-merged-components.ts
255
+ function useMergedComponents(propComponents) {
256
+ const contextComponents = useMdxComponents();
257
+ return (0, react.useMemo)(() => {
258
+ if (!propComponents) return contextComponents;
259
+ const merged = { ...contextComponents };
260
+ const mergedFrontmatter = { ...contextComponents.Frontmatter || {} };
261
+ let hasPropFrontmatter = false;
262
+ Object.entries(propComponents).forEach(([key, value]) => {
263
+ if (key.startsWith("Frontmatter_")) {
264
+ const cleanKey = key.slice(12);
265
+ mergedFrontmatter[cleanKey] = value;
266
+ hasPropFrontmatter = true;
267
+ } else if (key === "Frontmatter" && value && typeof value === "object") {
268
+ Object.assign(mergedFrontmatter, value);
269
+ hasPropFrontmatter = true;
270
+ } else merged[key] = value;
271
+ });
272
+ if (hasPropFrontmatter || contextComponents.Frontmatter) merged.Frontmatter = mergedFrontmatter;
273
+ return merged;
274
+ }, [contextComponents, propComponents]);
275
+ }
276
+
277
+ //#endregion
278
+ //#region src/client/app/doc-page.tsx
279
+ /**
280
+ * DocPage renders the MDX content and page-specific metadata.
281
+ * It is rendered inside the Outlet of DocsLayout.
282
+ */
283
+ function DocPage({ route, content: Content, mdxComponents: propComponents }) {
284
+ const allComponents = useMergedComponents(propComponents);
285
+ const { LastUpdated } = allComponents;
286
+ if (!Content) return null;
287
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Content, { components: allComponents }), route?.lastUpdated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LastUpdated, { date: route.lastUpdated })] });
288
+ }
289
+
290
+ //#endregion
291
+ //#region src/client/ssg/mdx-page.tsx
292
+ /**
293
+ * Renders an MDX page by consuming pre-loaded route data.
294
+ *
295
+ * - If the route belongs to a collection (`data.collection` is set), renders
296
+ * the custom post component if provided, else falls back to the standard DocPage.
297
+ * - Otherwise, renders the standard `DocPage` layout.
298
+ */
299
+ function MdxPage({ MDXComponent, mdxComponents: propComponents, collectionPostComponent: CollectionPost }) {
300
+ const data = (0, react_router_dom.useLoaderData)();
301
+ if (!MDXComponent) return null;
302
+ if (!!data?.collection && CollectionPost) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CollectionPost, {
303
+ MDXComponent,
304
+ mdxComponents: propComponents
305
+ });
306
+ const docData = data;
307
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocPage, {
308
+ route: {
309
+ path: docData.path,
310
+ filePath: docData.filePath,
311
+ title: docData.frontmatter?.title,
312
+ description: docData.frontmatter?.description,
313
+ headings: docData.headings,
314
+ locale: docData.locale,
315
+ version: docData.version,
316
+ group: docData.group,
317
+ groupTitle: docData.groupTitle,
318
+ lastUpdated: docData.lastUpdated,
319
+ frontmatter: docData.frontmatter
320
+ },
321
+ content: MDXComponent,
322
+ mdxComponents: propComponents
323
+ });
324
+ }
325
+
56
326
  //#endregion
57
327
  //#region src/client/hooks/use-breadcrumbs.ts
58
328
  /**
@@ -103,10 +373,20 @@ function Breadcrumbs() {
103
373
  //#region src/client/components/ui-base/copy-markdown.tsx
104
374
  const useCopyMarkdown = (content) => {
105
375
  const [copied, setCopied] = (0, react.useState)(false);
376
+ const timerRef = (0, react.useRef)(null);
377
+ (0, react.useEffect)(() => {
378
+ return () => {
379
+ if (timerRef.current) clearTimeout(timerRef.current);
380
+ };
381
+ }, []);
106
382
  const handleCopy = () => {
107
383
  navigator.clipboard.writeText(content);
108
384
  setCopied(true);
109
- setTimeout(() => setCopied(false), 2e3);
385
+ if (timerRef.current) clearTimeout(timerRef.current);
386
+ timerRef.current = setTimeout(() => {
387
+ setCopied(false);
388
+ timerRef.current = null;
389
+ }, 2e3);
110
390
  };
111
391
  const handleOpenRaw = () => {
112
392
  const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
@@ -128,20 +408,20 @@ function CopyMarkdown({ content, mdxRaw }) {
128
408
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.ButtonGroup, {
129
409
  className: "rounded-xl border border-subtle bg-surface transition-all duration-300 hover:border-primary-500/50 group overflow-hidden",
130
410
  children: [
131
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Button, {
411
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Button, {
132
412
  onPress: handleCopy,
133
413
  className: require_icons_dev.cn("md:hidden flex items-center justify-center w-8 h-8 bg-transparent outline-none select-none cursor-pointer border-none", "text-muted transition-all duration-300 hover:bg-primary-500/5 hover:text-body", copied && "text-emerald-500 hover:bg-emerald-500/5"),
134
414
  "aria-label": copied ? "Copied!" : "Copy Markdown",
135
415
  children: copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Check, { size: 14 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Copy, { size: 14 })
136
416
  }),
137
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Button, {
417
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Button, {
138
418
  onPress: handleCopy,
139
419
  className: require_icons_dev.cn("hidden md:flex items-center gap-2 px-5 py-2 bg-transparent text-[0.8125rem] font-semibold h-9 shrink-0 outline-none select-none cursor-pointer border-none", "text-body transition-all duration-300 hover:bg-primary-500/5", copied && "text-emerald-500 hover:bg-emerald-500/5"),
140
420
  children: [copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Check, { size: 16 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Copy, { size: 16 }), copied ? "Copied!" : "Copy Markdown"]
141
421
  }),
142
422
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Menu.Trigger, {
143
423
  placement: "bottom end",
144
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Button, {
424
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Button, {
145
425
  className: require_icons_dev.cn("flex items-center justify-center px-2.5 md:px-3.5 h-8 md:h-9 border-none border-l border-subtle/50 text-muted rounded-none bg-transparent shrink-0 outline-none select-none cursor-pointer", "transition-all duration-300 hover:bg-primary-500/5 hover:text-primary-500"),
146
426
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.ChevronDown, { size: 14 })
147
427
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Menu.Root, {
@@ -177,7 +457,7 @@ function CopyMarkdown({ content, mdxRaw }) {
177
457
  //#endregion
178
458
  //#region src/client/components/ui-base/error-boundary.tsx
179
459
  function ErrorBoundary({ children, fallback }) {
180
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.ErrorBoundary, {
460
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.ErrorBoundary, {
181
461
  fallback,
182
462
  children
183
463
  });
@@ -490,7 +770,7 @@ function Tabs({ tabs, routes }) {
490
770
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
491
771
  className: "mx-auto max-w-(--breakpoint-3xl) px-4 md:px-6 select-none",
492
772
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Tabs.List, {
493
- className: "border-none py-0 scrollbar-hide relative flex flex-row items-center",
773
+ className: "border-none py-0 scrollbar-hide relative flex flex-row items-center overflow-x-auto",
494
774
  children: [tabs.map((tab, index) => {
495
775
  const isActive = index === activeIndex;
496
776
  const firstRoute = routes.find((r) => r.tab && r.tab.toLowerCase() === tab.id.toLowerCase());
@@ -559,7 +839,7 @@ function useVersion() {
559
839
  currentVersion,
560
840
  currentVersionLabel: (versions?.versions?.find?.((v) => v.path === currentVersion))?.label || currentVersion,
561
841
  availableVersions: (0, react.useMemo)(() => {
562
- return versions ? versions.versions.map((v) => ({
842
+ return versions?.versions ? versions.versions.map((v) => ({
563
843
  key: v.path,
564
844
  label: v.label,
565
845
  value: v.path,
@@ -653,7 +933,7 @@ function useI18n() {
653
933
  function VersionSelector({ className }) {
654
934
  const { currentVersionLabel, availableVersions, handleVersionChange } = useVersion();
655
935
  if (availableVersions.length === 0) return null;
656
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Menu.Trigger, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Button, {
936
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Menu.Trigger, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Button, {
657
937
  className: require_icons_dev.cn("flex h-9 items-center justify-between gap-2 border border-subtle bg-surface px-4 py-1.5 rounded-xl text-xs font-semibold text-body hover:bg-primary-50/20 hover:border-primary-500/50 transition-all duration-300 outline-none select-none cursor-pointer", className),
658
938
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
659
939
  className: "font-semibold text-[0.8125rem]",
@@ -674,7 +954,7 @@ function VersionSelector({ className }) {
674
954
  function I18nSelector({ className }) {
675
955
  const { currentLocale, availableLocales, handleLocaleChange } = useI18n();
676
956
  if (availableLocales.length === 0) return null;
677
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Menu.Trigger, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Button, {
957
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Menu.Trigger, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Button, {
678
958
  className: require_icons_dev.cn("flex h-9 items-center justify-between gap-2 border border-subtle bg-surface px-4 py-1.5 rounded-xl text-xs font-semibold text-body hover:bg-primary-50/20 hover:border-primary-500/50 transition-all duration-300 outline-none select-none cursor-pointer", className),
679
959
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
680
960
  className: "flex items-center gap-1.5",
@@ -698,22 +978,21 @@ function I18nSelector({ className }) {
698
978
 
699
979
  //#endregion
700
980
  //#region src/client/components/ui-base/navbar.tsx
701
- const SearchDialog$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("../search-dialog-CIQg6k8c.cjs")).then((m) => ({ default: m.SearchDialog })));
981
+ const SearchDialog$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("../search-dialog-CUeAfy-8.cjs")).then((m) => ({ default: m.SearchDialog })));
702
982
  function Navbar() {
703
983
  const { links, title, logo, logoProps, github, social, config } = useNavbar();
704
- const { routes, allRoutes, currentRoute, currentVersion, currentLocale } = require_icons_dev.useRoutes();
705
- const { pathname } = (0, react_router_dom.useLocation)();
984
+ const { routes, currentRoute, isCollectionPage, currentVersion, currentLocale } = require_icons_dev.useRoutes();
706
985
  const { isSidebarOpen, toggleSidebar } = require_docs_layout.useUI();
707
986
  const [isMobileMenuOpen, setIsMobileMenuOpen] = (0, react.useState)(false);
708
987
  const themeConfig = config.theme || {};
709
- const isDocs = !!currentRoute?.filePath;
988
+ const isDocs = !!currentRoute?.filePath && !isCollectionPage;
710
989
  const hasTabs = themeConfig?.tabs && themeConfig.tabs.length > 0;
711
990
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Root, {
712
991
  className: require_icons_dev.cn("border-b border-subtle bg-main/80 backdrop-blur-md", hasTabs && "border-b-0"),
713
992
  children: [
714
993
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Content, { children: [
715
994
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Left, { children: [
716
- isDocs && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Button, {
995
+ isDocs && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Button, {
717
996
  onPress: toggleSidebar,
718
997
  className: "mr-2 lg:hidden p-1.5 h-8 w-8 flex items-center justify-center bg-transparent border-none outline-none select-none cursor-pointer rounded-xl hover:bg-primary-50/50 transition-colors",
719
998
  "aria-label": isSidebarOpen ? "Close sidebar" : "Open sidebar",
@@ -807,7 +1086,7 @@ function Navbar() {
807
1086
  className: "w-full border-b border-subtle bg-main",
808
1087
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tabs, {
809
1088
  tabs: themeConfig.tabs,
810
- routes: allRoutes || routes || []
1089
+ routes: routes || []
811
1090
  })
812
1091
  })
813
1092
  ]
@@ -860,38 +1139,6 @@ function NavbarMobileLinkItem({ link, onClose }) {
860
1139
  });
861
1140
  }
862
1141
 
863
- //#endregion
864
- //#region src/client/components/ui-base/not-found.tsx
865
- function NotFound() {
866
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
867
- className: "flex items-center justify-center min-h-[65vh] text-center px-4",
868
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
869
- className: "space-y-6 max-w-md mx-auto p-8 border border-subtle bg-surface rounded-2xl shadow-xs",
870
- children: [
871
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
872
- className: "block text-7xl font-extrabold tracking-tight text-primary-500",
873
- children: "404"
874
- }),
875
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
876
- className: "space-y-2",
877
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
878
- className: "text-xl font-bold text-body",
879
- children: "Page Not Found"
880
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
881
- className: "text-sm text-muted leading-relaxed",
882
- children: "The page you're looking for doesn't exist or has been moved."
883
- })]
884
- }),
885
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_icons_dev.Link, {
886
- href: "/",
887
- className: "inline-flex items-center gap-2 rounded-xl border border-subtle bg-main px-6 py-2.5 text-xs font-semibold text-body hover:bg-primary-50/50 hover:border-primary-500/50 transition-all duration-300 outline-none select-none",
888
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.ArrowLeft, { size: 14 }), " Go to Home"]
889
- })
890
- ]
891
- })
892
- });
893
- }
894
-
895
1142
  //#endregion
896
1143
  //#region src/client/components/ui-base/on-this-page.tsx
897
1144
  function OnThisPage({ headings = [], editLink, communityHelp, filePath }) {
@@ -1015,7 +1262,7 @@ function SidebarMain({ routes, config }) {
1015
1262
  })]
1016
1263
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1017
1264
  className: "flex items-center gap-2",
1018
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemeSwitcher, { className: "w-24 h-9 rounded-xl" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Button, {
1265
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemeSwitcher, { className: "w-24 h-9 rounded-xl" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Button, {
1019
1266
  onPress: closeSidebar,
1020
1267
  className: "h-9 w-9 flex items-center justify-center bg-transparent border-none outline-none select-none cursor-pointer rounded-xl hover:bg-primary-50/50 text-muted hover:text-body transition-colors",
1021
1268
  "aria-label": "Close sidebar",
@@ -1042,249 +1289,71 @@ const Sidebar = Object.assign(SidebarMain, {
1042
1289
  });
1043
1290
 
1044
1291
  //#endregion
1045
- //#region src/client/components/ui-base/last-updated.tsx
1046
- /**
1047
- * A subtle display for when the page was last updated.
1048
- * Small, opaque, and positioned at the bottom of the content with a thin top border divider.
1049
- */
1050
- function LastUpdated({ date }) {
1051
- if (!date) return null;
1052
- const d = new Date(date);
1053
- if (isNaN(d.getTime())) return null;
1054
- const formattedDate = d.toLocaleDateString(void 0, {
1055
- year: "numeric",
1056
- month: "long",
1057
- day: "numeric"
1058
- });
1292
+ //#region src/client/components/ui-base/banner.tsx
1293
+ function Banner({ children, className = "", dismissible = false, id = "boltdocs-banner", ...props }) {
1294
+ const [isVisible, setIsVisible] = (0, react.useState)(true);
1295
+ (0, react.useEffect)(() => {
1296
+ if (dismissible && id) {
1297
+ if (localStorage.getItem(`boltdocs-banner-dismissed-${id}`) === "true") setIsVisible(false);
1298
+ }
1299
+ }, [dismissible, id]);
1300
+ const handleDismiss = () => {
1301
+ setIsVisible(false);
1302
+ if (dismissible && id) localStorage.setItem(`boltdocs-banner-dismissed-${id}`, "true");
1303
+ };
1304
+ if (!isVisible) return null;
1059
1305
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1060
- className: "mt-16 pt-6 border-t border-subtle flex items-center justify-between text-xs text-muted select-none",
1061
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1062
- className: "italic",
1063
- children: ["Last updated on ", formattedDate]
1306
+ className: require_icons_dev.cn("relative flex items-center justify-center px-4 py-2.5 text-xs font-semibold tracking-wide bg-primary-500/10 dark:bg-primary-500/15 text-primary-700 dark:text-primary-300 border-b border-primary-500/20 select-none animate-in fade-in duration-300", className),
1307
+ ...props,
1308
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1309
+ className: "flex-1 text-center flex items-center justify-center gap-2",
1310
+ children
1311
+ }), dismissible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1312
+ onClick: handleDismiss,
1313
+ className: "absolute right-3 top-1/2 -translate-y-1/2 p-1.5 opacity-70 hover:opacity-100 transition-all duration-300 rounded-xl hover:bg-primary-500/10 cursor-pointer border-none bg-transparent flex items-center justify-center outline-none",
1314
+ "aria-label": "Dismiss banner",
1315
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.X, { className: "w-3.5 h-3.5" })
1064
1316
  })]
1065
1317
  });
1066
1318
  }
1067
1319
 
1068
1320
  //#endregion
1069
- //#region src/client/app/doc-page.tsx
1070
- /**
1071
- * DocPage renders the MDX content and page-specific metadata.
1072
- * It is rendered inside the Outlet of DocsLayout.
1073
- */
1074
- function DocPage({ route, content: Content, mdxComponents: propComponents }) {
1075
- const contextComponents = useMdxComponents();
1076
- const allComponents = (0, react.useMemo)(() => ({
1077
- LastUpdated,
1078
- ...contextComponents,
1079
- ...propComponents
1080
- }), [contextComponents, propComponents]);
1081
- const LastUpdated$1 = allComponents.LastUpdated || LastUpdated;
1082
- if (!Content) return null;
1083
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Content, { components: allComponents }), route?.lastUpdated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LastUpdated$1, { date: route.lastUpdated })] });
1084
- }
1085
-
1086
- //#endregion
1087
- //#region src/client/ssg/mdx-page.tsx
1088
- /**
1089
- * Renders an MDX page by consuming pre-loaded module data.
1090
- * Uses DocPage to ensure consistent layout and metadata application.
1091
- */
1092
- function MdxPage({ MDXComponent: propMDX, mdxComponents: propComponents }) {
1093
- const data = (0, react_router_dom.useLoaderData)();
1094
- const MDXComponent = propMDX || data?.MDXComponent;
1095
- const components = propComponents || data?.mdxComponents;
1096
- if (!MDXComponent) return null;
1097
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocPage, {
1098
- route: {
1099
- path: data.path,
1100
- filePath: data.filePath,
1101
- title: data.frontmatter.title,
1102
- description: data.frontmatter.description,
1103
- headings: data.headings,
1104
- locale: data.locale,
1105
- version: data.version,
1106
- group: data.group,
1107
- groupTitle: data.groupTitle,
1108
- lastUpdated: data.lastUpdated,
1109
- frontmatter: data.frontmatter
1110
- },
1111
- content: MDXComponent,
1112
- mdxComponents: components
1113
- });
1114
- }
1115
-
1116
- //#endregion
1117
- //#region src/client/app/helmet-compat.tsx
1118
- const mod = react_helmet_async;
1119
- /**
1120
- * The `<Helmet>` component, resolved across CJS/ESM module shapes.
1121
- * Falls back to a transparent fragment wrapper if the module cannot be resolved.
1122
- */
1123
- const Helmet = mod.Helmet || mod.default?.Helmet || (({ children }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children }));
1124
- /**
1125
- * The `<HelmetProvider>` component, resolved across CJS/ESM module shapes.
1126
- * Falls back to a transparent fragment wrapper if the module cannot be resolved.
1127
- */
1128
- const HelmetProvider = mod.HelmetProvider || mod.default?.HelmetProvider || (({ children }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children }));
1129
-
1130
- //#endregion
1131
- //#region src/client/app/scroll-handler.tsx
1132
- /**
1133
- * Handles scroll restoration and hash scrolling on navigation.
1134
- * It ensures the page scrolls to top on pathname changes,
1135
- * or specifically to an anchor element if a hash is present.
1136
- */
1137
- function ScrollHandler() {
1138
- const { pathname, hash } = (0, react_router_dom.useLocation)();
1139
- const handleScroll = (behavior = "auto") => {
1140
- const container = document.querySelector(".boltdocs-content") || window;
1141
- const getScrollTop = () => {
1142
- if (container === window) return window.scrollY;
1143
- return container.scrollTop;
1144
- };
1145
- const scrollTo = (top, scrollBehavior) => {
1146
- if (container === window) window.scrollTo({
1147
- top,
1148
- behavior: scrollBehavior
1149
- });
1150
- else container.scrollTo({
1151
- top,
1152
- behavior: scrollBehavior
1153
- });
1154
- };
1155
- if (hash) {
1156
- const id = hash.replace("#", "");
1157
- const element = document.getElementById(id);
1158
- if (element) {
1159
- const offset = 80;
1160
- const containerTop = container === window ? 0 : container.getBoundingClientRect().top;
1161
- scrollTo(element.getBoundingClientRect().top - containerTop - offset + getScrollTop(), behavior);
1162
- return true;
1163
- }
1164
- }
1165
- scrollTo(0, behavior);
1166
- return false;
1167
- };
1168
- (0, react.useLayoutEffect)(() => {
1169
- handleScroll("auto");
1170
- }, [pathname, hash]);
1171
- (0, react.useEffect)(() => {
1172
- handleScroll("auto");
1173
- const rafId = requestAnimationFrame(() => {
1174
- handleScroll("auto");
1175
- window.dispatchEvent(new Event("resize"));
1176
- });
1177
- return () => cancelAnimationFrame(rafId);
1178
- }, [pathname, hash]);
1179
- return null;
1180
- }
1181
-
1182
- //#endregion
1183
- //#region src/client/app/mdx-component.tsx
1184
- const mdxComponentsDefault = {
1185
- ...require_mdx.mdx_components_default,
1186
- NotFound,
1187
- "404": NotFound
1188
- };
1189
-
1190
- //#endregion
1191
- //#region src/client/ssg/boltdocs-shell.tsx
1192
- /** Normalize a path: strip trailing slash unless it is exactly '/'. */
1193
- function normalizePath(p) {
1194
- return p.endsWith("/") && p.length > 1 ? p.slice(0, -1) : p;
1321
+ //#region src/client/ssg/mdx-elements.tsx
1322
+ const Loading = () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1323
+ className: "text-muted text-sm py-4",
1324
+ children: "Loading..."
1325
+ });
1326
+ function resolveModuleLoader(loader) {
1327
+ return typeof loader === "function" ? loader() : Promise.resolve(loader);
1195
1328
  }
1196
- /**
1197
- * Updates the HTML lang and dir attributes based on the current locale configuration.
1198
- */
1199
- function I18nUpdater({ config }) {
1200
- const { currentLocale } = require_icons_dev.useBoltdocsContext();
1329
+ const EagerMdxElement = ({ moduleLoader, moduleKey, route, components, collectionPostComponent }) => {
1330
+ const [mod, setMod] = (0, react.useState)(moduleLoader);
1201
1331
  (0, react.useEffect)(() => {
1202
- if (!config.i18n || typeof document === "undefined") return;
1203
- const locale = currentLocale || config.i18n.defaultLocale;
1204
- const localeConfig = config.i18n.localeConfigs?.[locale];
1205
- document.documentElement.lang = localeConfig?.htmlLang || locale || "en";
1206
- document.documentElement.dir = localeConfig?.direction || "ltr";
1207
- }, [currentLocale, config.i18n]);
1208
- return null;
1209
- }
1210
- /**
1211
- * Synchronizes the Zustand store with the current URL pathname.
1212
- * Receives a pre-built Map for O(1) route lookups instead of O(n) .find().
1213
- */
1214
- function StoreSync({ config, routeMap }) {
1215
- const location = (0, react_router_dom.useLocation)();
1216
- const { setLocale, setVersion } = require_icons_dev.useBoltdocsContext();
1332
+ setMod(moduleLoader);
1333
+ }, [moduleLoader]);
1217
1334
  (0, react.useEffect)(() => {
1218
- const currentPath = normalizePath(location.pathname);
1219
- const matchedRoute = routeMap.get(currentPath);
1220
- if (matchedRoute) {
1221
- if (config.i18n) setLocale(matchedRoute.locale || config.i18n.defaultLocale);
1222
- if (config.versions) setVersion(matchedRoute.version || config.versions.defaultVersion);
1223
- }
1224
- }, [
1225
- location.pathname,
1226
- config,
1227
- routeMap,
1228
- setLocale,
1229
- setVersion
1230
- ]);
1231
- return null;
1232
- }
1233
- function BoltdocsShell({ config, routes, components = {} }) {
1234
- const allComponents = (0, react.useMemo)(() => ({
1235
- ...mdxComponentsDefault,
1236
- ...virtual_boltdocs_mdx_components.default,
1237
- ...components
1238
- }), [components]);
1239
- const { pathname } = (0, react_router_dom.useLocation)();
1240
- const currentPath = (0, react.useMemo)(() => normalizePath(pathname || "/"), [pathname]);
1241
- const routeMap = (0, react.useMemo)(() => {
1242
- const map = /* @__PURE__ */ new Map();
1243
- for (const r of routes) {
1244
- const key = normalizePath(r.path === "" ? "/" : r.path);
1245
- map.set(key, r);
1246
- }
1247
- return map;
1248
- }, [routes]);
1249
- const initialData = (0, react.useMemo)(() => {
1250
- const matched = routeMap.get(currentPath);
1251
- let initLocale = void 0;
1252
- let initVersion = void 0;
1253
- if (matched) {
1254
- if (config.i18n) initLocale = matched.locale || config.i18n.defaultLocale;
1255
- if (config.versions) initVersion = matched.version || config.versions.defaultVersion;
1256
- }
1257
- return {
1258
- initLocale,
1259
- initVersion
1335
+ if (!{}.hot || !moduleKey) return;
1336
+ const handler = (data) => {
1337
+ if (data.relPath.replace(/\\/g, "/").replace(/^\//, "") !== route.filePath.replace(/\\/g, "/").replace(/^\//, "")) return;
1338
+ import(moduleKey + "?t=" + Date.now()).then((m) => {
1339
+ setMod(m);
1340
+ });
1260
1341
  };
1261
- }, [
1262
- currentPath,
1263
- config,
1264
- routeMap
1265
- ]);
1266
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HelmetProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.RoutesProvider, {
1267
- routes,
1268
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_image.ThemeProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.UIProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MdxComponentsProvider, {
1269
- components: allComponents,
1270
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_icons_dev.ConfigContext.Provider, {
1271
- value: config,
1272
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollHandler, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_icons_dev.BoltdocsProvider, {
1273
- initialLocale: initialData.initLocale,
1274
- initialVersion: initialData.initVersion,
1275
- children: [
1276
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StoreSync, {
1277
- config,
1278
- routeMap
1279
- }),
1280
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(I18nUpdater, { config }),
1281
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_router_dom.Outlet, {})
1282
- ]
1283
- })]
1284
- })
1285
- }) }) })
1286
- }) });
1287
- }
1342
+ ({}).hot.on("boltdocs:mdx-update", handler);
1343
+ return () => ({}).hot?.off("boltdocs:mdx-update", handler);
1344
+ }, [moduleKey, route.filePath]);
1345
+ const MDXComponent = mod?.default ?? mod ?? null;
1346
+ if (!MDXComponent) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Loading, {});
1347
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MdxPage, {
1348
+ MDXComponent,
1349
+ mdxComponents: components,
1350
+ collectionPostComponent
1351
+ });
1352
+ };
1353
+ const NotFoundWrapper = () => {
1354
+ const components = useMdxComponents();
1355
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(components.NotFound || components["404"] || NotFound, {});
1356
+ };
1288
1357
 
1289
1358
  //#endregion
1290
1359
  //#region src/client/app/head.tsx
@@ -1299,6 +1368,8 @@ function Head({ siteTitle, siteDescription, routes }) {
1299
1368
  const translatedSiteTitle = getTranslated(siteTitle, currentLocale);
1300
1369
  const finalTitle = pageTitle ? `${pageTitle} | ${translatedSiteTitle}` : translatedSiteTitle;
1301
1370
  const seo = currentRoute?.seo || {};
1371
+ const canonicalUrl = seo.canonical || (config?.siteUrl && currentRoute?.path ? `${config.siteUrl.replace(/\/$/, "")}${currentRoute.path}` : void 0);
1372
+ const ogUrl = seo["og:url"] || canonicalUrl || (typeof window !== "undefined" ? window.location.href : void 0);
1302
1373
  const globalMetatags = config?.seo?.metatags || {};
1303
1374
  const defaultOgImage = config?.seo?.thumbnails?.background;
1304
1375
  const ogImage = seo["og:image"] || defaultOgImage;
@@ -1320,13 +1391,13 @@ function Head({ siteTitle, siteDescription, routes }) {
1320
1391
  property: "og:type",
1321
1392
  content: "article"
1322
1393
  }),
1323
- typeof window !== "undefined" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", {
1324
- property: "og:url",
1325
- content: window.location.href
1326
- }),
1327
- typeof window !== "undefined" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("link", {
1394
+ canonicalUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("link", {
1328
1395
  rel: "canonical",
1329
- href: window.location.origin + location.pathname
1396
+ href: canonicalUrl
1397
+ }),
1398
+ ogUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", {
1399
+ property: "og:url",
1400
+ content: ogUrl
1330
1401
  }),
1331
1402
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", {
1332
1403
  name: "twitter:card",
@@ -1370,10 +1441,7 @@ function Head({ siteTitle, siteDescription, routes }) {
1370
1441
  name: "robots",
1371
1442
  content: value
1372
1443
  }, "robots");
1373
- if (key === "canonical") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("link", {
1374
- rel: "canonical",
1375
- href: value
1376
- }, "canonical");
1444
+ if (key === "canonical" || key === "og:url") return null;
1377
1445
  return key.startsWith("og:") || key.startsWith("music:") || key.startsWith("video:") || key.startsWith("article:") || key.startsWith("book:") || key.startsWith("profile:") ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("meta", {
1378
1446
  property: key,
1379
1447
  content: value
@@ -1385,71 +1453,68 @@ function Head({ siteTitle, siteDescription, routes }) {
1385
1453
  ] });
1386
1454
  }
1387
1455
 
1456
+ //#endregion
1457
+ //#region src/client/collections/collections-context.tsx
1458
+ const CollectionsContext = (0, react.createContext)({});
1459
+ function useCollectionsData() {
1460
+ return (0, react.use)(CollectionsContext);
1461
+ }
1462
+
1388
1463
  //#endregion
1389
1464
  //#region src/client/app/docs-layout.tsx
1390
- /**
1391
- * Wraps the docs Outlet with the user's (or default) layout component.
1392
- * The Layout receives the routed page as `children`.
1393
- * We use useRoutes to pass the current route context to the persistent layout.
1394
- */
1395
- function DocsLayout$1() {
1465
+ function DocsLayout({ collectionsData }) {
1396
1466
  const config = require_icons_dev.useConfig();
1397
1467
  const { currentRoute, allRoutes } = require_icons_dev.useRoutes();
1398
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Head, {
1468
+ const content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Head, {
1399
1469
  siteTitle: config.theme?.title,
1400
1470
  siteDescription: config.theme?.description,
1401
1471
  routes: allRoutes || []
1402
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(virtual_boltdocs_layout.default, {
1472
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog$1.InternalErrorBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(virtual_boltdocs_layout.default, {
1403
1473
  route: currentRoute,
1404
1474
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_router_dom.Outlet, {})
1405
- })] });
1475
+ }) })] });
1476
+ if (collectionsData) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CollectionsContext.Provider, {
1477
+ value: collectionsData,
1478
+ children: content
1479
+ });
1480
+ return content;
1406
1481
  }
1407
1482
 
1408
1483
  //#endregion
1409
- //#region src/client/ssg/create-routes.tsx
1410
- const Loading = () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1411
- className: "text-muted text-sm py-4",
1412
- children: "Loading..."
1413
- });
1414
- /**
1415
- * Stable component to render MDX pages.
1416
- * By being outside createRoutes, it prevents React from unmounting the page on HMR.
1417
- */
1418
- const MdxRouteElement = ({ moduleLoader, moduleKey, route, components }) => {
1419
- const MDXComponent = moduleLoader?.default ?? moduleLoader ?? null;
1420
- (0, react.useEffect)(() => {
1421
- if (!{}.hot || !moduleKey) return;
1422
- const handler = (data) => {
1423
- if (data.relPath.replace(/\\/g, "/").replace(/^\//, "") !== route.filePath.replace(/\\/g, "/").replace(/^\//, "")) return;
1424
- import(moduleKey + "?t=" + Date.now()).then((m) => {});
1425
- };
1426
- ({}).hot.on("boltdocs:mdx-update", handler);
1427
- return () => ({}).hot?.off("boltdocs:mdx-update", handler);
1428
- }, [moduleKey, route.filePath]);
1429
- if (!MDXComponent) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Loading, {});
1430
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MdxPage, {
1431
- MDXComponent,
1432
- mdxComponents: components
1433
- });
1434
- };
1435
- const NotFoundWrapper = () => {
1436
- const components = useMdxComponents();
1437
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(components.NotFound || components["404"] || NotFound, {});
1438
- };
1439
- function createRoutes(options) {
1440
- const { routesData, config, mdxModules, externalPages, externalLayout, components } = options;
1441
- const EffectiveExternalLayout = externalLayout || (({ children }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children }));
1442
- const withBase = (path) => {
1443
- const base = config.base || "/";
1444
- if (path.startsWith(base)) return path;
1445
- return `${base === "/" ? "" : base.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}` || "/";
1446
- };
1484
+ //#region src/client/ssg/create-routes.utils.ts
1485
+ function withBase(path, config) {
1486
+ const base = config.base || "/";
1487
+ if (path.startsWith(base)) return path;
1488
+ return `${base === "/" ? "" : base.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}` || "/";
1489
+ }
1490
+ function buildModuleMap(mdxModules) {
1491
+ const moduleMap = /* @__PURE__ */ new Map();
1492
+ const mdxModuleKeys = Object.keys(mdxModules);
1493
+ if (mdxModuleKeys.length > 0) {
1494
+ const docsDirName = mdxModuleKeys[0].replace(/\\/g, "/").split("/").filter(Boolean)[0] || "docs";
1495
+ const primaryPrefix = `/${docsDirName}/`;
1496
+ const altPrefix = `./${docsDirName}/`;
1497
+ for (const rawKey of mdxModuleKeys) {
1498
+ const k = rawKey.replace(/\\/g, "/");
1499
+ let relativePath = "";
1500
+ if (k.indexOf(primaryPrefix) !== -1) relativePath = k.substring(k.indexOf(primaryPrefix) + primaryPrefix.length);
1501
+ else if (k.startsWith(altPrefix)) relativePath = k.substring(altPrefix.length);
1502
+ if (relativePath) moduleMap.set(relativePath, rawKey);
1503
+ else moduleMap.set(k, rawKey);
1504
+ }
1505
+ }
1506
+ return moduleMap;
1507
+ }
1508
+
1509
+ //#endregion
1510
+ //#region src/client/ssg/create-routes.doc.tsx
1511
+ function buildDocRoutes(options) {
1512
+ const { routesData, config, mdxModules, components, externalPages } = options;
1513
+ const baseDocsPath = (config.base || "/docs").replace(/\/$/, "") || "/";
1447
1514
  const defaultVersionMetadata = [];
1448
1515
  const defaultVersion = config.versions?.defaultVersion;
1449
1516
  const docsBase = (config.base || "/docs").replace(/\/$/, "");
1450
- let baseDocsPath = (config.base || "/docs").replace(/\/$/, "");
1451
- if (!baseDocsPath) baseDocsPath = "/";
1452
- if (defaultVersion) routesData.forEach((route) => {
1517
+ if (defaultVersion) routesData.filter((r) => !r.collection).forEach((route) => {
1453
1518
  if (route.version) return;
1454
1519
  const p = route.path || "";
1455
1520
  const subPath = p.startsWith(docsBase) ? p.substring(docsBase.length).replace(/^\//, "") : p.replace(/^\//, "");
@@ -1462,36 +1527,18 @@ function createRoutes(options) {
1462
1527
  });
1463
1528
  }
1464
1529
  });
1465
- const docMetadata = [...routesData, ...defaultVersionMetadata];
1466
- const moduleMap = /* @__PURE__ */ new Map();
1530
+ const docMetadata = [...routesData.filter((r) => !r.collection), ...defaultVersionMetadata];
1531
+ const moduleMap = buildModuleMap(mdxModules);
1467
1532
  const mdxModuleKeys = Object.keys(mdxModules);
1468
- if (mdxModuleKeys.length > 0) {
1469
- const docsDirName = mdxModuleKeys[0].replace(/\\/g, "/").split("/").filter(Boolean)[0] || "docs";
1470
- const primaryPrefix = `/${docsDirName}/`;
1471
- const altPrefix = `./${docsDirName}/`;
1472
- for (const rawKey of mdxModuleKeys) {
1473
- const k = rawKey.replace(/\\/g, "/");
1474
- let relativePath = "";
1475
- if (k.indexOf(primaryPrefix) !== -1) relativePath = k.substring(k.indexOf(primaryPrefix) + primaryPrefix.length);
1476
- else if (k.startsWith(altPrefix)) relativePath = k.substring(altPrefix.length);
1477
- if (relativePath) moduleMap.set(relativePath, rawKey);
1478
- else moduleMap.set(k, rawKey);
1479
- }
1480
- }
1533
+ const isLazy = mdxModuleKeys.length > 0 && typeof mdxModules[mdxModuleKeys[0]] === "function";
1481
1534
  const docRoutes = docMetadata.map((route) => {
1482
1535
  const normalizedFilePath = route.filePath.replace(/\\/g, "/");
1483
1536
  const moduleKey = moduleMap.get(normalizedFilePath);
1484
1537
  const moduleLoader = moduleKey ? mdxModules[moduleKey] : null;
1485
- const fullPath = withBase(route.path === "" ? "/" : route.path);
1538
+ const fullPath = withBase(route.path === "" ? "/" : route.path, config);
1486
1539
  const path = fullPath === baseDocsPath ? "." : fullPath.startsWith(baseDocsPath + "/") ? fullPath.slice(baseDocsPath.length + 1) : fullPath;
1487
- return {
1540
+ const routeRecord = {
1488
1541
  path,
1489
- element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MdxRouteElement, {
1490
- moduleKey,
1491
- moduleLoader,
1492
- route,
1493
- components
1494
- }, moduleKey || path),
1495
1542
  loader: async () => ({
1496
1543
  path,
1497
1544
  frontmatter: {
@@ -1499,6 +1546,7 @@ function createRoutes(options) {
1499
1546
  description: route.description || "",
1500
1547
  ...route.frontmatter || {}
1501
1548
  },
1549
+ seo: route.seo,
1502
1550
  headings: route.headings || [],
1503
1551
  filePath: route.filePath,
1504
1552
  locale: route.locale,
@@ -1510,6 +1558,24 @@ function createRoutes(options) {
1510
1558
  }),
1511
1559
  getStaticPaths: () => [path]
1512
1560
  };
1561
+ if (isLazy && moduleLoader) routeRecord.lazy = async () => {
1562
+ const mod = await resolveModuleLoader(moduleLoader);
1563
+ return { Component: function LoadedMdxRoute() {
1564
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EagerMdxElement, {
1565
+ moduleKey,
1566
+ moduleLoader: mod,
1567
+ route,
1568
+ components
1569
+ }, moduleKey || path);
1570
+ } };
1571
+ };
1572
+ else routeRecord.element = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EagerMdxElement, {
1573
+ moduleKey,
1574
+ moduleLoader,
1575
+ route,
1576
+ components
1577
+ }, moduleKey || path);
1578
+ return routeRecord;
1513
1579
  });
1514
1580
  const locales = config.i18n?.locales ? Array.isArray(config.i18n.locales) ? config.i18n.locales : Object.keys(config.i18n.locales) : [];
1515
1581
  const allVersions = config.versions?.versions?.map((v) => v.path) || [];
@@ -1560,11 +1626,11 @@ function createRoutes(options) {
1560
1626
  getStaticPaths: () => []
1561
1627
  });
1562
1628
  const matchedMetaObj = docMetadata.find((m) => {
1563
- const fullPath = withBase(m.path === "" ? "/" : m.path);
1629
+ const fullPath = withBase(m.path === "" ? "/" : m.path, config);
1564
1630
  return (fullPath === baseDocsPath ? "." : fullPath.startsWith(baseDocsPath + "/") ? fullPath.slice(baseDocsPath.length + 1) : fullPath) === matchedRouteObj.path;
1565
1631
  });
1566
1632
  if (matchedMetaObj) {
1567
- const canonicalPath = withBase(matchedMetaObj.path);
1633
+ const canonicalPath = withBase(matchedMetaObj.path, config);
1568
1634
  const canonicalUrl = config.siteUrl ? `${config.siteUrl.replace(/\/$/, "")}${canonicalPath}` : canonicalPath;
1569
1635
  docMetadata.push({
1570
1636
  ...matchedMetaObj,
@@ -1580,62 +1646,277 @@ function createRoutes(options) {
1580
1646
  }
1581
1647
  }
1582
1648
  });
1583
- const children = [{
1584
- path: baseDocsPath,
1585
- element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocsLayout$1, {}),
1586
- children: docRoutes
1587
- }];
1588
- const externalMetadata = [];
1589
- if (externalPages) Object.entries(externalPages).forEach(([rawPath, ExtComponent]) => {
1649
+ return {
1650
+ routes: docRoutes,
1651
+ metadata: docMetadata
1652
+ };
1653
+ }
1654
+
1655
+ //#endregion
1656
+ //#region src/client/ssg/create-routes.external.tsx
1657
+ function buildExternalRoutes(options) {
1658
+ const { externalPages, externalLayout, config } = options;
1659
+ const children = [];
1660
+ const metadata = [];
1661
+ if (!externalPages) return {
1662
+ children,
1663
+ metadata
1664
+ };
1665
+ const EffectiveExternalLayout = externalLayout || (({ children }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children }));
1666
+ Object.entries(externalPages).forEach(([rawPath, ExtComponent]) => {
1590
1667
  const path = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
1591
- if (!children.find((r) => r.path === path)) {
1592
- externalMetadata.push({
1668
+ metadata.push({
1669
+ path,
1670
+ locale: config.i18n?.defaultLocale,
1671
+ title: rawPath === "/" ? "Home" : rawPath.replace(/^\//, "").split("/").pop() || "Page",
1672
+ filePath: "",
1673
+ headings: []
1674
+ });
1675
+ children.push({
1676
+ path,
1677
+ element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EffectiveExternalLayout, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExtComponent, {}) }),
1678
+ loader: async () => ({
1593
1679
  path,
1594
- locale: config.i18n?.defaultLocale,
1595
- title: rawPath === "/" ? "Home" : rawPath.replace(/^\//, "").split("/").pop() || "Page",
1680
+ locale: config.i18n?.defaultLocale
1681
+ }),
1682
+ getStaticPaths: () => [path]
1683
+ });
1684
+ if (config.i18n) Object.keys(config.i18n.locales).forEach((locale) => {
1685
+ const localePath = `/${locale}${rawPath === "/" ? "" : rawPath}`;
1686
+ metadata.push({
1687
+ path: localePath,
1688
+ locale,
1689
+ title: rawPath,
1596
1690
  filePath: "",
1597
1691
  headings: []
1598
1692
  });
1599
1693
  children.push({
1600
- path,
1694
+ path: localePath,
1601
1695
  element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EffectiveExternalLayout, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExtComponent, {}) }),
1602
1696
  loader: async () => ({
1603
- path,
1604
- locale: config.i18n?.defaultLocale
1697
+ path: localePath,
1698
+ locale
1605
1699
  }),
1606
- getStaticPaths: () => [path]
1607
- });
1608
- if (config.i18n) Object.keys(config.i18n.locales).forEach((locale) => {
1609
- const localePath = `/${locale}${rawPath === "/" ? "" : rawPath}`;
1610
- if (!children.find((r) => r.path === localePath)) {
1611
- externalMetadata.push({
1612
- path: localePath,
1613
- locale,
1614
- title: rawPath,
1615
- filePath: "",
1616
- headings: []
1617
- });
1618
- children.push({
1619
- path: localePath,
1620
- element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EffectiveExternalLayout, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExtComponent, {}) }),
1621
- loader: async () => ({
1622
- path: localePath,
1623
- locale
1624
- }),
1625
- getStaticPaths: () => [localePath]
1626
- });
1627
- }
1700
+ getStaticPaths: () => [localePath]
1628
1701
  });
1629
- }
1702
+ });
1630
1703
  });
1631
- children.push({
1632
- path: "*",
1633
- element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EffectiveExternalLayout, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NotFoundWrapper, {}) })
1704
+ return {
1705
+ children,
1706
+ metadata
1707
+ };
1708
+ }
1709
+
1710
+ //#endregion
1711
+ //#region src/client/ssg/create-routes.collection.tsx
1712
+ function DefaultCollectionList() {
1713
+ const data = (0, react_router_dom.useLoaderData)();
1714
+ if (!data || !data.posts) return null;
1715
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1716
+ className: "py-8 max-w-2xl mx-auto px-4",
1717
+ children: [
1718
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
1719
+ className: "text-3xl font-bold mb-6 capitalize",
1720
+ children: data.collection
1721
+ }),
1722
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1723
+ className: "space-y-6",
1724
+ children: data.posts.map((post) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
1725
+ className: "border-b border-subtle pb-4",
1726
+ children: [
1727
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
1728
+ className: "text-xl font-semibold mb-2",
1729
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_router_dom.Link, {
1730
+ to: post.path,
1731
+ className: "text-primary-600 hover:underline",
1732
+ children: post.title
1733
+ })
1734
+ }),
1735
+ post.date && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
1736
+ className: "text-xs text-muted block mb-2",
1737
+ children: new Date(post.date).toLocaleDateString()
1738
+ }),
1739
+ post.excerpt && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1740
+ className: "text-sm text-body",
1741
+ children: post.excerpt
1742
+ })
1743
+ ]
1744
+ }, post.path))
1745
+ }),
1746
+ data.totalPages > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1747
+ className: "mt-8 flex gap-4 text-sm",
1748
+ children: [
1749
+ data.currentPage > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_router_dom.Link, {
1750
+ to: data.currentPage === 2 ? `/${data.collection}` : `/${data.collection}/page/${data.currentPage - 1}`,
1751
+ className: "text-primary-600 hover:underline",
1752
+ children: "Previous"
1753
+ }),
1754
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
1755
+ "Page ",
1756
+ data.currentPage,
1757
+ " of ",
1758
+ data.totalPages
1759
+ ] }),
1760
+ data.currentPage < data.totalPages && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_router_dom.Link, {
1761
+ to: `/${data.collection}/page/${data.currentPage + 1}`,
1762
+ className: "text-primary-600 hover:underline",
1763
+ children: "Next"
1764
+ })
1765
+ ]
1766
+ })
1767
+ ]
1634
1768
  });
1769
+ }
1770
+ function buildCollectionRoutes(options) {
1771
+ const { routesData, collectionsData, collectionLayouts, collectionLists, collectionPosts, config, mdxModules, components } = options;
1772
+ const postsPerPage = options.postsPerPage ?? config.collections?.postsPerPage ?? 10;
1773
+ const children = [];
1774
+ const metadata = [];
1775
+ const collectionsMap = /* @__PURE__ */ new Map();
1776
+ for (const r of routesData) if (r.collection) {
1777
+ if (!collectionsMap.has(r.collection)) collectionsMap.set(r.collection, []);
1778
+ collectionsMap.get(r.collection).push(r);
1779
+ }
1780
+ const moduleMap = buildModuleMap(mdxModules);
1781
+ const mdxModuleKeys = Object.keys(mdxModules);
1782
+ const isLazy = mdxModuleKeys.length > 0 && typeof mdxModules[mdxModuleKeys[0]] === "function";
1783
+ for (const [colName, colRoutes] of collectionsMap) {
1784
+ const colBase = `/${colName}`;
1785
+ colRoutes.sort((a, b) => {
1786
+ const da = a.date ? new Date(a.date).getTime() : 0;
1787
+ return (b.date ? new Date(b.date).getTime() : 0) - da;
1788
+ });
1789
+ const colChildren = [];
1790
+ for (const route of colRoutes) {
1791
+ const normalizedFilePath = route.filePath.replace(/\\/g, "/");
1792
+ const moduleKey = moduleMap.get(normalizedFilePath);
1793
+ const moduleLoader = moduleKey ? mdxModules[moduleKey] : null;
1794
+ const subPath = route.path.startsWith(colBase + "/") ? route.path.slice(colBase.length + 1) : route.path.replace(colBase, "") || "";
1795
+ const routeWithCollection = {
1796
+ ...route,
1797
+ collection: colName
1798
+ };
1799
+ const postComponent = collectionPosts?.[colName];
1800
+ const routeRecord = {
1801
+ path: subPath,
1802
+ loader: async () => ({
1803
+ route: routeWithCollection,
1804
+ headings: route.headings || [],
1805
+ collection: colName,
1806
+ path: subPath,
1807
+ frontmatter: {
1808
+ title: route.title,
1809
+ description: route.description || "",
1810
+ ...route.frontmatter || {}
1811
+ },
1812
+ filePath: route.filePath,
1813
+ locale: route.locale,
1814
+ version: route.version,
1815
+ date: route.date,
1816
+ lastUpdated: route.lastUpdated
1817
+ }),
1818
+ getStaticPaths: () => [subPath || "."]
1819
+ };
1820
+ if (isLazy && moduleLoader) routeRecord.lazy = async () => {
1821
+ const mod = await resolveModuleLoader(moduleLoader);
1822
+ return { Component: function LoadedCollectionMdxRoute() {
1823
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EagerMdxElement, {
1824
+ moduleKey,
1825
+ moduleLoader: mod,
1826
+ route,
1827
+ components,
1828
+ collectionPostComponent: postComponent
1829
+ }, moduleKey || subPath);
1830
+ } };
1831
+ };
1832
+ else routeRecord.element = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EagerMdxElement, {
1833
+ moduleKey,
1834
+ moduleLoader,
1835
+ route,
1836
+ components,
1837
+ collectionPostComponent: postComponent
1838
+ }, moduleKey || subPath);
1839
+ colChildren.push(routeRecord);
1840
+ metadata.push(route);
1841
+ }
1842
+ const totalPages = Math.ceil(colRoutes.length / postsPerPage);
1843
+ const paginatedPosts = colRoutes.map((r) => ({
1844
+ path: r.path,
1845
+ title: r.title,
1846
+ date: r.date,
1847
+ excerpt: r.excerpt,
1848
+ tags: r.tags,
1849
+ author: r.author,
1850
+ coverImage: r.coverImage,
1851
+ filePath: r.filePath,
1852
+ frontmatter: r.frontmatter
1853
+ }));
1854
+ const ListElement = collectionLists?.[colName] || DefaultCollectionList;
1855
+ colChildren.unshift({
1856
+ index: true,
1857
+ element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ListElement, {}),
1858
+ loader: async () => ({
1859
+ posts: paginatedPosts.slice(0, postsPerPage),
1860
+ totalPages,
1861
+ currentPage: 1,
1862
+ collection: colName
1863
+ }),
1864
+ getStaticPaths: () => []
1865
+ });
1866
+ for (let p = 2; p <= totalPages; p++) colChildren.push({
1867
+ path: `page/${p}`,
1868
+ element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ListElement, {}),
1869
+ loader: async () => ({
1870
+ posts: paginatedPosts.slice((p - 1) * postsPerPage, p * postsPerPage),
1871
+ totalPages,
1872
+ currentPage: p,
1873
+ collection: colName
1874
+ }),
1875
+ getStaticPaths: () => [`page/${p}`]
1876
+ });
1877
+ const blogLayoutRoute = {
1878
+ path: colBase,
1879
+ element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(collectionLayouts?.[colName] || DocsLayout, { collectionsData: collectionsData || {} }),
1880
+ children: colChildren
1881
+ };
1882
+ children.push(blogLayoutRoute);
1883
+ }
1884
+ return {
1885
+ children,
1886
+ metadata
1887
+ };
1888
+ }
1889
+
1890
+ //#endregion
1891
+ //#region src/client/ssg/create-routes.tsx
1892
+ function createRoutes(options) {
1893
+ const { config, components, externalLayout } = options;
1894
+ const EffectiveExternalLayout = externalLayout || (({ children }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children }));
1895
+ const baseDocsPath = (config.base || "/docs").replace(/\/$/, "") || "/";
1896
+ const { routes: docRoutes, metadata: docMetadata } = buildDocRoutes(options);
1897
+ const externalRoutes = buildExternalRoutes(options);
1898
+ const collectionRoutes = buildCollectionRoutes(options);
1899
+ const children = [
1900
+ {
1901
+ path: baseDocsPath,
1902
+ element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DocsLayout, {}),
1903
+ children: docRoutes
1904
+ },
1905
+ ...externalRoutes.children,
1906
+ ...collectionRoutes.children,
1907
+ {
1908
+ path: "*",
1909
+ element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EffectiveExternalLayout, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NotFoundWrapper, {}) })
1910
+ }
1911
+ ];
1635
1912
  return [{
1636
1913
  element: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoltdocsShell, {
1637
1914
  config,
1638
- routes: [...docMetadata, ...externalMetadata],
1915
+ routes: [
1916
+ ...docMetadata,
1917
+ ...externalRoutes.metadata,
1918
+ ...collectionRoutes.metadata
1919
+ ],
1639
1920
  components
1640
1921
  }),
1641
1922
  children
@@ -1821,29 +2102,40 @@ function useTrackEvent() {
1821
2102
  }
1822
2103
 
1823
2104
  //#endregion
1824
- //#region src/client/components/docs-layout-default.tsx
2105
+ //#region src/client/hooks/use-headings.ts
1825
2106
  /**
1826
- * Pre-assembled high-fidelity documentation layout component.
1827
- * Fully styled and optimized to adapt seamlessly to our custom Parchment/Slate theme.
2107
+ * Returns the headings of the current page, extracted from the route loader data.
2108
+ * Useful for building custom Tables of Contents or jumping to sections.
2109
+ *
2110
+ * @returns An array of heading objects with level, text, and id.
1828
2111
  */
2112
+ function useHeadings() {
2113
+ const matches = (0, react_router_dom.useMatches)();
2114
+ return (0, react.useMemo)(() => {
2115
+ return (matches[matches.length - 1]?.data)?.headings || [];
2116
+ }, [matches]);
2117
+ }
2118
+
2119
+ //#endregion
2120
+ //#region src/client/components/docs-layout-default.tsx
1829
2121
  function DocsLayoutComponent({ children }) {
1830
- const { routes: filteredRoutes, currentRoute } = require_icons_dev.useRoutes();
2122
+ const { routes: filteredRoutes, currentRoute, isCollectionPage } = require_icons_dev.useRoutes();
1831
2123
  const config = require_icons_dev.useConfig();
1832
2124
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.DocsLayout, {
1833
2125
  className: "selection:bg-primary-500/10 selection:text-primary-500",
1834
2126
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Navbar, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.DocsLayout.Body, {
1835
2127
  className: "bg-main",
1836
2128
  children: [
1837
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Sidebar, {
2129
+ !isCollectionPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Sidebar, {
1838
2130
  routes: filteredRoutes || [],
1839
2131
  config
1840
2132
  }),
1841
2133
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.DocsLayout.Content, {
1842
2134
  className: "animate-in fade-in duration-500 scroll-smooth",
1843
2135
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.DocsLayout.ContentMdx, {
1844
- className: "max-w-3xl sm:max-w-4xl lg:max-w-4xl px-2 pt-8 pb-24",
2136
+ className: "max-w-3xl sm:max-w-4xl lg:max-w-5xl px-4 sm:px-6 pt-8 pb-24",
1845
2137
  children: [
1846
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.DocsLayout.Header, { children: [
2138
+ !isCollectionPage && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.DocsLayout.Header, { children: [
1847
2139
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1848
2140
  className: "mb-4 border-b border-subtle pb-4 flex flex-wrap items-center justify-between gap-3",
1849
2141
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Breadcrumbs, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyMarkdown, {
@@ -1864,7 +2156,7 @@ function DocsLayoutComponent({ children }) {
1864
2156
  className: "prose prose-neutral dark:prose-invert max-w-none",
1865
2157
  children
1866
2158
  }) }),
1867
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.DocsLayout.Footer, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageNav, {}) })
2159
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.DocsLayout.Footer, { children: !isCollectionPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageNav, {}) })
1868
2160
  ]
1869
2161
  })
1870
2162
  }),
@@ -1878,21 +2170,63 @@ function DocsLayoutComponent({ children }) {
1878
2170
  })]
1879
2171
  });
1880
2172
  }
1881
- const DocsLayout = Object.assign(DocsLayoutComponent, {
1882
- Body: require_docs_layout.DocsLayout.Body,
1883
- Content: require_docs_layout.DocsLayout.Content,
1884
- ContentMdx: require_docs_layout.DocsLayout.ContentMdx,
1885
- Header: require_docs_layout.DocsLayout.Header,
1886
- Footer: require_docs_layout.DocsLayout.Footer
1887
- });
1888
2173
 
1889
2174
  //#endregion
2175
+ //#region src/client/collections/hooks.ts
2176
+ /**
2177
+ * Returns the posts of a collection.
2178
+ * @param collection - The name of the collection.
2179
+ * @returns The posts of the collection.
2180
+ */
2181
+ function usePosts(collection) {
2182
+ return useCollectionsData()[collection] || [];
2183
+ }
2184
+ /**
2185
+ * Returns a post by its slug.
2186
+ * @param collection - The name of the collection.
2187
+ * @param slug - The slug of the post.
2188
+ * @returns The post with the given slug.
2189
+ */
2190
+ function usePost(collection, slug) {
2191
+ const posts = usePosts(collection);
2192
+ return (0, react.useMemo)(() => posts.find((p) => p.path === `/${collection}/${slug}` || p.path.endsWith(`/${slug}`) || p.path === slug), [
2193
+ posts,
2194
+ collection,
2195
+ slug
2196
+ ]);
2197
+ }
2198
+ /**
2199
+ * Returns the recent posts of a collection.
2200
+ * @param collection - The name of the collection.
2201
+ * @param count - The number of recent posts to return.
2202
+ * @returns The recent posts of the collection.
2203
+ */
2204
+ function useRecentPosts(collection, count = 5) {
2205
+ const posts = usePosts(collection);
2206
+ return (0, react.useMemo)(() => posts.slice(0, count), [posts, count]);
2207
+ }
2208
+
2209
+ //#endregion
2210
+ //#region src/client/utils/react-to-text.ts
2211
+ const reactToText = (node, resolvers) => {
2212
+ if (node == null || typeof node === "boolean") return "";
2213
+ if (typeof node === "string" || typeof node === "number") return String(node);
2214
+ if (Array.isArray(node)) return node.map((n) => reactToText(n, resolvers)).join("");
2215
+ if ((0, react.isValidElement)(node)) {
2216
+ const resolver = resolvers?.get(node.type);
2217
+ if (resolver) return resolver(node.props);
2218
+ return reactToText(node.props.children, resolvers);
2219
+ }
2220
+ return "";
2221
+ };
2222
+
2223
+ //#endregion
2224
+ exports.Banner = Banner;
1890
2225
  exports.BoltdocsShell = BoltdocsShell;
1891
2226
  exports.Breadcrumbs = Breadcrumbs;
1892
- exports.Card = require_mdx.Card;
1893
- exports.Cards = require_mdx.Cards;
2227
+ exports.CollectionsContext = CollectionsContext;
1894
2228
  exports.CopyMarkdown = CopyMarkdown;
1895
- exports.DocsLayout = DocsLayout;
2229
+ exports.DocsLayout = DocsLayoutComponent;
1896
2230
  exports.ErrorBoundary = ErrorBoundary;
1897
2231
  exports.MdxPage = MdxPage;
1898
2232
  exports.Navbar = Navbar;
@@ -1912,16 +2246,21 @@ exports.copyToClipboard = require_mdx.copyToClipboard;
1912
2246
  exports.createRoutes = createRoutes;
1913
2247
  exports.getStarsRepo = getStarsRepo;
1914
2248
  exports.getTranslated = getTranslated;
1915
- exports.reactToText = require_mdx.reactToText;
2249
+ exports.reactToText = reactToText;
1916
2250
  exports.useAnalytics = useAnalytics;
1917
2251
  exports.useBreadcrumbs = useBreadcrumbs;
1918
2252
  exports.useConfig = require_icons_dev.useConfig;
2253
+ exports.useHeadings = useHeadings;
1919
2254
  exports.useI18n = useI18n;
1920
2255
  exports.useLocalizedTo = require_icons_dev.useLocalizedTo;
1921
2256
  exports.useLocation = require_docs_layout.useLocation;
1922
2257
  exports.useMdxComponents = useMdxComponents;
2258
+ exports.useMergedComponents = useMergedComponents;
1923
2259
  exports.useNavbar = useNavbar;
1924
2260
  exports.usePageNav = usePageNav;
2261
+ exports.usePost = usePost;
2262
+ exports.usePosts = usePosts;
2263
+ exports.useRecentPosts = useRecentPosts;
1925
2264
  exports.useRoutes = require_icons_dev.useRoutes;
1926
2265
  exports.useSearch = require_search_dialog$1.useSearch;
1927
2266
  exports.useSearchHighlight = require_docs_layout.useSearchHighlight;