boltdocs 2.8.3 → 2.9.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 (87) hide show
  1. package/bin/boltdocs.js +7 -6
  2. package/dist/{banner-MynZD_Ox.d.cts → banner-C_xkGxzI.d.cts} +1 -1
  3. package/dist/{banner-3N4Jd_L9.d.ts → banner-D2NddBfF.d.ts} +1 -1
  4. package/dist/cache-C2PiGyg8.cjs +6 -0
  5. package/dist/cache-DFW4R3S0.mjs +6 -0
  6. package/dist/chunk-Ds5LZdWN.cjs +6 -0
  7. package/dist/client/index.cjs +693 -488
  8. package/dist/client/index.d.cts +74 -8
  9. package/dist/client/index.d.ts +74 -8
  10. package/dist/client/index.js +692 -489
  11. package/dist/client/mdx.cjs +1 -1
  12. package/dist/client/mdx.js +1 -1
  13. package/dist/client/primitives.cjs +4 -4
  14. package/dist/client/primitives.d.cts +1 -1
  15. package/dist/client/primitives.d.ts +1 -1
  16. package/dist/client/primitives.js +4 -4
  17. package/dist/client/theme/neutral.css +5 -3
  18. package/dist/client/theme/reset.css +19 -0
  19. package/dist/{docs-layout-CwCq42Zt.cjs → docs-layout-3TpAt6MB.cjs} +302 -248
  20. package/dist/{docs-layout-Dn6S5g59.js → docs-layout-6FQ8__ok.js} +303 -249
  21. package/dist/doctor-BY1tSmQd.mjs +34 -0
  22. package/dist/{doctor-DyNUVe96.cjs → doctor-Bknon8f5.cjs} +1 -1
  23. package/dist/doctor-DcFLi4t1.cjs +34 -0
  24. package/dist/{doctor-aN_leTbh.mjs → doctor-wsPTzt8Y.mjs} +1 -1
  25. package/dist/{generator-CC2yHzhZ.cjs → generator-BEIF6MOx.cjs} +2 -2
  26. package/dist/{generator-BHCrLU6h.mjs → generator-DILs0EFN.mjs} +1 -1
  27. package/dist/handler-B31cxNw0.mjs +6 -0
  28. package/dist/handler-DfhH9D1b.mjs +28 -0
  29. package/dist/handler-Djy0HfsI.cjs +28 -0
  30. package/dist/{icons-dev-DvJ-hh9x.cjs → icons-dev-BryEFkJu.cjs} +96 -7
  31. package/dist/{icons-dev-Oju24Wjp.js → icons-dev-kJyGWNeg.js} +79 -8
  32. package/dist/{image-Ch4-GxdO.cjs → image-B9YA_oQ_.cjs} +24 -10
  33. package/dist/{image-Do8V9PCW.js → image-CjYu9Eml.js} +24 -10
  34. package/dist/{mdx-5oeCOFhH.js → mdx-Cy_c2zio.js} +116 -33
  35. package/dist/{mdx-BGM7LjW5.cjs → mdx-WXjAMS8Y.cjs} +121 -32
  36. package/dist/{meta-loader-Cv9O0Pzl.cjs → meta-loader-D0V6oOQt.cjs} +1 -1
  37. package/dist/node/cli-entry.cjs +3 -3
  38. package/dist/node/cli-entry.mjs +3 -3
  39. package/dist/node/index.cjs +1 -1
  40. package/dist/node/index.d.cts +368 -24
  41. package/dist/node/index.d.mts +369 -24
  42. package/dist/node/index.mjs +1 -1
  43. package/dist/node/routes/worker.cjs +1 -1
  44. package/dist/node/routes/worker.mjs +1 -1
  45. package/dist/node-DV-EPtMU.mjs +160 -0
  46. package/dist/node-vOVNRABe.cjs +160 -0
  47. package/dist/{package-CHxJV4Jy.mjs → package-BK_82QLX.mjs} +1 -1
  48. package/dist/{package-B_SoaGeu.cjs → package-OxKE0p6j.cjs} +1 -1
  49. package/dist/{parser-B7-6PyQz.cjs → parser-C2Pw18LY.cjs} +1 -1
  50. package/dist/{parser-BzB-zCkF.cjs → parser-DJoEF96Y.cjs} +1 -1
  51. package/dist/{parser-D0PVghVt.mjs → parser-DScG_PTs.mjs} +1 -1
  52. package/dist/routes--LYHSHT7.cjs +6 -0
  53. package/dist/routes-BAsfsn_e.mjs +6 -0
  54. package/dist/routes-C6Kr2HFN.cjs +6 -0
  55. package/dist/routes-CKgGAy8P.mjs +6 -0
  56. package/dist/{search-dialog-BXVoecTx.cjs → search-dialog-BhXg05Ri.cjs} +1 -1
  57. package/dist/{search-dialog-BYhOov4S.cjs → search-dialog-BsAiQgnx.cjs} +2 -2
  58. package/dist/{search-dialog-C09riYmx.js → search-dialog-CaOO1Q4i.js} +2 -2
  59. package/dist/{search-dialog-CUeAfy-8.cjs → search-dialog-CzwvKoLW.cjs} +1 -1
  60. package/dist/{search-dialog-DHc_8FFX.js → search-dialog-DRNJsxOv.js} +1 -1
  61. package/dist/{search-dialog-D8gLkhUV.js → search-dialog-DaR66wl0.js} +1 -1
  62. package/dist/shiki-adapter-CUtj-xKv.cjs +6 -0
  63. package/dist/shiki-adapter-EZptJAmW.mjs +6 -0
  64. package/dist/shiki-adapter-F-P-lDon.mjs +6 -0
  65. package/dist/shiki-adapter-PQBl32AN.cjs +6 -0
  66. package/dist/{sidebar-Dlkgbxs6.d.cts → sidebar-BtJyWHy4.d.cts} +43 -4
  67. package/dist/{sidebar-DNq4_ZAa.d.ts → sidebar-C4fuRYYS.d.ts} +43 -4
  68. package/dist/{utils-BYITg7T5.mjs → utils-DC4Wq-S2.mjs} +1 -1
  69. package/dist/{utils-Cjmx1hhk.cjs → utils-wHud9ny5.cjs} +1 -1
  70. package/dist/worker-pool-BS1LX67P.cjs +6 -0
  71. package/dist/worker-pool-DRv8ef4z.mjs +6 -0
  72. package/package.json +7 -3
  73. package/src/shared/types.ts +36 -3
  74. package/dist/cache-BMUyNiiA.mjs +0 -6
  75. package/dist/cache-CKm45d2w.cjs +0 -6
  76. package/dist/chunk-CU-zTemE.cjs +0 -6
  77. package/dist/doctor-BArviV8X.cjs +0 -28
  78. package/dist/doctor-CgLA7_Uv.mjs +0 -28
  79. package/dist/node-MsTvOgJN.mjs +0 -159
  80. package/dist/node-h9HmhAFB.cjs +0 -159
  81. package/dist/routes-BW6Dif_K.mjs +0 -6
  82. package/dist/routes-DJNJ-rTt.cjs +0 -6
  83. package/dist/routes-DiYC4nD2.cjs +0 -6
  84. package/dist/routes-ERSGuFQK.mjs +0 -6
  85. package/dist/worker-pool-CtqklOXq.cjs +0 -6
  86. package/dist/worker-pool-k0DY6k8T.mjs +0 -6
  87. /package/dist/{meta-loader-DzwDFtdT.mjs → meta-loader-By22EnYa.mjs} +0 -0
@@ -4,12 +4,12 @@
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-DvJ-hh9x.cjs');
8
- const require_image = require('../image-Ch4-GxdO.cjs');
9
- const require_mdx = require('../mdx-BGM7LjW5.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');
7
+ const require_icons_dev = require('../icons-dev-BryEFkJu.cjs');
8
+ const require_image = require('../image-B9YA_oQ_.cjs');
9
+ const require_mdx = require('../mdx-WXjAMS8Y.cjs');
10
+ const require_docs_layout = require('../docs-layout-3TpAt6MB.cjs');
11
+ const require_search_dialog = require('../search-dialog-BhXg05Ri.cjs');
12
+ const require_search_dialog$1 = require('../search-dialog-BsAiQgnx.cjs');
13
13
  let react = require("react");
14
14
  let react_router_dom = require("react-router-dom");
15
15
  let react_jsx_runtime = require("react/jsx-runtime");
@@ -159,6 +159,13 @@ const mdxComponentsDefault = {
159
159
  "404": NotFound
160
160
  };
161
161
 
162
+ //#endregion
163
+ //#region src/client/collections/collections-context.tsx
164
+ const CollectionsContext = (0, react.createContext)({});
165
+ function useCollectionsData() {
166
+ return (0, react.use)(CollectionsContext);
167
+ }
168
+
162
169
  //#endregion
163
170
  //#region src/client/ssg/boltdocs-shell.tsx
164
171
  /**
@@ -194,7 +201,7 @@ function StoreSync({ config, routeMap }) {
194
201
  ]);
195
202
  return null;
196
203
  }
197
- function BoltdocsShell({ config, routes, components = {} }) {
204
+ function BoltdocsShell({ config, routes, components = {}, collectionsData }) {
198
205
  const allComponents = (0, react.useMemo)(() => ({
199
206
  ...mdxComponentsDefault,
200
207
  ...virtual_boltdocs_mdx_components.default,
@@ -231,20 +238,23 @@ function BoltdocsShell({ config, routes, components = {} }) {
231
238
  routes,
232
239
  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
240
  components: allComponents,
234
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_icons_dev.ConfigContext.Provider, {
241
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.ConfigContext.Provider, {
235
242
  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
- })]
243
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CollectionsContext.Provider, {
244
+ value: collectionsData || {},
245
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollHandler, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_icons_dev.BoltdocsProvider, {
246
+ initialLocale: initialData.initLocale,
247
+ initialVersion: initialData.initVersion,
248
+ children: [
249
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StoreSync, {
250
+ config,
251
+ routeMap
252
+ }),
253
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(I18nUpdater, { config }),
254
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog$1.InternalErrorBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_router_dom.Outlet, {}) })
255
+ ]
256
+ })]
257
+ })
248
258
  })
249
259
  }) }) })
250
260
  }) });
@@ -850,6 +860,30 @@ function useVersion() {
850
860
  };
851
861
  }
852
862
 
863
+ //#endregion
864
+ //#region src/client/components/ui-base/version-selector.tsx
865
+ function VersionSelector({ className }) {
866
+ const { currentVersionLabel, availableVersions, handleVersionChange } = useVersion();
867
+ if (availableVersions.length === 0) return null;
868
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Menu.Trigger, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Button, {
869
+ 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),
870
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
871
+ className: "font-semibold text-[0.8125rem]",
872
+ children: currentVersionLabel
873
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.ChevronDown, { className: "w-3.5 h-3.5 text-muted/60" })]
874
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Root, {
875
+ className: "w-40 bg-main border border-subtle rounded-xl p-1.5 shadow-md outline-none flex flex-col gap-0.5 animate-fade-in z-100",
876
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Section, {
877
+ items: availableVersions,
878
+ children: (version) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Item, {
879
+ onPress: () => handleVersionChange(version.value),
880
+ className: "flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium text-body hover:bg-primary-50/50 cursor-pointer select-none outline-none group data-selected:text-primary-500 data-selected:bg-primary-500/5",
881
+ children: version.label
882
+ }, version.value)
883
+ })
884
+ })] });
885
+ }
886
+
853
887
  //#endregion
854
888
  //#region src/client/hooks/use-i18n.ts
855
889
  /**
@@ -929,209 +963,500 @@ function useI18n() {
929
963
  }
930
964
 
931
965
  //#endregion
932
- //#region src/client/components/ui-base/version-i18n.tsx
933
- function VersionSelector({ className }) {
934
- const { currentVersionLabel, availableVersions, handleVersionChange } = useVersion();
935
- if (availableVersions.length === 0) return null;
936
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Menu.Trigger, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Button, {
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),
938
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
939
- className: "font-semibold text-[0.8125rem]",
940
- children: currentVersionLabel
941
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.ChevronDown, { className: "w-3.5 h-3.5 text-muted/60" })]
942
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Root, {
943
- className: "w-40 bg-main border border-subtle rounded-xl p-1.5 shadow-md outline-none flex flex-col gap-0.5 animate-fade-in z-100",
944
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Section, {
945
- items: availableVersions,
946
- children: (version) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Item, {
947
- onPress: () => handleVersionChange(version.value),
948
- className: "flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium text-body hover:bg-primary-50/50 cursor-pointer select-none outline-none group data-selected:text-primary-500 data-selected:bg-primary-500/5",
949
- children: version.label
950
- }, `${version.value ?? ""}`)
951
- })
952
- })] });
953
- }
954
- function I18nSelector({ className }) {
955
- const { currentLocale, availableLocales, handleLocaleChange } = useI18n();
956
- if (availableLocales.length === 0) return null;
957
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Menu.Trigger, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Button, {
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),
959
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
960
- className: "flex items-center gap-1.5",
961
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Languages, { className: "w-3.5 h-3.5 text-primary-500" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
962
- className: "font-bold text-[0.75rem] uppercase opacity-90",
963
- children: currentLocale || "en"
964
- })]
965
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.ChevronDown, { className: "w-3.5 h-3.5 text-muted/60" })]
966
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Root, {
967
- className: "w-40 bg-main border border-subtle rounded-xl p-1.5 shadow-md outline-none flex flex-col gap-0.5 animate-fade-in z-100",
968
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Section, {
969
- items: availableLocales,
970
- children: (locale) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Item, {
971
- onPress: () => handleLocaleChange(locale.value),
972
- className: "flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium text-body dark:hover:bg-primary-300/50 hover:bg-primary-200/50 transition-colors duration-100 cursor-pointer select-none outline-none group data-selected:text-primary-500 data-selected:bg-primary-500/5",
973
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: locale.label })
974
- }, `${locale.value ?? ""}`)
975
- })
976
- })] });
966
+ //#region src/client/hooks/use-page-nav.ts
967
+ function usePageNav() {
968
+ const { routes, currentRoute } = require_icons_dev.useRoutes();
969
+ const location = (0, react_router_dom.useLocation)();
970
+ const { groups, ungrouped } = require_docs_layout.useSidebar(routes);
971
+ return (0, react.useMemo)(() => {
972
+ if (!currentRoute) return {
973
+ prevPage: null,
974
+ nextPage: null,
975
+ currentRoute: null
976
+ };
977
+ const mergedItems = [...ungrouped.map((route) => ({
978
+ type: "link",
979
+ position: route.sidebarPosition ?? 999,
980
+ title: route.title,
981
+ route
982
+ })), ...groups.map((group) => ({
983
+ type: "group",
984
+ position: group.sidebarPosition ?? 999,
985
+ title: group.title,
986
+ group
987
+ }))].sort((a, b) => {
988
+ if (a.position !== b.position) return a.position - b.position;
989
+ if (a.type !== b.type) return a.type === "link" ? -1 : 1;
990
+ return a.title.localeCompare(b.title);
991
+ });
992
+ const orderedRoutes = [];
993
+ const flattenNode = (node) => {
994
+ if (node.path && node.path !== "#" && !node.sidebarHidden) orderedRoutes.push(node);
995
+ const children = node.routes || node.subRoutes;
996
+ if (children && children.length > 0) for (const child of children) flattenNode(child);
997
+ };
998
+ for (const item of mergedItems) if (item.type === "link") flattenNode(item.route);
999
+ else if (item.group.routes) for (const route of item.group.routes) flattenNode(route);
1000
+ const currentNormalizedPath = require_icons_dev.normalizePath(location.pathname);
1001
+ const currentIndex = orderedRoutes.findIndex((r) => require_icons_dev.normalizePath(r.path) === currentNormalizedPath);
1002
+ return {
1003
+ prevPage: currentIndex > 0 ? orderedRoutes[currentIndex - 1] : null,
1004
+ nextPage: currentIndex !== -1 && currentIndex < orderedRoutes.length - 1 ? orderedRoutes[currentIndex + 1] : null,
1005
+ currentRoute
1006
+ };
1007
+ }, [
1008
+ groups,
1009
+ ungrouped,
1010
+ currentRoute,
1011
+ location.pathname
1012
+ ]);
977
1013
  }
978
1014
 
979
1015
  //#endregion
980
- //#region src/client/components/ui-base/navbar.tsx
981
- const SearchDialog$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("../search-dialog-CUeAfy-8.cjs")).then((m) => ({ default: m.SearchDialog })));
982
- function Navbar() {
983
- const { links, title, logo, logoProps, github, social, config } = useNavbar();
984
- const { routes, currentRoute, isCollectionPage, currentVersion, currentLocale } = require_icons_dev.useRoutes();
985
- const { isSidebarOpen, toggleSidebar } = require_docs_layout.useUI();
986
- const [isMobileMenuOpen, setIsMobileMenuOpen] = (0, react.useState)(false);
987
- const themeConfig = config.theme || {};
988
- const isDocs = !!currentRoute?.filePath && !isCollectionPage;
989
- const hasTabs = themeConfig?.tabs && themeConfig.tabs.length > 0;
990
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Root, {
991
- className: require_icons_dev.cn("border-b border-subtle bg-main/80 backdrop-blur-md", hasTabs && "border-b-0"),
992
- children: [
993
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Content, { children: [
994
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Left, { children: [
995
- isDocs && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Button, {
996
- onPress: toggleSidebar,
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",
998
- "aria-label": isSidebarOpen ? "Close sidebar" : "Open sidebar",
999
- children: isSidebarOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.X, { className: "w-5 h-5 text-body" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Menu, { className: "w-5 h-5 text-body" })
1000
- }),
1001
- logo && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Logo, {
1002
- src: logo,
1003
- alt: logoProps?.alt || title,
1004
- width: logoProps?.width ?? 24,
1005
- height: logoProps?.height ?? 24,
1006
- href: "site:/"
1007
- }),
1008
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Title, {
1009
- href: "site:/",
1010
- children: title
1011
- }),
1012
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1013
- className: "hidden sm:block",
1014
- children: config.versions && currentVersion && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VersionSelector, {})
1015
- })
1016
- ] }),
1017
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Center, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Suspense, {
1018
- fallback: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "h-9 w-32 animate-pulse rounded-md bg-surface" }),
1019
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchDialog$1, { routes: routes || [] })
1020
- }) }),
1021
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Right, { children: [
1022
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Suspense, {
1023
- fallback: null,
1024
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1025
- className: "lg:hidden",
1026
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchDialog$1, { routes: routes || [] })
1027
- })
1028
- }),
1029
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Links, { children: links.map((link) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NavbarLinkItem, { link }, link.href)) }),
1030
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1031
- className: "hidden sm:flex items-center gap-2",
1032
- children: [config.i18n && currentLocale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(I18nSelector, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Split, { className: "bg-subtle" })]
1033
- }),
1034
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1035
- className: "hidden md:block",
1036
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemeToggle, {})
1037
- }),
1038
- github && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1039
- className: "hidden md:block",
1040
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GithubStars, { repo: themeConfig?.githubRepo ?? "" })
1041
- }),
1042
- social.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1043
- className: "hidden md:block",
1044
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Split, { className: "bg-subtle" })
1045
- }),
1046
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1047
- className: "hidden md:flex items-center gap-1",
1048
- children: social.map(({ icon, link }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Socials, {
1049
- icon,
1050
- link,
1051
- className: "p-1.5 text-muted hover:text-body hover:bg-surface rounded-md transition-all focus-visible:ring-2 focus-visible:ring-primary-500/30"
1052
- }, link))
1053
- }),
1054
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.More, {
1055
- onPress: () => setIsMobileMenuOpen(true),
1056
- className: "text-muted hover:text-body active:scale-90 transition-all focus-visible:ring-2 focus-visible:ring-primary-500/30"
1057
- })
1058
- ] })
1059
- ] }),
1060
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.MobileMenu, {
1061
- isOpen: isMobileMenuOpen,
1062
- onClose: () => setIsMobileMenuOpen(false),
1063
- className: "bg-main/98 backdrop-blur-2xl",
1064
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1065
- className: "flex flex-col gap-1",
1066
- children: links.map((link) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NavbarMobileLinkItem, {
1067
- link,
1068
- onClose: () => setIsMobileMenuOpen(false)
1069
- }, link.href))
1070
- }), social.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1071
- className: "mt-6",
1072
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1073
- className: "px-4 mb-4 text-xs font-bold uppercase tracking-widest text-muted/50",
1074
- children: "Connect"
1075
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1076
- className: "flex flex-wrap gap-2 px-2",
1077
- children: social.map(({ icon, link }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Socials, {
1078
- icon,
1079
- link,
1080
- className: "p-3 bg-surface border border-subtle rounded-xl flex-1 justify-center"
1081
- }, link))
1082
- })]
1083
- })]
1084
- }),
1085
- isDocs && hasTabs && themeConfig?.tabs && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1086
- className: "w-full border-b border-subtle bg-main",
1087
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tabs, {
1088
- tabs: themeConfig.tabs,
1089
- routes: routes || []
1090
- })
1091
- })
1092
- ]
1093
- });
1094
- }
1095
- function NavbarLinkItem({ link }) {
1096
- const localizedHref = require_icons_dev.useLocalizedTo(link.href || "");
1097
- const { pathname } = (0, react_router_dom.useLocation)();
1098
- const active = pathname === localizedHref || pathname.startsWith(localizedHref + "/");
1099
- if (link.items && link.items.length > 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Dropdown, {
1100
- label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1101
- className: require_icons_dev.cn("transition-colors outline-none font-medium focus-visible:ring-2 focus-visible:ring-primary-500/30 rounded-sm px-2 py-1", active ? "text-primary-500" : "text-muted hover:text-body"),
1102
- children: link.label
1103
- }),
1104
- children: link.items?.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.DropdownItem, {
1105
- href: require_icons_dev.useLocalizedTo(item.href || ""),
1106
- label: item.label
1107
- }, item.href))
1108
- });
1109
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Link, {
1110
- ...link,
1111
- href: localizedHref,
1112
- active,
1113
- className: require_icons_dev.cn("transition-colors outline-none font-medium focus-visible:ring-2 focus-visible:ring-primary-500/30 rounded-sm", active ? "text-primary-500" : "text-muted hover:text-body")
1114
- });
1016
+ //#region src/client/hooks/use-analytics.ts
1017
+ function createAnalyticsInstance(config) {
1018
+ if (typeof window === "undefined") return createDisabledAnalytics();
1019
+ if (typeof window.gtag === "function") return createGtagAnalytics(config);
1020
+ if (window.dataLayer) return createDataLayerAnalytics(config);
1021
+ return createDisabledAnalytics();
1115
1022
  }
1116
- function NavbarMobileLinkItem({ link, onClose }) {
1117
- const localizedHref = require_icons_dev.useLocalizedTo(link.href || "");
1118
- const { pathname } = (0, react_router_dom.useLocation)();
1119
- const active = pathname === localizedHref;
1120
- if (link.items && link.items.length > 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1121
- className: "flex flex-col gap-1",
1122
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1123
- className: require_icons_dev.cn("px-3 py-2 text-sm transition-all", active ? "text-body" : "text-muted/80 hover:text-body"),
1124
- children: link.label
1125
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1126
- className: "flex flex-col gap-1 pl-4",
1127
- children: link.items?.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NavbarMobileLinkItem, {
1128
- link: item,
1129
- onClose
1130
- }, item.href))
1131
- })]
1132
- });
1133
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.MobileLink, {
1134
- ...link,
1023
+ function createGtagAnalytics(config) {
1024
+ return {
1025
+ trackPageView: (path, title) => {
1026
+ window.gtag?.("event", "page_view", {
1027
+ page_path: path,
1028
+ page_title: title || document.title,
1029
+ send_to: config?.ga4?.measurementId
1030
+ });
1031
+ },
1032
+ trackEvent: ({ action, category, label, value, params }) => {
1033
+ window.gtag?.("event", action, {
1034
+ event_category: category,
1035
+ event_label: label,
1036
+ value,
1037
+ send_to: config?.ga4?.measurementId,
1038
+ ...params
1039
+ });
1040
+ },
1041
+ trackSearch: (query, resultsCount) => {
1042
+ window.gtag?.("event", "search", {
1043
+ search_term: query,
1044
+ results_count: resultsCount,
1045
+ send_to: config?.ga4?.measurementId
1046
+ });
1047
+ },
1048
+ trackDownload: (file, type) => {
1049
+ window.gtag?.("event", "file_download", {
1050
+ file_name: file,
1051
+ file_type: type || file.split(".").pop(),
1052
+ send_to: config?.ga4?.measurementId
1053
+ });
1054
+ },
1055
+ trackExternalLink: (url) => {
1056
+ window.gtag?.("event", "external_link", {
1057
+ link_url: url,
1058
+ send_to: config?.ga4?.measurementId
1059
+ });
1060
+ },
1061
+ isEnabled: true
1062
+ };
1063
+ }
1064
+ function createDataLayerAnalytics(config) {
1065
+ return {
1066
+ trackPageView: (path, title) => {
1067
+ window.dataLayer?.push({
1068
+ event: "page_view",
1069
+ page_path: path,
1070
+ page_title: title || document.title,
1071
+ send_to: config?.gtm?.tagId
1072
+ });
1073
+ },
1074
+ trackEvent: ({ action, category, label, value, params }) => {
1075
+ window.dataLayer?.push({
1076
+ event: action,
1077
+ event_category: category,
1078
+ event_label: label,
1079
+ value,
1080
+ send_to: config?.gtm?.tagId,
1081
+ ...params
1082
+ });
1083
+ },
1084
+ trackSearch: (query, resultsCount) => {
1085
+ window.dataLayer?.push({
1086
+ event: "search",
1087
+ search_term: query,
1088
+ results_count: resultsCount,
1089
+ send_to: config?.gtm?.tagId
1090
+ });
1091
+ },
1092
+ trackDownload: (file, type) => {
1093
+ window.dataLayer?.push({
1094
+ event: "file_download",
1095
+ file_name: file,
1096
+ file_type: type || file.split(".").pop(),
1097
+ send_to: config?.gtm?.tagId
1098
+ });
1099
+ },
1100
+ trackExternalLink: (url) => {
1101
+ window.dataLayer?.push({
1102
+ event: "external_link",
1103
+ link_url: url,
1104
+ send_to: config?.gtm?.tagId
1105
+ });
1106
+ },
1107
+ isEnabled: true
1108
+ };
1109
+ }
1110
+ function createDisabledAnalytics() {
1111
+ return {
1112
+ trackPageView: () => {},
1113
+ trackEvent: () => {},
1114
+ trackSearch: () => {},
1115
+ trackDownload: () => {},
1116
+ trackExternalLink: () => {},
1117
+ isEnabled: false
1118
+ };
1119
+ }
1120
+ const CONFIG_INSTANCE_SYMBOL = Symbol.for("__BDOCS_CONFIG_INSTANCE__");
1121
+ function useAnalytics(options = {}) {
1122
+ const { config: optionsConfig, autoTrackPageViews = true, autoTrackDownloads = true, autoTrackExternalLinks = true, excludePatterns = [] } = options;
1123
+ const globalConfig = typeof globalThis !== "undefined" ? globalThis[CONFIG_INSTANCE_SYMBOL] : void 0;
1124
+ const config = optionsConfig ?? globalConfig?.integrations;
1125
+ const analytics = (0, react.useMemo)(() => createAnalyticsInstance(config), [config]);
1126
+ const previousPath = (0, react.useRef)("");
1127
+ const location = require_docs_layout.useLocation();
1128
+ (0, react.useEffect)(() => {
1129
+ if (!autoTrackPageViews || !analytics.isEnabled) return;
1130
+ const path = location.pathname + location.search;
1131
+ if (path !== previousPath.current) {
1132
+ previousPath.current = path;
1133
+ analytics.trackPageView(path, document.title);
1134
+ }
1135
+ }, [
1136
+ location.pathname,
1137
+ autoTrackPageViews,
1138
+ analytics
1139
+ ]);
1140
+ (0, react.useEffect)(() => {
1141
+ if (!autoTrackDownloads || !analytics.isEnabled) return;
1142
+ const handleClick = (event) => {
1143
+ const target = event.target?.closest("a");
1144
+ if (!target) return;
1145
+ const href = target.getAttribute("href");
1146
+ if (!href) return;
1147
+ if (excludePatterns.some((pattern) => pattern.test(href))) return;
1148
+ if (target.hasAttribute("download") || /\.(pdf|doc|docx|xls|xlsx|ppt|pptx|zip|rar|7z|tar|gz|mp3|mp4|avi|mov|png|jpg|jpeg|gif|svg|webp)$/i.test(href)) {
1149
+ const fileName = href.split("/").pop() || href;
1150
+ analytics.trackDownload(fileName, fileName.split(".").pop());
1151
+ }
1152
+ };
1153
+ document.addEventListener("click", handleClick);
1154
+ return () => document.removeEventListener("click", handleClick);
1155
+ }, [
1156
+ autoTrackDownloads,
1157
+ autoTrackExternalLinks,
1158
+ analytics,
1159
+ excludePatterns
1160
+ ]);
1161
+ (0, react.useEffect)(() => {
1162
+ if (!autoTrackExternalLinks || !analytics.isEnabled) return;
1163
+ const handleClick = (event) => {
1164
+ const target = event.target?.closest("a");
1165
+ if (!target) return;
1166
+ const href = target.getAttribute("href");
1167
+ if (!href) return;
1168
+ if (excludePatterns.some((pattern) => pattern.test(href))) return;
1169
+ if ((href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//")) && !href.includes(window.location.hostname)) analytics.trackExternalLink(href);
1170
+ };
1171
+ document.addEventListener("click", handleClick);
1172
+ return () => document.removeEventListener("click", handleClick);
1173
+ }, [
1174
+ autoTrackExternalLinks,
1175
+ analytics,
1176
+ excludePatterns
1177
+ ]);
1178
+ return analytics;
1179
+ }
1180
+ function useTrackPageView() {
1181
+ const analytics = (0, react.useMemo)(() => createAnalyticsInstance(), []);
1182
+ return (0, react.useCallback)((path, title) => {
1183
+ analytics.trackPageView(path, title);
1184
+ }, [analytics]);
1185
+ }
1186
+ function useTrackEvent() {
1187
+ const analytics = (0, react.useMemo)(() => createAnalyticsInstance(), []);
1188
+ return (0, react.useCallback)((event) => {
1189
+ analytics.trackEvent(event);
1190
+ }, [analytics]);
1191
+ }
1192
+
1193
+ //#endregion
1194
+ //#region src/client/hooks/use-headings.ts
1195
+ /**
1196
+ * Returns the headings of the current page, extracted from the route loader data.
1197
+ * Useful for building custom Tables of Contents or jumping to sections.
1198
+ *
1199
+ * @returns An array of heading objects with level, text, and id.
1200
+ */
1201
+ function useHeadings() {
1202
+ const matches = (0, react_router_dom.useMatches)();
1203
+ return (0, react.useMemo)(() => {
1204
+ return (matches[matches.length - 1]?.data)?.headings || [];
1205
+ }, [matches]);
1206
+ }
1207
+
1208
+ //#endregion
1209
+ //#region src/client/hooks/use-feedback.ts
1210
+ /**
1211
+ * Hook for managing the feedback rating form state and submission.
1212
+ * Resets automatically when navigating to a new page.
1213
+ */
1214
+ function useFeedback(options = {}) {
1215
+ const config = require_icons_dev.useConfig();
1216
+ const { currentRoute } = require_icons_dev.useRoutes();
1217
+ const [rating, setRating] = (0, react.useState)(null);
1218
+ const [comment, setComment] = (0, react.useState)("");
1219
+ const [loading, setLoading] = (0, react.useState)(false);
1220
+ const [submitted, setSubmitted] = (0, react.useState)(false);
1221
+ const [error, setError] = (0, react.useState)(null);
1222
+ (0, react.useEffect)(() => {
1223
+ setRating(null);
1224
+ setComment("");
1225
+ setSubmitted(false);
1226
+ setError(null);
1227
+ }, [currentRoute?.path]);
1228
+ const submit = async (commentOverride, blockId) => {
1229
+ if (!rating) return;
1230
+ setLoading(true);
1231
+ setError(null);
1232
+ const payload = {
1233
+ rating,
1234
+ comment: (commentOverride !== void 0 ? commentOverride : comment) || void 0,
1235
+ path: currentRoute?.path || window.location.pathname,
1236
+ title: currentRoute?.title || document.title,
1237
+ blockId
1238
+ };
1239
+ try {
1240
+ if (options.onSubmit) await options.onSubmit(payload);
1241
+ else {
1242
+ const endpoint = options.endpoint || config.integrations?.feedback?.custom?.endpoint || "/api/feedback";
1243
+ const res = await fetch(endpoint, {
1244
+ method: "POST",
1245
+ headers: { "Content-Type": "application/json" },
1246
+ body: JSON.stringify(payload)
1247
+ });
1248
+ if (!res.ok) {
1249
+ const text = await res.text();
1250
+ let errorText = text;
1251
+ try {
1252
+ const data = JSON.parse(text);
1253
+ errorText = data.error || data.message || text;
1254
+ } catch {}
1255
+ throw new Error(errorText || `Failed to submit feedback: ${res.statusText}`);
1256
+ }
1257
+ }
1258
+ setSubmitted(true);
1259
+ } catch (e) {
1260
+ setError(e.message || "An error occurred while submitting feedback.");
1261
+ } finally {
1262
+ setLoading(false);
1263
+ }
1264
+ };
1265
+ return {
1266
+ rating,
1267
+ setRating,
1268
+ comment,
1269
+ setComment,
1270
+ loading,
1271
+ submitted,
1272
+ error,
1273
+ submit
1274
+ };
1275
+ }
1276
+
1277
+ //#endregion
1278
+ //#region src/client/components/ui-base/i18n-selector.tsx
1279
+ function I18nSelector({ className }) {
1280
+ const { currentLocale, availableLocales, handleLocaleChange } = useI18n();
1281
+ if (availableLocales.length === 0) return null;
1282
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_docs_layout.Menu.Trigger, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Button, {
1283
+ 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),
1284
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1285
+ className: "flex items-center gap-1.5",
1286
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Languages, { className: "w-3.5 h-3.5 text-primary-500" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1287
+ className: "font-bold text-[0.75rem] uppercase opacity-90",
1288
+ children: currentLocale || "en"
1289
+ })]
1290
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.ChevronDown, { className: "w-3.5 h-3.5 text-muted/60" })]
1291
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Root, {
1292
+ className: "w-40 bg-main border border-subtle rounded-xl p-1.5 shadow-md outline-none flex flex-col gap-0.5 animate-fade-in z-100",
1293
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Section, {
1294
+ items: availableLocales,
1295
+ children: (locale) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.Menu.Item, {
1296
+ onPress: () => handleLocaleChange(locale.value),
1297
+ className: "flex items-center gap-2 px-3 py-2 rounded-lg text-xs font-medium text-body dark:hover:bg-primary-300/50 hover:bg-primary-200/50 transition-colors duration-100 cursor-pointer select-none outline-none group data-selected:text-primary-500 data-selected:bg-primary-500/5",
1298
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: locale.label })
1299
+ }, locale.value)
1300
+ })
1301
+ })] });
1302
+ }
1303
+
1304
+ //#endregion
1305
+ //#region src/client/components/ui-base/navbar.tsx
1306
+ const SearchDialog$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("../search-dialog-CzwvKoLW.cjs")).then((m) => ({ default: m.SearchDialog })));
1307
+ function Navbar() {
1308
+ const { links, title, logo, logoProps, github, social, config } = useNavbar();
1309
+ const { routes, currentRoute, isCollectionPage, currentVersion, currentLocale } = require_icons_dev.useRoutes();
1310
+ const { isSidebarOpen, toggleSidebar } = require_docs_layout.useUI();
1311
+ const [isMobileMenuOpen, setIsMobileMenuOpen] = (0, react.useState)(false);
1312
+ const themeConfig = config.theme || {};
1313
+ const isDocs = !!currentRoute?.filePath && !isCollectionPage;
1314
+ const hasTabs = themeConfig?.tabs && themeConfig.tabs.length > 0;
1315
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Root, {
1316
+ className: require_icons_dev.cn("border-b border-subtle bg-main/80 backdrop-blur-md", hasTabs && "border-b-0"),
1317
+ children: [
1318
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Content, { children: [
1319
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Left, { children: [
1320
+ isDocs && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Button, {
1321
+ onPress: toggleSidebar,
1322
+ 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",
1323
+ "aria-label": isSidebarOpen ? "Close sidebar" : "Open sidebar",
1324
+ children: isSidebarOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.X, { className: "w-5 h-5 text-body" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Menu, { className: "w-5 h-5 text-body" })
1325
+ }),
1326
+ logo && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Logo, {
1327
+ src: logo,
1328
+ alt: logoProps?.alt || title,
1329
+ width: logoProps?.width ?? 24,
1330
+ height: logoProps?.height ?? 24,
1331
+ href: "site:/"
1332
+ }),
1333
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Title, {
1334
+ href: "site:/",
1335
+ children: title
1336
+ }),
1337
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1338
+ className: "hidden sm:block",
1339
+ children: config.versions && currentVersion && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VersionSelector, {})
1340
+ })
1341
+ ] }),
1342
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Center, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Suspense, {
1343
+ fallback: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "h-9 w-32 animate-pulse rounded-md bg-surface" }),
1344
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchDialog$1, { routes: routes || [] })
1345
+ }) }),
1346
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.Right, { children: [
1347
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Suspense, {
1348
+ fallback: null,
1349
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1350
+ className: "lg:hidden",
1351
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchDialog$1, { routes: routes || [] })
1352
+ })
1353
+ }),
1354
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Links, { children: links.map((link) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NavbarLinkItem, { link }, link.href)) }),
1355
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1356
+ className: "hidden sm:flex items-center gap-2",
1357
+ children: [config.i18n && currentLocale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(I18nSelector, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Split, { className: "bg-subtle" })]
1358
+ }),
1359
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1360
+ className: "hidden md:block",
1361
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemeToggle, {})
1362
+ }),
1363
+ github && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1364
+ className: "hidden md:block",
1365
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GithubStars, { repo: themeConfig?.githubRepo ?? "" })
1366
+ }),
1367
+ social.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1368
+ className: "hidden md:block",
1369
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Split, { className: "bg-subtle" })
1370
+ }),
1371
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1372
+ className: "hidden md:flex items-center gap-1",
1373
+ children: social.map(({ icon, link }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Socials, {
1374
+ icon,
1375
+ link,
1376
+ className: "p-1.5 text-muted hover:text-body hover:bg-surface rounded-md transition-all focus-visible:ring-2 focus-visible:ring-primary-500/30"
1377
+ }, link))
1378
+ }),
1379
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.More, {
1380
+ onPress: () => setIsMobileMenuOpen(true),
1381
+ className: "text-muted hover:text-body active:scale-90 transition-all focus-visible:ring-2 focus-visible:ring-primary-500/30"
1382
+ })
1383
+ ] })
1384
+ ] }),
1385
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_search_dialog.Navbar.MobileMenu, {
1386
+ isOpen: isMobileMenuOpen,
1387
+ onClose: () => setIsMobileMenuOpen(false),
1388
+ className: "bg-main/98 backdrop-blur-2xl",
1389
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1390
+ className: "flex flex-col gap-1",
1391
+ children: links.map((link) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NavbarMobileLinkItem, {
1392
+ link,
1393
+ onClose: () => setIsMobileMenuOpen(false)
1394
+ }, link.href))
1395
+ }), social.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1396
+ className: "mt-6",
1397
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1398
+ className: "px-4 mb-4 text-xs font-bold uppercase tracking-widest text-muted/50",
1399
+ children: "Connect"
1400
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1401
+ className: "flex flex-wrap gap-2 px-2",
1402
+ children: social.map(({ icon, link }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Socials, {
1403
+ icon,
1404
+ link,
1405
+ className: "p-3 bg-surface border border-subtle rounded-xl flex-1 justify-center"
1406
+ }, link))
1407
+ })]
1408
+ })]
1409
+ }),
1410
+ isDocs && hasTabs && themeConfig?.tabs && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1411
+ className: "w-full border-b border-subtle bg-main",
1412
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Tabs, {
1413
+ tabs: themeConfig.tabs,
1414
+ routes: routes || []
1415
+ })
1416
+ })
1417
+ ]
1418
+ });
1419
+ }
1420
+ function NavbarLinkItem({ link }) {
1421
+ const localizedHref = require_icons_dev.useLocalizedTo(link.href || "");
1422
+ const { pathname } = (0, react_router_dom.useLocation)();
1423
+ const active = pathname === localizedHref || pathname.startsWith(`${localizedHref}/`);
1424
+ if (link.items && link.items.length > 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Dropdown, {
1425
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1426
+ className: require_icons_dev.cn("transition-colors outline-none font-medium focus-visible:ring-2 focus-visible:ring-primary-500/30 rounded-sm px-2 py-1", active ? "text-primary-500" : "text-muted hover:text-body"),
1427
+ children: link.label
1428
+ }),
1429
+ children: link.items?.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.DropdownItem, {
1430
+ href: require_icons_dev.useLocalizedTo(item.href || ""),
1431
+ label: item.label
1432
+ }, item.href))
1433
+ });
1434
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.Link, {
1435
+ ...link,
1436
+ href: localizedHref,
1437
+ active,
1438
+ className: require_icons_dev.cn("transition-colors outline-none font-medium focus-visible:ring-2 focus-visible:ring-primary-500/30 rounded-sm", active ? "text-primary-500" : "text-muted hover:text-body")
1439
+ });
1440
+ }
1441
+ function NavbarMobileLinkItem({ link, onClose }) {
1442
+ const localizedHref = require_icons_dev.useLocalizedTo(link.href || "");
1443
+ const { pathname } = (0, react_router_dom.useLocation)();
1444
+ const active = pathname === localizedHref;
1445
+ if (link.items && link.items.length > 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1446
+ className: "flex flex-col gap-1",
1447
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1448
+ className: require_icons_dev.cn("px-3 py-2 text-sm transition-all", active ? "text-body" : "text-muted/80 hover:text-body"),
1449
+ children: link.label
1450
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1451
+ className: "flex flex-col gap-1 pl-4",
1452
+ children: link.items?.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NavbarMobileLinkItem, {
1453
+ link: item,
1454
+ onClose
1455
+ }, item.href))
1456
+ })]
1457
+ });
1458
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_search_dialog.Navbar.MobileLink, {
1459
+ ...link,
1135
1460
  href: localizedHref,
1136
1461
  active,
1137
1462
  onPress: onClose,
@@ -1150,58 +1475,28 @@ function OnThisPage({ headings = [], editLink, communityHelp, filePath }) {
1150
1475
  }),
1151
1476
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.OnThisPage.Tree, { headings }),
1152
1477
  (editLink || communityHelp) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1153
- className: "mt-8 pt-8 border-t border-subtle space-y-4",
1154
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1155
- className: "text-xs font-bold text-body",
1156
- children: "Need help?"
1157
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
1158
- className: "space-y-3",
1159
- children: [editLink && filePath && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
1160
- href: editLink.replace(":path", filePath),
1161
- target: "_blank",
1162
- rel: "noopener noreferrer",
1163
- className: "flex items-center gap-2 text-sm text-muted hover:text-body transition-colors",
1164
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Pencil, { size: 16 }), "Edit this page"]
1165
- }) }), communityHelp && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
1166
- href: communityHelp,
1167
- target: "_blank",
1168
- rel: "noopener noreferrer",
1169
- className: "flex items-center gap-2 text-sm text-muted hover:text-body transition-colors",
1170
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.CircleHelp, { size: 16 }), "Community help"]
1171
- }) })]
1172
- })]
1173
- })
1174
- ] });
1175
- }
1176
-
1177
- //#endregion
1178
- //#region src/client/hooks/use-page-nav.ts
1179
- /**
1180
- * Hook to manage the previous and next button functionality for documentation pages.
1181
- * Intelligent: respects current locale, version, and tab to keep navigation logical.
1182
- */
1183
- function usePageNav() {
1184
- const { routes, currentRoute } = require_icons_dev.useRoutes();
1185
- const location = (0, react_router_dom.useLocation)();
1186
- return (0, react.useMemo)(() => {
1187
- if (!currentRoute) return {
1188
- prevPage: null,
1189
- nextPage: null,
1190
- currentRoute: null
1191
- };
1192
- const activeTabId = currentRoute.tab?.toLowerCase();
1193
- const contextRoutes = activeTabId ? routes.filter((r) => r.tab?.toLowerCase() === activeTabId) : routes.filter((r) => !r.tab);
1194
- const currentIndex = contextRoutes.findIndex((r) => r.path === location.pathname);
1195
- return {
1196
- prevPage: currentIndex > 0 ? contextRoutes[currentIndex - 1] : null,
1197
- nextPage: currentIndex !== -1 && currentIndex < contextRoutes.length - 1 ? contextRoutes[currentIndex + 1] : null,
1198
- currentRoute
1199
- };
1200
- }, [
1201
- routes,
1202
- currentRoute,
1203
- location.pathname
1204
- ]);
1478
+ className: "mt-8 pt-8 border-t border-subtle space-y-4",
1479
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1480
+ className: "text-xs font-bold text-body",
1481
+ children: "Need help?"
1482
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
1483
+ className: "space-y-3",
1484
+ children: [editLink && filePath && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
1485
+ href: editLink.replace(":path", filePath),
1486
+ target: "_blank",
1487
+ rel: "noopener noreferrer",
1488
+ className: "flex items-center gap-2 text-sm text-muted hover:text-body transition-colors",
1489
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Pencil, { size: 16 }), "Edit this page"]
1490
+ }) }), communityHelp && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
1491
+ href: communityHelp,
1492
+ target: "_blank",
1493
+ rel: "noopener noreferrer",
1494
+ className: "flex items-center gap-2 text-sm text-muted hover:text-body transition-colors",
1495
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.CircleHelp, { size: 16 }), "Community help"]
1496
+ }) })]
1497
+ })]
1498
+ })
1499
+ ] });
1205
1500
  }
1206
1501
 
1207
1502
  //#endregion
@@ -1293,13 +1588,15 @@ const Sidebar = Object.assign(SidebarMain, {
1293
1588
  function Banner({ children, className = "", dismissible = false, id = "boltdocs-banner", ...props }) {
1294
1589
  const [isVisible, setIsVisible] = (0, react.useState)(true);
1295
1590
  (0, react.useEffect)(() => {
1296
- if (dismissible && id) {
1297
- if (localStorage.getItem(`boltdocs-banner-dismissed-${id}`) === "true") setIsVisible(false);
1298
- }
1591
+ if (dismissible && id && typeof window !== "undefined") try {
1592
+ if (window.localStorage.getItem(`boltdocs-banner-dismissed-${id}`) === "true") setIsVisible(false);
1593
+ } catch {}
1299
1594
  }, [dismissible, id]);
1300
1595
  const handleDismiss = () => {
1301
1596
  setIsVisible(false);
1302
- if (dismissible && id) localStorage.setItem(`boltdocs-banner-dismissed-${id}`, "true");
1597
+ if (dismissible && id && typeof window !== "undefined") try {
1598
+ window.localStorage.setItem(`boltdocs-banner-dismissed-${id}`, "true");
1599
+ } catch {}
1303
1600
  };
1304
1601
  if (!isVisible) return null;
1305
1602
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -1317,6 +1614,90 @@ function Banner({ children, className = "", dismissible = false, id = "boltdocs-
1317
1614
  });
1318
1615
  }
1319
1616
 
1617
+ //#endregion
1618
+ //#region src/client/components/ui-base/feedback.tsx
1619
+ function Feedback({ className }) {
1620
+ if (!(require_icons_dev.useConfig().integrations?.feedback?.custom)?.enabled) return null;
1621
+ const { rating, setRating, comment, setComment, loading, submitted, error, submit } = useFeedback();
1622
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1623
+ className: require_icons_dev.cn("w-full max-w-2xl mt-12 mb-6 p-6 rounded-2xl border border-subtle bg-surface/50 backdrop-blur-xs select-none", className),
1624
+ children: submitted ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1625
+ className: "flex flex-col items-center justify-center py-4 text-center animate-in fade-in zoom-in duration-300",
1626
+ children: [
1627
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1628
+ className: "flex h-12 w-12 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-500 mb-3 border border-emerald-500/20",
1629
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.Check, { size: 24 })
1630
+ }),
1631
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
1632
+ className: "text-lg font-semibold text-default",
1633
+ children: "Thank you for your feedback!"
1634
+ }),
1635
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1636
+ className: "text-sm text-muted mt-1",
1637
+ children: "Your comments help us improve the documentation."
1638
+ })
1639
+ ]
1640
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1641
+ className: "flex flex-col gap-4",
1642
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1643
+ className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",
1644
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
1645
+ className: "text-base font-semibold text-default",
1646
+ children: "Was this page helpful?"
1647
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1648
+ className: "flex items-center gap-2",
1649
+ children: [
1650
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1651
+ type: "button",
1652
+ onClick: () => setRating("good"),
1653
+ className: require_icons_dev.cn("flex items-center gap-1.5 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all duration-200 outline-none cursor-pointer", rating === "good" ? "border-primary-500 bg-primary-500/10 text-primary-500 dark:text-primary-400" : "border-subtle hover:border-body hover:bg-surface text-muted hover:text-body"),
1654
+ "aria-label": "Helpful",
1655
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.FaceGood, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Yes" })]
1656
+ }),
1657
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1658
+ type: "button",
1659
+ onClick: () => setRating("neutral"),
1660
+ className: require_icons_dev.cn("flex items-center gap-1.5 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all duration-200 outline-none cursor-pointer", rating === "neutral" ? "border-primary-500 bg-primary-500/10 text-primary-500 dark:text-primary-400" : "border-subtle hover:border-body hover:bg-surface text-muted hover:text-body"),
1661
+ "aria-label": "Neutral",
1662
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.FaceRegular, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "Regular" })]
1663
+ }),
1664
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1665
+ type: "button",
1666
+ onClick: () => setRating("bad"),
1667
+ className: require_icons_dev.cn("flex items-center gap-1.5 px-3 py-1.5 rounded-lg border text-sm font-medium transition-all duration-200 outline-none cursor-pointer", rating === "bad" ? "border-primary-500 bg-primary-500/10 text-primary-500 dark:text-primary-400" : "border-subtle hover:border-body hover:bg-surface text-muted hover:text-body"),
1668
+ "aria-label": "Not helpful",
1669
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.FaceBad, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "No" })]
1670
+ })
1671
+ ]
1672
+ })]
1673
+ }), rating && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1674
+ className: "flex flex-col gap-3 mt-1 animate-in slide-in-from-top-3 duration-300",
1675
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1676
+ value: comment,
1677
+ onChange: (e) => setComment(e.target.value),
1678
+ placeholder: "¿Tienes alguna sugerencia para mejorar esta página? (Opcional)",
1679
+ className: "w-full h-24 p-3 text-sm rounded-xl border border-subtle bg-main text-body placeholder:text-muted focus:outline-none focus:ring-1 focus:ring-primary-500 focus:border-primary-500 resize-none transition-shadow"
1680
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1681
+ className: "flex items-center justify-between gap-3",
1682
+ children: [error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1683
+ className: "text-xs text-rose-500 font-medium flex-1",
1684
+ children: error
1685
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1686
+ className: "flex items-center gap-2 ml-auto",
1687
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1688
+ type: "button",
1689
+ onClick: () => submit(),
1690
+ disabled: loading,
1691
+ className: "px-4 py-2 rounded-xl text-xs font-semibold bg-primary-500 hover:bg-primary-600 active:bg-primary-700 text-white transition-colors outline-none cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",
1692
+ children: loading ? "Submitting..." : "Submit"
1693
+ })
1694
+ })]
1695
+ })]
1696
+ })]
1697
+ })
1698
+ });
1699
+ }
1700
+
1320
1701
  //#endregion
1321
1702
  //#region src/client/ssg/mdx-elements.tsx
1322
1703
  const Loading = () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1453,13 +1834,6 @@ function Head({ siteTitle, siteDescription, routes }) {
1453
1834
  ] });
1454
1835
  }
1455
1836
 
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
-
1463
1837
  //#endregion
1464
1838
  //#region src/client/app/docs-layout.tsx
1465
1839
  function DocsLayout({ collectionsData }) {
@@ -1582,21 +1956,37 @@ function buildDocRoutes(options) {
1582
1956
  const targetBasePaths = [];
1583
1957
  targetBasePaths.push({
1584
1958
  path: baseDocsPath,
1585
- filter: () => true
1959
+ filter: () => true,
1960
+ locale: config.i18n?.defaultLocale,
1961
+ version: config.versions?.defaultVersion
1586
1962
  });
1587
- const subPaths = [];
1588
- if (allVersions.length > 0) allVersions.forEach((v) => subPaths.push(`/${v}`));
1589
- if (locales.length > 0) locales.forEach((l) => subPaths.push(`/${l}`));
1590
- if (allVersions.length > 0 && locales.length > 0) allVersions.forEach((v) => {
1591
- locales.forEach((l) => {
1592
- subPaths.push(`/${v}/${l}`);
1963
+ if (allVersions.length > 0) allVersions.forEach((v) => {
1964
+ const fullP = baseDocsPath === "/" ? `/${v}` : `${baseDocsPath}/${v}`;
1965
+ targetBasePaths.push({
1966
+ path: fullP,
1967
+ filter: (rp) => !!rp && rp.startsWith(fullP.replace(/\/$/, "") + "/"),
1968
+ locale: config.i18n?.defaultLocale,
1969
+ version: v
1593
1970
  });
1594
1971
  });
1595
- subPaths.forEach((sp) => {
1596
- const fullP = baseDocsPath === "/" ? sp : `${baseDocsPath}${sp}`;
1972
+ if (locales.length > 0) locales.forEach((l) => {
1973
+ const fullP = baseDocsPath === "/" ? `/${l}` : `${baseDocsPath}/${l}`;
1597
1974
  targetBasePaths.push({
1598
1975
  path: fullP,
1599
- filter: (rp) => !!rp && rp.startsWith(fullP.replace(/\/$/, "") + "/")
1976
+ filter: (rp) => !!rp && rp.startsWith(fullP.replace(/\/$/, "") + "/"),
1977
+ locale: l,
1978
+ version: config.versions?.defaultVersion
1979
+ });
1980
+ });
1981
+ if (allVersions.length > 0 && locales.length > 0) allVersions.forEach((v) => {
1982
+ locales.forEach((l) => {
1983
+ const fullP = baseDocsPath === "/" ? `/${v}/${l}` : `${baseDocsPath}/${v}/${l}`;
1984
+ targetBasePaths.push({
1985
+ path: fullP,
1986
+ filter: (rp) => !!rp && rp.startsWith(fullP.replace(/\/$/, "") + "/"),
1987
+ locale: l,
1988
+ version: v
1989
+ });
1600
1990
  });
1601
1991
  });
1602
1992
  const docPathRegistry = new Set(docRoutes.map((r) => (r.path || "").replace(/\/$/, "")));
@@ -1608,7 +1998,7 @@ function buildDocRoutes(options) {
1608
1998
  externalPaths.add(`/${locale}${p === "/" ? "" : p}`.replace(/\/$/, ""));
1609
1999
  });
1610
2000
  });
1611
- targetBasePaths.forEach(({ path: bPath, filter }) => {
2001
+ targetBasePaths.forEach(({ path: bPath, filter, locale: bLocale, version: bVersion }) => {
1612
2002
  if (bPath === "/") return;
1613
2003
  const normalizedPath = bPath.replace(/\/$/, "");
1614
2004
  if (!(docPathRegistry.has(normalizedPath) || externalPaths.has(normalizedPath))) {
@@ -1622,6 +2012,7 @@ function buildDocRoutes(options) {
1622
2012
  docRoutes.push({
1623
2013
  ...isBasePathFallback ? { index: true } : { path: redirectPath },
1624
2014
  element: matchedRouteObj.element,
2015
+ lazy: matchedRouteObj.lazy,
1625
2016
  loader: matchedRouteObj.loader,
1626
2017
  getStaticPaths: () => []
1627
2018
  });
@@ -1635,8 +2026,11 @@ function buildDocRoutes(options) {
1635
2026
  docMetadata.push({
1636
2027
  ...matchedMetaObj,
1637
2028
  path: bPath,
1638
- filePath: "",
2029
+ filePath: matchedMetaObj.filePath,
2030
+ locale: bLocale,
2031
+ version: bVersion,
1639
2032
  slugParts: [],
2033
+ fallback: true,
1640
2034
  seo: {
1641
2035
  ...matchedMetaObj.seo,
1642
2036
  canonical: canonicalUrl
@@ -1917,205 +2311,13 @@ function createRoutes(options) {
1917
2311
  ...externalRoutes.metadata,
1918
2312
  ...collectionRoutes.metadata
1919
2313
  ],
1920
- components
2314
+ components,
2315
+ collectionsData: options.collectionsData
1921
2316
  }),
1922
2317
  children
1923
2318
  }];
1924
2319
  }
1925
2320
 
1926
- //#endregion
1927
- //#region src/client/hooks/use-analytics.ts
1928
- function createAnalyticsInstance(config) {
1929
- if (typeof window === "undefined") return createDisabledAnalytics();
1930
- if (typeof window.gtag === "function") return createGtagAnalytics(config);
1931
- if (window.dataLayer) return createDataLayerAnalytics(config);
1932
- return createDisabledAnalytics();
1933
- }
1934
- function createGtagAnalytics(config) {
1935
- return {
1936
- trackPageView: (path, title) => {
1937
- window.gtag?.("event", "page_view", {
1938
- page_path: path,
1939
- page_title: title || document.title,
1940
- send_to: config?.ga4?.measurementId
1941
- });
1942
- },
1943
- trackEvent: ({ action, category, label, value, params }) => {
1944
- window.gtag?.("event", action, {
1945
- event_category: category,
1946
- event_label: label,
1947
- value,
1948
- send_to: config?.ga4?.measurementId,
1949
- ...params
1950
- });
1951
- },
1952
- trackSearch: (query, resultsCount) => {
1953
- window.gtag?.("event", "search", {
1954
- search_term: query,
1955
- results_count: resultsCount,
1956
- send_to: config?.ga4?.measurementId
1957
- });
1958
- },
1959
- trackDownload: (file, type) => {
1960
- window.gtag?.("event", "file_download", {
1961
- file_name: file,
1962
- file_type: type || file.split(".").pop(),
1963
- send_to: config?.ga4?.measurementId
1964
- });
1965
- },
1966
- trackExternalLink: (url) => {
1967
- window.gtag?.("event", "external_link", {
1968
- link_url: url,
1969
- send_to: config?.ga4?.measurementId
1970
- });
1971
- },
1972
- isEnabled: true
1973
- };
1974
- }
1975
- function createDataLayerAnalytics(config) {
1976
- return {
1977
- trackPageView: (path, title) => {
1978
- window.dataLayer?.push({
1979
- event: "page_view",
1980
- page_path: path,
1981
- page_title: title || document.title,
1982
- send_to: config?.gtm?.tagId
1983
- });
1984
- },
1985
- trackEvent: ({ action, category, label, value, params }) => {
1986
- window.dataLayer?.push({
1987
- event: action,
1988
- event_category: category,
1989
- event_label: label,
1990
- value,
1991
- send_to: config?.gtm?.tagId,
1992
- ...params
1993
- });
1994
- },
1995
- trackSearch: (query, resultsCount) => {
1996
- window.dataLayer?.push({
1997
- event: "search",
1998
- search_term: query,
1999
- results_count: resultsCount,
2000
- send_to: config?.gtm?.tagId
2001
- });
2002
- },
2003
- trackDownload: (file, type) => {
2004
- window.dataLayer?.push({
2005
- event: "file_download",
2006
- file_name: file,
2007
- file_type: type || file.split(".").pop(),
2008
- send_to: config?.gtm?.tagId
2009
- });
2010
- },
2011
- trackExternalLink: (url) => {
2012
- window.dataLayer?.push({
2013
- event: "external_link",
2014
- link_url: url,
2015
- send_to: config?.gtm?.tagId
2016
- });
2017
- },
2018
- isEnabled: true
2019
- };
2020
- }
2021
- function createDisabledAnalytics() {
2022
- return {
2023
- trackPageView: () => {},
2024
- trackEvent: () => {},
2025
- trackSearch: () => {},
2026
- trackDownload: () => {},
2027
- trackExternalLink: () => {},
2028
- isEnabled: false
2029
- };
2030
- }
2031
- const CONFIG_INSTANCE_SYMBOL = Symbol.for("__BDOCS_CONFIG_INSTANCE__");
2032
- function useAnalytics(options = {}) {
2033
- const { config: optionsConfig, autoTrackPageViews = true, autoTrackDownloads = true, autoTrackExternalLinks = true, excludePatterns = [] } = options;
2034
- const globalConfig = typeof globalThis !== "undefined" ? globalThis[CONFIG_INSTANCE_SYMBOL] : void 0;
2035
- const config = optionsConfig ?? globalConfig?.integrations;
2036
- const analytics = (0, react.useMemo)(() => createAnalyticsInstance(config), [config]);
2037
- const previousPath = (0, react.useRef)("");
2038
- const location = require_docs_layout.useLocation();
2039
- (0, react.useEffect)(() => {
2040
- if (!autoTrackPageViews || !analytics.isEnabled) return;
2041
- const path = location.pathname + location.search;
2042
- if (path !== previousPath.current) {
2043
- previousPath.current = path;
2044
- analytics.trackPageView(path, document.title);
2045
- }
2046
- }, [
2047
- location.pathname,
2048
- autoTrackPageViews,
2049
- analytics
2050
- ]);
2051
- (0, react.useEffect)(() => {
2052
- if (!autoTrackDownloads || !analytics.isEnabled) return;
2053
- const handleClick = (event) => {
2054
- const target = event.target?.closest("a");
2055
- if (!target) return;
2056
- const href = target.getAttribute("href");
2057
- if (!href) return;
2058
- if (excludePatterns.some((pattern) => pattern.test(href))) return;
2059
- if (target.hasAttribute("download") || /\.(pdf|doc|docx|xls|xlsx|ppt|pptx|zip|rar|7z|tar|gz|mp3|mp4|avi|mov|png|jpg|jpeg|gif|svg|webp)$/i.test(href)) {
2060
- const fileName = href.split("/").pop() || href;
2061
- analytics.trackDownload(fileName, fileName.split(".").pop());
2062
- }
2063
- };
2064
- document.addEventListener("click", handleClick);
2065
- return () => document.removeEventListener("click", handleClick);
2066
- }, [
2067
- autoTrackDownloads,
2068
- autoTrackExternalLinks,
2069
- analytics,
2070
- excludePatterns
2071
- ]);
2072
- (0, react.useEffect)(() => {
2073
- if (!autoTrackExternalLinks || !analytics.isEnabled) return;
2074
- const handleClick = (event) => {
2075
- const target = event.target?.closest("a");
2076
- if (!target) return;
2077
- const href = target.getAttribute("href");
2078
- if (!href) return;
2079
- if (excludePatterns.some((pattern) => pattern.test(href))) return;
2080
- if ((href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//")) && !href.includes(window.location.hostname)) analytics.trackExternalLink(href);
2081
- };
2082
- document.addEventListener("click", handleClick);
2083
- return () => document.removeEventListener("click", handleClick);
2084
- }, [
2085
- autoTrackExternalLinks,
2086
- analytics,
2087
- excludePatterns
2088
- ]);
2089
- return analytics;
2090
- }
2091
- function useTrackPageView() {
2092
- const analytics = (0, react.useMemo)(() => createAnalyticsInstance(), []);
2093
- return (0, react.useCallback)((path, title) => {
2094
- analytics.trackPageView(path, title);
2095
- }, [analytics]);
2096
- }
2097
- function useTrackEvent() {
2098
- const analytics = (0, react.useMemo)(() => createAnalyticsInstance(), []);
2099
- return (0, react.useCallback)((event) => {
2100
- analytics.trackEvent(event);
2101
- }, [analytics]);
2102
- }
2103
-
2104
- //#endregion
2105
- //#region src/client/hooks/use-headings.ts
2106
- /**
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.
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
2321
  //#endregion
2120
2322
  //#region src/client/components/docs-layout-default.tsx
2121
2323
  function DocsLayoutComponent({ children }) {
@@ -2156,6 +2358,7 @@ function DocsLayoutComponent({ children }) {
2156
2358
  className: "prose prose-neutral dark:prose-invert max-w-none",
2157
2359
  children
2158
2360
  }) }),
2361
+ !isCollectionPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Feedback, {}),
2159
2362
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_docs_layout.DocsLayout.Footer, { children: !isCollectionPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageNav, {}) })
2160
2363
  ]
2161
2364
  })
@@ -2249,7 +2452,9 @@ exports.getTranslated = getTranslated;
2249
2452
  exports.reactToText = reactToText;
2250
2453
  exports.useAnalytics = useAnalytics;
2251
2454
  exports.useBreadcrumbs = useBreadcrumbs;
2455
+ exports.useCodeBlock = require_mdx.useCodeBlock;
2252
2456
  exports.useConfig = require_icons_dev.useConfig;
2457
+ exports.useFeedback = useFeedback;
2253
2458
  exports.useHeadings = useHeadings;
2254
2459
  exports.useI18n = useI18n;
2255
2460
  exports.useLocalizedTo = require_icons_dev.useLocalizedTo;