boltdocs 3.2.1 → 3.3.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.
- package/bin/boltdocs.js +20 -1
- package/bin/preloader.mjs +28 -0
- package/dist/{adapters-ByYY44Zy.mjs → adapters-BmB4TKCc.mjs} +1 -1
- package/dist/{adapters-DvmtpdSF.cjs → adapters-Cp1Maurn.cjs} +1 -1
- package/dist/audit-CLXjMzwQ.mjs +11 -0
- package/dist/audit-COgjnQ5n.cjs +11 -0
- package/dist/build-BS2hefiL.cjs +6 -0
- package/dist/build-C5mNh9D-.mjs +6 -0
- package/dist/cache-CJE9nWLE.cjs +6 -0
- package/dist/cache-OY4HzIXl.mjs +6 -0
- package/dist/callout-oI_LCbxS.d.ts +71 -0
- package/dist/callout-plqx9Dw-.d.cts +71 -0
- package/dist/client/index.cjs +1265 -569
- package/dist/client/index.d.cts +3 -542
- package/dist/client/index.d.ts +3 -542
- package/dist/client/index.js +1167 -521
- package/dist/client/mdx.cjs +1 -1
- package/dist/client/mdx.d.cts +24 -2
- package/dist/client/mdx.d.ts +24 -2
- package/dist/client/mdx.js +1 -1
- package/dist/client/primitives.cjs +14 -4
- package/dist/client/primitives.d.cts +281 -38
- package/dist/client/primitives.d.ts +281 -38
- package/dist/client/primitives.js +5 -5
- package/dist/client/router.cjs +49 -0
- package/dist/client/router.d.cts +3 -0
- package/dist/client/router.d.ts +3 -0
- package/dist/client/router.js +8 -0
- package/dist/client/theme/reset.css +40 -4
- package/dist/{config-BpzaPsJj.d.cts → config-BoRlz0Ca.d.mts} +157 -14
- package/dist/{config-xtS0ZkMm.d.mts → config-CTsX_tGM.d.cts} +157 -14
- package/dist/config-Ceib-AOH.cjs +7 -0
- package/dist/config-DGLQsy7y.mjs +7 -0
- package/dist/{package-BcISI5-P.cjs → config-files-BYHDOrKn.mjs} +1 -1
- package/dist/config-files-D9cdBMl2.cjs +6 -0
- package/dist/config-jJh8WYJI.cjs +6 -0
- package/dist/csp-C4LmN1ko.cjs +6 -0
- package/dist/csp-D6JEOqKh.mjs +6 -0
- package/dist/dev-Ch3hEe5Y.cjs +6 -0
- package/dist/dev-QPNxysrd.mjs +6 -0
- package/dist/{docs-layout-BdtZ9z6s.js → docs-layout-CbZ7LDRe.js} +504 -249
- package/dist/{docs-layout-CFWI15Id.cjs → docs-layout-vzfXed1Q.cjs} +516 -254
- package/dist/{doctor-BBtmNJE0.cjs → doctor-B1_YL0Wt.cjs} +1 -1
- package/dist/doctor-C7whl4ED.cjs +6 -0
- package/dist/doctor-DmQnml2k.mjs +6 -0
- package/dist/{generator-COepVWGi.cjs → generator-BlW45ST7.cjs} +5 -3
- package/dist/{generator-CcOBN5vI.mjs → generator-BwknNejd.mjs} +5 -3
- package/dist/{handler-XX7cLTqe.cjs → handler-CDEoKARD.cjs} +2 -2
- package/dist/{handler-DzQae4eA.mjs → handler-D7UyZlPm.mjs} +2 -2
- package/dist/{image-Bz87fCla.js → image-B-NDSDuY.js} +129 -11
- package/dist/{image-C4TlpMHn.cjs → image-Hnaa2bJd.cjs} +175 -9
- package/dist/index-C56bL-A-.d.cts +1344 -0
- package/dist/{sidebar-COTaMHR-.d.ts → index-CPUUKzxD.d.cts} +344 -327
- package/dist/{sidebar-CrEdJuHX.d.cts → index-Ci4kfOHF.d.ts} +344 -327
- package/dist/index-Cu9H6CRa.d.ts +1344 -0
- package/dist/link-CgdI6O2o.js +872 -0
- package/dist/{link-D1Gjkb-2.cjs → link-vZjmD-es.cjs} +406 -223
- package/dist/{mdx-BuO6a1f7.js → mdx-BRT71V5Q.js} +211 -168
- package/dist/{mdx-CD-tSjRG.cjs → mdx-D0Absdq5.cjs} +225 -169
- package/dist/native-BNCY7PRF.cjs +6 -0
- package/dist/native-Di9Fnfrv.mjs +6 -0
- package/dist/native-Kre2T5eS.cjs +6 -0
- package/dist/node/cache.cjs +1 -1
- package/dist/node/cache.d.cts +19 -3
- package/dist/node/cache.d.mts +19 -3
- package/dist/node/cache.mjs +1 -1
- package/dist/node/cli-entry.cjs +1 -9
- package/dist/node/cli-entry.mjs +1 -9
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +245 -17
- package/dist/node/index.d.mts +246 -18
- package/dist/node/index.mjs +1 -1
- package/dist/node/mdx/shiki-adapter.cjs +1 -1
- package/dist/node/mdx/shiki-adapter.d.cts +24 -3
- package/dist/node/mdx/shiki-adapter.d.mts +24 -2
- package/dist/node/mdx/shiki-adapter.mjs +1 -1
- package/dist/node-Du5UL5wo.mjs +23 -0
- package/dist/node-DunuGqyp.cjs +23 -0
- package/dist/{package-CCYEAYeA.mjs → package-DA848keM.mjs} +1 -1
- package/dist/package-wplzySjz.cjs +6 -0
- package/dist/pages-external-BBw8ObVK.mjs +6 -0
- package/dist/pages-external-DPiPFxxP.cjs +6 -0
- package/dist/parser-BqTOsEUa.cjs +6 -0
- package/dist/parser-CGMY2lJ7.mjs +6 -0
- package/dist/plugin-BcTzvHAJ.mjs +69 -0
- package/dist/plugin-TulVMt1z.cjs +69 -0
- package/dist/plugin-context-C-l90hFt.cjs +15 -0
- package/dist/plugin-context-wqHNSZum.mjs +15 -0
- package/dist/plugin-lifecycle-B1BzSHdn.cjs +6 -0
- package/dist/resolve-B7vWOd8R.cjs +6 -0
- package/dist/resolve-C2kKnk_5.mjs +6 -0
- package/dist/resolve-It1Iug83.cjs +6 -0
- package/dist/resolve-YdTrt_FG.mjs +6 -0
- package/dist/router-C3kygdRK.cjs +1285 -0
- package/dist/router-CZBxMRAH.js +987 -0
- package/dist/routes-BL4y79tb.mjs +6 -0
- package/dist/routes-C2nPecwu.cjs +6 -0
- package/dist/routes-U9L8psZ9.cjs +6 -0
- package/dist/{search-dialog-DHqwjJuG.cjs → search-dialog-BCOHQGSt.cjs} +1 -1
- package/dist/search-dialog-Bp_P1MPP.js +481 -0
- package/dist/{search-dialog-DFnlx8LO.js → search-dialog-BqkzDTq2.js} +107 -57
- package/dist/{search-dialog-BRFno7HD.cjs → search-dialog-CIeIUhAn.cjs} +218 -43
- package/dist/{search-dialog-D6TvjcuV.js → search-dialog-DtmxmfEu.js} +1 -1
- package/dist/{search-dialog-B1NERUNx.cjs → search-dialog-x_qHU8ty.cjs} +107 -58
- package/dist/server/index.cjs +1 -1
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.mjs +1 -1
- package/dist/update-check-BKqmYfwT.cjs +11 -0
- package/dist/update-check-QnrVR3q1.mjs +11 -0
- package/dist/utils-8lzafE49.mjs +7 -0
- package/dist/utils-ej6_SjIZ.cjs +7 -0
- package/dist/virtual-modules-Ca5tHk1X.cjs +30 -0
- package/dist/virtual-modules-Dlgt1fP0.mjs +30 -0
- package/package.json +18 -16
- package/src/shared/mdx-path.ts +12 -0
- package/src/shared/structured-data.ts +145 -0
- package/src/shared/types.ts +220 -16
- package/dist/banner-BMop1KLF.d.ts +0 -100
- package/dist/banner-CVD0GugR.d.cts +0 -100
- package/dist/cache-CO4Dy2uQ.cjs +0 -6
- package/dist/cache-Dk53iOo6.mjs +0 -6
- package/dist/config-CCXp3aXO.mjs +0 -7
- package/dist/config-CMd4XoFq.cjs +0 -6
- package/dist/config-DlGoEM9D.cjs +0 -7
- package/dist/csp-CRp_3U7a.cjs +0 -6
- package/dist/csp-oTC2ygvF.mjs +0 -6
- package/dist/doctor-Bv16QSrI.cjs +0 -7
- package/dist/doctor-DOAbSaiL.mjs +0 -7
- package/dist/headers-Ddwek8K7.mjs +0 -6
- package/dist/headers-dg4SDrjY.cjs +0 -6
- package/dist/link-2PzgTnaP.js +0 -673
- package/dist/meta-loader-C4Hu9RN9.mjs +0 -6
- package/dist/meta-loader-Dq1zcFnh.cjs +0 -6
- package/dist/node-BXtqM1uH.mjs +0 -6
- package/dist/node-BlVk4EVg.cjs +0 -104
- package/dist/node-DOf4zhWc.mjs +0 -104
- package/dist/node-aD1eisrR.cjs +0 -6
- package/dist/pages-external-BYa4JSda.mjs +0 -6
- package/dist/pages-external-XkYIs-d5.cjs +0 -6
- package/dist/parser-DCiEWkSk.cjs +0 -8
- package/dist/parser-qk9FIHJ7.mjs +0 -8
- package/dist/plugin-C95kvu6h.mjs +0 -73
- package/dist/plugin-DM3u2bVj.cjs +0 -73
- package/dist/routes-BW6zsk7Z.mjs +0 -6
- package/dist/routes-BgoIB5wb.cjs +0 -6
- package/dist/routes-CORVxc02.cjs +0 -6
- package/dist/search-dialog-BmxHiKwt.js +0 -312
- package/dist/shiki-adapter-CoQ6jyJ4.cjs +0 -6
- package/dist/shiki-adapter-D-aKw7PP.mjs +0 -6
- package/dist/utils-Crm9oPcV.mjs +0 -7
- package/dist/utils-D6Xtj0FZ.cjs +0 -7
- /package/dist/{errors-0zGHRLue.mjs → errors-N-b6Sn2G.mjs} +0 -0
- /package/dist/{index-1KsTDq4o.d.mts → index-lFoyzCXy.d.mts} +0 -0
- /package/dist/{types-generator-BXhv7Ill.cjs → types-generator-DDSA93P3.cjs} +0 -0
- /package/dist/{types-generator-bDPvUztF.mjs → types-generator-DG1GX1EZ.mjs} +0 -0
package/dist/client/index.js
CHANGED
|
@@ -3,21 +3,19 @@
|
|
|
3
3
|
* Copyright (c) 2026 Jesus Alcala
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
import { A as
|
|
7
|
-
import { c as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { n as useSearch, r as InternalErrorBoundary, t as SearchDialog } from "../search-dialog-
|
|
6
|
+
import { A as Languages, B as TextAlignStart, C as FaceBad, F as Moon, K as BoltdocsProvider, L as Pencil, N as Menu, O as Home, P as Monitor, S as ExternalLink, T as FaceRegular, U as ConfigContext, V as X, W as useConfig, _ as ChevronLeft, a as useViewTransition, b as Copy, c as RoutesProvider, d as resolvePublicAssetUrl, g as ChevronDown, h as Check, i as startViewTransition, m as ArrowLeft, o as cn, q as useBoltdocsContext, s as useLocalizedTo, t as Link, u as normalizePath, v as ChevronRight, w as FaceGood, y as CircleHelp, z as Sun } from "../link-CgdI6O2o.js";
|
|
7
|
+
import { A as useRouteData, B as normalizeBasename, C as Outlet, D as useMatches, E as useLocation, F as PrefetchContext, I as RouteDataContext, L as defaultNavigate, M as LocationProvider, N as MatchesContext, O as useNavigate, P as NavigateContext, R as addBasename, S as resolveRouteBranch, T as useLoaderData, V as stripBasename, _ as stripSiteProtocol, a as getConfiguredVersions, b as matchRouteBranch, c as hasUriScheme, d as isConfiguredVersion, f as normalizeUrlBase, g as splitUrlReference, h as resolveUrlReference, i as getConfiguredLocales, j as LocationContext, k as usePrefetch, l as hasUrlBase, m as parseUrlReference, n as buildUrl, o as getVersionPrefixSegments, p as normalizeUrlPath, r as classifyUrlPath, s as getVersionSegments, t as addUrlBase, u as isConfiguredLocale, v as stripUrlBase, w as OutletContext, x as matchRouteBranchWithParams, y as RouteRenderer, z as hasBasename } from "../router-CZBxMRAH.js";
|
|
8
|
+
import { _ as useTheme, g as ThemeProvider } from "../image-B-NDSDuY.js";
|
|
9
|
+
import { a as useCopyButton, i as useExpandable, n as Timeline, o as copyToClipboard, r as useCodeBlockFeedback, t as mdx_components_default } from "../mdx-BRT71V5Q.js";
|
|
10
|
+
import { A as UIProvider, C as IconRenderer, E as Menu$1, O as ButtonGroup, S as useSidebar, T as Tabs$1, f as PageNav$1, j as useUI, k as Breadcrumbs$2, m as OnThisPage$1, n as Sidebar$1, t as DocsLayout$1, w as resolveIcon, x as useSearchHighlight } from "../docs-layout-CbZ7LDRe.js";
|
|
11
|
+
import { i as useRoutes, n as useSearch, r as InternalErrorBoundary, t as SearchDialog } from "../search-dialog-Bp_P1MPP.js";
|
|
12
|
+
import { i as ErrorBoundary$1, n as Navbar$1, o as Button$1, r as Github } from "../search-dialog-BqkzDTq2.js";
|
|
12
13
|
import { ViteReactSSG } from "@bdocs/ssg";
|
|
13
|
-
import { Suspense, createContext, isValidElement, lazy, use, useCallback, useEffect,
|
|
14
|
-
import {
|
|
15
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
import { Suspense, createContext, isValidElement, lazy, use, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
15
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
16
16
|
import { Button } from "react-aria-components";
|
|
17
17
|
import * as ReactHelmetAsync from "react-helmet-async";
|
|
18
18
|
import virtualCustomComponents from "virtual:boltdocs-mdx-components";
|
|
19
|
-
import virtualIcons from "virtual:boltdocs-icons";
|
|
20
|
-
import DOMPurify from "isomorphic-dompurify";
|
|
21
19
|
import UserLayout from "virtual:boltdocs-layout";
|
|
22
20
|
|
|
23
21
|
//#region src/client/app/mdx-components-context.tsx
|
|
@@ -52,12 +50,13 @@ function MdxComponentsProvider({ components, children }) {
|
|
|
52
50
|
//#endregion
|
|
53
51
|
//#region src/client/app/scroll-handler.tsx
|
|
54
52
|
/**
|
|
55
|
-
* Handles scroll restoration
|
|
56
|
-
*
|
|
57
|
-
*
|
|
53
|
+
* Handles scroll restoration after navigation.
|
|
54
|
+
*
|
|
55
|
+
* Normal page navigation returns the active content container to the top
|
|
56
|
+
* instantly. Explicit hash navigation is positioned at its anchor instead.
|
|
58
57
|
*/
|
|
59
58
|
function ScrollHandler() {
|
|
60
|
-
const { pathname, hash } = useLocation
|
|
59
|
+
const { pathname, hash } = useLocation();
|
|
61
60
|
const handleScroll = (behavior = "auto") => {
|
|
62
61
|
const container = document.querySelector(".boltdocs-content") || document.querySelector(".boltdocs-external-content") || document.querySelector(".boltdocs-shell-content") || window;
|
|
63
62
|
const getScrollTop = () => {
|
|
@@ -75,7 +74,10 @@ function ScrollHandler() {
|
|
|
75
74
|
});
|
|
76
75
|
};
|
|
77
76
|
if (hash) {
|
|
78
|
-
|
|
77
|
+
let id = hash.slice(1);
|
|
78
|
+
try {
|
|
79
|
+
id = decodeURIComponent(id);
|
|
80
|
+
} catch {}
|
|
79
81
|
const element = document.getElementById(id);
|
|
80
82
|
if (element) {
|
|
81
83
|
const offset = 80;
|
|
@@ -84,23 +86,43 @@ function ScrollHandler() {
|
|
|
84
86
|
return true;
|
|
85
87
|
}
|
|
86
88
|
}
|
|
87
|
-
|
|
89
|
+
if (container === window) {
|
|
90
|
+
document.documentElement.scrollTop = 0;
|
|
91
|
+
document.body.scrollTop = 0;
|
|
92
|
+
} else container.scrollTop = 0;
|
|
88
93
|
return false;
|
|
89
94
|
};
|
|
90
|
-
useLayoutEffect(() => {
|
|
91
|
-
handleScroll("auto");
|
|
92
|
-
}, [pathname, hash]);
|
|
93
95
|
useEffect(() => {
|
|
94
|
-
|
|
96
|
+
const handleRouteCommit = (event) => {
|
|
97
|
+
const detail = event.detail;
|
|
98
|
+
if (detail?.pathname && detail.pathname !== pathname) return;
|
|
99
|
+
if (detail?.hash !== void 0 && detail.hash !== hash) return;
|
|
100
|
+
handleScroll("auto");
|
|
101
|
+
};
|
|
102
|
+
window.addEventListener("boltdocs:route-commit", handleRouteCommit);
|
|
103
|
+
let frame = 0;
|
|
104
|
+
if (hash) {
|
|
105
|
+
let attempts = 0;
|
|
106
|
+
const retry = () => {
|
|
107
|
+
if (handleScroll("auto") || attempts >= 8) return;
|
|
108
|
+
attempts++;
|
|
109
|
+
frame = requestAnimationFrame(retry);
|
|
110
|
+
};
|
|
111
|
+
frame = requestAnimationFrame(retry);
|
|
112
|
+
}
|
|
113
|
+
return () => {
|
|
114
|
+
window.removeEventListener("boltdocs:route-commit", handleRouteCommit);
|
|
115
|
+
if (frame) cancelAnimationFrame(frame);
|
|
116
|
+
};
|
|
95
117
|
}, [pathname, hash]);
|
|
96
118
|
return null;
|
|
97
119
|
}
|
|
98
120
|
|
|
99
121
|
//#endregion
|
|
100
122
|
//#region src/client/components/ui-base/not-found.tsx
|
|
101
|
-
function NotFound() {
|
|
123
|
+
function NotFound({ className }) {
|
|
102
124
|
return /* @__PURE__ */ jsx("div", {
|
|
103
|
-
className: "flex items-center justify-center min-h-[65vh] text-center px-4",
|
|
125
|
+
className: cn("flex items-center justify-center min-h-[65vh] text-center px-4", className),
|
|
104
126
|
children: /* @__PURE__ */ jsxs("div", {
|
|
105
127
|
className: "space-y-6 max-w-md mx-auto p-8 border border-subtle bg-surface rounded-2xl shadow-xs",
|
|
106
128
|
children: [
|
|
@@ -118,7 +140,7 @@ function NotFound() {
|
|
|
118
140
|
children: "The page you're looking for doesn't exist or has been moved."
|
|
119
141
|
})]
|
|
120
142
|
}),
|
|
121
|
-
/* @__PURE__ */ jsxs(Link
|
|
143
|
+
/* @__PURE__ */ jsxs(Link, {
|
|
122
144
|
href: "/",
|
|
123
145
|
className: "inline-flex items-center gap-2 rounded-xl border border-subtle bg-main px-6 py-2.5 text-xs font-semibold text-body hover:bg-primary-50/50 hover:border-primary-500/50 transition-all duration-300 outline-none select-none",
|
|
124
146
|
children: [/* @__PURE__ */ jsx(ArrowLeft, { size: 14 }), " Go to Home"]
|
|
@@ -143,15 +165,14 @@ const mod = ReactHelmetAsync;
|
|
|
143
165
|
* The `<Helmet>` component, resolved across CJS/ESM module shapes.
|
|
144
166
|
* Falls back to a transparent fragment wrapper if the module cannot be resolved.
|
|
145
167
|
*/
|
|
146
|
-
const Helmet = mod.Helmet || mod.default?.Helmet || (({ children }) => /* @__PURE__ */ jsx(Fragment, { children }));
|
|
168
|
+
const Helmet = mod.Helmet || mod.default?.Helmet || (({ children }) => /* @__PURE__ */ jsx(Fragment$1, { children }));
|
|
147
169
|
/**
|
|
148
170
|
* The `<HelmetProvider>` component, resolved across CJS/ESM module shapes.
|
|
149
171
|
* Falls back to a transparent fragment wrapper if the module cannot be resolved.
|
|
150
172
|
*/
|
|
151
|
-
const HelmetProvider = mod.HelmetProvider || mod.default?.HelmetProvider || (({ children }) => /* @__PURE__ */ jsx(Fragment, { children }));
|
|
173
|
+
const HelmetProvider = mod.HelmetProvider || mod.default?.HelmetProvider || (({ children }) => /* @__PURE__ */ jsx(Fragment$1, { children }));
|
|
152
174
|
if (typeof globalThis !== "undefined" && globalThis.__BOLTDOCS_SSG_RENDERING__) {
|
|
153
|
-
|
|
154
|
-
if (hp && typeof hp === "function" && hp.canUseDOM) hp.canUseDOM = false;
|
|
175
|
+
if (typeof HelmetProvider === "function" && HelmetProvider.canUseDOM) HelmetProvider.canUseDOM = false;
|
|
155
176
|
}
|
|
156
177
|
if (typeof globalThis !== "undefined") {
|
|
157
178
|
globalThis.__BOLTDOCS_HELMET_PROVIDER__ = HelmetProvider;
|
|
@@ -175,16 +196,120 @@ function getTranslated(value, locale) {
|
|
|
175
196
|
return Object.values(value)[0] || "";
|
|
176
197
|
}
|
|
177
198
|
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region src/shared/structured-data.ts
|
|
201
|
+
/** Preserve literal JSON-LD types in config files and frontmatter helpers. */
|
|
202
|
+
function defineStructuredData(data) {
|
|
203
|
+
return data;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Creates one JSON-LD value from the common website/article/breadcrumb presets.
|
|
207
|
+
* Single-node input returns an object; multiple nodes return a graph array.
|
|
208
|
+
*/
|
|
209
|
+
function createStructuredData(options) {
|
|
210
|
+
const nodes = [];
|
|
211
|
+
if (options.website) nodes.push(createWebSiteStructuredData(options.website));
|
|
212
|
+
if (options.article) nodes.push(createArticleStructuredData(options.article));
|
|
213
|
+
if (options.breadcrumbs?.length) nodes.push(createBreadcrumbStructuredData(options.breadcrumbs));
|
|
214
|
+
if (options.additional) nodes.push(...Array.isArray(options.additional) ? options.additional : [options.additional]);
|
|
215
|
+
if (nodes.length === 0) throw new Error("createStructuredData() requires at least one of website, article, breadcrumbs, or additional");
|
|
216
|
+
return nodes.length === 1 ? nodes[0] : nodes;
|
|
217
|
+
}
|
|
218
|
+
function createWebSiteStructuredData(options) {
|
|
219
|
+
const data = {
|
|
220
|
+
"@context": "https://schema.org",
|
|
221
|
+
"@type": "WebSite",
|
|
222
|
+
name: options.name,
|
|
223
|
+
url: options.url
|
|
224
|
+
};
|
|
225
|
+
if (options.description) data.description = options.description;
|
|
226
|
+
if (options.searchUrl) data.potentialAction = {
|
|
227
|
+
"@type": "SearchAction",
|
|
228
|
+
target: `${options.searchUrl}{search_term_string}`,
|
|
229
|
+
"query-input": "required name=search_term_string"
|
|
230
|
+
};
|
|
231
|
+
return data;
|
|
232
|
+
}
|
|
233
|
+
function toIsoDate(value, field) {
|
|
234
|
+
const date = new Date(value);
|
|
235
|
+
if (Number.isNaN(date.getTime())) throw new TypeError(`Invalid ${field} value: ${String(value)}`);
|
|
236
|
+
return date.toISOString();
|
|
237
|
+
}
|
|
238
|
+
function createArticleStructuredData(options) {
|
|
239
|
+
const data = {
|
|
240
|
+
"@context": "https://schema.org",
|
|
241
|
+
"@type": "Article",
|
|
242
|
+
headline: options.headline,
|
|
243
|
+
url: options.url
|
|
244
|
+
};
|
|
245
|
+
if (options.description) data.description = options.description;
|
|
246
|
+
if (options.datePublished) data.datePublished = toIsoDate(options.datePublished, "datePublished");
|
|
247
|
+
if (options.dateModified) data.dateModified = toIsoDate(options.dateModified, "dateModified");
|
|
248
|
+
if (options.image) data.image = options.image;
|
|
249
|
+
if (options.author) data.author = typeof options.author === "string" ? {
|
|
250
|
+
"@type": "Person",
|
|
251
|
+
name: options.author
|
|
252
|
+
} : {
|
|
253
|
+
"@type": "Person",
|
|
254
|
+
...options.author
|
|
255
|
+
};
|
|
256
|
+
return data;
|
|
257
|
+
}
|
|
258
|
+
function createBreadcrumbStructuredData(items) {
|
|
259
|
+
return {
|
|
260
|
+
"@context": "https://schema.org",
|
|
261
|
+
"@type": "BreadcrumbList",
|
|
262
|
+
itemListElement: items.map((item, index) => ({
|
|
263
|
+
"@type": "ListItem",
|
|
264
|
+
position: index + 1,
|
|
265
|
+
name: item.name,
|
|
266
|
+
item: item.url
|
|
267
|
+
}))
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
//#endregion
|
|
272
|
+
//#region src/client/components/structured-data.tsx
|
|
273
|
+
/**
|
|
274
|
+
* Renders safe, valid JSON-LD. Escaping `<` prevents a JSON value from closing
|
|
275
|
+
* the surrounding script tag when the document is rendered server-side.
|
|
276
|
+
*/
|
|
277
|
+
function StructuredData({ data, id }) {
|
|
278
|
+
return /* @__PURE__ */ jsx("script", {
|
|
279
|
+
id,
|
|
280
|
+
type: "application/ld+json",
|
|
281
|
+
dangerouslySetInnerHTML: { __html: JSON.stringify(data).replace(/</g, "\\u003c") }
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
178
285
|
//#endregion
|
|
179
286
|
//#region src/client/app/head.tsx
|
|
287
|
+
function stringifyMetaValue(value) {
|
|
288
|
+
if (value == null) return "";
|
|
289
|
+
if (typeof value === "string") return value;
|
|
290
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
291
|
+
if (Array.isArray(value)) return value.map(stringifyMetaValue).join(", ");
|
|
292
|
+
if (typeof value === "object") {
|
|
293
|
+
const record = value;
|
|
294
|
+
const namedValue = record.name ?? record.value ?? record.url;
|
|
295
|
+
if (namedValue !== void 0) return stringifyMetaValue(namedValue);
|
|
296
|
+
try {
|
|
297
|
+
return JSON.stringify(value);
|
|
298
|
+
} catch {
|
|
299
|
+
return "";
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return String(value);
|
|
303
|
+
}
|
|
180
304
|
function Head({ siteTitle, siteDescription, routes }) {
|
|
181
|
-
const location = useLocation
|
|
305
|
+
const location = useLocation();
|
|
182
306
|
const config = useConfig();
|
|
183
307
|
const { currentLocale, currentRoute } = useRoutes();
|
|
184
308
|
const route = useMemo(() => {
|
|
185
309
|
if (currentRoute) return currentRoute;
|
|
186
310
|
const normalizedPath = location.pathname.endsWith("/") && location.pathname.length > 1 ? location.pathname.slice(0, -1) : location.pathname;
|
|
187
311
|
return routes?.find?.((r) => {
|
|
312
|
+
if (!r?.path) return false;
|
|
188
313
|
return (r.path.endsWith("/") && r.path.length > 1 ? r.path.slice(0, -1) : r.path) === normalizedPath;
|
|
189
314
|
});
|
|
190
315
|
}, [
|
|
@@ -198,18 +323,23 @@ function Head({ siteTitle, siteDescription, routes }) {
|
|
|
198
323
|
const translatedSiteTitle = getTranslated(siteTitle, currentLocale);
|
|
199
324
|
const finalTitle = pageTitle ? `${pageTitle} | ${translatedSiteTitle}` : translatedSiteTitle;
|
|
200
325
|
const seo = route?.seo || {};
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
const
|
|
326
|
+
const structuredData = [...Array.isArray(config?.seo?.structuredData) ? config.seo.structuredData : config?.seo?.structuredData ? [config.seo.structuredData] : [], ...Array.isArray(seo.structuredData) ? seo.structuredData : seo.structuredData ? [seo.structuredData] : []];
|
|
327
|
+
const canonicalUrl = stringifyMetaValue(seo.canonical) || (config?.siteUrl && route?.path ? `${config.siteUrl.replace(/\/$/, "")}${route.path}` : void 0);
|
|
328
|
+
const ogUrl = stringifyMetaValue(seo["og:url"]) || canonicalUrl || (typeof window !== "undefined" ? window.location.href : void 0);
|
|
204
329
|
const defaultOgImage = config?.seo?.thumbnails?.background;
|
|
205
|
-
let ogImage = seo["og:image"] || route?.coverImage || defaultOgImage;
|
|
206
|
-
if (ogImage &&
|
|
330
|
+
let ogImage = stringifyMetaValue(seo["og:image"]) || route?.coverImage || defaultOgImage;
|
|
331
|
+
if (ogImage && !/^https?:\/\/|^\/\//.test(ogImage)) {
|
|
332
|
+
const assetPath = resolvePublicAssetUrl(ogImage.startsWith("/") ? ogImage : `/${ogImage}`, config.base);
|
|
333
|
+
if (config?.siteUrl) ogImage = `${config.siteUrl.replace(/\/$/, "")}${assetPath}`;
|
|
334
|
+
else ogImage = assetPath;
|
|
335
|
+
}
|
|
207
336
|
return /* @__PURE__ */ jsxs(Helmet, { children: [
|
|
208
337
|
/* @__PURE__ */ jsx("title", { children: finalTitle }),
|
|
209
338
|
/* @__PURE__ */ jsx("meta", {
|
|
210
339
|
name: "description",
|
|
211
340
|
content: pageDescription
|
|
212
341
|
}),
|
|
342
|
+
structuredData.map((data) => /* @__PURE__ */ jsx(StructuredData, { data }, JSON.stringify(data))),
|
|
213
343
|
/* @__PURE__ */ jsx("meta", {
|
|
214
344
|
property: "og:title",
|
|
215
345
|
content: finalTitle
|
|
@@ -250,41 +380,6 @@ function Head({ siteTitle, siteDescription, routes }) {
|
|
|
250
380
|
property: "og:image",
|
|
251
381
|
content: ogImage
|
|
252
382
|
}),
|
|
253
|
-
/* @__PURE__ */ jsx("meta", {
|
|
254
|
-
name: "generator",
|
|
255
|
-
content: "Boltdocs"
|
|
256
|
-
}),
|
|
257
|
-
config?.seo?.verification?.google && /* @__PURE__ */ jsx("meta", {
|
|
258
|
-
name: "google-site-verification",
|
|
259
|
-
content: config.seo.verification.google
|
|
260
|
-
}),
|
|
261
|
-
config?.seo?.verification?.bing && /* @__PURE__ */ jsx("meta", {
|
|
262
|
-
name: "msvalidate.01",
|
|
263
|
-
content: config.seo.verification.bing
|
|
264
|
-
}),
|
|
265
|
-
config?.seo?.verification?.yandex && /* @__PURE__ */ jsx("meta", {
|
|
266
|
-
name: "yandex-verification",
|
|
267
|
-
content: config.seo.verification.yandex
|
|
268
|
-
}),
|
|
269
|
-
config?.seo?.verification?.pinterest && /* @__PURE__ */ jsx("meta", {
|
|
270
|
-
name: "p:domain_verify",
|
|
271
|
-
content: config.seo.verification.pinterest
|
|
272
|
-
}),
|
|
273
|
-
config?.seo?.verification?.facebook && /* @__PURE__ */ jsx("meta", {
|
|
274
|
-
name: "facebook-domain-verification",
|
|
275
|
-
content: config.seo.verification.facebook
|
|
276
|
-
}),
|
|
277
|
-
Object.entries(globalMetatags).map(([key, value]) => {
|
|
278
|
-
const isProperty = key.startsWith("og:") || key.startsWith("music:") || key.startsWith("video:") || key.startsWith("article:") || key.startsWith("book:") || key.startsWith("profile:");
|
|
279
|
-
const strVal = String(value ?? "");
|
|
280
|
-
return isProperty ? /* @__PURE__ */ jsx("meta", {
|
|
281
|
-
property: key,
|
|
282
|
-
content: strVal
|
|
283
|
-
}, key) : /* @__PURE__ */ jsx("meta", {
|
|
284
|
-
name: key,
|
|
285
|
-
content: strVal
|
|
286
|
-
}, key);
|
|
287
|
-
}),
|
|
288
383
|
Object.entries(seo).map(([key, value]) => {
|
|
289
384
|
if (key === "noindex" && value === true) return /* @__PURE__ */ jsx("meta", {
|
|
290
385
|
name: "robots",
|
|
@@ -292,11 +387,11 @@ function Head({ siteTitle, siteDescription, routes }) {
|
|
|
292
387
|
}, "noindex");
|
|
293
388
|
if (key === "robots") return /* @__PURE__ */ jsx("meta", {
|
|
294
389
|
name: "robots",
|
|
295
|
-
content:
|
|
390
|
+
content: stringifyMetaValue(value)
|
|
296
391
|
}, "robots");
|
|
297
|
-
if (key === "canonical" || key === "og:url" || key === "og:image" || key === "twitter:image") return null;
|
|
392
|
+
if (key === "canonical" || key === "og:url" || key === "og:image" || key === "twitter:image" || key === "structuredData") return null;
|
|
298
393
|
const isProperty = key.startsWith("og:") || key.startsWith("music:") || key.startsWith("video:") || key.startsWith("article:") || key.startsWith("book:") || key.startsWith("profile:");
|
|
299
|
-
const strVal =
|
|
394
|
+
const strVal = stringifyMetaValue(value);
|
|
300
395
|
return isProperty ? /* @__PURE__ */ jsx("meta", {
|
|
301
396
|
property: key,
|
|
302
397
|
content: strVal
|
|
@@ -314,6 +409,35 @@ const CollectionsContext = createContext({});
|
|
|
314
409
|
function useCollectionsData() {
|
|
315
410
|
return use(CollectionsContext);
|
|
316
411
|
}
|
|
412
|
+
function CollectionsProvider({ collectionsData, children }) {
|
|
413
|
+
const [data, setData] = useState(collectionsData);
|
|
414
|
+
useEffect(() => {
|
|
415
|
+
if (!import.meta.hot) return;
|
|
416
|
+
const handler = (payload) => {
|
|
417
|
+
setData((prev) => {
|
|
418
|
+
const next = { ...prev };
|
|
419
|
+
for (const post of payload.collections.updated) {
|
|
420
|
+
const collection = post.collection;
|
|
421
|
+
if (!collection) continue;
|
|
422
|
+
const arr = next[collection] ? [...next[collection]] : [];
|
|
423
|
+
const idx = arr.findIndex((p) => p.filePath === post.filePath);
|
|
424
|
+
if (idx >= 0) arr[idx] = post;
|
|
425
|
+
else arr.push(post);
|
|
426
|
+
next[collection] = arr;
|
|
427
|
+
}
|
|
428
|
+
for (const filePath of payload.collections.deleted) for (const key of Object.keys(next)) next[key] = next[key].filter((p) => p.filePath !== filePath);
|
|
429
|
+
return next;
|
|
430
|
+
});
|
|
431
|
+
};
|
|
432
|
+
const hot = import.meta.hot;
|
|
433
|
+
hot.on("boltdocs:frontmatter-update", handler);
|
|
434
|
+
return () => hot.off?.("boltdocs:frontmatter-update", handler);
|
|
435
|
+
}, []);
|
|
436
|
+
return /* @__PURE__ */ jsx(CollectionsContext.Provider, {
|
|
437
|
+
value: data,
|
|
438
|
+
children
|
|
439
|
+
});
|
|
440
|
+
}
|
|
317
441
|
const CurrentPostContext = createContext(null);
|
|
318
442
|
function CurrentPostProvider({ value, children }) {
|
|
319
443
|
return /* @__PURE__ */ jsx(CurrentPostContext.Provider, {
|
|
@@ -332,41 +456,58 @@ function useCurrentPostData() {
|
|
|
332
456
|
*/
|
|
333
457
|
function I18nUpdater({ config }) {
|
|
334
458
|
const { currentLocale } = useBoltdocsContext();
|
|
459
|
+
const locale = currentLocale || config.i18n?.defaultLocale || "en";
|
|
460
|
+
const localeConfig = config.i18n?.localeConfigs?.[locale];
|
|
461
|
+
const htmlLang = localeConfig?.htmlLang || locale;
|
|
462
|
+
const direction = localeConfig?.direction || "ltr";
|
|
335
463
|
useEffect(() => {
|
|
336
464
|
if (!config.i18n || typeof document === "undefined") return;
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
465
|
+
document.documentElement.lang = htmlLang;
|
|
466
|
+
document.documentElement.dir = direction;
|
|
467
|
+
}, [
|
|
468
|
+
config.i18n,
|
|
469
|
+
direction,
|
|
470
|
+
htmlLang
|
|
471
|
+
]);
|
|
472
|
+
return /* @__PURE__ */ jsx(Helmet, { htmlAttributes: {
|
|
473
|
+
lang: htmlLang,
|
|
474
|
+
dir: direction
|
|
475
|
+
} });
|
|
343
476
|
}
|
|
344
477
|
function StoreSync({ config, routeMap }) {
|
|
345
|
-
const location = useLocation
|
|
346
|
-
const { setLocale, setVersion } = useBoltdocsContext();
|
|
478
|
+
const location = useLocation();
|
|
479
|
+
const { currentLocale, currentVersion, setLocale, setVersion } = useBoltdocsContext();
|
|
347
480
|
useEffect(() => {
|
|
348
|
-
const currentPath = normalizePath(location.pathname);
|
|
481
|
+
const currentPath = normalizePath(typeof window !== "undefined" ? window.location.pathname : location.pathname);
|
|
349
482
|
const matchedRoute = routeMap.get(currentPath);
|
|
350
483
|
if (matchedRoute) {
|
|
351
|
-
if (config.i18n)
|
|
352
|
-
|
|
353
|
-
|
|
484
|
+
if (config.i18n) {
|
|
485
|
+
const targetLocale = matchedRoute.locale || config.i18n.defaultLocale;
|
|
486
|
+
if (targetLocale !== currentLocale) setLocale(targetLocale);
|
|
487
|
+
}
|
|
488
|
+
if (config.versions) {
|
|
489
|
+
const targetVersion = matchedRoute.version || config.versions.defaultVersion;
|
|
490
|
+
if (targetVersion !== currentVersion) setVersion(targetVersion);
|
|
491
|
+
}
|
|
492
|
+
} else if (config.versions && currentVersion !== config.versions.defaultVersion) setVersion(config.versions.defaultVersion);
|
|
354
493
|
}, [
|
|
355
494
|
location.pathname,
|
|
356
495
|
config,
|
|
357
496
|
routeMap,
|
|
497
|
+
currentLocale,
|
|
498
|
+
currentVersion,
|
|
358
499
|
setLocale,
|
|
359
500
|
setVersion
|
|
360
501
|
]);
|
|
361
502
|
return null;
|
|
362
503
|
}
|
|
363
|
-
function BoltdocsShell({ config, routes, components = {}, collectionsData }) {
|
|
504
|
+
function BoltdocsShell({ config, routes, components = {}, collectionsData, contentClassName }) {
|
|
364
505
|
const allComponents = useMemo(() => ({
|
|
365
506
|
...mdxComponentsDefault,
|
|
366
507
|
...virtualCustomComponents,
|
|
367
508
|
...components
|
|
368
509
|
}), [components]);
|
|
369
|
-
const { pathname } = useLocation
|
|
510
|
+
const { pathname } = useLocation();
|
|
370
511
|
const currentPath = useMemo(() => normalizePath(pathname || "/"), [pathname]);
|
|
371
512
|
const routeMap = useMemo(() => {
|
|
372
513
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -399,8 +540,8 @@ function BoltdocsShell({ config, routes, components = {}, collectionsData }) {
|
|
|
399
540
|
components: allComponents,
|
|
400
541
|
children: /* @__PURE__ */ jsx(ConfigContext.Provider, {
|
|
401
542
|
value: config,
|
|
402
|
-
children: /* @__PURE__ */ jsxs(
|
|
403
|
-
|
|
543
|
+
children: /* @__PURE__ */ jsxs(CollectionsProvider, {
|
|
544
|
+
collectionsData: collectionsData || {},
|
|
404
545
|
children: [/* @__PURE__ */ jsx(ScrollHandler, {}), /* @__PURE__ */ jsxs(BoltdocsProvider, {
|
|
405
546
|
initialLocale: initialData.initLocale,
|
|
406
547
|
initialVersion: initialData.initVersion,
|
|
@@ -416,7 +557,7 @@ function BoltdocsShell({ config, routes, components = {}, collectionsData }) {
|
|
|
416
557
|
routes
|
|
417
558
|
}),
|
|
418
559
|
/* @__PURE__ */ jsx(InternalErrorBoundary, { children: /* @__PURE__ */ jsx("div", {
|
|
419
|
-
className: "boltdocs-shell-content h-screen overflow-hidden",
|
|
560
|
+
className: cn("boltdocs-shell-content h-screen overflow-hidden", contentClassName),
|
|
420
561
|
children: /* @__PURE__ */ jsx(Outlet, {})
|
|
421
562
|
}) })
|
|
422
563
|
]
|
|
@@ -461,7 +602,7 @@ function DocPage({ route, content: Content, mdxComponents: propComponents }) {
|
|
|
461
602
|
const allComponents = useMergedComponents(propComponents);
|
|
462
603
|
const { LastUpdated } = allComponents;
|
|
463
604
|
if (!Content) return null;
|
|
464
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Content, { components: allComponents }), route?.lastUpdated && /* @__PURE__ */ jsx(LastUpdated, { date: route.lastUpdated })] });
|
|
605
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Content, { components: allComponents }), route?.lastUpdated && /* @__PURE__ */ jsx(LastUpdated, { date: route.lastUpdated })] });
|
|
465
606
|
}
|
|
466
607
|
|
|
467
608
|
//#endregion
|
|
@@ -476,26 +617,30 @@ function DocPage({ route, content: Content, mdxComponents: propComponents }) {
|
|
|
476
617
|
*/
|
|
477
618
|
function MdxPage({ MDXComponent, mdxComponents: propComponents, collectionPostComponent: CollectionPost }) {
|
|
478
619
|
const data = useLoaderData();
|
|
620
|
+
const mdxComponents = {
|
|
621
|
+
...useMdxComponents(),
|
|
622
|
+
...propComponents
|
|
623
|
+
};
|
|
479
624
|
if (!MDXComponent) return null;
|
|
480
|
-
const collectionData = data;
|
|
481
|
-
if (!!collectionData?.collection) {
|
|
625
|
+
const collectionData = data || {};
|
|
626
|
+
if (!!collectionData?.collection && !!collectionData?.route) {
|
|
482
627
|
const postElement = CollectionPost ? /* @__PURE__ */ jsx(CollectionPost, {
|
|
483
628
|
MDXComponent,
|
|
484
|
-
mdxComponents
|
|
629
|
+
mdxComponents
|
|
485
630
|
}) : /* @__PURE__ */ jsx(DocPage, {
|
|
486
631
|
route: {
|
|
487
|
-
path: collectionData.route
|
|
488
|
-
filePath: collectionData.route
|
|
489
|
-
title: collectionData.route
|
|
490
|
-
description: collectionData.route
|
|
491
|
-
headings: collectionData.headings,
|
|
492
|
-
locale: collectionData.route
|
|
493
|
-
version: collectionData.route
|
|
494
|
-
lastUpdated: collectionData.route
|
|
495
|
-
frontmatter: collectionData.route
|
|
632
|
+
path: collectionData.route?.path || "",
|
|
633
|
+
filePath: collectionData.route?.filePath || "",
|
|
634
|
+
title: collectionData.route?.title,
|
|
635
|
+
description: collectionData.route?.description,
|
|
636
|
+
headings: collectionData.headings || [],
|
|
637
|
+
locale: collectionData.route?.locale,
|
|
638
|
+
version: collectionData.route?.version,
|
|
639
|
+
lastUpdated: collectionData.route?.lastUpdated,
|
|
640
|
+
frontmatter: collectionData.route?.frontmatter
|
|
496
641
|
},
|
|
497
642
|
content: MDXComponent,
|
|
498
|
-
mdxComponents
|
|
643
|
+
mdxComponents
|
|
499
644
|
});
|
|
500
645
|
return /* @__PURE__ */ jsx(CurrentPostProvider, {
|
|
501
646
|
value: {
|
|
@@ -506,23 +651,23 @@ function MdxPage({ MDXComponent, mdxComponents: propComponents, collectionPostCo
|
|
|
506
651
|
children: postElement
|
|
507
652
|
});
|
|
508
653
|
}
|
|
509
|
-
const docData = data;
|
|
654
|
+
const docData = data || {};
|
|
510
655
|
return /* @__PURE__ */ jsx(DocPage, {
|
|
511
656
|
route: {
|
|
512
|
-
path: docData
|
|
513
|
-
filePath: docData
|
|
514
|
-
title: docData
|
|
515
|
-
description: docData
|
|
516
|
-
headings: docData
|
|
517
|
-
locale: docData
|
|
518
|
-
version: docData
|
|
519
|
-
group: docData
|
|
520
|
-
groupTitle: docData
|
|
521
|
-
lastUpdated: docData
|
|
522
|
-
frontmatter: docData
|
|
657
|
+
path: docData?.path || "",
|
|
658
|
+
filePath: docData?.filePath || "",
|
|
659
|
+
title: docData?.frontmatter?.title,
|
|
660
|
+
description: docData?.frontmatter?.description,
|
|
661
|
+
headings: docData?.headings || [],
|
|
662
|
+
locale: docData?.locale,
|
|
663
|
+
version: docData?.version,
|
|
664
|
+
group: docData?.group,
|
|
665
|
+
groupTitle: docData?.groupTitle,
|
|
666
|
+
lastUpdated: docData?.lastUpdated,
|
|
667
|
+
frontmatter: docData?.frontmatter
|
|
523
668
|
},
|
|
524
669
|
content: MDXComponent,
|
|
525
|
-
mdxComponents
|
|
670
|
+
mdxComponents
|
|
526
671
|
});
|
|
527
672
|
}
|
|
528
673
|
|
|
@@ -549,11 +694,11 @@ function useBreadcrumbs() {
|
|
|
549
694
|
|
|
550
695
|
//#endregion
|
|
551
696
|
//#region src/client/components/ui-base/breadcrumbs.tsx
|
|
552
|
-
function Breadcrumbs() {
|
|
697
|
+
function Breadcrumbs({ className }) {
|
|
553
698
|
const { crumbs, activeRoute } = useBreadcrumbs();
|
|
554
699
|
if (crumbs.length === 0) return null;
|
|
555
700
|
return /* @__PURE__ */ jsxs(Breadcrumbs$2.Root, {
|
|
556
|
-
className: "gap-2 text-xs sm:text-sm font-medium",
|
|
701
|
+
className: cn("gap-2 text-xs sm:text-sm font-medium", className),
|
|
557
702
|
children: [/* @__PURE__ */ jsx(Breadcrumbs$2.Item, { children: /* @__PURE__ */ jsx(Breadcrumbs$2.Link, {
|
|
558
703
|
href: "/",
|
|
559
704
|
className: "text-muted hover:text-body transition-colors flex items-center",
|
|
@@ -602,12 +747,12 @@ const useCopyMarkdown = (content) => {
|
|
|
602
747
|
handleOpenRaw
|
|
603
748
|
};
|
|
604
749
|
};
|
|
605
|
-
function CopyMarkdown({ content, mdxRaw }) {
|
|
750
|
+
function CopyMarkdown({ content, mdxRaw, className }) {
|
|
606
751
|
const displayContent = mdxRaw || content || "";
|
|
607
752
|
const { copied, handleCopy, handleOpenRaw } = useCopyMarkdown(displayContent);
|
|
608
753
|
if (!displayContent) return null;
|
|
609
754
|
return /* @__PURE__ */ jsx("div", {
|
|
610
|
-
className: "relative inline-flex z-100 shrink-0 w-max",
|
|
755
|
+
className: cn("relative inline-flex z-100 shrink-0 w-max", className),
|
|
611
756
|
children: /* @__PURE__ */ jsxs(ButtonGroup, {
|
|
612
757
|
className: "rounded-xl border border-subtle bg-surface transition-all duration-300 hover:border-primary-500/50 group overflow-hidden",
|
|
613
758
|
children: [
|
|
@@ -699,7 +844,7 @@ const formatStars = (count) => {
|
|
|
699
844
|
|
|
700
845
|
//#endregion
|
|
701
846
|
//#region src/client/components/ui-base/github-stars.tsx
|
|
702
|
-
function GithubStars({ repo }) {
|
|
847
|
+
function GithubStars({ repo, className }) {
|
|
703
848
|
const [stars, setStars] = useState(null);
|
|
704
849
|
useEffect(() => {
|
|
705
850
|
if (repo) getStarsRepo(repo).then((stars) => setStars(stars)).catch(() => setStars("0"));
|
|
@@ -708,7 +853,7 @@ function GithubStars({ repo }) {
|
|
|
708
853
|
href: `https://github.com/${repo}`,
|
|
709
854
|
target: "_blank",
|
|
710
855
|
rel: "noopener noreferrer",
|
|
711
|
-
className: "inline-flex items-center gap-2 rounded-xl border border-subtle bg-surface px-3 py-1.5 text-xs font-semibold text-muted dark:hover:bg-primary-300/50 hover:bg-primary-200/50 transition-colors duration-100 hover:border-primary-500/50 hover:text-body select-none outline-none",
|
|
856
|
+
className: cn("inline-flex items-center gap-2 rounded-xl border border-subtle bg-surface px-3 py-1.5 text-xs font-semibold text-muted dark:hover:bg-primary-300/50 hover:bg-primary-200/50 transition-colors duration-100 hover:border-primary-500/50 hover:text-body select-none outline-none", className),
|
|
712
857
|
children: [/* @__PURE__ */ jsx(Github, { className: "h-4 w-4 text-body" }), stars !== null && /* @__PURE__ */ jsxs("span", {
|
|
713
858
|
className: "tabular-nums font-medium",
|
|
714
859
|
children: [stars, " stars"]
|
|
@@ -721,7 +866,7 @@ function GithubStars({ repo }) {
|
|
|
721
866
|
function useNavbar() {
|
|
722
867
|
const config = useConfig();
|
|
723
868
|
const { theme, resolvedTheme } = useTheme();
|
|
724
|
-
const location = useLocation
|
|
869
|
+
const location = useLocation();
|
|
725
870
|
const { currentLocale } = useRoutes();
|
|
726
871
|
const themeConfig = config.theme || {};
|
|
727
872
|
const title = getTranslated(themeConfig.title, currentLocale) || "Boltdocs";
|
|
@@ -796,18 +941,18 @@ function useNavbar() {
|
|
|
796
941
|
|
|
797
942
|
//#endregion
|
|
798
943
|
//#region src/client/components/ui-base/theme-toggle.tsx
|
|
799
|
-
function ThemeToggle() {
|
|
944
|
+
function ThemeToggle({ className }) {
|
|
800
945
|
const { theme, setTheme } = useTheme();
|
|
801
946
|
const [mounted, setMounted] = useState(false);
|
|
802
947
|
useEffect(() => {
|
|
803
948
|
setMounted(true);
|
|
804
949
|
}, []);
|
|
805
|
-
if (!mounted) return /* @__PURE__ */ jsx("div", { className: "h-9 w-9" });
|
|
950
|
+
if (!mounted) return /* @__PURE__ */ jsx("div", { className: cn("h-9 w-9", className) });
|
|
806
951
|
const Icon = theme === "system" ? Monitor : theme === "dark" ? Moon : Sun;
|
|
807
952
|
return /* @__PURE__ */ jsxs(Menu$1.Trigger, {
|
|
808
953
|
placement: "bottom right",
|
|
809
954
|
children: [/* @__PURE__ */ jsx(Button, {
|
|
810
|
-
className: "flex h-9 w-9 items-center justify-center rounded-xl text-muted transition-colors hover:bg-surface hover:text-body outline-none border-none bg-transparent cursor-pointer",
|
|
955
|
+
className: cn("flex h-9 w-9 items-center justify-center rounded-xl text-muted transition-colors hover:bg-surface hover:text-body outline-none border-none bg-transparent cursor-pointer", className),
|
|
811
956
|
"aria-label": "Selection theme",
|
|
812
957
|
children: /* @__PURE__ */ jsx(Icon, {
|
|
813
958
|
size: 20,
|
|
@@ -890,7 +1035,7 @@ function ThemeSwitcher({ className }) {
|
|
|
890
1035
|
//#endregion
|
|
891
1036
|
//#region src/client/hooks/use-tabs.ts
|
|
892
1037
|
function useTabs(tabs = [], routes = []) {
|
|
893
|
-
const location = useLocation
|
|
1038
|
+
const location = useLocation();
|
|
894
1039
|
const tabRefs = useRef([]);
|
|
895
1040
|
const [indicatorStyle, setIndicatorStyle] = useState({
|
|
896
1041
|
opacity: 0,
|
|
@@ -924,9 +1069,11 @@ function useTabs(tabs = [], routes = []) {
|
|
|
924
1069
|
|
|
925
1070
|
//#endregion
|
|
926
1071
|
//#region src/client/components/ui-base/tabs.tsx
|
|
927
|
-
function Tabs({ tabs, routes }) {
|
|
1072
|
+
function Tabs({ tabs, routes, allRoutes, className }) {
|
|
928
1073
|
const { currentLocale } = useRoutes();
|
|
929
1074
|
const { indicatorStyle, tabRefs, activeIndex } = useTabs(tabs, routes);
|
|
1075
|
+
const routeCandidates = routes;
|
|
1076
|
+
const fallbackRouteCandidates = allRoutes || [];
|
|
930
1077
|
useEffect(() => {
|
|
931
1078
|
const activeTab = tabRefs.current[activeIndex];
|
|
932
1079
|
if (activeTab) activeTab.scrollIntoView({
|
|
@@ -934,33 +1081,19 @@ function Tabs({ tabs, routes }) {
|
|
|
934
1081
|
block: "nearest",
|
|
935
1082
|
inline: "center"
|
|
936
1083
|
});
|
|
937
|
-
}, [activeIndex]);
|
|
938
|
-
const renderTabIcon = (iconName) => {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(iconName, { USE_PROFILES: { svg: true } }) }
|
|
943
|
-
});
|
|
944
|
-
const icons = {
|
|
945
|
-
...icons_exports,
|
|
946
|
-
...virtualIcons
|
|
947
|
-
};
|
|
948
|
-
const TabIcon = icons[iconName] || icons[iconName + "Icon"];
|
|
949
|
-
if (TabIcon) return /* @__PURE__ */ jsx(TabIcon, { size: 16 });
|
|
950
|
-
return /* @__PURE__ */ jsx("img", {
|
|
951
|
-
src: iconName,
|
|
952
|
-
alt: "",
|
|
953
|
-
className: "h-4 w-4 object-contain"
|
|
954
|
-
});
|
|
955
|
-
};
|
|
1084
|
+
}, [activeIndex, tabRefs]);
|
|
1085
|
+
const renderTabIcon = (iconName) => /* @__PURE__ */ jsx(IconRenderer, {
|
|
1086
|
+
icon: resolveIcon(iconName),
|
|
1087
|
+
size: 16
|
|
1088
|
+
});
|
|
956
1089
|
return /* @__PURE__ */ jsx("div", {
|
|
957
|
-
className: "mx-auto max-w-(--breakpoint-3xl) px-4 md:px-6 select-none",
|
|
1090
|
+
className: cn("mx-auto max-w-(--breakpoint-3xl) px-4 md:px-6 select-none", className),
|
|
958
1091
|
children: /* @__PURE__ */ jsxs(Tabs$1.List, {
|
|
959
1092
|
className: "border-none py-0 scrollbar-hide relative flex flex-row items-center overflow-x-auto",
|
|
960
1093
|
children: [tabs.map((tab, index) => {
|
|
961
1094
|
const isActive = index === activeIndex;
|
|
962
|
-
const firstRoute =
|
|
963
|
-
return /* @__PURE__ */ jsxs(Link
|
|
1095
|
+
const firstRoute = routeCandidates.find((r) => r.tab && r.tab.toLowerCase() === tab.id.toLowerCase()) || fallbackRouteCandidates.find((r) => r.tab && r.tab.toLowerCase() === tab.id.toLowerCase());
|
|
1096
|
+
return /* @__PURE__ */ jsxs(Link, {
|
|
964
1097
|
href: firstRoute ? firstRoute.path : "#",
|
|
965
1098
|
ref: (el) => {
|
|
966
1099
|
tabRefs.current[index] = el;
|
|
@@ -1067,6 +1200,7 @@ function VersionSelector({ className }) {
|
|
|
1067
1200
|
*/
|
|
1068
1201
|
function useI18n() {
|
|
1069
1202
|
const navigate = useNavigate();
|
|
1203
|
+
const location = useLocation();
|
|
1070
1204
|
const config = useConfig();
|
|
1071
1205
|
const { allRoutes, currentRoute, currentLocale, isCollectionPage } = useRoutes();
|
|
1072
1206
|
const i18n = config.i18n;
|
|
@@ -1079,16 +1213,16 @@ function useI18n() {
|
|
|
1079
1213
|
const isDocRoute = !!currentRoute?.filePath;
|
|
1080
1214
|
let targetPath = "";
|
|
1081
1215
|
if (currentRoute) if (isDocRoute && !currentRoute.collection && !isCollectionPage) {
|
|
1082
|
-
const baseFile = getBaseFilePath(currentRoute.filePath, currentRoute.version, currentRoute.locale);
|
|
1083
|
-
const targetRoute = allRoutes.find((r) => getBaseFilePath(r.filePath, r.version, r.locale) === baseFile && (r.locale || i18n.defaultLocale) === locale && r.version === currentRoute.version);
|
|
1216
|
+
const baseFile = currentRoute.filePath ? getBaseFilePath(currentRoute.filePath, currentRoute.version, currentRoute.locale) : "";
|
|
1217
|
+
const targetRoute = allRoutes.find((r) => r.filePath && getBaseFilePath(r.filePath, r.version, r.locale) === baseFile && (r.locale || i18n.defaultLocale) === locale && r.version === currentRoute.version);
|
|
1084
1218
|
if (targetRoute) targetPath = targetRoute.path;
|
|
1085
1219
|
else {
|
|
1086
|
-
const defaultIndexRoute = allRoutes.find((r) => getBaseFilePath(r.filePath, r.version, r.locale)
|
|
1220
|
+
const defaultIndexRoute = allRoutes.find((r) => r.filePath && ["index.md", "_index.md"].includes(getBaseFilePath(r.filePath, r.version, r.locale)) && (r.locale || i18n.defaultLocale) === locale && r.version === currentRoute.version);
|
|
1087
1221
|
if (defaultIndexRoute) targetPath = defaultIndexRoute.path;
|
|
1088
1222
|
else targetPath = `${safeBase}${currentRoute.version ? `/${currentRoute.version}` : ""}${locale === i18n.defaultLocale ? "" : `/${locale}`}` || "/";
|
|
1089
1223
|
}
|
|
1090
1224
|
} else {
|
|
1091
|
-
let rawExternal = currentRoute.path;
|
|
1225
|
+
let rawExternal = currentRoute.path || "";
|
|
1092
1226
|
const parts = rawExternal.split("/").filter(Boolean);
|
|
1093
1227
|
const localePosition = currentRoute.collection ? 1 : 0;
|
|
1094
1228
|
if (parts.length > localePosition && (Array.isArray(i18n.locales) ? i18n.locales.includes(parts[localePosition]) : !!i18n.locales[parts[localePosition]])) {
|
|
@@ -1112,7 +1246,7 @@ function useI18n() {
|
|
|
1112
1246
|
targetPath = "/" + parts.join("/");
|
|
1113
1247
|
}
|
|
1114
1248
|
}
|
|
1115
|
-
if (!targetPath || targetPath === "") targetPath = "/
|
|
1249
|
+
if (!targetPath || targetPath === "") targetPath = "/";
|
|
1116
1250
|
targetPath = targetPath.replace(/\/+/g, "/");
|
|
1117
1251
|
navigate(targetPath);
|
|
1118
1252
|
};
|
|
@@ -1146,7 +1280,7 @@ function useI18n() {
|
|
|
1146
1280
|
//#region src/client/hooks/use-page-nav.ts
|
|
1147
1281
|
function usePageNav() {
|
|
1148
1282
|
const { routes, currentRoute } = useRoutes();
|
|
1149
|
-
const location = useLocation
|
|
1283
|
+
const location = useLocation();
|
|
1150
1284
|
const { groups, ungrouped } = useSidebar(routes);
|
|
1151
1285
|
return useMemo(() => {
|
|
1152
1286
|
if (!currentRoute) return {
|
|
@@ -1171,14 +1305,20 @@ function usePageNav() {
|
|
|
1171
1305
|
});
|
|
1172
1306
|
const orderedRoutes = [];
|
|
1173
1307
|
const flattenNode = (node) => {
|
|
1308
|
+
if (!node) return;
|
|
1174
1309
|
if (node.path && node.path !== "#" && !node.sidebarHidden) orderedRoutes.push(node);
|
|
1175
1310
|
const children = node.routes || node.subRoutes;
|
|
1176
|
-
if (children && children.length > 0)
|
|
1311
|
+
if (children && children.length > 0) {
|
|
1312
|
+
for (const child of children) if (child) flattenNode(child);
|
|
1313
|
+
}
|
|
1177
1314
|
};
|
|
1178
|
-
for (const item of mergedItems) if (item.type === "link")
|
|
1179
|
-
|
|
1315
|
+
for (const item of mergedItems) if (item.type === "link") {
|
|
1316
|
+
if (item.route) flattenNode(item.route);
|
|
1317
|
+
} else if (item.group.routes) {
|
|
1318
|
+
for (const route of item.group.routes) if (route) flattenNode(route);
|
|
1319
|
+
}
|
|
1180
1320
|
const currentNormalizedPath = normalizePath(location.pathname);
|
|
1181
|
-
const currentIndex = orderedRoutes.findIndex((r) => normalizePath(r.path) === currentNormalizedPath);
|
|
1321
|
+
const currentIndex = orderedRoutes.findIndex((r) => r && r.path && normalizePath(r.path) === currentNormalizedPath);
|
|
1182
1322
|
return {
|
|
1183
1323
|
prevPage: currentIndex > 0 ? orderedRoutes[currentIndex - 1] : null,
|
|
1184
1324
|
nextPage: currentIndex !== -1 && currentIndex < orderedRoutes.length - 1 ? orderedRoutes[currentIndex + 1] : null,
|
|
@@ -1336,16 +1476,17 @@ function useAnalytics(options = {}) {
|
|
|
1336
1476
|
const config = optionsConfig ?? globalConfig?.integrations;
|
|
1337
1477
|
const analytics = useMemo(() => createAnalyticsInstance(config), [config]);
|
|
1338
1478
|
const previousPath = useRef("");
|
|
1339
|
-
const
|
|
1479
|
+
const { pathname, search } = location;
|
|
1340
1480
|
useEffect(() => {
|
|
1341
1481
|
if (!autoTrackPageViews || !analytics.isEnabled) return;
|
|
1342
|
-
const path =
|
|
1482
|
+
const path = pathname + search;
|
|
1343
1483
|
if (path !== previousPath.current) {
|
|
1344
1484
|
previousPath.current = path;
|
|
1345
1485
|
analytics.trackPageView(path, document.title);
|
|
1346
1486
|
}
|
|
1347
1487
|
}, [
|
|
1348
|
-
|
|
1488
|
+
pathname,
|
|
1489
|
+
search,
|
|
1349
1490
|
autoTrackPageViews,
|
|
1350
1491
|
analytics
|
|
1351
1492
|
]);
|
|
@@ -1366,7 +1507,6 @@ function useAnalytics(options = {}) {
|
|
|
1366
1507
|
return () => document.removeEventListener("click", handleClick);
|
|
1367
1508
|
}, [
|
|
1368
1509
|
autoTrackDownloads,
|
|
1369
|
-
autoTrackExternalLinks,
|
|
1370
1510
|
analytics,
|
|
1371
1511
|
excludePatterns
|
|
1372
1512
|
]);
|
|
@@ -1431,12 +1571,13 @@ function useFeedback(options = {}) {
|
|
|
1431
1571
|
const [loading, setLoading] = useState(false);
|
|
1432
1572
|
const [submitted, setSubmitted] = useState(false);
|
|
1433
1573
|
const [error, setError] = useState(null);
|
|
1574
|
+
const routePath = currentRoute?.path;
|
|
1434
1575
|
useEffect(() => {
|
|
1435
1576
|
setRating(null);
|
|
1436
1577
|
setComment("");
|
|
1437
1578
|
setSubmitted(false);
|
|
1438
1579
|
setError(null);
|
|
1439
|
-
}, [
|
|
1580
|
+
}, [routePath]);
|
|
1440
1581
|
const submit = async (commentOverride, blockId) => {
|
|
1441
1582
|
if (!rating) return;
|
|
1442
1583
|
setLoading(true);
|
|
@@ -1515,17 +1656,17 @@ function I18nSelector({ className }) {
|
|
|
1515
1656
|
|
|
1516
1657
|
//#endregion
|
|
1517
1658
|
//#region src/client/components/ui-base/navbar.tsx
|
|
1518
|
-
const SearchDialog$1 = lazy(() => import("../search-dialog-
|
|
1519
|
-
function Navbar() {
|
|
1659
|
+
const SearchDialog$1 = lazy(() => import("../search-dialog-DtmxmfEu.js").then((m) => ({ default: m.SearchDialog })));
|
|
1660
|
+
function Navbar({ className }) {
|
|
1520
1661
|
const { links, title, logo, logoProps, github, social, config } = useNavbar();
|
|
1521
|
-
const { routes, currentRoute, isCollectionPage, currentVersion, currentLocale } = useRoutes();
|
|
1662
|
+
const { routes, allRoutes, currentRoute, isCollectionPage, currentVersion, currentLocale } = useRoutes();
|
|
1522
1663
|
const { isSidebarOpen, toggleSidebar } = useUI();
|
|
1523
1664
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
1524
1665
|
const themeConfig = config.theme;
|
|
1525
1666
|
const isDocs = !!currentRoute?.filePath && !isCollectionPage;
|
|
1526
1667
|
const hasTabs = themeConfig?.tabs && themeConfig.tabs.length > 0;
|
|
1527
1668
|
return /* @__PURE__ */ jsxs(Navbar$1.Root, {
|
|
1528
|
-
className: cn("border-b border-subtle bg-main/80 backdrop-blur-md", hasTabs && "border-b-0"),
|
|
1669
|
+
className: cn("border-b border-subtle bg-main/80 backdrop-blur-md", hasTabs && "border-b-0", className),
|
|
1529
1670
|
children: [
|
|
1530
1671
|
/* @__PURE__ */ jsxs(Navbar$1.Content, { children: [
|
|
1531
1672
|
/* @__PURE__ */ jsxs(Navbar$1.Left, { children: [
|
|
@@ -1630,7 +1771,8 @@ function Navbar() {
|
|
|
1630
1771
|
className: "w-full border-b border-subtle bg-main",
|
|
1631
1772
|
children: /* @__PURE__ */ jsx(Tabs, {
|
|
1632
1773
|
tabs: themeConfig.tabs,
|
|
1633
|
-
routes: routes || []
|
|
1774
|
+
routes: routes || [],
|
|
1775
|
+
allRoutes: allRoutes || []
|
|
1634
1776
|
})
|
|
1635
1777
|
})
|
|
1636
1778
|
]
|
|
@@ -1638,7 +1780,7 @@ function Navbar() {
|
|
|
1638
1780
|
}
|
|
1639
1781
|
function NavbarLinkItem({ link }) {
|
|
1640
1782
|
const localizedHref = useLocalizedTo(link.href || "");
|
|
1641
|
-
const { pathname } = useLocation
|
|
1783
|
+
const { pathname } = useLocation();
|
|
1642
1784
|
const active = pathname === localizedHref || pathname.startsWith(`${localizedHref}/`);
|
|
1643
1785
|
if (link.items && link.items.length > 0) return /* @__PURE__ */ jsx(Navbar$1.Dropdown, {
|
|
1644
1786
|
label: /* @__PURE__ */ jsx("span", {
|
|
@@ -1658,70 +1800,58 @@ function NavbarLinkItem({ link }) {
|
|
|
1658
1800
|
});
|
|
1659
1801
|
}
|
|
1660
1802
|
function NavbarMobileLinkItem({ link, onClose }) {
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
if (link.items && link.items.length > 0) return /* @__PURE__ */ jsxs("div", {
|
|
1665
|
-
className: "flex flex-col gap-1",
|
|
1666
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
1667
|
-
className: cn("px-3 py-2 text-sm transition-all", active ? "text-body" : "text-muted/80 hover:text-body"),
|
|
1668
|
-
children: link.label
|
|
1669
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
1670
|
-
className: "flex flex-col gap-1 pl-4",
|
|
1671
|
-
children: link.items?.map((item) => /* @__PURE__ */ jsx(NavbarMobileLinkItem, {
|
|
1672
|
-
link: item,
|
|
1673
|
-
onClose
|
|
1674
|
-
}, item.href))
|
|
1675
|
-
})]
|
|
1676
|
-
});
|
|
1677
|
-
return /* @__PURE__ */ jsx(Navbar$1.MobileLink, {
|
|
1678
|
-
...link,
|
|
1679
|
-
href: localizedHref,
|
|
1680
|
-
active,
|
|
1681
|
-
onPress: onClose,
|
|
1682
|
-
className: cn("transition-all", active ? "text-body" : "text-muted/80 hover:text-body")
|
|
1803
|
+
return /* @__PURE__ */ jsx(Navbar$1.MobileLinkItem, {
|
|
1804
|
+
link,
|
|
1805
|
+
onClose
|
|
1683
1806
|
});
|
|
1684
1807
|
}
|
|
1685
1808
|
|
|
1686
1809
|
//#endregion
|
|
1687
1810
|
//#region src/client/components/ui-base/on-this-page.tsx
|
|
1688
|
-
function OnThisPage({ headings = [], editLink, communityHelp, filePath }) {
|
|
1811
|
+
function OnThisPage({ headings = [], editLink, communityHelp, filePath, className }) {
|
|
1689
1812
|
if (headings.length === 0) return /* @__PURE__ */ jsx("nav", {
|
|
1690
|
-
className: "w-toc shrink-0 hidden xl:block",
|
|
1813
|
+
className: cn("w-toc shrink-0 hidden xl:block", className),
|
|
1691
1814
|
"aria-hidden": "true"
|
|
1692
1815
|
});
|
|
1693
|
-
return /* @__PURE__ */ jsxs(OnThisPage$1.Root, {
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
}),
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1816
|
+
return /* @__PURE__ */ jsxs(OnThisPage$1.Root, {
|
|
1817
|
+
className: cn("sticky top-navbar hidden xl:flex flex-col shrink-0 w-toc py-4 pl-6 pr-4", className),
|
|
1818
|
+
children: [
|
|
1819
|
+
/* @__PURE__ */ jsxs(OnThisPage$1.Header, {
|
|
1820
|
+
className: "mb-4 text-xs font-bold text-body flex flex-row gap-x-2",
|
|
1821
|
+
children: [/* @__PURE__ */ jsx(TextAlignStart, { size: 16 }), "On this page"]
|
|
1822
|
+
}),
|
|
1823
|
+
/* @__PURE__ */ jsx(OnThisPage$1.Tree, {
|
|
1824
|
+
className: "space-y-0.5 text-sm border-l border-subtle",
|
|
1825
|
+
itemClassName: "data-[level=3]:pl-3",
|
|
1826
|
+
linkClassName: "block py-0.5 pl-4 text-[13px] outline-none transition-colors text-muted hover:text-body data-active:text-primary-500",
|
|
1827
|
+
indicatorClassName: "-left-px w-0.5 rounded-full bg-primary-500",
|
|
1828
|
+
fadeClassName: "bg-linear-to-b from-transparent to-main",
|
|
1829
|
+
headings
|
|
1830
|
+
}),
|
|
1831
|
+
(editLink || communityHelp) && /* @__PURE__ */ jsxs("div", {
|
|
1832
|
+
className: "mt-8 pt-8 border-t border-subtle space-y-4",
|
|
1833
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
1834
|
+
className: "text-xs font-bold text-body",
|
|
1835
|
+
children: "Need help?"
|
|
1836
|
+
}), /* @__PURE__ */ jsxs("ul", {
|
|
1837
|
+
className: "space-y-3",
|
|
1838
|
+
children: [editLink && filePath && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("a", {
|
|
1839
|
+
href: editLink.replace(":path", filePath),
|
|
1840
|
+
target: "_blank",
|
|
1841
|
+
rel: "noopener noreferrer",
|
|
1842
|
+
className: "flex items-center gap-2 text-sm text-muted hover:text-body transition-colors",
|
|
1843
|
+
children: [/* @__PURE__ */ jsx(Pencil, { size: 16 }), "Edit this page"]
|
|
1844
|
+
}) }), communityHelp && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("a", {
|
|
1845
|
+
href: communityHelp,
|
|
1846
|
+
target: "_blank",
|
|
1847
|
+
rel: "noopener noreferrer",
|
|
1848
|
+
className: "flex items-center gap-2 text-sm text-muted hover:text-body transition-colors",
|
|
1849
|
+
children: [/* @__PURE__ */ jsx(CircleHelp, { size: 16 }), "Community help"]
|
|
1850
|
+
}) })]
|
|
1851
|
+
})]
|
|
1852
|
+
})
|
|
1853
|
+
]
|
|
1854
|
+
});
|
|
1725
1855
|
}
|
|
1726
1856
|
|
|
1727
1857
|
//#endregion
|
|
@@ -1730,32 +1860,44 @@ function OnThisPage({ headings = [], editLink, communityHelp, filePath }) {
|
|
|
1730
1860
|
* Component to display the previous and next page navigation buttons.
|
|
1731
1861
|
* Enhanced with subtle entrance animations, modern card layout, and hover highlights.
|
|
1732
1862
|
*/
|
|
1733
|
-
function PageNav() {
|
|
1863
|
+
function PageNav({ className }) {
|
|
1734
1864
|
const { prevPage, nextPage } = usePageNav();
|
|
1735
1865
|
if (!prevPage && !nextPage) return null;
|
|
1736
1866
|
return /* @__PURE__ */ jsxs(PageNav$1.Root, {
|
|
1737
|
-
className: "pt-8 border-t border-subtle grid sm:grid-cols-2 gap-4 animate-in fade-in slide-in-from-bottom-4 duration-700 select-none",
|
|
1867
|
+
className: cn("pt-8 border-t border-subtle grid sm:grid-cols-2 gap-4 animate-in fade-in slide-in-from-bottom-4 duration-700 select-none", className),
|
|
1738
1868
|
children: [prevPage ? /* @__PURE__ */ jsxs(PageNav$1.Link, {
|
|
1739
1869
|
to: prevPage.path,
|
|
1740
1870
|
direction: "prev",
|
|
1741
1871
|
className: "group border border-subtle bg-surface p-5 rounded-2xl transition-all duration-300 hover:border-primary-500/50 hover:bg-primary-50/20",
|
|
1742
|
-
children: [/* @__PURE__ */ jsx(PageNav$1.
|
|
1743
|
-
className: "text-
|
|
1744
|
-
children:
|
|
1745
|
-
}), /* @__PURE__ */
|
|
1746
|
-
className: "
|
|
1747
|
-
children:
|
|
1872
|
+
children: [/* @__PURE__ */ jsx(PageNav$1.Icon, {
|
|
1873
|
+
className: "text-muted/60 shrink-0",
|
|
1874
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, {})
|
|
1875
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1876
|
+
className: "flex flex-col",
|
|
1877
|
+
children: [/* @__PURE__ */ jsx(PageNav$1.Title, {
|
|
1878
|
+
className: "text-xs font-bold uppercase tracking-wider text-muted/60 mb-1",
|
|
1879
|
+
children: "Previous"
|
|
1880
|
+
}), /* @__PURE__ */ jsx(PageNav$1.Description, {
|
|
1881
|
+
className: "text-sm sm:text-base font-bold text-body group-hover:text-primary-500 transition-colors",
|
|
1882
|
+
children: prevPage.title
|
|
1883
|
+
})]
|
|
1748
1884
|
})]
|
|
1749
1885
|
}) : /* @__PURE__ */ jsx("div", {}), nextPage ? /* @__PURE__ */ jsxs(PageNav$1.Link, {
|
|
1750
1886
|
to: nextPage.path,
|
|
1751
1887
|
direction: "next",
|
|
1752
1888
|
className: "group border border-subtle bg-surface p-5 rounded-2xl transition-all duration-300 hover:border-primary-500/50 hover:bg-primary-50/20",
|
|
1753
|
-
children: [/* @__PURE__ */
|
|
1754
|
-
className: "
|
|
1755
|
-
children:
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1889
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1890
|
+
className: "flex flex-col",
|
|
1891
|
+
children: [/* @__PURE__ */ jsx(PageNav$1.Title, {
|
|
1892
|
+
className: "text-xs font-bold uppercase tracking-wider text-muted/60 mb-1",
|
|
1893
|
+
children: "Next"
|
|
1894
|
+
}), /* @__PURE__ */ jsx(PageNav$1.Description, {
|
|
1895
|
+
className: "text-sm sm:text-base font-bold text-body group-hover:text-primary-500 transition-colors",
|
|
1896
|
+
children: nextPage.title
|
|
1897
|
+
})]
|
|
1898
|
+
}), /* @__PURE__ */ jsx(PageNav$1.Icon, {
|
|
1899
|
+
className: "text-muted/60 shrink-0",
|
|
1900
|
+
children: /* @__PURE__ */ jsx(ChevronRight, {})
|
|
1759
1901
|
})]
|
|
1760
1902
|
}) : /* @__PURE__ */ jsx("div", {})]
|
|
1761
1903
|
});
|
|
@@ -1763,38 +1905,90 @@ function PageNav() {
|
|
|
1763
1905
|
|
|
1764
1906
|
//#endregion
|
|
1765
1907
|
//#region src/client/components/ui-base/sidebar.tsx
|
|
1766
|
-
|
|
1908
|
+
/**
|
|
1909
|
+
* Default look for the sidebar tree. States are driven by the primitive's
|
|
1910
|
+
* `data-*` attributes (`data-active`, `data-open`, `data-badge`).
|
|
1911
|
+
*/
|
|
1912
|
+
const defaultItemsClassNames = {
|
|
1913
|
+
item: "rounded-lg px-2.5 py-1.5 text-sm transition-all text-muted hover:bg-surface hover:text-body data-active:bg-primary-500/10 data-active:text-primary-500 data-active:font-medium data-active:shadow-sm",
|
|
1914
|
+
groupHeader: "px-2 mb-2 text-[11px] font-bold uppercase tracking-widest text-muted/50",
|
|
1915
|
+
groupContent: "gap-0.5",
|
|
1916
|
+
subgroup: "gap-0.5",
|
|
1917
|
+
subgroupLink: "rounded-lg px-2.5 py-1.5 text-sm transition-all text-muted hover:bg-surface hover:text-body data-active:bg-primary-500/10 data-active:text-primary-500 data-active:font-medium data-active:shadow-sm",
|
|
1918
|
+
subgroupContent: "ml-4 pl-3 border-l border-subtle/50 mt-0.5 gap-0.5",
|
|
1919
|
+
toggle: "p-1.5 text-muted hover:text-body transition-colors"
|
|
1920
|
+
};
|
|
1921
|
+
const defaultContentClassName = "flex-1 overflow-y-auto p-4 pb-16 custom-scrollbar flex flex-col gap-6";
|
|
1922
|
+
const mergeSlots = (defaults, overrides) => {
|
|
1923
|
+
if (!overrides) return defaults;
|
|
1924
|
+
const merged = { ...defaults };
|
|
1925
|
+
for (const key of Object.keys(defaults)) if (overrides[key]) merged[key] = cn(defaults[key], overrides[key]);
|
|
1926
|
+
return merged;
|
|
1927
|
+
};
|
|
1928
|
+
function SidebarMain({ routes, config, className }) {
|
|
1767
1929
|
const { logo, title, logoProps } = useNavbar();
|
|
1768
1930
|
const { closeSidebar } = useUI();
|
|
1769
1931
|
const SidebarLogo = logo ? /* @__PURE__ */ jsx("img", {
|
|
1770
|
-
src: logo,
|
|
1932
|
+
src: resolvePublicAssetUrl(logo, config.base),
|
|
1771
1933
|
alt: logoProps?.alt || title,
|
|
1772
1934
|
width: 24,
|
|
1773
1935
|
height: 24,
|
|
1774
1936
|
className: "rounded-xl"
|
|
1775
1937
|
}) : null;
|
|
1776
1938
|
const hasUtilities = config.versions || config.i18n;
|
|
1777
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Sidebar$1.Root, {
|
|
1778
|
-
className: "flex
|
|
1779
|
-
children:
|
|
1780
|
-
className:
|
|
1781
|
-
children:
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1939
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Sidebar$1.Root, {
|
|
1940
|
+
className: cn("hidden lg:flex flex-col w-sidebar sticky top-navbar h-[calc(100vh-var(--spacing-navbar))] border-r border-subtle bg-main", className),
|
|
1941
|
+
children: /* @__PURE__ */ jsx(Sidebar$1.Content, {
|
|
1942
|
+
className: defaultContentClassName,
|
|
1943
|
+
children: /* @__PURE__ */ jsx(Sidebar$1.Items, {
|
|
1944
|
+
routes,
|
|
1945
|
+
className: "flex flex-col gap-6",
|
|
1946
|
+
classNames: defaultItemsClassNames
|
|
1947
|
+
})
|
|
1948
|
+
})
|
|
1949
|
+
}), /* @__PURE__ */ jsxs(Sidebar$1.Mobile, {
|
|
1950
|
+
overlayClassName: "fixed inset-0 z-50 bg-black/20 backdrop-blur-sm lg:hidden entering:animate-in entering:fade-in exiting:animate-out exiting:fade-out duration-300",
|
|
1951
|
+
className: cn("fixed top-0 left-0 bottom-0 w-80 bg-main border-r border-subtle shadow-2xl outline-none entering:animate-in entering:slide-in-from-left exiting:animate-out exiting:slide-out-to-left duration-300", className),
|
|
1952
|
+
children: [/* @__PURE__ */ jsxs(Sidebar$1.Header, {
|
|
1953
|
+
className: "flex items-center justify-between p-4 border-b border-subtle",
|
|
1954
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1955
|
+
className: "flex items-center gap-3",
|
|
1956
|
+
children: [SidebarLogo, /* @__PURE__ */ jsx("span", {
|
|
1957
|
+
className: "font-bold text-lg tracking-tight text-body truncate max-w-[120px]",
|
|
1958
|
+
children: title
|
|
1959
|
+
})]
|
|
1960
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1961
|
+
className: "flex items-center gap-2",
|
|
1962
|
+
children: [/* @__PURE__ */ jsx(ThemeSwitcher, { className: "w-24 h-9 rounded-xl" }), /* @__PURE__ */ jsx(Button$1, {
|
|
1963
|
+
onPress: closeSidebar,
|
|
1964
|
+
className: "h-9 w-9 flex items-center justify-center bg-transparent border-none outline-none select-none cursor-pointer rounded-xl hover:bg-primary-50/50 text-muted hover:text-body transition-colors",
|
|
1965
|
+
"aria-label": "Close sidebar",
|
|
1966
|
+
children: /* @__PURE__ */ jsx(X, { size: 20 })
|
|
1967
|
+
})]
|
|
1968
|
+
})]
|
|
1969
|
+
}), /* @__PURE__ */ jsxs(Sidebar$1.Content, {
|
|
1970
|
+
className: defaultContentClassName,
|
|
1971
|
+
children: [hasUtilities && /* @__PURE__ */ jsxs("div", {
|
|
1972
|
+
className: "flex flex-col gap-4 mb-10",
|
|
1973
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1974
|
+
className: "flex gap-3",
|
|
1975
|
+
children: [config.versions && /* @__PURE__ */ jsx(VersionSelector, { className: "flex-1 justify-between h-10 bg-surface border-subtle rounded-xl" }), config.i18n && /* @__PURE__ */ jsx(I18nSelector, { className: "flex-1 justify-between h-10 bg-surface border-subtle rounded-xl" })]
|
|
1976
|
+
}), /* @__PURE__ */ jsx("div", { className: "mt-2 border-b border-subtle" })]
|
|
1977
|
+
}), /* @__PURE__ */ jsx(Sidebar$1.Items, {
|
|
1978
|
+
routes,
|
|
1979
|
+
className: "flex flex-col gap-6",
|
|
1980
|
+
classNames: defaultItemsClassNames
|
|
1981
|
+
})]
|
|
1790
1982
|
})]
|
|
1791
|
-
})] })
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1983
|
+
})] });
|
|
1984
|
+
}
|
|
1985
|
+
function SidebarItems(props) {
|
|
1986
|
+
const { classNames, ...rest } = props;
|
|
1987
|
+
return /* @__PURE__ */ jsx(Sidebar$1.Items, {
|
|
1988
|
+
...rest,
|
|
1989
|
+
className: cn("flex flex-col gap-6", rest.className),
|
|
1990
|
+
classNames: mergeSlots(defaultItemsClassNames, classNames)
|
|
1991
|
+
});
|
|
1798
1992
|
}
|
|
1799
1993
|
const Sidebar = Object.assign(SidebarMain, {
|
|
1800
1994
|
Root: Sidebar$1.Root,
|
|
@@ -1805,7 +1999,7 @@ const Sidebar = Object.assign(SidebarMain, {
|
|
|
1805
1999
|
Link: Sidebar$1.Link,
|
|
1806
2000
|
SubGroup: Sidebar$1.SubGroup,
|
|
1807
2001
|
Item: Sidebar$1.Item,
|
|
1808
|
-
Items:
|
|
2002
|
+
Items: SidebarItems
|
|
1809
2003
|
});
|
|
1810
2004
|
|
|
1811
2005
|
//#endregion
|
|
@@ -1969,10 +2163,12 @@ function Giscus({ className }) {
|
|
|
1969
2163
|
return () => {
|
|
1970
2164
|
initializedRef.current = false;
|
|
1971
2165
|
if (script.parentNode) script.parentNode.removeChild(script);
|
|
1972
|
-
(ref.current?.querySelectorAll("iframe"))?.forEach((iframe) =>
|
|
2166
|
+
(ref.current?.querySelectorAll("iframe"))?.forEach((iframe) => {
|
|
2167
|
+
iframe.remove();
|
|
2168
|
+
});
|
|
1973
2169
|
};
|
|
1974
2170
|
}
|
|
1975
|
-
}, [giscusConfig]);
|
|
2171
|
+
}, [giscusConfig, resolvedTheme]);
|
|
1976
2172
|
useEffect(() => {
|
|
1977
2173
|
if (!giscusConfig || !initializedRef.current) return;
|
|
1978
2174
|
const theme = giscusConfig.theme || (resolvedTheme === "dark" ? "dark" : "light");
|
|
@@ -1986,14 +2182,44 @@ function Giscus({ className }) {
|
|
|
1986
2182
|
});
|
|
1987
2183
|
}
|
|
1988
2184
|
|
|
2185
|
+
//#endregion
|
|
2186
|
+
//#region src/shared/mdx-path.ts
|
|
2187
|
+
function normalizeMdxPath(value) {
|
|
2188
|
+
return value.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
2189
|
+
}
|
|
2190
|
+
function matchesMdxUpdatePath(routeFilePath, updateRelativePath) {
|
|
2191
|
+
return normalizeMdxPath(routeFilePath) === normalizeMdxPath(updateRelativePath);
|
|
2192
|
+
}
|
|
2193
|
+
|
|
1989
2194
|
//#endregion
|
|
1990
2195
|
//#region src/client/ssg/mdx-elements.tsx
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
2196
|
+
async function resolveModuleLoader(loader) {
|
|
2197
|
+
if (typeof loader !== "function") return Promise.resolve(loader);
|
|
2198
|
+
try {
|
|
2199
|
+
const res = loader();
|
|
2200
|
+
if (res && typeof res.then === "function") return await res;
|
|
2201
|
+
return { default: loader };
|
|
2202
|
+
} catch {
|
|
2203
|
+
return { default: loader };
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
function extractMdxComponent(mod, moduleKey, pathKey) {
|
|
2207
|
+
if (!mod) return null;
|
|
2208
|
+
let target = mod;
|
|
2209
|
+
if (mod.default !== void 0) target = mod.default;
|
|
2210
|
+
if (typeof target === "function" || typeof target === "string") return target;
|
|
2211
|
+
if (target && typeof target === "object") {
|
|
2212
|
+
const possibleKeys = [moduleKey, pathKey].filter(Boolean);
|
|
2213
|
+
for (const key of possibleKeys) {
|
|
2214
|
+
const value = target[key];
|
|
2215
|
+
if (value) {
|
|
2216
|
+
if (typeof value === "function" || typeof value === "string") return value;
|
|
2217
|
+
if (typeof value === "object" && value.default) return value.default;
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
if (target.default !== void 0) return extractMdxComponent({ default: target.default }, moduleKey, pathKey);
|
|
2221
|
+
}
|
|
2222
|
+
return null;
|
|
1997
2223
|
}
|
|
1998
2224
|
const EagerMdxElement = ({ moduleLoader, moduleKey, route, components, collectionPostComponent }) => {
|
|
1999
2225
|
const [mod, setMod] = useState(moduleLoader);
|
|
@@ -2003,16 +2229,20 @@ const EagerMdxElement = ({ moduleLoader, moduleKey, route, components, collectio
|
|
|
2003
2229
|
useEffect(() => {
|
|
2004
2230
|
if (!import.meta.hot || !moduleKey) return;
|
|
2005
2231
|
const handler = (data) => {
|
|
2006
|
-
if (
|
|
2007
|
-
import(
|
|
2232
|
+
if (!matchesMdxUpdatePath(route.filePath, data.relPath)) return;
|
|
2233
|
+
import(`${import.meta.env.BASE_URL.replace(/\/$/, "")}${moduleKey}?t=${Date.now()}`).then((m) => {
|
|
2008
2234
|
setMod(m);
|
|
2009
2235
|
});
|
|
2010
2236
|
};
|
|
2011
|
-
import.meta.hot
|
|
2012
|
-
|
|
2237
|
+
const hot = import.meta.hot;
|
|
2238
|
+
hot.on("boltdocs:mdx-update", handler);
|
|
2239
|
+
return () => hot.off?.("boltdocs:mdx-update", handler);
|
|
2013
2240
|
}, [moduleKey, route.filePath]);
|
|
2014
|
-
const MDXComponent = mod
|
|
2015
|
-
if (!MDXComponent) return /* @__PURE__ */
|
|
2241
|
+
const MDXComponent = extractMdxComponent(mod, moduleKey, route.path || "/");
|
|
2242
|
+
if (!MDXComponent) return /* @__PURE__ */ jsxs("div", {
|
|
2243
|
+
className: "prose dark:prose-invert py-8",
|
|
2244
|
+
children: [/* @__PURE__ */ jsx("h1", { children: route.title }), route.description && /* @__PURE__ */ jsx("p", { children: route.description })]
|
|
2245
|
+
});
|
|
2016
2246
|
return /* @__PURE__ */ jsx(MdxPage, {
|
|
2017
2247
|
MDXComponent,
|
|
2018
2248
|
mdxComponents: components ?? {},
|
|
@@ -2086,21 +2316,59 @@ function buildModuleMap(mdxModules) {
|
|
|
2086
2316
|
}
|
|
2087
2317
|
return moduleMap;
|
|
2088
2318
|
}
|
|
2319
|
+
function cleanModulePath(value) {
|
|
2320
|
+
return value.replace(/\\/g, "/").replace(/^\/+/, "").replace(/\/\([^)]+\)/g, "").replace(/^\([^)]+\)\//, "");
|
|
2321
|
+
}
|
|
2322
|
+
/**
|
|
2323
|
+
* Resolves a route source path against both Vite glob keys and relative keys.
|
|
2324
|
+
* Exact cleaned matches are preferred so `es/guide.md` cannot select the
|
|
2325
|
+
* default-locale `guide.md` when both modules are present.
|
|
2326
|
+
*/
|
|
2327
|
+
function resolveModuleKey(filePath, moduleMap) {
|
|
2328
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
2329
|
+
const cleanPath = cleanModulePath(normalized);
|
|
2330
|
+
for (const candidate of [
|
|
2331
|
+
normalized,
|
|
2332
|
+
normalized.replace(/^\//, ""),
|
|
2333
|
+
cleanPath
|
|
2334
|
+
]) {
|
|
2335
|
+
const direct = moduleMap.get(candidate);
|
|
2336
|
+
if (direct) return direct;
|
|
2337
|
+
}
|
|
2338
|
+
for (const [relativePath, moduleKey] of moduleMap.entries()) {
|
|
2339
|
+
const cleanRelative = cleanModulePath(relativePath);
|
|
2340
|
+
if (normalized.endsWith(relativePath) || relativePath.endsWith(normalized) || cleanPath.endsWith(cleanRelative) || cleanRelative.endsWith(cleanPath)) return moduleKey;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2089
2343
|
|
|
2090
2344
|
//#endregion
|
|
2091
2345
|
//#region src/client/ssg/create-routes.doc.tsx
|
|
2346
|
+
function FallbackWrapper({ children }) {
|
|
2347
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
2348
|
+
}
|
|
2092
2349
|
function buildDocRoutes(options) {
|
|
2093
2350
|
const { routesData, config, mdxModules, components, externalPages } = options;
|
|
2094
2351
|
const baseDocsPath = (config.base || "/docs").replace(/\/$/, "") || "/";
|
|
2095
2352
|
const defaultVersionMetadata = [];
|
|
2096
2353
|
const defaultVersion = config.versions?.defaultVersion;
|
|
2097
2354
|
const docsBase = (config.base || "/docs").replace(/\/$/, "");
|
|
2355
|
+
const urlConfig = {
|
|
2356
|
+
base: config.base,
|
|
2357
|
+
i18n: config.i18n,
|
|
2358
|
+
versions: config.versions,
|
|
2359
|
+
collections: []
|
|
2360
|
+
};
|
|
2098
2361
|
if (defaultVersion) routesData.filter((r) => !r.collection).forEach((route) => {
|
|
2099
2362
|
if (route.version) return;
|
|
2100
2363
|
const p = route.path || "";
|
|
2101
2364
|
const subPath = p.startsWith(docsBase) ? p.substring(docsBase.length).replace(/^\//, "") : p.replace(/^\//, "");
|
|
2102
|
-
if (!(
|
|
2103
|
-
const explicitPath =
|
|
2365
|
+
if (!(route.version === defaultVersion)) {
|
|
2366
|
+
const explicitPath = buildUrl({
|
|
2367
|
+
kind: "doc",
|
|
2368
|
+
path: `/${subPath}`,
|
|
2369
|
+
locale: route.locale,
|
|
2370
|
+
version: defaultVersion
|
|
2371
|
+
}, urlConfig);
|
|
2104
2372
|
defaultVersionMetadata.push({
|
|
2105
2373
|
...route,
|
|
2106
2374
|
path: explicitPath,
|
|
@@ -2110,16 +2378,22 @@ function buildDocRoutes(options) {
|
|
|
2110
2378
|
});
|
|
2111
2379
|
const docMetadata = [...routesData.filter((r) => !r.collection), ...defaultVersionMetadata];
|
|
2112
2380
|
const moduleMap = buildModuleMap(mdxModules);
|
|
2113
|
-
const
|
|
2114
|
-
const
|
|
2381
|
+
const routeMetadata = /* @__PURE__ */ new Map();
|
|
2382
|
+
const getDocumentIdentity = (route) => {
|
|
2383
|
+
const parsed = parseUrlReference(route.path, urlConfig, { kind: "doc" });
|
|
2384
|
+
return {
|
|
2385
|
+
path: parsed.routePath,
|
|
2386
|
+
version: route.version || parsed.version || config.versions?.defaultVersion
|
|
2387
|
+
};
|
|
2388
|
+
};
|
|
2115
2389
|
const docRoutes = docMetadata.map((route) => {
|
|
2116
|
-
const
|
|
2117
|
-
const moduleKey = moduleMap.get(normalizedFilePath);
|
|
2390
|
+
const moduleKey = resolveModuleKey(route.filePath, moduleMap);
|
|
2118
2391
|
const moduleLoader = moduleKey ? mdxModules[moduleKey] : null;
|
|
2119
2392
|
const fullPath = withBase(route.path === "" ? "/" : route.path, config);
|
|
2120
2393
|
const path = fullPath === baseDocsPath ? "." : fullPath.startsWith(baseDocsPath + "/") ? fullPath.slice(baseDocsPath.length + 1) : fullPath;
|
|
2121
2394
|
const routeRecord = {
|
|
2122
2395
|
path,
|
|
2396
|
+
locale: route.locale,
|
|
2123
2397
|
loader: async () => ({
|
|
2124
2398
|
path,
|
|
2125
2399
|
frontmatter: {
|
|
@@ -2139,7 +2413,8 @@ function buildDocRoutes(options) {
|
|
|
2139
2413
|
}),
|
|
2140
2414
|
getStaticPaths: () => [path]
|
|
2141
2415
|
};
|
|
2142
|
-
|
|
2416
|
+
routeMetadata.set(routeRecord, route);
|
|
2417
|
+
if (moduleLoader) routeRecord.lazy = async () => {
|
|
2143
2418
|
const mod = await resolveModuleLoader(moduleLoader);
|
|
2144
2419
|
return { Component: function LoadedMdxRoute() {
|
|
2145
2420
|
return /* @__PURE__ */ jsx(EagerMdxElement, {
|
|
@@ -2147,7 +2422,7 @@ function buildDocRoutes(options) {
|
|
|
2147
2422
|
moduleLoader: mod,
|
|
2148
2423
|
route,
|
|
2149
2424
|
components: components ?? {}
|
|
2150
|
-
}, moduleKey || path);
|
|
2425
|
+
}, `${moduleKey || path}-${route.locale || config.i18n?.defaultLocale || "en"}`);
|
|
2151
2426
|
} };
|
|
2152
2427
|
};
|
|
2153
2428
|
else routeRecord.element = /* @__PURE__ */ jsx(EagerMdxElement, {
|
|
@@ -2155,95 +2430,147 @@ function buildDocRoutes(options) {
|
|
|
2155
2430
|
moduleLoader: moduleLoader ?? {},
|
|
2156
2431
|
route,
|
|
2157
2432
|
components: components ?? {}
|
|
2158
|
-
}, moduleKey || path);
|
|
2433
|
+
}, `${moduleKey || path}-${route.locale || config.i18n?.defaultLocale || "en"}`);
|
|
2159
2434
|
return routeRecord;
|
|
2160
2435
|
});
|
|
2161
2436
|
const locales = config.i18n?.locales ? Array.isArray(config.i18n.locales) ? config.i18n.locales : Object.keys(config.i18n.locales) : [];
|
|
2162
2437
|
const allVersions = config.versions?.versions?.map((v) => v.path) || [];
|
|
2163
2438
|
const targetBasePaths = [];
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
const fullP = baseDocsPath === "/" ? `/${v}` : `${baseDocsPath}/${v}`;
|
|
2439
|
+
const addTargetBase = (locale, version) => {
|
|
2440
|
+
const fullPath = buildUrl({
|
|
2441
|
+
kind: "doc",
|
|
2442
|
+
path: "/",
|
|
2443
|
+
locale,
|
|
2444
|
+
version
|
|
2445
|
+
}, urlConfig);
|
|
2172
2446
|
targetBasePaths.push({
|
|
2173
|
-
path:
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
version: v
|
|
2447
|
+
path: fullPath,
|
|
2448
|
+
locale,
|
|
2449
|
+
version
|
|
2177
2450
|
});
|
|
2178
|
-
}
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
filter: (rp) => !!rp && rp.startsWith(fullP.replace(/\/$/, "") + "/"),
|
|
2184
|
-
locale: l,
|
|
2185
|
-
version: config.versions?.defaultVersion
|
|
2186
|
-
});
|
|
2187
|
-
});
|
|
2188
|
-
if (allVersions.length > 0 && locales.length > 0) allVersions.forEach((v) => {
|
|
2189
|
-
locales.forEach((l) => {
|
|
2190
|
-
const fullP = baseDocsPath === "/" ? `/${v}/${l}` : `${baseDocsPath}/${v}/${l}`;
|
|
2191
|
-
targetBasePaths.push({
|
|
2192
|
-
path: fullP,
|
|
2193
|
-
filter: (rp) => !!rp && rp.startsWith(fullP.replace(/\/$/, "") + "/"),
|
|
2194
|
-
locale: l,
|
|
2195
|
-
version: v
|
|
2196
|
-
});
|
|
2197
|
-
});
|
|
2198
|
-
});
|
|
2451
|
+
};
|
|
2452
|
+
addTargetBase(config.i18n?.defaultLocale);
|
|
2453
|
+
for (const version of allVersions) addTargetBase(config.i18n?.defaultLocale, version);
|
|
2454
|
+
for (const locale of locales) addTargetBase(locale);
|
|
2455
|
+
for (const version of allVersions) for (const locale of locales) addTargetBase(locale, version);
|
|
2199
2456
|
const docPathRegistry = new Set(docRoutes.map((r) => (r.path || "").replace(/\/$/, "")));
|
|
2200
2457
|
const externalPaths = /* @__PURE__ */ new Set();
|
|
2201
2458
|
if (externalPages) Object.keys(externalPages).forEach((rawPath) => {
|
|
2202
2459
|
const p = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
|
|
2203
2460
|
externalPaths.add(p.replace(/\/$/, ""));
|
|
2204
|
-
if (config.i18n) Object.keys(config.i18n.locales).forEach((locale) => {
|
|
2461
|
+
if (config.i18n) (Array.isArray(config.i18n.locales) ? config.i18n.locales : Object.keys(config.i18n.locales)).forEach((locale) => {
|
|
2205
2462
|
externalPaths.add(`/${locale}${p === "/" ? "" : p}`.replace(/\/$/, ""));
|
|
2206
2463
|
});
|
|
2207
2464
|
});
|
|
2208
|
-
targetBasePaths.forEach(({ path: bPath,
|
|
2465
|
+
targetBasePaths.forEach(({ path: bPath, locale: bLocale, version: bVersion }) => {
|
|
2209
2466
|
if (bPath === "/") return;
|
|
2210
2467
|
const normalizedPath = bPath.replace(/\/$/, "");
|
|
2211
2468
|
if (!(docPathRegistry.has(normalizedPath) || externalPaths.has(normalizedPath))) {
|
|
2212
2469
|
const defaultTab = config.theme?.tabs?.[0]?.id;
|
|
2213
2470
|
const defaultTabPath = defaultTab ? `${normalizedPath}/${defaultTab}`.replace(/\/+/g, "/") : null;
|
|
2214
|
-
let matchedRouteObj = defaultTabPath
|
|
2471
|
+
let matchedRouteObj = defaultTabPath ? docRoutes.find((r) => {
|
|
2472
|
+
return routeMetadata.get(r)?.path?.replace(/\/$/, "") === defaultTabPath.replace(/\/$/, "");
|
|
2473
|
+
}) : void 0;
|
|
2474
|
+
if (!matchedRouteObj) matchedRouteObj = docRoutes.find((r) => {
|
|
2475
|
+
const routePath = routeMetadata.get(r)?.path?.replace(/\/$/, "");
|
|
2476
|
+
return !!routePath && (routePath === normalizedPath || routePath.startsWith(`${normalizedPath}/`));
|
|
2477
|
+
});
|
|
2215
2478
|
if (!matchedRouteObj && docRoutes.length > 0) matchedRouteObj = docRoutes[0];
|
|
2479
|
+
if (matchedRouteObj && bLocale) {
|
|
2480
|
+
const localeBaseRoute = matchedRouteObj;
|
|
2481
|
+
const defaultLocale = config.i18n?.defaultLocale;
|
|
2482
|
+
const matchedMeta = routeMetadata.get(localeBaseRoute);
|
|
2483
|
+
const matchedIdentity = matchedMeta ? getDocumentIdentity(matchedMeta) : void 0;
|
|
2484
|
+
const localeMatch = docRoutes.find((r) => {
|
|
2485
|
+
const meta = routeMetadata.get(r);
|
|
2486
|
+
if (!meta || !matchedIdentity) return false;
|
|
2487
|
+
if (!(meta.locale === bLocale || bLocale === defaultLocale && !meta.locale)) return false;
|
|
2488
|
+
const identity = getDocumentIdentity(meta);
|
|
2489
|
+
return identity.path === matchedIdentity.path && identity.version === (bVersion || config.versions?.defaultVersion);
|
|
2490
|
+
});
|
|
2491
|
+
if (localeMatch) matchedRouteObj = localeMatch;
|
|
2492
|
+
}
|
|
2216
2493
|
if (matchedRouteObj) {
|
|
2494
|
+
const matchedRoute = matchedRouteObj;
|
|
2217
2495
|
const redirectPath = bPath === baseDocsPath ? "." : bPath.startsWith(baseDocsPath + "/") ? bPath.slice(baseDocsPath.length + 1) : bPath;
|
|
2218
2496
|
const isBasePathFallback = redirectPath === ".";
|
|
2219
|
-
|
|
2497
|
+
const matchedMetaObj = (() => {
|
|
2498
|
+
const matchedMeta = routeMetadata.get(matchedRoute);
|
|
2499
|
+
if (!matchedMeta) return void 0;
|
|
2500
|
+
const matchedIdentity = getDocumentIdentity(matchedMeta);
|
|
2501
|
+
const targetVersion = bVersion || config.versions?.defaultVersion;
|
|
2502
|
+
const targetLocale = bLocale || config.i18n?.defaultLocale;
|
|
2503
|
+
return docMetadata.find((m) => {
|
|
2504
|
+
const identity = getDocumentIdentity(m);
|
|
2505
|
+
const locale = m.locale || config.i18n?.defaultLocale;
|
|
2506
|
+
return identity.path === matchedIdentity.path && locale === targetLocale && identity.version === targetVersion;
|
|
2507
|
+
}) || matchedMeta;
|
|
2508
|
+
})();
|
|
2509
|
+
const fallbackMetaObj = matchedMetaObj ? {
|
|
2510
|
+
...matchedMetaObj,
|
|
2511
|
+
path: bPath,
|
|
2512
|
+
filePath: matchedMetaObj.filePath,
|
|
2513
|
+
locale: bLocale,
|
|
2514
|
+
version: bVersion,
|
|
2515
|
+
slugParts: [],
|
|
2516
|
+
fallback: true,
|
|
2517
|
+
seo: {
|
|
2518
|
+
...matchedMetaObj.seo,
|
|
2519
|
+
canonical: config.siteUrl ? `${config.siteUrl.replace(/\/$/, "")}${withBase(bPath, config)}` : withBase(bPath, config)
|
|
2520
|
+
}
|
|
2521
|
+
} : {
|
|
2522
|
+
path: bPath,
|
|
2523
|
+
filePath: "",
|
|
2524
|
+
title: redirectPath,
|
|
2525
|
+
componentPath: "",
|
|
2526
|
+
headings: [],
|
|
2527
|
+
locale: bLocale,
|
|
2528
|
+
version: bVersion,
|
|
2529
|
+
fallback: true
|
|
2530
|
+
};
|
|
2531
|
+
const fallbackRoute = {
|
|
2220
2532
|
...isBasePathFallback ? { index: true } : { path: redirectPath },
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
loader: matchedRouteObj.loader,
|
|
2533
|
+
locale: bLocale,
|
|
2534
|
+
loader: matchedRoute.loader,
|
|
2224
2535
|
getStaticPaths: () => []
|
|
2536
|
+
};
|
|
2537
|
+
const resolveFallbackComponent = async () => {
|
|
2538
|
+
const moduleKey = resolveModuleKey(fallbackMetaObj.filePath, moduleMap);
|
|
2539
|
+
const moduleLoader = moduleKey ? mdxModules[moduleKey] : null;
|
|
2540
|
+
const localeKey = bLocale || config.i18n?.defaultLocale || "en";
|
|
2541
|
+
const key = `${moduleKey || bPath}-${localeKey}`;
|
|
2542
|
+
if (!moduleLoader) return null;
|
|
2543
|
+
return /* @__PURE__ */ jsx(EagerMdxElement, {
|
|
2544
|
+
moduleKey,
|
|
2545
|
+
moduleLoader: await resolveModuleLoader(moduleLoader),
|
|
2546
|
+
route: fallbackMetaObj,
|
|
2547
|
+
components: components ?? {}
|
|
2548
|
+
}, key);
|
|
2549
|
+
};
|
|
2550
|
+
if (matchedRoute.lazy) fallbackRoute.lazy = async () => {
|
|
2551
|
+
const fallbackComponent = await resolveFallbackComponent();
|
|
2552
|
+
return { Component: () => /* @__PURE__ */ jsx(FallbackWrapper, { children: fallbackComponent }) };
|
|
2553
|
+
};
|
|
2554
|
+
else if (matchedRoute.element) fallbackRoute.element = matchedRoute.element;
|
|
2555
|
+
fallbackRoute.loader = async () => ({
|
|
2556
|
+
path: redirectPath,
|
|
2557
|
+
frontmatter: {
|
|
2558
|
+
title: fallbackMetaObj.title,
|
|
2559
|
+
description: fallbackMetaObj.description || "",
|
|
2560
|
+
...fallbackMetaObj.frontmatter || {}
|
|
2561
|
+
},
|
|
2562
|
+
seo: fallbackMetaObj.seo,
|
|
2563
|
+
headings: fallbackMetaObj.headings || [],
|
|
2564
|
+
filePath: fallbackMetaObj.filePath,
|
|
2565
|
+
locale: fallbackMetaObj.locale,
|
|
2566
|
+
version: fallbackMetaObj.version,
|
|
2567
|
+
group: fallbackMetaObj.group,
|
|
2568
|
+
groupTitle: fallbackMetaObj.groupTitle,
|
|
2569
|
+
date: fallbackMetaObj.date,
|
|
2570
|
+
lastUpdated: fallbackMetaObj.lastUpdated
|
|
2225
2571
|
});
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
return (fullPath === baseDocsPath ? "." : fullPath.startsWith(baseDocsPath + "/") ? fullPath.slice(baseDocsPath.length + 1) : fullPath) === matchedRouteObj.path;
|
|
2229
|
-
});
|
|
2230
|
-
if (matchedMetaObj) {
|
|
2231
|
-
const canonicalPath = withBase(matchedMetaObj.path, config);
|
|
2232
|
-
const canonicalUrl = config.siteUrl ? `${config.siteUrl.replace(/\/$/, "")}${canonicalPath}` : canonicalPath;
|
|
2233
|
-
docMetadata.push({
|
|
2234
|
-
...matchedMetaObj,
|
|
2235
|
-
path: bPath,
|
|
2236
|
-
filePath: matchedMetaObj.filePath,
|
|
2237
|
-
locale: bLocale,
|
|
2238
|
-
version: bVersion,
|
|
2239
|
-
slugParts: [],
|
|
2240
|
-
fallback: true,
|
|
2241
|
-
seo: {
|
|
2242
|
-
...matchedMetaObj.seo,
|
|
2243
|
-
canonical: canonicalUrl
|
|
2244
|
-
}
|
|
2245
|
-
});
|
|
2246
|
-
}
|
|
2572
|
+
docRoutes.push(fallbackRoute);
|
|
2573
|
+
docMetadata.push(fallbackMetaObj);
|
|
2247
2574
|
}
|
|
2248
2575
|
}
|
|
2249
2576
|
});
|
|
@@ -2264,6 +2591,97 @@ function ExternalPageWrapper({ children }) {
|
|
|
2264
2591
|
|
|
2265
2592
|
//#endregion
|
|
2266
2593
|
//#region src/client/ssg/create-routes.external.tsx
|
|
2594
|
+
function getLocales(config) {
|
|
2595
|
+
if (!config.i18n) return [];
|
|
2596
|
+
return Array.isArray(config.i18n.locales) ? config.i18n.locales : Object.keys(config.i18n.locales);
|
|
2597
|
+
}
|
|
2598
|
+
function getLocalizedPaths(pathname, config) {
|
|
2599
|
+
const paths = [{
|
|
2600
|
+
path: pathname,
|
|
2601
|
+
locale: config.i18n?.defaultLocale
|
|
2602
|
+
}];
|
|
2603
|
+
for (const locale of getLocales(config)) {
|
|
2604
|
+
const localizedPath = pathname === "/" ? `/${locale}` : `/${locale}${pathname}`;
|
|
2605
|
+
if (!paths.some((entry) => entry.path === localizedPath)) paths.push({
|
|
2606
|
+
path: localizedPath,
|
|
2607
|
+
locale
|
|
2608
|
+
});
|
|
2609
|
+
}
|
|
2610
|
+
return paths;
|
|
2611
|
+
}
|
|
2612
|
+
/**
|
|
2613
|
+
* Content wrapper for file-routed MDX pages. The external layout renders the
|
|
2614
|
+
* site chrome (navbar/footer), but unlike docs pages these routes are not
|
|
2615
|
+
* nested inside DocsLayout, so the MDX content needs its own page container
|
|
2616
|
+
* with the page title and prose typography — otherwise it renders raw and
|
|
2617
|
+
* edge-to-edge directly below the navbar.
|
|
2618
|
+
*/
|
|
2619
|
+
function ExternalMdxContent({ title, children, className, contentClassName }) {
|
|
2620
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2621
|
+
className: cn("boltdocs-page w-full pt-4 pb-20 px-4 sm:px-8", className),
|
|
2622
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2623
|
+
className: cn("mx-auto w-full max-w-3xl sm:max-w-4xl lg:max-w-5xl", contentClassName),
|
|
2624
|
+
children: [title && /* @__PURE__ */ jsx("h1", {
|
|
2625
|
+
className: "text-4xl font-bold tracking-tight text-body mb-3",
|
|
2626
|
+
children: title
|
|
2627
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2628
|
+
className: "prose prose-neutral dark:prose-invert max-w-none",
|
|
2629
|
+
children
|
|
2630
|
+
})]
|
|
2631
|
+
})
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2634
|
+
function routeTitle(pathname) {
|
|
2635
|
+
const segment = pathname === "/" ? "Home" : pathname.split("/").filter(Boolean).at(-1);
|
|
2636
|
+
return segment ? segment.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase()) : "Page";
|
|
2637
|
+
}
|
|
2638
|
+
function buildExternalRouteRecord(options) {
|
|
2639
|
+
const { path, locale, component, mdxLoader, externalLayout, components, title } = options;
|
|
2640
|
+
const record = {
|
|
2641
|
+
path,
|
|
2642
|
+
locale,
|
|
2643
|
+
loader: async () => ({
|
|
2644
|
+
path,
|
|
2645
|
+
locale
|
|
2646
|
+
}),
|
|
2647
|
+
getStaticPaths: () => [path]
|
|
2648
|
+
};
|
|
2649
|
+
const ExternalLayout = externalLayout;
|
|
2650
|
+
const ExternalComponent = component;
|
|
2651
|
+
if (ExternalComponent) record.element = /* @__PURE__ */ jsx(ExternalPageWrapper, { children: /* @__PURE__ */ jsx(ExternalLayout, { children: /* @__PURE__ */ jsx(ExternalComponent, {}) }) });
|
|
2652
|
+
else if (mdxLoader) record.lazy = async () => {
|
|
2653
|
+
const module = await resolveModuleLoader(mdxLoader);
|
|
2654
|
+
return { Component: function ExternalMdxRoute() {
|
|
2655
|
+
return /* @__PURE__ */ jsx(ExternalPageWrapper, { children: /* @__PURE__ */ jsx(ExternalLayout, { children: /* @__PURE__ */ jsx(ExternalMdxContent, {
|
|
2656
|
+
title,
|
|
2657
|
+
children: /* @__PURE__ */ jsx(EagerMdxElement, {
|
|
2658
|
+
moduleLoader: module,
|
|
2659
|
+
moduleKey: path,
|
|
2660
|
+
route: {
|
|
2661
|
+
path,
|
|
2662
|
+
title,
|
|
2663
|
+
filePath: path,
|
|
2664
|
+
componentPath: "",
|
|
2665
|
+
headings: [],
|
|
2666
|
+
locale
|
|
2667
|
+
},
|
|
2668
|
+
components: components || {}
|
|
2669
|
+
})
|
|
2670
|
+
}) }) });
|
|
2671
|
+
} };
|
|
2672
|
+
};
|
|
2673
|
+
return record;
|
|
2674
|
+
}
|
|
2675
|
+
function buildExternalRouteMetadata(path, locale, title) {
|
|
2676
|
+
return {
|
|
2677
|
+
path,
|
|
2678
|
+
locale,
|
|
2679
|
+
title,
|
|
2680
|
+
filePath: "",
|
|
2681
|
+
componentPath: "",
|
|
2682
|
+
headings: []
|
|
2683
|
+
};
|
|
2684
|
+
}
|
|
2267
2685
|
function buildExternalRoutes(options) {
|
|
2268
2686
|
const { externalPages, externalLayout, config } = options;
|
|
2269
2687
|
const children = [];
|
|
@@ -2272,56 +2690,78 @@ function buildExternalRoutes(options) {
|
|
|
2272
2690
|
children,
|
|
2273
2691
|
metadata
|
|
2274
2692
|
};
|
|
2275
|
-
const EffectiveExternalLayout = externalLayout || (({ children }) => /* @__PURE__ */ jsx(Fragment, { children }));
|
|
2693
|
+
const EffectiveExternalLayout = externalLayout || (({ children }) => /* @__PURE__ */ jsx(Fragment$1, { children }));
|
|
2276
2694
|
Object.entries(externalPages).forEach(([rawPath, ExtComponent]) => {
|
|
2277
|
-
const
|
|
2278
|
-
|
|
2279
|
-
path,
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
element: /* @__PURE__ */ jsx(ExternalPageWrapper, { children: /* @__PURE__ */ jsx(EffectiveExternalLayout, { children: /* @__PURE__ */ jsx(ExtComponent, {}) }) }),
|
|
2289
|
-
loader: async () => ({
|
|
2290
|
-
path,
|
|
2291
|
-
locale: config.i18n?.defaultLocale
|
|
2292
|
-
}),
|
|
2293
|
-
getStaticPaths: () => [path]
|
|
2294
|
-
});
|
|
2295
|
-
if (config.i18n) Object.keys(config.i18n.locales).forEach((locale) => {
|
|
2296
|
-
const localePath = `/${locale}${rawPath === "/" ? "" : rawPath}`;
|
|
2297
|
-
metadata.push({
|
|
2298
|
-
path: localePath,
|
|
2299
|
-
locale,
|
|
2300
|
-
title: rawPath,
|
|
2301
|
-
filePath: "",
|
|
2302
|
-
componentPath: "",
|
|
2303
|
-
headings: []
|
|
2304
|
-
});
|
|
2305
|
-
children.push({
|
|
2306
|
-
path: localePath,
|
|
2307
|
-
element: /* @__PURE__ */ jsx(ExternalPageWrapper, { children: /* @__PURE__ */ jsx(EffectiveExternalLayout, { children: /* @__PURE__ */ jsx(ExtComponent, {}) }) }),
|
|
2308
|
-
loader: async () => ({
|
|
2309
|
-
path: localePath,
|
|
2310
|
-
locale
|
|
2311
|
-
}),
|
|
2312
|
-
getStaticPaths: () => [localePath]
|
|
2313
|
-
});
|
|
2314
|
-
});
|
|
2695
|
+
const pathname = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
|
|
2696
|
+
for (const localized of getLocalizedPaths(pathname, config)) {
|
|
2697
|
+
metadata.push(buildExternalRouteMetadata(localized.path, localized.locale, routeTitle(pathname)));
|
|
2698
|
+
children.push({ ...buildExternalRouteRecord({
|
|
2699
|
+
path: localized.path,
|
|
2700
|
+
locale: localized.locale,
|
|
2701
|
+
component: ExtComponent,
|
|
2702
|
+
externalLayout: EffectiveExternalLayout,
|
|
2703
|
+
title: routeTitle(pathname)
|
|
2704
|
+
}) });
|
|
2705
|
+
}
|
|
2315
2706
|
});
|
|
2316
2707
|
return {
|
|
2317
2708
|
children,
|
|
2318
2709
|
metadata
|
|
2319
2710
|
};
|
|
2320
2711
|
}
|
|
2712
|
+
function buildExternalFileRoutes(options) {
|
|
2713
|
+
const { externalFilePages, externalFileMdx, externalLayout, components, config } = options;
|
|
2714
|
+
const children = [];
|
|
2715
|
+
const metadata = [];
|
|
2716
|
+
if (!externalFilePages && !externalFileMdx) return {
|
|
2717
|
+
children,
|
|
2718
|
+
metadata
|
|
2719
|
+
};
|
|
2720
|
+
const EffectiveExternalLayout = externalLayout || (({ children }) => /* @__PURE__ */ jsx(Fragment$1, { children }));
|
|
2721
|
+
const locales = getLocales(config);
|
|
2722
|
+
const isLocalizedPath = (pathname) => locales.some((locale) => pathname === `/${locale}` || pathname.startsWith(`/${locale}/`));
|
|
2723
|
+
const localeOfPath = (pathname) => {
|
|
2724
|
+
const first = pathname.split("/").filter(Boolean)[0];
|
|
2725
|
+
return first && locales.includes(first) ? first : void 0;
|
|
2726
|
+
};
|
|
2727
|
+
const fileRoutes = new Set([...Object.keys(externalFilePages || {}), ...Object.keys(externalFileMdx || {})]);
|
|
2728
|
+
const registeredPaths = /* @__PURE__ */ new Set();
|
|
2729
|
+
const pushRoute = (pathname, locale, mdxLoader, component) => {
|
|
2730
|
+
if (registeredPaths.has(pathname)) return;
|
|
2731
|
+
registeredPaths.add(pathname);
|
|
2732
|
+
metadata.push(buildExternalRouteMetadata(pathname, locale, routeTitle(pathname)));
|
|
2733
|
+
children.push(buildExternalRouteRecord({
|
|
2734
|
+
path: pathname,
|
|
2735
|
+
locale,
|
|
2736
|
+
component,
|
|
2737
|
+
mdxLoader,
|
|
2738
|
+
externalLayout: EffectiveExternalLayout,
|
|
2739
|
+
components,
|
|
2740
|
+
title: routeTitle(pathname)
|
|
2741
|
+
}));
|
|
2742
|
+
};
|
|
2743
|
+
for (const pathname of fileRoutes) pushRoute(pathname, localeOfPath(pathname) || config.i18n?.defaultLocale, externalFileMdx?.[pathname], externalFilePages?.[pathname]);
|
|
2744
|
+
for (const pathname of fileRoutes) {
|
|
2745
|
+
if (isLocalizedPath(pathname)) continue;
|
|
2746
|
+
const mdxLoader = externalFileMdx?.[pathname];
|
|
2747
|
+
const component = externalFilePages?.[pathname];
|
|
2748
|
+
for (const localized of getLocalizedPaths(pathname, config)) pushRoute(localized.path, localized.locale, mdxLoader, component);
|
|
2749
|
+
}
|
|
2750
|
+
return {
|
|
2751
|
+
children,
|
|
2752
|
+
metadata
|
|
2753
|
+
};
|
|
2754
|
+
}
|
|
2321
2755
|
|
|
2322
2756
|
//#endregion
|
|
2323
2757
|
//#region src/client/collections/hooks.ts
|
|
2324
2758
|
const DEFAULT_COLLECTION = "blog";
|
|
2759
|
+
const NO_DATE = Number.NEGATIVE_INFINITY;
|
|
2760
|
+
function getPostTimestamp(date) {
|
|
2761
|
+
if (!date) return NO_DATE;
|
|
2762
|
+
const timestamp = new Date(date).getTime();
|
|
2763
|
+
return Number.isFinite(timestamp) ? timestamp : NO_DATE;
|
|
2764
|
+
}
|
|
2325
2765
|
/**
|
|
2326
2766
|
* Returns the posts of a collection, filtered by the current locale and version.
|
|
2327
2767
|
* Defaults to "blog" if no collection is specified.
|
|
@@ -2345,6 +2785,10 @@ function usePosts(collection = DEFAULT_COLLECTION, options) {
|
|
|
2345
2785
|
const versionMatch = !currentVersion || postVersion === currentVersion;
|
|
2346
2786
|
const draftMatch = options?.includeDrafts || !post.draft;
|
|
2347
2787
|
return localeMatch && versionMatch && draftMatch;
|
|
2788
|
+
}).sort((a, b) => {
|
|
2789
|
+
const dateA = getPostTimestamp(a.date);
|
|
2790
|
+
const dateOrder = getPostTimestamp(b.date) - dateA;
|
|
2791
|
+
return dateOrder !== 0 ? dateOrder : a.path.localeCompare(b.path);
|
|
2348
2792
|
});
|
|
2349
2793
|
}, [
|
|
2350
2794
|
posts,
|
|
@@ -2396,20 +2840,57 @@ function useRecentPosts(collection = DEFAULT_COLLECTION, count = 5) {
|
|
|
2396
2840
|
|
|
2397
2841
|
//#endregion
|
|
2398
2842
|
//#region src/client/ssg/create-routes.collection.tsx
|
|
2843
|
+
function CollectionIndex({ indexContent, ListElement }) {
|
|
2844
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [indexContent, /* @__PURE__ */ jsx(ListElement, {})] });
|
|
2845
|
+
}
|
|
2846
|
+
function splitCollectionPath(routePath) {
|
|
2847
|
+
return routePath.split("/").filter(Boolean);
|
|
2848
|
+
}
|
|
2849
|
+
/**
|
|
2850
|
+
* Resolve the child path of a collection post relative to its layout route.
|
|
2851
|
+
*
|
|
2852
|
+
* Route generation emits collection paths without the configured docs base
|
|
2853
|
+
* (e.g. `/blog/post` or `/es/blog/post`), while the collection layout lives
|
|
2854
|
+
* under the base (`/docs/blog`). Keeping everything after the collection
|
|
2855
|
+
* segment as a *relative* child path is what makes the router match
|
|
2856
|
+
* `/docs/blog/post` and the SSG emit `dist/docs/blog/post.html` — never a
|
|
2857
|
+
* root-level `/blog/post` that neither the matcher nor the cache can reach.
|
|
2858
|
+
*/
|
|
2859
|
+
function getCollectionSubPath(routePath, colBase, collection) {
|
|
2860
|
+
if (routePath.startsWith(`${colBase}/`)) return routePath.slice(colBase.length + 1);
|
|
2861
|
+
const parts = splitCollectionPath(routePath);
|
|
2862
|
+
const collectionIndex = parts.indexOf(collection);
|
|
2863
|
+
if (collectionIndex >= 0) return parts.slice(collectionIndex + 1).join("/");
|
|
2864
|
+
return parts.join("/");
|
|
2865
|
+
}
|
|
2866
|
+
function isCollectionIndexRoute(route, collection) {
|
|
2867
|
+
const normalizedPath = route.path.replace(/\/$/, "");
|
|
2868
|
+
return normalizedPath === `/${collection}` || normalizedPath.endsWith(`/${collection}`);
|
|
2869
|
+
}
|
|
2870
|
+
function getCollectionModule(route, moduleMap, mdxModules) {
|
|
2871
|
+
const moduleKey = resolveModuleKey(route.filePath, moduleMap);
|
|
2872
|
+
return {
|
|
2873
|
+
moduleKey,
|
|
2874
|
+
moduleLoader: moduleKey ? mdxModules[moduleKey] : null
|
|
2875
|
+
};
|
|
2876
|
+
}
|
|
2399
2877
|
function DefaultCollectionList() {
|
|
2400
|
-
const location = useLocation
|
|
2878
|
+
const location = useLocation();
|
|
2401
2879
|
const config = useConfig();
|
|
2880
|
+
const loaderData = useLoaderData();
|
|
2402
2881
|
const postsPerPage = config.collections?.postsPerPage ?? 10;
|
|
2403
|
-
const
|
|
2404
|
-
const
|
|
2405
|
-
const collection =
|
|
2406
|
-
const currentPage = (isLocalePrefixed ? segments[3] : segments[2]) === "page" ? Number(isLocalePrefixed ? segments[4] : segments[3]) || 1 : 1;
|
|
2882
|
+
const basePath = location.pathname.replace(/\/page\/\d+\/?$/, "").replace(/\/$/, "");
|
|
2883
|
+
const segments = basePath.split("/").filter(Boolean);
|
|
2884
|
+
const collection = loaderData && loaderData.collection || segments[segments.length - 1];
|
|
2407
2885
|
const allPosts = usePosts(collection);
|
|
2408
|
-
const totalPages = Math.ceil(allPosts.length / postsPerPage);
|
|
2886
|
+
const totalPages = loaderData && loaderData.totalPages || Math.ceil(allPosts.length / postsPerPage);
|
|
2887
|
+
const currentPage = loaderData && loaderData.currentPage || (() => {
|
|
2888
|
+
const match = location.pathname.match(/\/page\/(\d+)\/?$/);
|
|
2889
|
+
return match ? Number(match[1]) : 1;
|
|
2890
|
+
})();
|
|
2409
2891
|
const start = (currentPage - 1) * postsPerPage;
|
|
2410
|
-
const posts = allPosts.slice(start, start + postsPerPage);
|
|
2892
|
+
const posts = loaderData && loaderData.posts || allPosts.slice(start, start + postsPerPage);
|
|
2411
2893
|
if (!posts.length) return null;
|
|
2412
|
-
const basePath = isLocalePrefixed ? `/${segments[0]}/${segments[1]}` : `/${segments[0]}`;
|
|
2413
2894
|
return /* @__PURE__ */ jsxs("div", {
|
|
2414
2895
|
className: "py-8 max-w-2xl mx-auto px-4",
|
|
2415
2896
|
children: [
|
|
@@ -2476,111 +2957,197 @@ function buildCollectionRoutes(options) {
|
|
|
2476
2957
|
collectionsMap.get(r.collection).push(r);
|
|
2477
2958
|
}
|
|
2478
2959
|
const moduleMap = buildModuleMap(mdxModules);
|
|
2479
|
-
const
|
|
2480
|
-
const isLazy = mdxModuleKeys.length > 0 && typeof mdxModules[mdxModuleKeys[0]] === "function";
|
|
2960
|
+
const defaultLocale = config.i18n?.defaultLocale || "en";
|
|
2481
2961
|
for (const [colName, colRoutes] of collectionsMap) {
|
|
2482
|
-
const
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
const
|
|
2493
|
-
const
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2962
|
+
const postsByVariant = /* @__PURE__ */ new Map();
|
|
2963
|
+
const indexByVariant = /* @__PURE__ */ new Map();
|
|
2964
|
+
for (const r of colRoutes) {
|
|
2965
|
+
const effectiveLocale = r.locale || defaultLocale;
|
|
2966
|
+
const key = `${r.version || ""}::${effectiveLocale}`;
|
|
2967
|
+
if (!postsByVariant.has(key)) postsByVariant.set(key, []);
|
|
2968
|
+
if (isCollectionIndexRoute(r, colName)) indexByVariant.set(key, r);
|
|
2969
|
+
else postsByVariant.get(key).push(r);
|
|
2970
|
+
}
|
|
2971
|
+
for (const [variant, variantRoutes] of postsByVariant) {
|
|
2972
|
+
const [version, locale] = variant.split("::");
|
|
2973
|
+
const localeRoutes = variantRoutes;
|
|
2974
|
+
const colBase = buildUrl({
|
|
2975
|
+
kind: "collection",
|
|
2976
|
+
collection: colName,
|
|
2977
|
+
path: "/",
|
|
2978
|
+
locale: locale === defaultLocale ? void 0 : locale,
|
|
2979
|
+
version: version || void 0
|
|
2980
|
+
}, {
|
|
2981
|
+
base: config.base,
|
|
2982
|
+
i18n: config.i18n,
|
|
2983
|
+
versions: config.versions,
|
|
2984
|
+
collections: [colName]
|
|
2985
|
+
});
|
|
2986
|
+
localeRoutes.sort((a, b) => {
|
|
2987
|
+
const getTimestamp = (date) => {
|
|
2988
|
+
if (!date) return Number.NEGATIVE_INFINITY;
|
|
2989
|
+
const value = new Date(date).getTime();
|
|
2990
|
+
return Number.isFinite(value) ? value : Number.NEGATIVE_INFINITY;
|
|
2991
|
+
};
|
|
2992
|
+
const da = getTimestamp(a.date);
|
|
2993
|
+
const dateOrder = getTimestamp(b.date) - da;
|
|
2994
|
+
return dateOrder !== 0 ? dateOrder : a.path.localeCompare(b.path);
|
|
2995
|
+
});
|
|
2996
|
+
const colChildren = [];
|
|
2997
|
+
for (const route of localeRoutes) {
|
|
2998
|
+
const { moduleKey, moduleLoader } = getCollectionModule(route, moduleMap, mdxModules);
|
|
2999
|
+
const subPath = getCollectionSubPath(route.path, colBase, colName);
|
|
3000
|
+
const routeWithCollection = {
|
|
3001
|
+
...route,
|
|
3002
|
+
collection: colName
|
|
3003
|
+
};
|
|
3004
|
+
const postComponent = collectionPosts?.[colName];
|
|
3005
|
+
const routeRecord = {
|
|
3006
|
+
path: subPath,
|
|
3007
|
+
loader: async () => ({
|
|
3008
|
+
route: routeWithCollection,
|
|
3009
|
+
headings: route.headings || [],
|
|
3010
|
+
collection: colName,
|
|
3011
|
+
path: subPath,
|
|
3012
|
+
frontmatter: {
|
|
3013
|
+
title: route.title,
|
|
3014
|
+
description: route.description || "",
|
|
3015
|
+
...route.frontmatter || {}
|
|
3016
|
+
},
|
|
3017
|
+
filePath: route.filePath,
|
|
3018
|
+
locale: route.locale,
|
|
3019
|
+
version: route.version,
|
|
3020
|
+
date: route.date,
|
|
3021
|
+
lastUpdated: route.lastUpdated
|
|
3022
|
+
}),
|
|
3023
|
+
getStaticPaths: () => [subPath || "."]
|
|
3024
|
+
};
|
|
3025
|
+
if (moduleLoader) routeRecord.lazy = async () => {
|
|
3026
|
+
const mod = await resolveModuleLoader(moduleLoader);
|
|
3027
|
+
return { Component: function LoadedCollectionMdxRoute() {
|
|
3028
|
+
return /* @__PURE__ */ jsx(EagerMdxElement, {
|
|
3029
|
+
moduleKey,
|
|
3030
|
+
moduleLoader: mod,
|
|
3031
|
+
route,
|
|
3032
|
+
components,
|
|
3033
|
+
collectionPostComponent: postComponent
|
|
3034
|
+
}, `${moduleKey || subPath}-${locale}`);
|
|
3035
|
+
} };
|
|
3036
|
+
};
|
|
3037
|
+
else routeRecord.element = /* @__PURE__ */ jsx(EagerMdxElement, {
|
|
3038
|
+
moduleKey,
|
|
3039
|
+
moduleLoader: {},
|
|
3040
|
+
route,
|
|
3041
|
+
components,
|
|
3042
|
+
collectionPostComponent: postComponent
|
|
3043
|
+
}, `${moduleKey || subPath}-${locale}`);
|
|
3044
|
+
colChildren.push(routeRecord);
|
|
3045
|
+
metadata.push(route);
|
|
3046
|
+
}
|
|
3047
|
+
const totalPages = Math.ceil(localeRoutes.length / postsPerPage);
|
|
3048
|
+
const paginatedPosts = localeRoutes.map((r) => ({
|
|
3049
|
+
path: r.path,
|
|
3050
|
+
title: r.title,
|
|
3051
|
+
date: r.date,
|
|
3052
|
+
excerpt: r.excerpt,
|
|
3053
|
+
tags: r.tags,
|
|
3054
|
+
author: r.author,
|
|
3055
|
+
coverImage: r.coverImage,
|
|
3056
|
+
filePath: r.filePath,
|
|
3057
|
+
locale: r.locale,
|
|
3058
|
+
version: r.version,
|
|
3059
|
+
lastUpdated: r.lastUpdated,
|
|
3060
|
+
frontmatter: r.frontmatter
|
|
3061
|
+
}));
|
|
3062
|
+
const ListElement = collectionLists?.[colName] || DefaultCollectionList;
|
|
3063
|
+
const indexRoute = indexByVariant.get(variant);
|
|
3064
|
+
const indexRecord = {
|
|
3065
|
+
index: true,
|
|
3066
|
+
path: "",
|
|
2500
3067
|
loader: async () => ({
|
|
2501
|
-
|
|
2502
|
-
|
|
3068
|
+
posts: paginatedPosts.slice(0, postsPerPage),
|
|
3069
|
+
totalPages,
|
|
3070
|
+
currentPage: 1,
|
|
2503
3071
|
collection: colName,
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
3072
|
+
...indexRoute ? {
|
|
3073
|
+
route: indexRoute,
|
|
3074
|
+
headings: indexRoute.headings || [],
|
|
3075
|
+
frontmatter: {
|
|
3076
|
+
title: indexRoute.title,
|
|
3077
|
+
description: indexRoute.description || "",
|
|
3078
|
+
...indexRoute.frontmatter || {}
|
|
3079
|
+
},
|
|
3080
|
+
filePath: indexRoute.filePath,
|
|
3081
|
+
locale: indexRoute.locale,
|
|
3082
|
+
version: indexRoute.version
|
|
3083
|
+
} : {}
|
|
2515
3084
|
}),
|
|
2516
|
-
getStaticPaths: () => [
|
|
3085
|
+
getStaticPaths: () => [""]
|
|
2517
3086
|
};
|
|
2518
|
-
if (
|
|
2519
|
-
const
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
3087
|
+
if (indexRoute) {
|
|
3088
|
+
const { moduleKey, moduleLoader } = getCollectionModule(indexRoute, moduleMap, mdxModules);
|
|
3089
|
+
const postComponent = collectionPosts?.[colName];
|
|
3090
|
+
const createIndexContent = (resolvedModule) => /* @__PURE__ */ jsx(EagerMdxElement, {
|
|
3091
|
+
moduleKey,
|
|
3092
|
+
moduleLoader: resolvedModule,
|
|
3093
|
+
route: indexRoute,
|
|
3094
|
+
components,
|
|
3095
|
+
collectionPostComponent: postComponent
|
|
3096
|
+
}, `${moduleKey || colBase}-${locale}`);
|
|
3097
|
+
if (moduleLoader) indexRecord.lazy = async () => {
|
|
3098
|
+
const mod = await resolveModuleLoader(moduleLoader);
|
|
3099
|
+
return { Component: function LoadedCollectionIndex() {
|
|
3100
|
+
return /* @__PURE__ */ jsx(CollectionIndex, {
|
|
3101
|
+
indexContent: createIndexContent(mod),
|
|
3102
|
+
ListElement
|
|
3103
|
+
});
|
|
3104
|
+
} };
|
|
3105
|
+
};
|
|
3106
|
+
else indexRecord.element = /* @__PURE__ */ jsx(CollectionIndex, {
|
|
3107
|
+
indexContent: createIndexContent({}),
|
|
3108
|
+
ListElement
|
|
3109
|
+
});
|
|
3110
|
+
} else indexRecord.element = /* @__PURE__ */ jsx(ListElement, {});
|
|
3111
|
+
colChildren.unshift(indexRecord);
|
|
3112
|
+
metadata.push({
|
|
3113
|
+
path: colBase,
|
|
3114
|
+
locale,
|
|
3115
|
+
collection: colName,
|
|
3116
|
+
title: indexRoute?.title || colName,
|
|
3117
|
+
filePath: indexRoute?.filePath || "",
|
|
3118
|
+
componentPath: indexRoute?.componentPath || "",
|
|
3119
|
+
headings: indexRoute?.headings || []
|
|
3120
|
+
});
|
|
3121
|
+
for (let p = 2; p <= totalPages; p++) {
|
|
3122
|
+
const pagePath = `page/${p}`;
|
|
3123
|
+
colChildren.push({
|
|
3124
|
+
path: pagePath,
|
|
3125
|
+
element: /* @__PURE__ */ jsx(ListElement, {}),
|
|
3126
|
+
loader: async () => ({
|
|
3127
|
+
posts: paginatedPosts.slice((p - 1) * postsPerPage, p * postsPerPage),
|
|
3128
|
+
totalPages,
|
|
3129
|
+
currentPage: p,
|
|
3130
|
+
collection: colName
|
|
3131
|
+
}),
|
|
3132
|
+
getStaticPaths: () => [pagePath]
|
|
3133
|
+
});
|
|
3134
|
+
metadata.push({
|
|
3135
|
+
path: `${colBase}/${pagePath}`.replace(/\/+/g, "/"),
|
|
3136
|
+
locale,
|
|
3137
|
+
collection: colName,
|
|
3138
|
+
title: colName,
|
|
3139
|
+
filePath: "",
|
|
3140
|
+
componentPath: "",
|
|
3141
|
+
headings: []
|
|
3142
|
+
});
|
|
3143
|
+
}
|
|
3144
|
+
const blogLayoutRoute = {
|
|
3145
|
+
path: colBase,
|
|
3146
|
+
element: /* @__PURE__ */ jsx(collectionLayouts?.[colName] || DocsLayout, { collectionsData: collectionsData || {} }),
|
|
3147
|
+
children: colChildren
|
|
2529
3148
|
};
|
|
2530
|
-
|
|
2531
|
-
moduleKey,
|
|
2532
|
-
moduleLoader,
|
|
2533
|
-
route,
|
|
2534
|
-
components,
|
|
2535
|
-
collectionPostComponent: postComponent
|
|
2536
|
-
}, moduleKey || subPath);
|
|
2537
|
-
colChildren.push(routeRecord);
|
|
2538
|
-
metadata.push(route);
|
|
3149
|
+
children.push(blogLayoutRoute);
|
|
2539
3150
|
}
|
|
2540
|
-
const totalPages = Math.ceil(colRoutes.length / postsPerPage);
|
|
2541
|
-
const paginatedPosts = colRoutes.map((r) => ({
|
|
2542
|
-
path: r.path,
|
|
2543
|
-
title: r.title,
|
|
2544
|
-
date: r.date,
|
|
2545
|
-
excerpt: r.excerpt,
|
|
2546
|
-
tags: r.tags,
|
|
2547
|
-
author: r.author,
|
|
2548
|
-
coverImage: r.coverImage,
|
|
2549
|
-
filePath: r.filePath,
|
|
2550
|
-
locale: r.locale,
|
|
2551
|
-
version: r.version,
|
|
2552
|
-
lastUpdated: r.lastUpdated,
|
|
2553
|
-
frontmatter: r.frontmatter
|
|
2554
|
-
}));
|
|
2555
|
-
const ListElement = collectionLists?.[colName] || DefaultCollectionList;
|
|
2556
|
-
colChildren.unshift({
|
|
2557
|
-
index: true,
|
|
2558
|
-
element: /* @__PURE__ */ jsx(ListElement, {}),
|
|
2559
|
-
loader: async () => ({
|
|
2560
|
-
posts: paginatedPosts.slice(0, postsPerPage),
|
|
2561
|
-
totalPages,
|
|
2562
|
-
currentPage: 1,
|
|
2563
|
-
collection: colName
|
|
2564
|
-
}),
|
|
2565
|
-
getStaticPaths: () => []
|
|
2566
|
-
});
|
|
2567
|
-
for (let p = 2; p <= totalPages; p++) colChildren.push({
|
|
2568
|
-
path: `page/${p}`,
|
|
2569
|
-
element: /* @__PURE__ */ jsx(ListElement, {}),
|
|
2570
|
-
loader: async () => ({
|
|
2571
|
-
posts: paginatedPosts.slice((p - 1) * postsPerPage, p * postsPerPage),
|
|
2572
|
-
totalPages,
|
|
2573
|
-
currentPage: p,
|
|
2574
|
-
collection: colName
|
|
2575
|
-
}),
|
|
2576
|
-
getStaticPaths: () => [`page/${p}`]
|
|
2577
|
-
});
|
|
2578
|
-
const blogLayoutRoute = {
|
|
2579
|
-
path: colBase,
|
|
2580
|
-
element: /* @__PURE__ */ jsx(collectionLayouts?.[colName] || DocsLayout, { collectionsData: collectionsData || {} }),
|
|
2581
|
-
children: colChildren
|
|
2582
|
-
};
|
|
2583
|
-
children.push(blogLayoutRoute);
|
|
2584
3151
|
}
|
|
2585
3152
|
return {
|
|
2586
3153
|
children,
|
|
@@ -2592,10 +3159,26 @@ function buildCollectionRoutes(options) {
|
|
|
2592
3159
|
//#region src/client/ssg/create-routes.tsx
|
|
2593
3160
|
function createRoutes(options) {
|
|
2594
3161
|
const { config, components, externalLayout } = options;
|
|
2595
|
-
const EffectiveExternalLayout = externalLayout || (({ children }) => /* @__PURE__ */ jsx(Fragment, { children }));
|
|
3162
|
+
const EffectiveExternalLayout = externalLayout || (({ children }) => /* @__PURE__ */ jsx(Fragment$1, { children }));
|
|
2596
3163
|
const baseDocsPath = (config.base || "/docs").replace(/\/$/, "") || "/";
|
|
2597
3164
|
const { routes: docRoutes, metadata: docMetadata } = buildDocRoutes(options);
|
|
2598
3165
|
const externalRoutes = buildExternalRoutes(options);
|
|
3166
|
+
const externalFileRoutes = config.experimental?.fileRouting ? buildExternalFileRoutes(options) : {
|
|
3167
|
+
children: [],
|
|
3168
|
+
metadata: []
|
|
3169
|
+
};
|
|
3170
|
+
const occupiedPaths = new Set([...docMetadata.map((route) => route.path), ...externalRoutes.metadata.map((route) => route.path)]);
|
|
3171
|
+
const acceptedExternalFilePaths = /* @__PURE__ */ new Set();
|
|
3172
|
+
const filteredExternalFileRoutes = {
|
|
3173
|
+
children: externalFileRoutes.children,
|
|
3174
|
+
metadata: externalFileRoutes.metadata.filter((route) => {
|
|
3175
|
+
if (occupiedPaths.has(route.path)) return false;
|
|
3176
|
+
occupiedPaths.add(route.path);
|
|
3177
|
+
acceptedExternalFilePaths.add(route.path);
|
|
3178
|
+
return true;
|
|
3179
|
+
})
|
|
3180
|
+
};
|
|
3181
|
+
filteredExternalFileRoutes.children = externalFileRoutes.children.filter((route) => !route.path || acceptedExternalFilePaths.has(route.path));
|
|
2599
3182
|
const collectionRoutes = buildCollectionRoutes(options);
|
|
2600
3183
|
const children = [
|
|
2601
3184
|
{
|
|
@@ -2604,18 +3187,20 @@ function createRoutes(options) {
|
|
|
2604
3187
|
children: docRoutes
|
|
2605
3188
|
},
|
|
2606
3189
|
...externalRoutes.children,
|
|
3190
|
+
...filteredExternalFileRoutes.children,
|
|
2607
3191
|
...collectionRoutes.children,
|
|
2608
3192
|
{
|
|
2609
3193
|
path: "*",
|
|
2610
3194
|
element: /* @__PURE__ */ jsx(ExternalPageWrapper, { children: /* @__PURE__ */ jsx(EffectiveExternalLayout, { children: /* @__PURE__ */ jsx(NotFoundWrapper, {}) }) })
|
|
2611
3195
|
}
|
|
2612
3196
|
];
|
|
2613
|
-
|
|
3197
|
+
const routes = [{
|
|
2614
3198
|
element: /* @__PURE__ */ jsx(BoltdocsShell, {
|
|
2615
3199
|
config,
|
|
2616
3200
|
routes: [
|
|
2617
3201
|
...docMetadata,
|
|
2618
3202
|
...externalRoutes.metadata,
|
|
3203
|
+
...filteredExternalFileRoutes.metadata,
|
|
2619
3204
|
...collectionRoutes.metadata
|
|
2620
3205
|
],
|
|
2621
3206
|
components,
|
|
@@ -2623,6 +3208,19 @@ function createRoutes(options) {
|
|
|
2623
3208
|
}),
|
|
2624
3209
|
children
|
|
2625
3210
|
}];
|
|
3211
|
+
const BaseAwareRouteRenderer = (props) => /* @__PURE__ */ jsx(RouteRenderer, {
|
|
3212
|
+
...props,
|
|
3213
|
+
basename: config.base,
|
|
3214
|
+
defaultLocale: config.i18n?.defaultLocale,
|
|
3215
|
+
viewTransitions: config.experimental?.viewTransitions === true ? true : typeof config.experimental?.viewTransitions === "object" ? config.experimental.viewTransitions : void 0
|
|
3216
|
+
});
|
|
3217
|
+
return {
|
|
3218
|
+
routes,
|
|
3219
|
+
RouteRenderer: BaseAwareRouteRenderer,
|
|
3220
|
+
matchRouteBranch,
|
|
3221
|
+
matchRouteBranchWithParams,
|
|
3222
|
+
resolveRouteBranch
|
|
3223
|
+
};
|
|
2626
3224
|
}
|
|
2627
3225
|
|
|
2628
3226
|
//#endregion
|
|
@@ -2647,32 +3245,38 @@ function DocsLayoutComponent({ children }) {
|
|
|
2647
3245
|
routes: filteredRoutes || [],
|
|
2648
3246
|
config
|
|
2649
3247
|
}),
|
|
2650
|
-
/* @__PURE__ */ jsx(DocsLayout$1.Content, { children: /* @__PURE__ */ jsxs(DocsLayout$1.ContentMdx, {
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
3248
|
+
/* @__PURE__ */ jsx(DocsLayout$1.Content, { children: /* @__PURE__ */ jsxs(DocsLayout$1.ContentMdx, {
|
|
3249
|
+
className: "pt-4 pb-20 px-4 sm:px-8",
|
|
3250
|
+
children: [
|
|
3251
|
+
!isCollectionPage && /* @__PURE__ */ jsxs(DocsLayout$1.Header, { children: [
|
|
3252
|
+
/* @__PURE__ */ jsxs("div", {
|
|
3253
|
+
className: "mb-4 border-b border-subtle pb-4 flex flex-wrap items-center justify-between gap-3",
|
|
3254
|
+
children: [/* @__PURE__ */ jsx(Breadcrumbs, {}), /* @__PURE__ */ jsx(CopyMarkdown, {
|
|
3255
|
+
mdxRaw: currentRoute?._rawContent,
|
|
3256
|
+
route: currentRoute
|
|
3257
|
+
})]
|
|
3258
|
+
}),
|
|
3259
|
+
currentRoute?.title && /* @__PURE__ */ jsx("h1", {
|
|
3260
|
+
className: "text-4xl font-bold tracking-tight text-body mb-3",
|
|
3261
|
+
children: currentRoute.title
|
|
3262
|
+
}),
|
|
3263
|
+
currentRoute?.description && /* @__PURE__ */ jsx("p", {
|
|
3264
|
+
className: "text-lg text-muted mb-6 leading-relaxed",
|
|
3265
|
+
children: currentRoute.description
|
|
3266
|
+
})
|
|
3267
|
+
] }),
|
|
3268
|
+
/* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx("div", {
|
|
3269
|
+
className: "prose prose-neutral dark:prose-invert max-w-none",
|
|
3270
|
+
children: children ?? /* @__PURE__ */ jsx(Outlet, {})
|
|
3271
|
+
}) }),
|
|
3272
|
+
!isCollectionPage && /* @__PURE__ */ jsx(Feedback, {}),
|
|
3273
|
+
!isCollectionPage && /* @__PURE__ */ jsx(Giscus, {}),
|
|
3274
|
+
!isCollectionPage && /* @__PURE__ */ jsx("div", {
|
|
3275
|
+
className: "mt-20",
|
|
3276
|
+
children: /* @__PURE__ */ jsx(PageNav, {})
|
|
2666
3277
|
})
|
|
2667
|
-
]
|
|
2668
|
-
|
|
2669
|
-
className: "prose prose-neutral dark:prose-invert max-w-none",
|
|
2670
|
-
children
|
|
2671
|
-
}) }),
|
|
2672
|
-
!isCollectionPage && /* @__PURE__ */ jsx(Feedback, {}),
|
|
2673
|
-
!isCollectionPage && /* @__PURE__ */ jsx(Giscus, {}),
|
|
2674
|
-
/* @__PURE__ */ jsx(DocsLayout$1.Footer, { children: !isCollectionPage && /* @__PURE__ */ jsx(PageNav, {}) })
|
|
2675
|
-
] }) }),
|
|
3278
|
+
]
|
|
3279
|
+
}) }),
|
|
2676
3280
|
/* @__PURE__ */ jsx("div", {
|
|
2677
3281
|
className: "overflow-y-auto sticky",
|
|
2678
3282
|
children: /* @__PURE__ */ jsx(OnThisPage, {
|
|
@@ -2702,4 +3306,46 @@ const reactToText = (node, resolvers) => {
|
|
|
2702
3306
|
};
|
|
2703
3307
|
|
|
2704
3308
|
//#endregion
|
|
2705
|
-
|
|
3309
|
+
//#region src/client/components/mdx/use-code-block.ts
|
|
3310
|
+
/**
|
|
3311
|
+
* @deprecated Use the feature-scoped hooks instead: `useCopyButton`,
|
|
3312
|
+
* `useExpandable` and `useCodeBlockFeedback`. This composition keeps the
|
|
3313
|
+
* historical single-hook API and will be removed in a future major version.
|
|
3314
|
+
*/
|
|
3315
|
+
function useCodeBlock(props) {
|
|
3316
|
+
const lang = props.lang || props["data-lang"] || "";
|
|
3317
|
+
const isHighlighted = props["data-highlighted"] === "true" || typeof props.className === "string" && props.className.includes("shiki");
|
|
3318
|
+
const rawHighlightedHtml = props.highlightedHtml || props["data-highlighted-html"];
|
|
3319
|
+
const effectiveHighlightedHtml = typeof rawHighlightedHtml === "string" ? rawHighlightedHtml.replace(/<span class="line">\s*(?:<span[^>]*>\s*<\/span>)?\s*<\/span>\s*(<\/code>\s*<\/pre>)/g, "$1") : rawHighlightedHtml;
|
|
3320
|
+
const effectiveTitle = props.title || props["data-title"];
|
|
3321
|
+
const { copied, handleCopy } = useCopyButton();
|
|
3322
|
+
const { isExpanded, setIsExpanded, isExpandable, shouldTruncate, preRef } = useExpandable({
|
|
3323
|
+
children: props.children,
|
|
3324
|
+
highlightedHtml: effectiveHighlightedHtml
|
|
3325
|
+
});
|
|
3326
|
+
const { rated, handleRate, enabled: showCodeBlockFeedback } = useCodeBlockFeedback({
|
|
3327
|
+
plain: props.plain,
|
|
3328
|
+
lang
|
|
3329
|
+
});
|
|
3330
|
+
const copyFromRef = () => handleCopy(preRef.current?.textContent ?? "");
|
|
3331
|
+
const rateFromRef = (type) => handleRate(type, preRef.current?.textContent ?? "");
|
|
3332
|
+
return {
|
|
3333
|
+
copied,
|
|
3334
|
+
isExpanded,
|
|
3335
|
+
setIsExpanded,
|
|
3336
|
+
isExpandable,
|
|
3337
|
+
preRef,
|
|
3338
|
+
handleCopy: copyFromRef,
|
|
3339
|
+
shouldTruncate,
|
|
3340
|
+
isHighlighted,
|
|
3341
|
+
effectiveHighlightedHtml,
|
|
3342
|
+
effectiveTitle,
|
|
3343
|
+
lang,
|
|
3344
|
+
showCodeBlockFeedback,
|
|
3345
|
+
rated,
|
|
3346
|
+
handleRate: rateFromRef
|
|
3347
|
+
};
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3350
|
+
//#endregion
|
|
3351
|
+
export { Banner, BoltdocsShell, Breadcrumbs, CollectionsContext, CopyMarkdown, CurrentPostProvider, DocsLayoutComponent as DocsLayout, ErrorBoundary, LocationContext, LocationProvider, MatchesContext, MdxPage, Navbar, NavigateContext, NotFound, OnThisPage, Outlet, OutletContext, PageNav, PrefetchContext, RouteDataContext, RouteRenderer, SearchDialog, Sidebar, StructuredData, Timeline, ViteReactSSG, addBasename, addUrlBase, buildUrl, classifyUrlPath, cn, copyToClipboard, createArticleStructuredData, createBreadcrumbStructuredData, createRoutes, createStructuredData, createWebSiteStructuredData, defaultNavigate, defineStructuredData, getConfiguredLocales, getConfiguredVersions, getStarsRepo, getTranslated, getVersionPrefixSegments, getVersionSegments, hasBasename, hasUriScheme, hasUrlBase, isConfiguredLocale, isConfiguredVersion, matchRouteBranch, matchRouteBranchWithParams, normalizeBasename, normalizeUrlBase, normalizeUrlPath, parseUrlReference, reactToText, resolvePublicAssetUrl, resolveRouteBranch, resolveUrlReference, splitUrlReference, startViewTransition, stripBasename, stripSiteProtocol, stripUrlBase, useAnalytics, useBreadcrumbs, useCodeBlock, useCodeBlockFeedback, useConfig, useCopyButton, useExpandable, useFeedback, useHeadings, useI18n, useLoaderData, useLocalizedTo, useLocation, useMatches, useMdxComponents, useMergedComponents, useNavbar, useNavigate, usePageNav, usePost, usePosts, usePrefetch, useRecentPosts, useRouteData, useRoutes, useSearch, useSearchHighlight, useSidebar, useTabs, useTheme, useTrackEvent, useTrackPageView, useUI, useVersion, useViewTransition };
|