boltdocs 2.8.4 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/bin/boltdocs.js +7 -6
  2. package/dist/{banner-DFACg5Dy.d.cts → banner-C_xkGxzI.d.cts} +1 -1
  3. package/dist/{banner-BLTQUA2O.d.ts → banner-D2NddBfF.d.ts} +1 -1
  4. package/dist/cache-B19MLTpN.cjs +6 -0
  5. package/dist/cache-CfhOTR3Q.mjs +6 -0
  6. package/dist/chunk-Ds5LZdWN.cjs +6 -0
  7. package/dist/client/index.cjs +464 -279
  8. package/dist/client/index.d.cts +74 -8
  9. package/dist/client/index.d.ts +74 -8
  10. package/dist/client/index.js +463 -280
  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/config-BqZUYono.cjs +7 -0
  20. package/dist/config-DBKBEj3j.mjs +7 -0
  21. package/dist/config-GPVEdeon.mjs +6 -0
  22. package/dist/config-kIQOJHXC.cjs +6 -0
  23. package/dist/csp-CBysWlAf.cjs +6 -0
  24. package/dist/csp-RJyh0nHV.mjs +6 -0
  25. package/dist/{docs-layout-CVCf3xkZ.cjs → docs-layout-3TpAt6MB.cjs} +302 -238
  26. package/dist/{docs-layout-BBv6wILp.js → docs-layout-6FQ8__ok.js} +303 -239
  27. package/dist/doctor-C19DsI1e.mjs +7 -0
  28. package/dist/{doctor-DT4jh07O.cjs → doctor-D8fl3Sbg.cjs} +1 -1
  29. package/dist/doctor-DzEgMMRo.cjs +7 -0
  30. package/dist/errors-C0Hx15Ag.mjs +6 -0
  31. package/dist/errors-Dx6JHoKE.cjs +6 -0
  32. package/dist/{generator-BHCrLU6h.mjs → generator-B6lrnDZ-.mjs} +1 -1
  33. package/dist/{generator-CC2yHzhZ.cjs → generator-DtUU3Cfk.cjs} +2 -2
  34. package/dist/handler-1LRMYeI4.cjs +28 -0
  35. package/dist/handler-CyIBbZdb.mjs +28 -0
  36. package/dist/{doctor-BGPdO1Ah.mjs → handler-eNNcucnf.mjs} +1 -1
  37. package/dist/headers-BJ4jJAhU.cjs +6 -0
  38. package/dist/headers-HD_qTVVW.mjs +6 -0
  39. package/dist/{icons-dev-C8sFxeBk.cjs → icons-dev-BryEFkJu.cjs} +90 -4
  40. package/dist/{icons-dev-CFcv5Nb8.js → icons-dev-kJyGWNeg.js} +73 -5
  41. package/dist/{image-DCMxxidi.cjs → image-B9YA_oQ_.cjs} +17 -9
  42. package/dist/{image-DufDOid8.js → image-CjYu9Eml.js} +17 -9
  43. package/dist/{mdx-Bto8CvGl.js → mdx-Cy_c2zio.js} +116 -33
  44. package/dist/{mdx-BH9kHiF9.cjs → mdx-WXjAMS8Y.cjs} +121 -32
  45. package/dist/{meta-loader-Cv9O0Pzl.cjs → meta-loader-C9MKjAs0.cjs} +1 -1
  46. package/dist/{meta-loader-DzwDFtdT.mjs → meta-loader-CxAoQthW.mjs} +1 -1
  47. package/dist/node/cli-entry.cjs +8 -2
  48. package/dist/node/cli-entry.mjs +8 -2
  49. package/dist/node/index.cjs +1 -1
  50. package/dist/node/index.d.cts +362 -18
  51. package/dist/node/index.d.mts +364 -19
  52. package/dist/node/index.mjs +1 -1
  53. package/dist/node/routes/worker.cjs +1 -1
  54. package/dist/node/routes/worker.mjs +1 -1
  55. package/dist/node-B7qbjtLl.mjs +105 -0
  56. package/dist/node-Dj3-2YYP.cjs +105 -0
  57. package/dist/{package-CwNjt3Sd.cjs → package-ByXh2JHp.cjs} +1 -1
  58. package/dist/{package-DlgexgpQ.mjs → package-DQBAV8uo.mjs} +1 -1
  59. package/dist/{parser-BzB-zCkF.cjs → parser-B8naUXl2.cjs} +1 -1
  60. package/dist/parser-D4oEyuP-.cjs +6 -0
  61. package/dist/parser-IR9tfyGE.mjs +6 -0
  62. package/dist/plugin-BkquLpOI.mjs +61 -0
  63. package/dist/plugin-CL1LsQXk.cjs +61 -0
  64. package/dist/routes-DR13Y1em.mjs +6 -0
  65. package/dist/routes-DX8ryKjs.cjs +6 -0
  66. package/dist/routes-DgTQxpZi.cjs +6 -0
  67. package/dist/routes-TUSK5wD7.mjs +6 -0
  68. package/dist/{search-dialog-Cvux-qSk.cjs → search-dialog-BhXg05Ri.cjs} +1 -1
  69. package/dist/{search-dialog-CmHYOt18.cjs → search-dialog-BsAiQgnx.cjs} +2 -2
  70. package/dist/{search-dialog-jHZ21G4i.js → search-dialog-CaOO1Q4i.js} +2 -2
  71. package/dist/{search-dialog-Cr7SC8Xt.cjs → search-dialog-CzwvKoLW.cjs} +1 -1
  72. package/dist/{search-dialog-DBNaG5At.js → search-dialog-DRNJsxOv.js} +1 -1
  73. package/dist/{search-dialog-e86WPpck.js → search-dialog-DaR66wl0.js} +1 -1
  74. package/dist/shiki-adapter-BB71nVsG.cjs +6 -0
  75. package/dist/shiki-adapter-CL-IQwKI.cjs +6 -0
  76. package/dist/shiki-adapter-CxTLkjew.mjs +6 -0
  77. package/dist/shiki-adapter-rQ087Lx3.mjs +6 -0
  78. package/dist/{sidebar-kQBonN82.d.ts → sidebar-BtJyWHy4.d.cts} +42 -5
  79. package/dist/{sidebar---RgTmZD.d.cts → sidebar-C4fuRYYS.d.ts} +42 -5
  80. package/dist/types-generator-BRyf4o9F.mjs +26 -0
  81. package/dist/types-generator-BqNKCbrx.cjs +26 -0
  82. package/dist/types-generator-Cu2jQP-V.mjs +6 -0
  83. package/dist/utils-BWy_8ASj.cjs +7 -0
  84. package/dist/utils-DexBrwiP.mjs +7 -0
  85. package/dist/worker-pool-C6r6V05j.mjs +6 -0
  86. package/dist/worker-pool-m81xuM5v.cjs +6 -0
  87. package/package.json +6 -3
  88. package/src/shared/types.ts +36 -3
  89. package/dist/cache-BMUyNiiA.mjs +0 -6
  90. package/dist/cache-CKm45d2w.cjs +0 -6
  91. package/dist/chunk-CU-zTemE.cjs +0 -6
  92. package/dist/doctor-Dnv77Lfx.mjs +0 -28
  93. package/dist/doctor-VBPlQf7d.cjs +0 -28
  94. package/dist/node-JM9bx0mO.cjs +0 -160
  95. package/dist/node-q-Y2mdLX.mjs +0 -160
  96. package/dist/parser-9LqyiEnB.mjs +0 -6
  97. package/dist/parser-B7-6PyQz.cjs +0 -6
  98. package/dist/routes-3sAccArX.cjs +0 -6
  99. package/dist/routes-DZpXqq1p.mjs +0 -6
  100. package/dist/routes-DjoxNeef.mjs +0 -6
  101. package/dist/routes-DpJnb2VS.cjs +0 -6
  102. package/dist/utils-BYITg7T5.mjs +0 -7
  103. package/dist/utils-Cjmx1hhk.cjs +0 -7
  104. package/dist/worker-pool-DXLyeHJg.cjs +0 -6
  105. package/dist/worker-pool-Kn4F9gDq.mjs +0 -6
@@ -3,12 +3,12 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- import { $ as ConfigContext, B as Languages, C as RoutesProvider, D as Check, E as ArrowLeft, G as Moon, M as Copy, O as ChevronDown, P as ExternalLink, Q as icons_exports, R as Home, S as normalizePath, U as Menu, W as Monitor, X as TextAlignStart, Y as Sun, Z as X, _ as Link$1, b as useLocalizedTo, et as useConfig, j as CircleHelp, nt as useBoltdocsContext, q as Pencil, s as Github, tt as BoltdocsProvider, x as useRoutes, y as cn } from "../icons-dev-CFcv5Nb8.js";
7
- import { c as ThemeProvider, l as useTheme } from "../image-DufDOid8.js";
8
- import { n as copyToClipboard, t as mdx_components_default } from "../mdx-Bto8CvGl.js";
9
- import { A as useUI, D as ButtonGroup, O as Breadcrumbs$2, T as Menu$1, _ as OnThisPage$1, h as PageNav$1, i as Sidebar$1, k as UIProvider, m as useSidebar, n as useSearchHighlight, r as useLocation, t as DocsLayout$1, w as Tabs$1 } from "../docs-layout-BBv6wILp.js";
10
- import { a as Button$1, n as Navbar$1, r as ErrorBoundary$1 } from "../search-dialog-e86WPpck.js";
11
- import { n as useSearch, r as InternalErrorBoundary, t as SearchDialog } from "../search-dialog-jHZ21G4i.js";
6
+ import { $ as TextAlignStart, C as RoutesProvider, D as Check, E as ArrowLeft, F as FaceBad, I as FaceGood, J as Moon, K as Menu, L as FaceRegular, M as Copy, O as ChevronDown, P as ExternalLink, Q as Sun, S as normalizePath, U as Languages, V as Home, X as Pencil, _ as Link$1, at as useBoltdocsContext, b as useLocalizedTo, et as X, it as BoltdocsProvider, j as CircleHelp, nt as ConfigContext, q as Monitor, rt as useConfig, s as Github, tt as icons_exports, x as useRoutes, y as cn } from "../icons-dev-kJyGWNeg.js";
7
+ import { c as ThemeProvider, l as useTheme } from "../image-CjYu9Eml.js";
8
+ import { n as useCodeBlock, r as copyToClipboard, t as mdx_components_default } from "../mdx-Cy_c2zio.js";
9
+ import { A as useUI, C as useSidebar, D as ButtonGroup, O as Breadcrumbs$2, S as useLocation, T as Menu$1, f as PageNav$1, k as UIProvider, m as OnThisPage$1, n as Sidebar$1, t as DocsLayout$1, w as Tabs$1, x as useSearchHighlight } from "../docs-layout-6FQ8__ok.js";
10
+ import { a as Button$1, n as Navbar$1, r as ErrorBoundary$1 } from "../search-dialog-DaR66wl0.js";
11
+ import { n as useSearch, r as InternalErrorBoundary, t as SearchDialog } from "../search-dialog-CaOO1Q4i.js";
12
12
  import { ViteReactSSG } from "@bdocs/ssg";
13
13
  import { Suspense, createContext, isValidElement, lazy, use, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
14
14
  import { Link, Outlet, useLoaderData, useLocation as useLocation$1, useMatches, useNavigate } from "react-router-dom";
@@ -154,6 +154,13 @@ const mdxComponentsDefault = {
154
154
  "404": NotFound
155
155
  };
156
156
 
157
+ //#endregion
158
+ //#region src/client/collections/collections-context.tsx
159
+ const CollectionsContext = createContext({});
160
+ function useCollectionsData() {
161
+ return use(CollectionsContext);
162
+ }
163
+
157
164
  //#endregion
158
165
  //#region src/client/ssg/boltdocs-shell.tsx
159
166
  /**
@@ -189,7 +196,7 @@ function StoreSync({ config, routeMap }) {
189
196
  ]);
190
197
  return null;
191
198
  }
192
- function BoltdocsShell({ config, routes, components = {} }) {
199
+ function BoltdocsShell({ config, routes, components = {}, collectionsData }) {
193
200
  const allComponents = useMemo(() => ({
194
201
  ...mdxComponentsDefault,
195
202
  ...virtualCustomComponents,
@@ -226,20 +233,23 @@ function BoltdocsShell({ config, routes, components = {} }) {
226
233
  routes,
227
234
  children: /* @__PURE__ */ jsx(ThemeProvider, { children: /* @__PURE__ */ jsx(UIProvider, { children: /* @__PURE__ */ jsx(MdxComponentsProvider, {
228
235
  components: allComponents,
229
- children: /* @__PURE__ */ jsxs(ConfigContext.Provider, {
236
+ children: /* @__PURE__ */ jsx(ConfigContext.Provider, {
230
237
  value: config,
231
- children: [/* @__PURE__ */ jsx(ScrollHandler, {}), /* @__PURE__ */ jsxs(BoltdocsProvider, {
232
- initialLocale: initialData.initLocale,
233
- initialVersion: initialData.initVersion,
234
- children: [
235
- /* @__PURE__ */ jsx(StoreSync, {
236
- config,
237
- routeMap
238
- }),
239
- /* @__PURE__ */ jsx(I18nUpdater, { config }),
240
- /* @__PURE__ */ jsx(InternalErrorBoundary, { children: /* @__PURE__ */ jsx(Outlet, {}) })
241
- ]
242
- })]
238
+ children: /* @__PURE__ */ jsxs(CollectionsContext.Provider, {
239
+ value: collectionsData || {},
240
+ children: [/* @__PURE__ */ jsx(ScrollHandler, {}), /* @__PURE__ */ jsxs(BoltdocsProvider, {
241
+ initialLocale: initialData.initLocale,
242
+ initialVersion: initialData.initVersion,
243
+ children: [
244
+ /* @__PURE__ */ jsx(StoreSync, {
245
+ config,
246
+ routeMap
247
+ }),
248
+ /* @__PURE__ */ jsx(I18nUpdater, { config }),
249
+ /* @__PURE__ */ jsx(InternalErrorBoundary, { children: /* @__PURE__ */ jsx(Outlet, {}) })
250
+ ]
251
+ })]
252
+ })
243
253
  })
244
254
  }) }) })
245
255
  }) });
@@ -845,6 +855,30 @@ function useVersion() {
845
855
  };
846
856
  }
847
857
 
858
+ //#endregion
859
+ //#region src/client/components/ui-base/version-selector.tsx
860
+ function VersionSelector({ className }) {
861
+ const { currentVersionLabel, availableVersions, handleVersionChange } = useVersion();
862
+ if (availableVersions.length === 0) return null;
863
+ return /* @__PURE__ */ jsxs(Menu$1.Trigger, { children: [/* @__PURE__ */ jsxs(Button$1, {
864
+ className: 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),
865
+ children: [/* @__PURE__ */ jsx("span", {
866
+ className: "font-semibold text-[0.8125rem]",
867
+ children: currentVersionLabel
868
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: "w-3.5 h-3.5 text-muted/60" })]
869
+ }), /* @__PURE__ */ jsx(Menu$1.Root, {
870
+ 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",
871
+ children: /* @__PURE__ */ jsx(Menu$1.Section, {
872
+ items: availableVersions,
873
+ children: (version) => /* @__PURE__ */ jsx(Menu$1.Item, {
874
+ onPress: () => handleVersionChange(version.value),
875
+ 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",
876
+ children: version.label
877
+ }, version.value)
878
+ })
879
+ })] });
880
+ }
881
+
848
882
  //#endregion
849
883
  //#region src/client/hooks/use-i18n.ts
850
884
  /**
@@ -924,28 +958,319 @@ function useI18n() {
924
958
  }
925
959
 
926
960
  //#endregion
927
- //#region src/client/components/ui-base/version-i18n.tsx
928
- function VersionSelector({ className }) {
929
- const { currentVersionLabel, availableVersions, handleVersionChange } = useVersion();
930
- if (availableVersions.length === 0) return null;
931
- return /* @__PURE__ */ jsxs(Menu$1.Trigger, { children: [/* @__PURE__ */ jsxs(Button$1, {
932
- className: 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),
933
- children: [/* @__PURE__ */ jsx("span", {
934
- className: "font-semibold text-[0.8125rem]",
935
- children: currentVersionLabel
936
- }), /* @__PURE__ */ jsx(ChevronDown, { className: "w-3.5 h-3.5 text-muted/60" })]
937
- }), /* @__PURE__ */ jsx(Menu$1.Root, {
938
- 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",
939
- children: /* @__PURE__ */ jsx(Menu$1.Section, {
940
- items: availableVersions,
941
- children: (version) => /* @__PURE__ */ jsx(Menu$1.Item, {
942
- onPress: () => handleVersionChange(version.value),
943
- 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",
944
- children: version.label
945
- }, `${version.value ?? ""}`)
946
- })
947
- })] });
961
+ //#region src/client/hooks/use-page-nav.ts
962
+ function usePageNav() {
963
+ const { routes, currentRoute } = useRoutes();
964
+ const location = useLocation$1();
965
+ const { groups, ungrouped } = useSidebar(routes);
966
+ return useMemo(() => {
967
+ if (!currentRoute) return {
968
+ prevPage: null,
969
+ nextPage: null,
970
+ currentRoute: null
971
+ };
972
+ const mergedItems = [...ungrouped.map((route) => ({
973
+ type: "link",
974
+ position: route.sidebarPosition ?? 999,
975
+ title: route.title,
976
+ route
977
+ })), ...groups.map((group) => ({
978
+ type: "group",
979
+ position: group.sidebarPosition ?? 999,
980
+ title: group.title,
981
+ group
982
+ }))].sort((a, b) => {
983
+ if (a.position !== b.position) return a.position - b.position;
984
+ if (a.type !== b.type) return a.type === "link" ? -1 : 1;
985
+ return a.title.localeCompare(b.title);
986
+ });
987
+ const orderedRoutes = [];
988
+ const flattenNode = (node) => {
989
+ if (node.path && node.path !== "#" && !node.sidebarHidden) orderedRoutes.push(node);
990
+ const children = node.routes || node.subRoutes;
991
+ if (children && children.length > 0) for (const child of children) flattenNode(child);
992
+ };
993
+ for (const item of mergedItems) if (item.type === "link") flattenNode(item.route);
994
+ else if (item.group.routes) for (const route of item.group.routes) flattenNode(route);
995
+ const currentNormalizedPath = normalizePath(location.pathname);
996
+ const currentIndex = orderedRoutes.findIndex((r) => normalizePath(r.path) === currentNormalizedPath);
997
+ return {
998
+ prevPage: currentIndex > 0 ? orderedRoutes[currentIndex - 1] : null,
999
+ nextPage: currentIndex !== -1 && currentIndex < orderedRoutes.length - 1 ? orderedRoutes[currentIndex + 1] : null,
1000
+ currentRoute
1001
+ };
1002
+ }, [
1003
+ groups,
1004
+ ungrouped,
1005
+ currentRoute,
1006
+ location.pathname
1007
+ ]);
1008
+ }
1009
+
1010
+ //#endregion
1011
+ //#region src/client/hooks/use-analytics.ts
1012
+ function createAnalyticsInstance(config) {
1013
+ if (typeof window === "undefined") return createDisabledAnalytics();
1014
+ if (typeof window.gtag === "function") return createGtagAnalytics(config);
1015
+ if (window.dataLayer) return createDataLayerAnalytics(config);
1016
+ return createDisabledAnalytics();
1017
+ }
1018
+ function createGtagAnalytics(config) {
1019
+ return {
1020
+ trackPageView: (path, title) => {
1021
+ window.gtag?.("event", "page_view", {
1022
+ page_path: path,
1023
+ page_title: title || document.title,
1024
+ send_to: config?.ga4?.measurementId
1025
+ });
1026
+ },
1027
+ trackEvent: ({ action, category, label, value, params }) => {
1028
+ window.gtag?.("event", action, {
1029
+ event_category: category,
1030
+ event_label: label,
1031
+ value,
1032
+ send_to: config?.ga4?.measurementId,
1033
+ ...params
1034
+ });
1035
+ },
1036
+ trackSearch: (query, resultsCount) => {
1037
+ window.gtag?.("event", "search", {
1038
+ search_term: query,
1039
+ results_count: resultsCount,
1040
+ send_to: config?.ga4?.measurementId
1041
+ });
1042
+ },
1043
+ trackDownload: (file, type) => {
1044
+ window.gtag?.("event", "file_download", {
1045
+ file_name: file,
1046
+ file_type: type || file.split(".").pop(),
1047
+ send_to: config?.ga4?.measurementId
1048
+ });
1049
+ },
1050
+ trackExternalLink: (url) => {
1051
+ window.gtag?.("event", "external_link", {
1052
+ link_url: url,
1053
+ send_to: config?.ga4?.measurementId
1054
+ });
1055
+ },
1056
+ isEnabled: true
1057
+ };
1058
+ }
1059
+ function createDataLayerAnalytics(config) {
1060
+ return {
1061
+ trackPageView: (path, title) => {
1062
+ window.dataLayer?.push({
1063
+ event: "page_view",
1064
+ page_path: path,
1065
+ page_title: title || document.title,
1066
+ send_to: config?.gtm?.tagId
1067
+ });
1068
+ },
1069
+ trackEvent: ({ action, category, label, value, params }) => {
1070
+ window.dataLayer?.push({
1071
+ event: action,
1072
+ event_category: category,
1073
+ event_label: label,
1074
+ value,
1075
+ send_to: config?.gtm?.tagId,
1076
+ ...params
1077
+ });
1078
+ },
1079
+ trackSearch: (query, resultsCount) => {
1080
+ window.dataLayer?.push({
1081
+ event: "search",
1082
+ search_term: query,
1083
+ results_count: resultsCount,
1084
+ send_to: config?.gtm?.tagId
1085
+ });
1086
+ },
1087
+ trackDownload: (file, type) => {
1088
+ window.dataLayer?.push({
1089
+ event: "file_download",
1090
+ file_name: file,
1091
+ file_type: type || file.split(".").pop(),
1092
+ send_to: config?.gtm?.tagId
1093
+ });
1094
+ },
1095
+ trackExternalLink: (url) => {
1096
+ window.dataLayer?.push({
1097
+ event: "external_link",
1098
+ link_url: url,
1099
+ send_to: config?.gtm?.tagId
1100
+ });
1101
+ },
1102
+ isEnabled: true
1103
+ };
1104
+ }
1105
+ function createDisabledAnalytics() {
1106
+ return {
1107
+ trackPageView: () => {},
1108
+ trackEvent: () => {},
1109
+ trackSearch: () => {},
1110
+ trackDownload: () => {},
1111
+ trackExternalLink: () => {},
1112
+ isEnabled: false
1113
+ };
1114
+ }
1115
+ const CONFIG_INSTANCE_SYMBOL = Symbol.for("__BDOCS_CONFIG_INSTANCE__");
1116
+ function useAnalytics(options = {}) {
1117
+ const { config: optionsConfig, autoTrackPageViews = true, autoTrackDownloads = true, autoTrackExternalLinks = true, excludePatterns = [] } = options;
1118
+ const globalConfig = typeof globalThis !== "undefined" ? globalThis[CONFIG_INSTANCE_SYMBOL] : void 0;
1119
+ const config = optionsConfig ?? globalConfig?.integrations;
1120
+ const analytics = useMemo(() => createAnalyticsInstance(config), [config]);
1121
+ const previousPath = useRef("");
1122
+ const location = useLocation();
1123
+ useEffect(() => {
1124
+ if (!autoTrackPageViews || !analytics.isEnabled) return;
1125
+ const path = location.pathname + location.search;
1126
+ if (path !== previousPath.current) {
1127
+ previousPath.current = path;
1128
+ analytics.trackPageView(path, document.title);
1129
+ }
1130
+ }, [
1131
+ location.pathname,
1132
+ autoTrackPageViews,
1133
+ analytics
1134
+ ]);
1135
+ useEffect(() => {
1136
+ if (!autoTrackDownloads || !analytics.isEnabled) return;
1137
+ const handleClick = (event) => {
1138
+ const target = event.target?.closest("a");
1139
+ if (!target) return;
1140
+ const href = target.getAttribute("href");
1141
+ if (!href) return;
1142
+ if (excludePatterns.some((pattern) => pattern.test(href))) return;
1143
+ 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)) {
1144
+ const fileName = href.split("/").pop() || href;
1145
+ analytics.trackDownload(fileName, fileName.split(".").pop());
1146
+ }
1147
+ };
1148
+ document.addEventListener("click", handleClick);
1149
+ return () => document.removeEventListener("click", handleClick);
1150
+ }, [
1151
+ autoTrackDownloads,
1152
+ autoTrackExternalLinks,
1153
+ analytics,
1154
+ excludePatterns
1155
+ ]);
1156
+ useEffect(() => {
1157
+ if (!autoTrackExternalLinks || !analytics.isEnabled) return;
1158
+ const handleClick = (event) => {
1159
+ const target = event.target?.closest("a");
1160
+ if (!target) return;
1161
+ const href = target.getAttribute("href");
1162
+ if (!href) return;
1163
+ if (excludePatterns.some((pattern) => pattern.test(href))) return;
1164
+ if ((href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//")) && !href.includes(window.location.hostname)) analytics.trackExternalLink(href);
1165
+ };
1166
+ document.addEventListener("click", handleClick);
1167
+ return () => document.removeEventListener("click", handleClick);
1168
+ }, [
1169
+ autoTrackExternalLinks,
1170
+ analytics,
1171
+ excludePatterns
1172
+ ]);
1173
+ return analytics;
1174
+ }
1175
+ function useTrackPageView() {
1176
+ const analytics = useMemo(() => createAnalyticsInstance(), []);
1177
+ return useCallback((path, title) => {
1178
+ analytics.trackPageView(path, title);
1179
+ }, [analytics]);
1180
+ }
1181
+ function useTrackEvent() {
1182
+ const analytics = useMemo(() => createAnalyticsInstance(), []);
1183
+ return useCallback((event) => {
1184
+ analytics.trackEvent(event);
1185
+ }, [analytics]);
1186
+ }
1187
+
1188
+ //#endregion
1189
+ //#region src/client/hooks/use-headings.ts
1190
+ /**
1191
+ * Returns the headings of the current page, extracted from the route loader data.
1192
+ * Useful for building custom Tables of Contents or jumping to sections.
1193
+ *
1194
+ * @returns An array of heading objects with level, text, and id.
1195
+ */
1196
+ function useHeadings() {
1197
+ const matches = useMatches();
1198
+ return useMemo(() => {
1199
+ return (matches[matches.length - 1]?.data)?.headings || [];
1200
+ }, [matches]);
1201
+ }
1202
+
1203
+ //#endregion
1204
+ //#region src/client/hooks/use-feedback.ts
1205
+ /**
1206
+ * Hook for managing the feedback rating form state and submission.
1207
+ * Resets automatically when navigating to a new page.
1208
+ */
1209
+ function useFeedback(options = {}) {
1210
+ const config = useConfig();
1211
+ const { currentRoute } = useRoutes();
1212
+ const [rating, setRating] = useState(null);
1213
+ const [comment, setComment] = useState("");
1214
+ const [loading, setLoading] = useState(false);
1215
+ const [submitted, setSubmitted] = useState(false);
1216
+ const [error, setError] = useState(null);
1217
+ useEffect(() => {
1218
+ setRating(null);
1219
+ setComment("");
1220
+ setSubmitted(false);
1221
+ setError(null);
1222
+ }, [currentRoute?.path]);
1223
+ const submit = async (commentOverride, blockId) => {
1224
+ if (!rating) return;
1225
+ setLoading(true);
1226
+ setError(null);
1227
+ const payload = {
1228
+ rating,
1229
+ comment: (commentOverride !== void 0 ? commentOverride : comment) || void 0,
1230
+ path: currentRoute?.path || window.location.pathname,
1231
+ title: currentRoute?.title || document.title,
1232
+ blockId
1233
+ };
1234
+ try {
1235
+ if (options.onSubmit) await options.onSubmit(payload);
1236
+ else {
1237
+ const endpoint = options.endpoint || config.integrations?.feedback?.custom?.endpoint || "/api/feedback";
1238
+ const res = await fetch(endpoint, {
1239
+ method: "POST",
1240
+ headers: { "Content-Type": "application/json" },
1241
+ body: JSON.stringify(payload)
1242
+ });
1243
+ if (!res.ok) {
1244
+ const text = await res.text();
1245
+ let errorText = text;
1246
+ try {
1247
+ const data = JSON.parse(text);
1248
+ errorText = data.error || data.message || text;
1249
+ } catch {}
1250
+ throw new Error(errorText || `Failed to submit feedback: ${res.statusText}`);
1251
+ }
1252
+ }
1253
+ setSubmitted(true);
1254
+ } catch (e) {
1255
+ setError(e.message || "An error occurred while submitting feedback.");
1256
+ } finally {
1257
+ setLoading(false);
1258
+ }
1259
+ };
1260
+ return {
1261
+ rating,
1262
+ setRating,
1263
+ comment,
1264
+ setComment,
1265
+ loading,
1266
+ submitted,
1267
+ error,
1268
+ submit
1269
+ };
948
1270
  }
1271
+
1272
+ //#endregion
1273
+ //#region src/client/components/ui-base/i18n-selector.tsx
949
1274
  function I18nSelector({ className }) {
950
1275
  const { currentLocale, availableLocales, handleLocaleChange } = useI18n();
951
1276
  if (availableLocales.length === 0) return null;
@@ -966,14 +1291,14 @@ function I18nSelector({ className }) {
966
1291
  onPress: () => handleLocaleChange(locale.value),
967
1292
  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",
968
1293
  children: /* @__PURE__ */ jsx("span", { children: locale.label })
969
- }, `${locale.value ?? ""}`)
1294
+ }, locale.value)
970
1295
  })
971
1296
  })] });
972
1297
  }
973
1298
 
974
1299
  //#endregion
975
1300
  //#region src/client/components/ui-base/navbar.tsx
976
- const SearchDialog$1 = lazy(() => import("../search-dialog-DBNaG5At.js").then((m) => ({ default: m.SearchDialog })));
1301
+ const SearchDialog$1 = lazy(() => import("../search-dialog-DRNJsxOv.js").then((m) => ({ default: m.SearchDialog })));
977
1302
  function Navbar() {
978
1303
  const { links, title, logo, logoProps, github, social, config } = useNavbar();
979
1304
  const { routes, currentRoute, isCollectionPage, currentVersion, currentLocale } = useRoutes();
@@ -1090,7 +1415,7 @@ function Navbar() {
1090
1415
  function NavbarLinkItem({ link }) {
1091
1416
  const localizedHref = useLocalizedTo(link.href || "");
1092
1417
  const { pathname } = useLocation$1();
1093
- const active = pathname === localizedHref || pathname.startsWith(localizedHref + "/");
1418
+ const active = pathname === localizedHref || pathname.startsWith(`${localizedHref}/`);
1094
1419
  if (link.items && link.items.length > 0) return /* @__PURE__ */ jsx(Navbar$1.Dropdown, {
1095
1420
  label: /* @__PURE__ */ jsx("span", {
1096
1421
  className: 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"),
@@ -1169,36 +1494,6 @@ function OnThisPage({ headings = [], editLink, communityHelp, filePath }) {
1169
1494
  ] });
1170
1495
  }
1171
1496
 
1172
- //#endregion
1173
- //#region src/client/hooks/use-page-nav.ts
1174
- /**
1175
- * Hook to manage the previous and next button functionality for documentation pages.
1176
- * Intelligent: respects current locale, version, and tab to keep navigation logical.
1177
- */
1178
- function usePageNav() {
1179
- const { routes, currentRoute } = useRoutes();
1180
- const location = useLocation$1();
1181
- return useMemo(() => {
1182
- if (!currentRoute) return {
1183
- prevPage: null,
1184
- nextPage: null,
1185
- currentRoute: null
1186
- };
1187
- const activeTabId = currentRoute.tab?.toLowerCase();
1188
- const contextRoutes = activeTabId ? routes.filter((r) => r.tab?.toLowerCase() === activeTabId) : routes.filter((r) => !r.tab);
1189
- const currentIndex = contextRoutes.findIndex((r) => r.path === location.pathname);
1190
- return {
1191
- prevPage: currentIndex > 0 ? contextRoutes[currentIndex - 1] : null,
1192
- nextPage: currentIndex !== -1 && currentIndex < contextRoutes.length - 1 ? contextRoutes[currentIndex + 1] : null,
1193
- currentRoute
1194
- };
1195
- }, [
1196
- routes,
1197
- currentRoute,
1198
- location.pathname
1199
- ]);
1200
- }
1201
-
1202
1497
  //#endregion
1203
1498
  //#region src/client/components/ui-base/page-nav.tsx
1204
1499
  /**
@@ -1288,13 +1583,15 @@ const Sidebar = Object.assign(SidebarMain, {
1288
1583
  function Banner({ children, className = "", dismissible = false, id = "boltdocs-banner", ...props }) {
1289
1584
  const [isVisible, setIsVisible] = useState(true);
1290
1585
  useEffect(() => {
1291
- if (dismissible && id) {
1292
- if (localStorage.getItem(`boltdocs-banner-dismissed-${id}`) === "true") setIsVisible(false);
1293
- }
1586
+ if (dismissible && id && typeof window !== "undefined") try {
1587
+ if (window.localStorage.getItem(`boltdocs-banner-dismissed-${id}`) === "true") setIsVisible(false);
1588
+ } catch {}
1294
1589
  }, [dismissible, id]);
1295
1590
  const handleDismiss = () => {
1296
1591
  setIsVisible(false);
1297
- if (dismissible && id) localStorage.setItem(`boltdocs-banner-dismissed-${id}`, "true");
1592
+ if (dismissible && id && typeof window !== "undefined") try {
1593
+ window.localStorage.setItem(`boltdocs-banner-dismissed-${id}`, "true");
1594
+ } catch {}
1298
1595
  };
1299
1596
  if (!isVisible) return null;
1300
1597
  return /* @__PURE__ */ jsxs("div", {
@@ -1312,6 +1609,90 @@ function Banner({ children, className = "", dismissible = false, id = "boltdocs-
1312
1609
  });
1313
1610
  }
1314
1611
 
1612
+ //#endregion
1613
+ //#region src/client/components/ui-base/feedback.tsx
1614
+ function Feedback({ className }) {
1615
+ if (!(useConfig().integrations?.feedback?.custom)?.enabled) return null;
1616
+ const { rating, setRating, comment, setComment, loading, submitted, error, submit } = useFeedback();
1617
+ return /* @__PURE__ */ jsx("div", {
1618
+ className: 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),
1619
+ children: submitted ? /* @__PURE__ */ jsxs("div", {
1620
+ className: "flex flex-col items-center justify-center py-4 text-center animate-in fade-in zoom-in duration-300",
1621
+ children: [
1622
+ /* @__PURE__ */ jsx("div", {
1623
+ 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",
1624
+ children: /* @__PURE__ */ jsx(Check, { size: 24 })
1625
+ }),
1626
+ /* @__PURE__ */ jsx("h3", {
1627
+ className: "text-lg font-semibold text-default",
1628
+ children: "Thank you for your feedback!"
1629
+ }),
1630
+ /* @__PURE__ */ jsx("p", {
1631
+ className: "text-sm text-muted mt-1",
1632
+ children: "Your comments help us improve the documentation."
1633
+ })
1634
+ ]
1635
+ }) : /* @__PURE__ */ jsxs("div", {
1636
+ className: "flex flex-col gap-4",
1637
+ children: [/* @__PURE__ */ jsxs("div", {
1638
+ className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",
1639
+ children: [/* @__PURE__ */ jsx("h4", {
1640
+ className: "text-base font-semibold text-default",
1641
+ children: "Was this page helpful?"
1642
+ }), /* @__PURE__ */ jsxs("div", {
1643
+ className: "flex items-center gap-2",
1644
+ children: [
1645
+ /* @__PURE__ */ jsxs("button", {
1646
+ type: "button",
1647
+ onClick: () => setRating("good"),
1648
+ className: 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"),
1649
+ "aria-label": "Helpful",
1650
+ children: [/* @__PURE__ */ jsx(FaceGood, {}), /* @__PURE__ */ jsx("span", { children: "Yes" })]
1651
+ }),
1652
+ /* @__PURE__ */ jsxs("button", {
1653
+ type: "button",
1654
+ onClick: () => setRating("neutral"),
1655
+ className: 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"),
1656
+ "aria-label": "Neutral",
1657
+ children: [/* @__PURE__ */ jsx(FaceRegular, {}), /* @__PURE__ */ jsx("span", { children: "Regular" })]
1658
+ }),
1659
+ /* @__PURE__ */ jsxs("button", {
1660
+ type: "button",
1661
+ onClick: () => setRating("bad"),
1662
+ className: 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"),
1663
+ "aria-label": "Not helpful",
1664
+ children: [/* @__PURE__ */ jsx(FaceBad, {}), /* @__PURE__ */ jsx("span", { children: "No" })]
1665
+ })
1666
+ ]
1667
+ })]
1668
+ }), rating && /* @__PURE__ */ jsxs("div", {
1669
+ className: "flex flex-col gap-3 mt-1 animate-in slide-in-from-top-3 duration-300",
1670
+ children: [/* @__PURE__ */ jsx("textarea", {
1671
+ value: comment,
1672
+ onChange: (e) => setComment(e.target.value),
1673
+ placeholder: "¿Tienes alguna sugerencia para mejorar esta página? (Opcional)",
1674
+ 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"
1675
+ }), /* @__PURE__ */ jsxs("div", {
1676
+ className: "flex items-center justify-between gap-3",
1677
+ children: [error && /* @__PURE__ */ jsx("p", {
1678
+ className: "text-xs text-rose-500 font-medium flex-1",
1679
+ children: error
1680
+ }), /* @__PURE__ */ jsx("div", {
1681
+ className: "flex items-center gap-2 ml-auto",
1682
+ children: /* @__PURE__ */ jsx("button", {
1683
+ type: "button",
1684
+ onClick: () => submit(),
1685
+ disabled: loading,
1686
+ 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",
1687
+ children: loading ? "Submitting..." : "Submit"
1688
+ })
1689
+ })]
1690
+ })]
1691
+ })]
1692
+ })
1693
+ });
1694
+ }
1695
+
1315
1696
  //#endregion
1316
1697
  //#region src/client/ssg/mdx-elements.tsx
1317
1698
  const Loading = () => /* @__PURE__ */ jsx("div", {
@@ -1448,13 +1829,6 @@ function Head({ siteTitle, siteDescription, routes }) {
1448
1829
  ] });
1449
1830
  }
1450
1831
 
1451
- //#endregion
1452
- //#region src/client/collections/collections-context.tsx
1453
- const CollectionsContext = createContext({});
1454
- function useCollectionsData() {
1455
- return use(CollectionsContext);
1456
- }
1457
-
1458
1832
  //#endregion
1459
1833
  //#region src/client/app/docs-layout.tsx
1460
1834
  function DocsLayout({ collectionsData }) {
@@ -1932,205 +2306,13 @@ function createRoutes(options) {
1932
2306
  ...externalRoutes.metadata,
1933
2307
  ...collectionRoutes.metadata
1934
2308
  ],
1935
- components
2309
+ components,
2310
+ collectionsData: options.collectionsData
1936
2311
  }),
1937
2312
  children
1938
2313
  }];
1939
2314
  }
1940
2315
 
1941
- //#endregion
1942
- //#region src/client/hooks/use-analytics.ts
1943
- function createAnalyticsInstance(config) {
1944
- if (typeof window === "undefined") return createDisabledAnalytics();
1945
- if (typeof window.gtag === "function") return createGtagAnalytics(config);
1946
- if (window.dataLayer) return createDataLayerAnalytics(config);
1947
- return createDisabledAnalytics();
1948
- }
1949
- function createGtagAnalytics(config) {
1950
- return {
1951
- trackPageView: (path, title) => {
1952
- window.gtag?.("event", "page_view", {
1953
- page_path: path,
1954
- page_title: title || document.title,
1955
- send_to: config?.ga4?.measurementId
1956
- });
1957
- },
1958
- trackEvent: ({ action, category, label, value, params }) => {
1959
- window.gtag?.("event", action, {
1960
- event_category: category,
1961
- event_label: label,
1962
- value,
1963
- send_to: config?.ga4?.measurementId,
1964
- ...params
1965
- });
1966
- },
1967
- trackSearch: (query, resultsCount) => {
1968
- window.gtag?.("event", "search", {
1969
- search_term: query,
1970
- results_count: resultsCount,
1971
- send_to: config?.ga4?.measurementId
1972
- });
1973
- },
1974
- trackDownload: (file, type) => {
1975
- window.gtag?.("event", "file_download", {
1976
- file_name: file,
1977
- file_type: type || file.split(".").pop(),
1978
- send_to: config?.ga4?.measurementId
1979
- });
1980
- },
1981
- trackExternalLink: (url) => {
1982
- window.gtag?.("event", "external_link", {
1983
- link_url: url,
1984
- send_to: config?.ga4?.measurementId
1985
- });
1986
- },
1987
- isEnabled: true
1988
- };
1989
- }
1990
- function createDataLayerAnalytics(config) {
1991
- return {
1992
- trackPageView: (path, title) => {
1993
- window.dataLayer?.push({
1994
- event: "page_view",
1995
- page_path: path,
1996
- page_title: title || document.title,
1997
- send_to: config?.gtm?.tagId
1998
- });
1999
- },
2000
- trackEvent: ({ action, category, label, value, params }) => {
2001
- window.dataLayer?.push({
2002
- event: action,
2003
- event_category: category,
2004
- event_label: label,
2005
- value,
2006
- send_to: config?.gtm?.tagId,
2007
- ...params
2008
- });
2009
- },
2010
- trackSearch: (query, resultsCount) => {
2011
- window.dataLayer?.push({
2012
- event: "search",
2013
- search_term: query,
2014
- results_count: resultsCount,
2015
- send_to: config?.gtm?.tagId
2016
- });
2017
- },
2018
- trackDownload: (file, type) => {
2019
- window.dataLayer?.push({
2020
- event: "file_download",
2021
- file_name: file,
2022
- file_type: type || file.split(".").pop(),
2023
- send_to: config?.gtm?.tagId
2024
- });
2025
- },
2026
- trackExternalLink: (url) => {
2027
- window.dataLayer?.push({
2028
- event: "external_link",
2029
- link_url: url,
2030
- send_to: config?.gtm?.tagId
2031
- });
2032
- },
2033
- isEnabled: true
2034
- };
2035
- }
2036
- function createDisabledAnalytics() {
2037
- return {
2038
- trackPageView: () => {},
2039
- trackEvent: () => {},
2040
- trackSearch: () => {},
2041
- trackDownload: () => {},
2042
- trackExternalLink: () => {},
2043
- isEnabled: false
2044
- };
2045
- }
2046
- const CONFIG_INSTANCE_SYMBOL = Symbol.for("__BDOCS_CONFIG_INSTANCE__");
2047
- function useAnalytics(options = {}) {
2048
- const { config: optionsConfig, autoTrackPageViews = true, autoTrackDownloads = true, autoTrackExternalLinks = true, excludePatterns = [] } = options;
2049
- const globalConfig = typeof globalThis !== "undefined" ? globalThis[CONFIG_INSTANCE_SYMBOL] : void 0;
2050
- const config = optionsConfig ?? globalConfig?.integrations;
2051
- const analytics = useMemo(() => createAnalyticsInstance(config), [config]);
2052
- const previousPath = useRef("");
2053
- const location = useLocation();
2054
- useEffect(() => {
2055
- if (!autoTrackPageViews || !analytics.isEnabled) return;
2056
- const path = location.pathname + location.search;
2057
- if (path !== previousPath.current) {
2058
- previousPath.current = path;
2059
- analytics.trackPageView(path, document.title);
2060
- }
2061
- }, [
2062
- location.pathname,
2063
- autoTrackPageViews,
2064
- analytics
2065
- ]);
2066
- useEffect(() => {
2067
- if (!autoTrackDownloads || !analytics.isEnabled) return;
2068
- const handleClick = (event) => {
2069
- const target = event.target?.closest("a");
2070
- if (!target) return;
2071
- const href = target.getAttribute("href");
2072
- if (!href) return;
2073
- if (excludePatterns.some((pattern) => pattern.test(href))) return;
2074
- 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)) {
2075
- const fileName = href.split("/").pop() || href;
2076
- analytics.trackDownload(fileName, fileName.split(".").pop());
2077
- }
2078
- };
2079
- document.addEventListener("click", handleClick);
2080
- return () => document.removeEventListener("click", handleClick);
2081
- }, [
2082
- autoTrackDownloads,
2083
- autoTrackExternalLinks,
2084
- analytics,
2085
- excludePatterns
2086
- ]);
2087
- useEffect(() => {
2088
- if (!autoTrackExternalLinks || !analytics.isEnabled) return;
2089
- const handleClick = (event) => {
2090
- const target = event.target?.closest("a");
2091
- if (!target) return;
2092
- const href = target.getAttribute("href");
2093
- if (!href) return;
2094
- if (excludePatterns.some((pattern) => pattern.test(href))) return;
2095
- if ((href.startsWith("http://") || href.startsWith("https://") || href.startsWith("//")) && !href.includes(window.location.hostname)) analytics.trackExternalLink(href);
2096
- };
2097
- document.addEventListener("click", handleClick);
2098
- return () => document.removeEventListener("click", handleClick);
2099
- }, [
2100
- autoTrackExternalLinks,
2101
- analytics,
2102
- excludePatterns
2103
- ]);
2104
- return analytics;
2105
- }
2106
- function useTrackPageView() {
2107
- const analytics = useMemo(() => createAnalyticsInstance(), []);
2108
- return useCallback((path, title) => {
2109
- analytics.trackPageView(path, title);
2110
- }, [analytics]);
2111
- }
2112
- function useTrackEvent() {
2113
- const analytics = useMemo(() => createAnalyticsInstance(), []);
2114
- return useCallback((event) => {
2115
- analytics.trackEvent(event);
2116
- }, [analytics]);
2117
- }
2118
-
2119
- //#endregion
2120
- //#region src/client/hooks/use-headings.ts
2121
- /**
2122
- * Returns the headings of the current page, extracted from the route loader data.
2123
- * Useful for building custom Tables of Contents or jumping to sections.
2124
- *
2125
- * @returns An array of heading objects with level, text, and id.
2126
- */
2127
- function useHeadings() {
2128
- const matches = useMatches();
2129
- return useMemo(() => {
2130
- return (matches[matches.length - 1]?.data)?.headings || [];
2131
- }, [matches]);
2132
- }
2133
-
2134
2316
  //#endregion
2135
2317
  //#region src/client/components/docs-layout-default.tsx
2136
2318
  function DocsLayoutComponent({ children }) {
@@ -2171,6 +2353,7 @@ function DocsLayoutComponent({ children }) {
2171
2353
  className: "prose prose-neutral dark:prose-invert max-w-none",
2172
2354
  children
2173
2355
  }) }),
2356
+ !isCollectionPage && /* @__PURE__ */ jsx(Feedback, {}),
2174
2357
  /* @__PURE__ */ jsx(DocsLayout$1.Footer, { children: !isCollectionPage && /* @__PURE__ */ jsx(PageNav, {}) })
2175
2358
  ]
2176
2359
  })
@@ -2236,4 +2419,4 @@ const reactToText = (node, resolvers) => {
2236
2419
  };
2237
2420
 
2238
2421
  //#endregion
2239
- export { Banner, BoltdocsShell, Breadcrumbs, CollectionsContext, CopyMarkdown, DocsLayoutComponent as DocsLayout, ErrorBoundary, MdxPage, Navbar, NotFound, OnThisPage, PageNav, SearchDialog, Sidebar, ViteReactSSG, cn, copyToClipboard, createRoutes, getStarsRepo, getTranslated, reactToText, useAnalytics, useBreadcrumbs, useConfig, useHeadings, useI18n, useLocalizedTo, useLocation, useMdxComponents, useMergedComponents, useNavbar, usePageNav, usePost, usePosts, useRecentPosts, useRoutes, useSearch, useSearchHighlight, useSidebar, useTabs, useTheme, useTrackEvent, useTrackPageView, useUI, useVersion };
2422
+ export { Banner, BoltdocsShell, Breadcrumbs, CollectionsContext, CopyMarkdown, DocsLayoutComponent as DocsLayout, ErrorBoundary, MdxPage, Navbar, NotFound, OnThisPage, PageNav, SearchDialog, Sidebar, ViteReactSSG, cn, copyToClipboard, createRoutes, getStarsRepo, getTranslated, reactToText, useAnalytics, useBreadcrumbs, useCodeBlock, useConfig, useFeedback, useHeadings, useI18n, useLocalizedTo, useLocation, useMdxComponents, useMergedComponents, useNavbar, usePageNav, usePost, usePosts, useRecentPosts, useRoutes, useSearch, useSearchHighlight, useSidebar, useTabs, useTheme, useTrackEvent, useTrackPageView, useUI, useVersion };