boltdocs 2.8.3 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/boltdocs.js +7 -6
- package/dist/{banner-MynZD_Ox.d.cts → banner-C_xkGxzI.d.cts} +1 -1
- package/dist/{banner-3N4Jd_L9.d.ts → banner-D2NddBfF.d.ts} +1 -1
- package/dist/cache-C2PiGyg8.cjs +6 -0
- package/dist/cache-DFW4R3S0.mjs +6 -0
- package/dist/chunk-Ds5LZdWN.cjs +6 -0
- package/dist/client/index.cjs +693 -488
- package/dist/client/index.d.cts +74 -8
- package/dist/client/index.d.ts +74 -8
- package/dist/client/index.js +692 -489
- package/dist/client/mdx.cjs +1 -1
- package/dist/client/mdx.js +1 -1
- package/dist/client/primitives.cjs +4 -4
- package/dist/client/primitives.d.cts +1 -1
- package/dist/client/primitives.d.ts +1 -1
- package/dist/client/primitives.js +4 -4
- package/dist/client/theme/neutral.css +5 -3
- package/dist/client/theme/reset.css +19 -0
- package/dist/{docs-layout-CwCq42Zt.cjs → docs-layout-3TpAt6MB.cjs} +302 -248
- package/dist/{docs-layout-Dn6S5g59.js → docs-layout-6FQ8__ok.js} +303 -249
- package/dist/doctor-BY1tSmQd.mjs +34 -0
- package/dist/{doctor-DyNUVe96.cjs → doctor-Bknon8f5.cjs} +1 -1
- package/dist/doctor-DcFLi4t1.cjs +34 -0
- package/dist/{doctor-aN_leTbh.mjs → doctor-wsPTzt8Y.mjs} +1 -1
- package/dist/{generator-CC2yHzhZ.cjs → generator-BEIF6MOx.cjs} +2 -2
- package/dist/{generator-BHCrLU6h.mjs → generator-DILs0EFN.mjs} +1 -1
- package/dist/handler-B31cxNw0.mjs +6 -0
- package/dist/handler-DfhH9D1b.mjs +28 -0
- package/dist/handler-Djy0HfsI.cjs +28 -0
- package/dist/{icons-dev-DvJ-hh9x.cjs → icons-dev-BryEFkJu.cjs} +96 -7
- package/dist/{icons-dev-Oju24Wjp.js → icons-dev-kJyGWNeg.js} +79 -8
- package/dist/{image-Ch4-GxdO.cjs → image-B9YA_oQ_.cjs} +24 -10
- package/dist/{image-Do8V9PCW.js → image-CjYu9Eml.js} +24 -10
- package/dist/{mdx-5oeCOFhH.js → mdx-Cy_c2zio.js} +116 -33
- package/dist/{mdx-BGM7LjW5.cjs → mdx-WXjAMS8Y.cjs} +121 -32
- package/dist/{meta-loader-Cv9O0Pzl.cjs → meta-loader-D0V6oOQt.cjs} +1 -1
- package/dist/node/cli-entry.cjs +3 -3
- package/dist/node/cli-entry.mjs +3 -3
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +368 -24
- package/dist/node/index.d.mts +369 -24
- package/dist/node/index.mjs +1 -1
- package/dist/node/routes/worker.cjs +1 -1
- package/dist/node/routes/worker.mjs +1 -1
- package/dist/node-DV-EPtMU.mjs +160 -0
- package/dist/node-vOVNRABe.cjs +160 -0
- package/dist/{package-CHxJV4Jy.mjs → package-BK_82QLX.mjs} +1 -1
- package/dist/{package-B_SoaGeu.cjs → package-OxKE0p6j.cjs} +1 -1
- package/dist/{parser-B7-6PyQz.cjs → parser-C2Pw18LY.cjs} +1 -1
- package/dist/{parser-BzB-zCkF.cjs → parser-DJoEF96Y.cjs} +1 -1
- package/dist/{parser-D0PVghVt.mjs → parser-DScG_PTs.mjs} +1 -1
- package/dist/routes--LYHSHT7.cjs +6 -0
- package/dist/routes-BAsfsn_e.mjs +6 -0
- package/dist/routes-C6Kr2HFN.cjs +6 -0
- package/dist/routes-CKgGAy8P.mjs +6 -0
- package/dist/{search-dialog-BXVoecTx.cjs → search-dialog-BhXg05Ri.cjs} +1 -1
- package/dist/{search-dialog-BYhOov4S.cjs → search-dialog-BsAiQgnx.cjs} +2 -2
- package/dist/{search-dialog-C09riYmx.js → search-dialog-CaOO1Q4i.js} +2 -2
- package/dist/{search-dialog-CUeAfy-8.cjs → search-dialog-CzwvKoLW.cjs} +1 -1
- package/dist/{search-dialog-DHc_8FFX.js → search-dialog-DRNJsxOv.js} +1 -1
- package/dist/{search-dialog-D8gLkhUV.js → search-dialog-DaR66wl0.js} +1 -1
- package/dist/shiki-adapter-CUtj-xKv.cjs +6 -0
- package/dist/shiki-adapter-EZptJAmW.mjs +6 -0
- package/dist/shiki-adapter-F-P-lDon.mjs +6 -0
- package/dist/shiki-adapter-PQBl32AN.cjs +6 -0
- package/dist/{sidebar-Dlkgbxs6.d.cts → sidebar-BtJyWHy4.d.cts} +43 -4
- package/dist/{sidebar-DNq4_ZAa.d.ts → sidebar-C4fuRYYS.d.ts} +43 -4
- package/dist/{utils-BYITg7T5.mjs → utils-DC4Wq-S2.mjs} +1 -1
- package/dist/{utils-Cjmx1hhk.cjs → utils-wHud9ny5.cjs} +1 -1
- package/dist/worker-pool-BS1LX67P.cjs +6 -0
- package/dist/worker-pool-DRv8ef4z.mjs +6 -0
- package/package.json +7 -3
- package/src/shared/types.ts +36 -3
- package/dist/cache-BMUyNiiA.mjs +0 -6
- package/dist/cache-CKm45d2w.cjs +0 -6
- package/dist/chunk-CU-zTemE.cjs +0 -6
- package/dist/doctor-BArviV8X.cjs +0 -28
- package/dist/doctor-CgLA7_Uv.mjs +0 -28
- package/dist/node-MsTvOgJN.mjs +0 -159
- package/dist/node-h9HmhAFB.cjs +0 -159
- package/dist/routes-BW6Dif_K.mjs +0 -6
- package/dist/routes-DJNJ-rTt.cjs +0 -6
- package/dist/routes-DiYC4nD2.cjs +0 -6
- package/dist/routes-ERSGuFQK.mjs +0 -6
- package/dist/worker-pool-CtqklOXq.cjs +0 -6
- package/dist/worker-pool-k0DY6k8T.mjs +0 -6
- /package/dist/{meta-loader-DzwDFtdT.mjs → meta-loader-By22EnYa.mjs} +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright (c) 2026 Jesus Alcala
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
import { A as ChevronRight, D as Check,
|
|
6
|
+
import { A as ChevronRight, D as Check, S as normalizePath, _ as Link$1, b as useLocalizedTo, k as ChevronLeft, rt as useConfig, tt as icons_exports, y as cn } from "./icons-dev-kJyGWNeg.js";
|
|
7
7
|
import { Children, createContext, use, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
8
8
|
import { useLocation } from "react-router-dom";
|
|
9
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -242,6 +242,235 @@ Tabs.Item = TabsItem;
|
|
|
242
242
|
Tabs.Content = TabsContent;
|
|
243
243
|
Tabs.Indicator = TabsIndicator;
|
|
244
244
|
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/client/hooks/use-sidebar.ts
|
|
247
|
+
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
|
|
248
|
+
const getCleanDirectoryMeta = (directoryMeta) => {
|
|
249
|
+
const meta = {};
|
|
250
|
+
if (!directoryMeta) return meta;
|
|
251
|
+
for (const [key, value] of Object.entries(directoryMeta)) {
|
|
252
|
+
const cleanKey = key.split("/").filter((part) => !part.startsWith("(") || !part.endsWith(")")).map((part) => part.replace(/^\d+-/, "")).join("/");
|
|
253
|
+
meta[cleanKey === "" ? "." : cleanKey] = value;
|
|
254
|
+
}
|
|
255
|
+
return meta;
|
|
256
|
+
};
|
|
257
|
+
const getOrCreateNode = (parts, rootMap, directoryMeta) => {
|
|
258
|
+
let currentMap = rootMap;
|
|
259
|
+
let parentPath = "";
|
|
260
|
+
let lastNode;
|
|
261
|
+
for (const segment of parts) {
|
|
262
|
+
const currentRelPath = parentPath ? `${parentPath}/${segment}` : segment;
|
|
263
|
+
if (!currentMap.has(segment)) {
|
|
264
|
+
const meta = directoryMeta[currentRelPath] || {};
|
|
265
|
+
const newNode = {
|
|
266
|
+
path: "#",
|
|
267
|
+
title: meta.title || capitalize(segment),
|
|
268
|
+
componentPath: "",
|
|
269
|
+
filePath: "",
|
|
270
|
+
icon: meta.icon,
|
|
271
|
+
groupPosition: typeof meta.order === "number" ? meta.order : 999,
|
|
272
|
+
collapsible: meta.collapsible,
|
|
273
|
+
collapsed: meta.collapsed,
|
|
274
|
+
hasCustomTitle: meta.title !== void 0,
|
|
275
|
+
subRoutes: [],
|
|
276
|
+
childrenMap: /* @__PURE__ */ new Map()
|
|
277
|
+
};
|
|
278
|
+
currentMap.set(segment, newNode);
|
|
279
|
+
}
|
|
280
|
+
lastNode = currentMap.get(segment);
|
|
281
|
+
currentMap = lastNode.childrenMap;
|
|
282
|
+
parentPath = currentRelPath;
|
|
283
|
+
}
|
|
284
|
+
return lastNode;
|
|
285
|
+
};
|
|
286
|
+
const getRoutePosition = (r) => r.sidebarPosition ?? r.order ?? 999;
|
|
287
|
+
const getNodePosition = (n) => n.sidebarPosition ?? n.groupPosition ?? 999;
|
|
288
|
+
const finalizeTree = (nodes) => {
|
|
289
|
+
return nodes.map((node) => {
|
|
290
|
+
if (node.childrenMap && node.childrenMap.size > 0) {
|
|
291
|
+
const childDirs = Array.from(node.childrenMap.values());
|
|
292
|
+
node.subRoutes = [...node.subRoutes || [], ...childDirs];
|
|
293
|
+
}
|
|
294
|
+
const { childrenMap, ...restNode } = node;
|
|
295
|
+
if (restNode.subRoutes && restNode.subRoutes.length > 0) restNode.subRoutes = finalizeTree(restNode.subRoutes);
|
|
296
|
+
return restNode;
|
|
297
|
+
}).sort((a, b) => {
|
|
298
|
+
const posA = getNodePosition(a);
|
|
299
|
+
const posB = getNodePosition(b);
|
|
300
|
+
return posA !== posB ? posA - posB : a.title.localeCompare(b.title);
|
|
301
|
+
});
|
|
302
|
+
};
|
|
303
|
+
function useSidebar(routes) {
|
|
304
|
+
const config = useConfig();
|
|
305
|
+
const { pathname } = useLocation();
|
|
306
|
+
return useMemo(() => {
|
|
307
|
+
const currentPath = normalizePath(pathname);
|
|
308
|
+
const activeRoute = routes.find((r) => normalizePath(r.path) === currentPath);
|
|
309
|
+
const activeTabId = activeRoute?.tab?.toLowerCase();
|
|
310
|
+
const filteredRoutes = routes.filter((r) => !r.collection && !r.sidebarHidden && !r.fallback).filter((r) => !activeTabId || r.tab?.toLowerCase() === activeTabId).sort((a, b) => getRoutePosition(a) - getRoutePosition(b));
|
|
311
|
+
const directoryMeta = getCleanDirectoryMeta(config.directoryMeta);
|
|
312
|
+
const rootNodesMap = /* @__PURE__ */ new Map();
|
|
313
|
+
const ungrouped = [];
|
|
314
|
+
for (const route of filteredRoutes) {
|
|
315
|
+
const parts = route.slugParts || [];
|
|
316
|
+
const isIndex = /^index\.mdx?$/.test(route.filePath.split("/").pop() || "");
|
|
317
|
+
if (parts.length === 0) {
|
|
318
|
+
if (route.filePath) ungrouped.push(route);
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
const containerNode = getOrCreateNode(parts, rootNodesMap, directoryMeta);
|
|
322
|
+
if (isIndex) Object.assign(containerNode, {
|
|
323
|
+
path: route.path,
|
|
324
|
+
title: containerNode.hasCustomTitle ? containerNode.title : route.title || containerNode.title,
|
|
325
|
+
icon: route.icon || containerNode.icon,
|
|
326
|
+
badge: route.badge,
|
|
327
|
+
sidebarPosition: route.sidebarPosition,
|
|
328
|
+
frontmatter: route.frontmatter,
|
|
329
|
+
filePath: route.filePath
|
|
330
|
+
});
|
|
331
|
+
else containerNode.subRoutes.push(route);
|
|
332
|
+
}
|
|
333
|
+
const finalizedTopNodes = finalizeTree(Array.from(rootNodesMap.values()));
|
|
334
|
+
const groups = [];
|
|
335
|
+
for (const node of finalizedTopNodes) if (node.subRoutes && node.subRoutes.length > 0) groups.push({
|
|
336
|
+
slug: node.title.toLowerCase().replace(/\s+/g, "-"),
|
|
337
|
+
title: node.title,
|
|
338
|
+
icon: node.icon,
|
|
339
|
+
path: node.path,
|
|
340
|
+
filePath: node.filePath,
|
|
341
|
+
routes: node.subRoutes,
|
|
342
|
+
sidebarPosition: node.sidebarPosition ?? node.groupPosition ?? 999,
|
|
343
|
+
collapsible: node.collapsible,
|
|
344
|
+
collapsed: node.collapsed
|
|
345
|
+
});
|
|
346
|
+
else ungrouped.push(node);
|
|
347
|
+
return {
|
|
348
|
+
groups,
|
|
349
|
+
ungrouped: finalizeTree(ungrouped),
|
|
350
|
+
activeRoute,
|
|
351
|
+
activePath: currentPath,
|
|
352
|
+
config
|
|
353
|
+
};
|
|
354
|
+
}, [
|
|
355
|
+
routes,
|
|
356
|
+
config,
|
|
357
|
+
pathname
|
|
358
|
+
]);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
//#endregion
|
|
362
|
+
//#region src/client/hooks/use-location.ts
|
|
363
|
+
const useLocation$1 = () => {
|
|
364
|
+
return useLocation();
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
//#endregion
|
|
368
|
+
//#region src/client/hooks/use-search-highlight.ts
|
|
369
|
+
/**
|
|
370
|
+
* Hook to highlight search terms based on the 'hl' query parameter.
|
|
371
|
+
*/
|
|
372
|
+
function useSearchHighlight(containerSelector = ".boltdocs-page") {
|
|
373
|
+
const { search } = useLocation$1();
|
|
374
|
+
const query = new URLSearchParams(search).get("hl");
|
|
375
|
+
useEffect(() => {
|
|
376
|
+
if (!query) {
|
|
377
|
+
clearHighlights(containerSelector);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const container = document.querySelector(containerSelector);
|
|
381
|
+
if (!container) return;
|
|
382
|
+
let rafId;
|
|
383
|
+
const observer = new MutationObserver((mutations) => {
|
|
384
|
+
if (mutations.some((m) => {
|
|
385
|
+
const addedNodes = Array.from(m.addedNodes);
|
|
386
|
+
const removedNodes = Array.from(m.removedNodes);
|
|
387
|
+
return addedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight"))) || removedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight")));
|
|
388
|
+
})) run();
|
|
389
|
+
});
|
|
390
|
+
function run() {
|
|
391
|
+
cancelAnimationFrame(rafId);
|
|
392
|
+
rafId = requestAnimationFrame(() => {
|
|
393
|
+
observer.disconnect();
|
|
394
|
+
clearHighlights(containerSelector);
|
|
395
|
+
const terms = query.split(/\s+/).map((t) => t.trim()).filter((t) => t.length >= 2);
|
|
396
|
+
if (terms.length > 0) highlightTerms(container, terms);
|
|
397
|
+
observer.observe(container, {
|
|
398
|
+
childList: true,
|
|
399
|
+
subtree: true
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
run();
|
|
404
|
+
return () => {
|
|
405
|
+
cancelAnimationFrame(rafId);
|
|
406
|
+
observer.disconnect();
|
|
407
|
+
clearHighlights(containerSelector);
|
|
408
|
+
};
|
|
409
|
+
}, [
|
|
410
|
+
query,
|
|
411
|
+
search,
|
|
412
|
+
containerSelector
|
|
413
|
+
]);
|
|
414
|
+
}
|
|
415
|
+
function clearHighlights(selector) {
|
|
416
|
+
document.querySelectorAll(`${selector} mark[data-search-highlight]`).forEach((mark) => {
|
|
417
|
+
try {
|
|
418
|
+
const parent = mark.parentNode;
|
|
419
|
+
if (parent && parent.contains(mark)) {
|
|
420
|
+
const text = mark.textContent || "";
|
|
421
|
+
parent.replaceChild(document.createTextNode(text), mark);
|
|
422
|
+
}
|
|
423
|
+
} catch (e) {}
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
function highlightTerms(container, terms) {
|
|
427
|
+
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, { acceptNode: (node) => {
|
|
428
|
+
const parent = node.parentElement;
|
|
429
|
+
if (parent && (parent.tagName === "SCRIPT" || parent.tagName === "STYLE" || parent.tagName === "MARK" || parent.closest("pre") || parent.closest("code"))) return NodeFilter.FILTER_REJECT;
|
|
430
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
431
|
+
} });
|
|
432
|
+
const nodes = [];
|
|
433
|
+
let node;
|
|
434
|
+
while (node = walker.nextNode()) nodes.push(node);
|
|
435
|
+
const accentMap = {
|
|
436
|
+
a: "[aáàäâã]",
|
|
437
|
+
e: "[eéèëê]",
|
|
438
|
+
i: "[iíìïî]",
|
|
439
|
+
o: "[oóòöôõ]",
|
|
440
|
+
u: "[uúùüû]",
|
|
441
|
+
n: "[nñ]",
|
|
442
|
+
c: "[cç]"
|
|
443
|
+
};
|
|
444
|
+
const prepareRegex = (term) => {
|
|
445
|
+
let pattern = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
446
|
+
pattern = pattern.split("").map((char) => {
|
|
447
|
+
return accentMap[char.toLowerCase()] || char;
|
|
448
|
+
}).join("");
|
|
449
|
+
return pattern;
|
|
450
|
+
};
|
|
451
|
+
const combinedPattern = terms.map(prepareRegex).join("|");
|
|
452
|
+
const regex = new RegExp(`(${combinedPattern})`, "gi");
|
|
453
|
+
const matchRegexes = terms.map((term) => {
|
|
454
|
+
const p = prepareRegex(term);
|
|
455
|
+
return new RegExp(`^${p}$`, "i");
|
|
456
|
+
});
|
|
457
|
+
nodes.forEach((textNode) => {
|
|
458
|
+
const text = textNode.textContent;
|
|
459
|
+
if (text && regex.test(text)) {
|
|
460
|
+
const fragment = document.createDocumentFragment();
|
|
461
|
+
text.split(regex).forEach((part) => {
|
|
462
|
+
if (matchRegexes.some((rx) => rx.test(part))) {
|
|
463
|
+
const mark = document.createElement("mark");
|
|
464
|
+
mark.textContent = part;
|
|
465
|
+
mark.setAttribute("data-search-highlight", "true");
|
|
466
|
+
fragment.appendChild(mark);
|
|
467
|
+
} else if (part) fragment.appendChild(document.createTextNode(part));
|
|
468
|
+
});
|
|
469
|
+
if (textNode.parentNode) textNode.parentNode.replaceChild(fragment, textNode);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
245
474
|
//#endregion
|
|
246
475
|
//#region src/client/components/primitives/helpers/observer.ts
|
|
247
476
|
function getItemId(url) {
|
|
@@ -617,126 +846,6 @@ PageNav.Title = PageNavTitle;
|
|
|
617
846
|
PageNav.Description = PageNavDescription;
|
|
618
847
|
PageNav.Icon = PageNavIcon;
|
|
619
848
|
|
|
620
|
-
//#endregion
|
|
621
|
-
//#region src/client/hooks/use-sidebar.ts
|
|
622
|
-
function useSidebar(routes) {
|
|
623
|
-
const config = useConfig();
|
|
624
|
-
const currentPath = normalizePath(useLocation().pathname);
|
|
625
|
-
return useMemo(() => {
|
|
626
|
-
const activeRoute = routes.find((r) => normalizePath(r.path) === currentPath);
|
|
627
|
-
const activeTabId = activeRoute?.tab?.toLowerCase();
|
|
628
|
-
const noCollection = routes.filter((r) => !r.collection);
|
|
629
|
-
const filteredRoutes = activeTabId ? noCollection.filter((r) => !r.tab || r.tab.toLowerCase() === activeTabId) : noCollection;
|
|
630
|
-
const directoryMeta = {};
|
|
631
|
-
if (config.directoryMeta) for (const [key, value] of Object.entries(config.directoryMeta)) {
|
|
632
|
-
const cleanKey = key.split("/").filter((part) => !part.startsWith("(") || !part.endsWith(")")).map((part) => part.replace(/^\d+-/, "")).join("/");
|
|
633
|
-
directoryMeta[cleanKey === "" ? "." : cleanKey] = value;
|
|
634
|
-
}
|
|
635
|
-
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
|
|
636
|
-
const rootNodesMap = /* @__PURE__ */ new Map();
|
|
637
|
-
const ungrouped = [];
|
|
638
|
-
const getOrCreateNode = (parts, rootStore) => {
|
|
639
|
-
let currentMap = rootStore;
|
|
640
|
-
let parentPath = "";
|
|
641
|
-
let lastNode = null;
|
|
642
|
-
for (let i = 0; i < parts.length; i++) {
|
|
643
|
-
const segment = parts[i];
|
|
644
|
-
const currentRelPath = parentPath ? `${parentPath}/${segment}` : segment;
|
|
645
|
-
if (!currentMap.has(segment)) {
|
|
646
|
-
const meta = directoryMeta[currentRelPath] || {};
|
|
647
|
-
const newNode = {
|
|
648
|
-
path: "#",
|
|
649
|
-
title: meta.title || capitalize(segment),
|
|
650
|
-
componentPath: "",
|
|
651
|
-
filePath: "",
|
|
652
|
-
icon: meta.icon,
|
|
653
|
-
groupPosition: typeof meta.order === "number" ? meta.order : 999,
|
|
654
|
-
subRoutes: []
|
|
655
|
-
};
|
|
656
|
-
currentMap.set(segment, newNode);
|
|
657
|
-
}
|
|
658
|
-
lastNode = currentMap.get(segment);
|
|
659
|
-
if (!lastNode._subMap) lastNode._subMap = /* @__PURE__ */ new Map();
|
|
660
|
-
currentMap = lastNode._subMap;
|
|
661
|
-
parentPath = currentRelPath;
|
|
662
|
-
}
|
|
663
|
-
return lastNode;
|
|
664
|
-
};
|
|
665
|
-
const sortedRoutes = [...filteredRoutes].sort((a, b) => {
|
|
666
|
-
return (a.sidebarPosition ?? a.order ?? 999) - (b.sidebarPosition ?? b.order ?? 999);
|
|
667
|
-
});
|
|
668
|
-
for (const route of sortedRoutes) {
|
|
669
|
-
if (route.sidebarHidden) continue;
|
|
670
|
-
const parts = route.slugParts || [];
|
|
671
|
-
const fileName = route.filePath.split("/").pop() || "";
|
|
672
|
-
const isIndex = /^index\.mdx?$/.test(fileName);
|
|
673
|
-
if (parts.length === 0) {
|
|
674
|
-
if (route.filePath) ungrouped.push(route);
|
|
675
|
-
continue;
|
|
676
|
-
}
|
|
677
|
-
if (isIndex) {
|
|
678
|
-
const containerNode = getOrCreateNode(parts, rootNodesMap);
|
|
679
|
-
if (containerNode) {
|
|
680
|
-
containerNode.path = route.path;
|
|
681
|
-
containerNode.title = route.title || containerNode.title;
|
|
682
|
-
containerNode.icon = route.icon || containerNode.icon;
|
|
683
|
-
containerNode.badge = route.badge;
|
|
684
|
-
containerNode.sidebarPosition = route.sidebarPosition;
|
|
685
|
-
containerNode.frontmatter = route.frontmatter;
|
|
686
|
-
}
|
|
687
|
-
} else {
|
|
688
|
-
const parentNode = getOrCreateNode(parts, rootNodesMap);
|
|
689
|
-
if (parentNode) parentNode.subRoutes.push(route);
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
const finalizeTree = (nodes, currentPathPrefix = "") => {
|
|
693
|
-
nodes.forEach((node) => {
|
|
694
|
-
if (node._subMap) {
|
|
695
|
-
const childDirs = Array.from(node._subMap.values());
|
|
696
|
-
node.subRoutes = [...node.subRoutes || [], ...childDirs];
|
|
697
|
-
delete node._subMap;
|
|
698
|
-
}
|
|
699
|
-
if (node.subRoutes && node.subRoutes.length > 0) node.subRoutes = finalizeTree(node.subRoutes);
|
|
700
|
-
});
|
|
701
|
-
return nodes.sort((a, b) => {
|
|
702
|
-
const posA = a.sidebarPosition ?? a.groupPosition ?? 999;
|
|
703
|
-
const posB = b.sidebarPosition ?? b.groupPosition ?? 999;
|
|
704
|
-
if (posA !== posB) return posA - posB;
|
|
705
|
-
return a.title.localeCompare(b.title);
|
|
706
|
-
});
|
|
707
|
-
};
|
|
708
|
-
const finalizedTopNodes = finalizeTree(Array.from(rootNodesMap.values()));
|
|
709
|
-
finalizedTopNodes.map((node) => {
|
|
710
|
-
return {
|
|
711
|
-
slug: node.title.toLowerCase().replace(/\s+/g, "-"),
|
|
712
|
-
title: node.title,
|
|
713
|
-
icon: node.icon,
|
|
714
|
-
routes: [node]
|
|
715
|
-
};
|
|
716
|
-
});
|
|
717
|
-
return {
|
|
718
|
-
groups: finalizedTopNodes.map((node) => {
|
|
719
|
-
if (node.subRoutes && node.subRoutes.length > 0) return {
|
|
720
|
-
slug: node.title.toLowerCase().replace(/\s+/g, "-"),
|
|
721
|
-
title: node.title,
|
|
722
|
-
icon: node.icon,
|
|
723
|
-
routes: node.subRoutes
|
|
724
|
-
};
|
|
725
|
-
ungrouped.push(node);
|
|
726
|
-
return null;
|
|
727
|
-
}).filter(Boolean),
|
|
728
|
-
ungrouped: finalizeTree(ungrouped),
|
|
729
|
-
activeRoute,
|
|
730
|
-
activePath: currentPath,
|
|
731
|
-
config
|
|
732
|
-
};
|
|
733
|
-
}, [
|
|
734
|
-
routes,
|
|
735
|
-
config,
|
|
736
|
-
currentPath
|
|
737
|
-
]);
|
|
738
|
-
}
|
|
739
|
-
|
|
740
849
|
//#endregion
|
|
741
850
|
//#region src/client/components/primitives/sidebar.tsx
|
|
742
851
|
let sidebarScrollPos = 0;
|
|
@@ -830,13 +939,29 @@ function SidebarContent({ children, className }) {
|
|
|
830
939
|
/**
|
|
831
940
|
* Navigation Group
|
|
832
941
|
*/
|
|
833
|
-
function SidebarGroup({ title, icon: Icon, children, className }) {
|
|
942
|
+
function SidebarGroup({ title, icon: Icon, children, className, collapsible = false, collapsed = false, active = false }) {
|
|
943
|
+
const [isOpen, setIsOpen] = useState(() => active || !collapsed);
|
|
944
|
+
const [prevActive, setPrevActive] = useState(active);
|
|
945
|
+
if (active !== prevActive) {
|
|
946
|
+
setPrevActive(active);
|
|
947
|
+
if (active) setIsOpen(true);
|
|
948
|
+
}
|
|
834
949
|
return /* @__PURE__ */ jsxs("div", {
|
|
835
950
|
className,
|
|
836
|
-
children: [title && /* @__PURE__ */ jsxs("
|
|
951
|
+
children: [title && (collapsible ? /* @__PURE__ */ jsxs("button", {
|
|
952
|
+
onClick: () => setIsOpen(!isOpen),
|
|
953
|
+
className: "w-full text-left px-2 mb-2 flex items-center justify-between text-xs font-regular tracking-widest text-muted/50 hover:text-body transition-colors outline-none cursor-pointer group",
|
|
954
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
955
|
+
className: "flex items-center gap-2",
|
|
956
|
+
children: [Icon && /* @__PURE__ */ jsx(Icon, { size: 12 }), title]
|
|
957
|
+
}), /* @__PURE__ */ jsx(ChevronRight, {
|
|
958
|
+
size: 12,
|
|
959
|
+
className: cn("transition-transform duration-200 text-muted/40 group-hover:text-body", isOpen && "rotate-90")
|
|
960
|
+
})]
|
|
961
|
+
}) : /* @__PURE__ */ jsxs("h4", {
|
|
837
962
|
className: "px-2 mb-2 flex items-center gap-2 text-[11px] font-bold uppercase tracking-widest text-muted/50",
|
|
838
963
|
children: [Icon && /* @__PURE__ */ jsx(Icon, { size: 12 }), title]
|
|
839
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
964
|
+
})), (!collapsible || isOpen) && /* @__PURE__ */ jsx("div", {
|
|
840
965
|
className: "flex flex-col gap-0.5",
|
|
841
966
|
children
|
|
842
967
|
})]
|
|
@@ -927,23 +1052,65 @@ function SidebarItem({ route, activePath, activeRoute, className }) {
|
|
|
927
1052
|
className
|
|
928
1053
|
});
|
|
929
1054
|
}
|
|
1055
|
+
const isRouteActive = (route, activePath, activeRoute) => {
|
|
1056
|
+
const normalizedPath = route.path.endsWith("/") ? route.path.slice(0, -1) : route.path;
|
|
1057
|
+
if ((activePath.endsWith("/") ? activePath.slice(0, -1) : activePath) === normalizedPath) return true;
|
|
1058
|
+
if (activeRoute?.filePath && route.filePath && activeRoute.filePath === route.filePath) return true;
|
|
1059
|
+
if (route.routes && route.routes.some((r) => isRouteActive(r, activePath, activeRoute))) return true;
|
|
1060
|
+
if (route.subRoutes && route.subRoutes.some((r) => isRouteActive(r, activePath, activeRoute))) return true;
|
|
1061
|
+
return false;
|
|
1062
|
+
};
|
|
930
1063
|
function SidebarItems({ routes, className }) {
|
|
931
1064
|
const { groups, ungrouped, activePath, activeRoute } = useSidebar(routes);
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
1065
|
+
const mergedItems = [...ungrouped.map((route) => ({
|
|
1066
|
+
type: "link",
|
|
1067
|
+
position: route.sidebarPosition ?? 999,
|
|
1068
|
+
title: route.title,
|
|
1069
|
+
route
|
|
1070
|
+
})), ...groups.map((group) => ({
|
|
1071
|
+
type: "group",
|
|
1072
|
+
position: group.sidebarPosition ?? 999,
|
|
1073
|
+
title: group.title,
|
|
1074
|
+
group
|
|
1075
|
+
}))].sort((a, b) => {
|
|
1076
|
+
if (a.position !== b.position) return a.position - b.position;
|
|
1077
|
+
if (a.type !== b.type) return a.type === "link" ? -1 : 1;
|
|
1078
|
+
return a.title.localeCompare(b.title);
|
|
1079
|
+
});
|
|
1080
|
+
const renderedElements = [];
|
|
1081
|
+
let currentUngrouped = [];
|
|
1082
|
+
const pushUngrouped = () => {
|
|
1083
|
+
if (currentUngrouped.length > 0) {
|
|
1084
|
+
const routesToRender = [...currentUngrouped];
|
|
1085
|
+
renderedElements.push(/* @__PURE__ */ jsx(SidebarGroup, { children: routesToRender.map((route) => /* @__PURE__ */ jsx(SidebarItem, {
|
|
1086
|
+
route,
|
|
1087
|
+
activePath,
|
|
1088
|
+
activeRoute
|
|
1089
|
+
}, route.path)) }, `ungrouped-${routesToRender[0].path}`));
|
|
1090
|
+
currentUngrouped = [];
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
for (const item of mergedItems) if (item.type === "link") currentUngrouped.push(item.route);
|
|
1094
|
+
else {
|
|
1095
|
+
pushUngrouped();
|
|
1096
|
+
const isGroupActive = item.group.routes.some((route) => isRouteActive(route, activePath, activeRoute));
|
|
1097
|
+
renderedElements.push(/* @__PURE__ */ jsx(SidebarGroup, {
|
|
1098
|
+
title: item.group.title,
|
|
1099
|
+
icon: getIcon(item.group.icon),
|
|
1100
|
+
collapsible: item.group.collapsible,
|
|
1101
|
+
collapsed: item.group.collapsed,
|
|
1102
|
+
active: isGroupActive,
|
|
1103
|
+
children: item.group.routes.map((route) => /* @__PURE__ */ jsx(SidebarItem, {
|
|
942
1104
|
route,
|
|
943
1105
|
activePath,
|
|
944
1106
|
activeRoute
|
|
945
1107
|
}, route.path))
|
|
946
|
-
}, group.title))
|
|
1108
|
+
}, item.group.title));
|
|
1109
|
+
}
|
|
1110
|
+
pushUngrouped();
|
|
1111
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1112
|
+
className: cn("flex flex-col gap-6", className),
|
|
1113
|
+
children: renderedElements
|
|
947
1114
|
});
|
|
948
1115
|
}
|
|
949
1116
|
/**
|
|
@@ -961,119 +1128,6 @@ const Sidebar = Object.assign(SidebarRoot, {
|
|
|
961
1128
|
Items: SidebarItems
|
|
962
1129
|
});
|
|
963
1130
|
|
|
964
|
-
//#endregion
|
|
965
|
-
//#region src/client/hooks/use-location.ts
|
|
966
|
-
const useLocation$1 = () => {
|
|
967
|
-
return useLocation();
|
|
968
|
-
};
|
|
969
|
-
|
|
970
|
-
//#endregion
|
|
971
|
-
//#region src/client/hooks/use-search-highlight.ts
|
|
972
|
-
/**
|
|
973
|
-
* Hook to highlight search terms based on the 'hl' query parameter.
|
|
974
|
-
*/
|
|
975
|
-
function useSearchHighlight(containerSelector = ".boltdocs-page") {
|
|
976
|
-
const { search } = useLocation$1();
|
|
977
|
-
const query = new URLSearchParams(search).get("hl");
|
|
978
|
-
useEffect(() => {
|
|
979
|
-
if (!query) {
|
|
980
|
-
clearHighlights(containerSelector);
|
|
981
|
-
return;
|
|
982
|
-
}
|
|
983
|
-
const container = document.querySelector(containerSelector);
|
|
984
|
-
if (!container) return;
|
|
985
|
-
let rafId;
|
|
986
|
-
const observer = new MutationObserver((mutations) => {
|
|
987
|
-
if (mutations.some((m) => {
|
|
988
|
-
const addedNodes = Array.from(m.addedNodes);
|
|
989
|
-
const removedNodes = Array.from(m.removedNodes);
|
|
990
|
-
return addedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight"))) || removedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight")));
|
|
991
|
-
})) run();
|
|
992
|
-
});
|
|
993
|
-
function run() {
|
|
994
|
-
cancelAnimationFrame(rafId);
|
|
995
|
-
rafId = requestAnimationFrame(() => {
|
|
996
|
-
observer.disconnect();
|
|
997
|
-
clearHighlights(containerSelector);
|
|
998
|
-
const terms = query.split(/\s+/).map((t) => t.trim()).filter((t) => t.length >= 2);
|
|
999
|
-
if (terms.length > 0) highlightTerms(container, terms);
|
|
1000
|
-
observer.observe(container, {
|
|
1001
|
-
childList: true,
|
|
1002
|
-
subtree: true
|
|
1003
|
-
});
|
|
1004
|
-
});
|
|
1005
|
-
}
|
|
1006
|
-
run();
|
|
1007
|
-
return () => {
|
|
1008
|
-
cancelAnimationFrame(rafId);
|
|
1009
|
-
observer.disconnect();
|
|
1010
|
-
clearHighlights(containerSelector);
|
|
1011
|
-
};
|
|
1012
|
-
}, [
|
|
1013
|
-
query,
|
|
1014
|
-
search,
|
|
1015
|
-
containerSelector
|
|
1016
|
-
]);
|
|
1017
|
-
}
|
|
1018
|
-
function clearHighlights(selector) {
|
|
1019
|
-
document.querySelectorAll(`${selector} mark[data-search-highlight]`).forEach((mark) => {
|
|
1020
|
-
try {
|
|
1021
|
-
const parent = mark.parentNode;
|
|
1022
|
-
if (parent && parent.contains(mark)) {
|
|
1023
|
-
const text = mark.textContent || "";
|
|
1024
|
-
parent.replaceChild(document.createTextNode(text), mark);
|
|
1025
|
-
}
|
|
1026
|
-
} catch (e) {}
|
|
1027
|
-
});
|
|
1028
|
-
}
|
|
1029
|
-
function highlightTerms(container, terms) {
|
|
1030
|
-
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, { acceptNode: (node) => {
|
|
1031
|
-
const parent = node.parentElement;
|
|
1032
|
-
if (parent && (parent.tagName === "SCRIPT" || parent.tagName === "STYLE" || parent.tagName === "MARK" || parent.closest("pre") || parent.closest("code"))) return NodeFilter.FILTER_REJECT;
|
|
1033
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
1034
|
-
} });
|
|
1035
|
-
const nodes = [];
|
|
1036
|
-
let node;
|
|
1037
|
-
while (node = walker.nextNode()) nodes.push(node);
|
|
1038
|
-
const accentMap = {
|
|
1039
|
-
a: "[aáàäâã]",
|
|
1040
|
-
e: "[eéèëê]",
|
|
1041
|
-
i: "[iíìïî]",
|
|
1042
|
-
o: "[oóòöôõ]",
|
|
1043
|
-
u: "[uúùüû]",
|
|
1044
|
-
n: "[nñ]",
|
|
1045
|
-
c: "[cç]"
|
|
1046
|
-
};
|
|
1047
|
-
const prepareRegex = (term) => {
|
|
1048
|
-
let pattern = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1049
|
-
pattern = pattern.split("").map((char) => {
|
|
1050
|
-
return accentMap[char.toLowerCase()] || char;
|
|
1051
|
-
}).join("");
|
|
1052
|
-
return pattern;
|
|
1053
|
-
};
|
|
1054
|
-
const combinedPattern = terms.map(prepareRegex).join("|");
|
|
1055
|
-
const regex = new RegExp(`(${combinedPattern})`, "gi");
|
|
1056
|
-
const matchRegexes = terms.map((term) => {
|
|
1057
|
-
const p = prepareRegex(term);
|
|
1058
|
-
return new RegExp(`^${p}$`, "i");
|
|
1059
|
-
});
|
|
1060
|
-
nodes.forEach((textNode) => {
|
|
1061
|
-
const text = textNode.textContent;
|
|
1062
|
-
if (text && regex.test(text)) {
|
|
1063
|
-
const fragment = document.createDocumentFragment();
|
|
1064
|
-
text.split(regex).forEach((part) => {
|
|
1065
|
-
if (matchRegexes.some((rx) => rx.test(part))) {
|
|
1066
|
-
const mark = document.createElement("mark");
|
|
1067
|
-
mark.textContent = part;
|
|
1068
|
-
mark.setAttribute("data-search-highlight", "true");
|
|
1069
|
-
fragment.appendChild(mark);
|
|
1070
|
-
} else if (part) fragment.appendChild(document.createTextNode(part));
|
|
1071
|
-
});
|
|
1072
|
-
if (textNode.parentNode) textNode.parentNode.replaceChild(fragment, textNode);
|
|
1073
|
-
}
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
1131
|
//#endregion
|
|
1078
1132
|
//#region src/client/components/ui-base/search-highlight.tsx
|
|
1079
1133
|
/**
|
|
@@ -1164,4 +1218,4 @@ const DocsLayout = Object.assign(DocsLayoutRoot, {
|
|
|
1164
1218
|
});
|
|
1165
1219
|
|
|
1166
1220
|
//#endregion
|
|
1167
|
-
export { useUI as A,
|
|
1221
|
+
export { useUI as A, useSidebar as C, ButtonGroup as D, Popover$1 as E, Breadcrumbs$1 as O, useLocation$1 as S, Menu as T, ScrollProvider as _, SidebarHeader as a, useItems as b, SidebarLink as c, SidebarSubGroup as d, PageNav as f, OnThisPageTree as g, OnThisPageItems as h, SidebarGroup as i, UIProvider as k, SidebarMobile as l, OnThisPage as m, Sidebar as n, SidebarItem as o, AnchorProvider as p, SidebarContent as r, SidebarItems as s, DocsLayout as t, SidebarRoot as u, useActiveAnchor as v, Tabs as w, useSearchHighlight as x, useActiveAnchors as y };
|