boltdocs 2.8.4 → 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-DFACg5Dy.d.cts → banner-C_xkGxzI.d.cts} +1 -1
- package/dist/{banner-BLTQUA2O.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 +464 -279
- package/dist/client/index.d.cts +74 -8
- package/dist/client/index.d.ts +74 -8
- package/dist/client/index.js +463 -280
- 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-CVCf3xkZ.cjs → docs-layout-3TpAt6MB.cjs} +302 -238
- package/dist/{docs-layout-BBv6wILp.js → docs-layout-6FQ8__ok.js} +303 -239
- package/dist/doctor-BY1tSmQd.mjs +34 -0
- package/dist/{doctor-DT4jh07O.cjs → doctor-Bknon8f5.cjs} +1 -1
- package/dist/doctor-DcFLi4t1.cjs +34 -0
- package/dist/{doctor-BGPdO1Ah.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-C8sFxeBk.cjs → icons-dev-BryEFkJu.cjs} +90 -4
- package/dist/{icons-dev-CFcv5Nb8.js → icons-dev-kJyGWNeg.js} +73 -5
- package/dist/{image-DCMxxidi.cjs → image-B9YA_oQ_.cjs} +17 -9
- package/dist/{image-DufDOid8.js → image-CjYu9Eml.js} +17 -9
- package/dist/{mdx-Bto8CvGl.js → mdx-Cy_c2zio.js} +116 -33
- package/dist/{mdx-BH9kHiF9.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-DlgexgpQ.mjs → package-BK_82QLX.mjs} +1 -1
- package/dist/{package-CwNjt3Sd.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-9LqyiEnB.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-Cvux-qSk.cjs → search-dialog-BhXg05Ri.cjs} +1 -1
- package/dist/{search-dialog-CmHYOt18.cjs → search-dialog-BsAiQgnx.cjs} +2 -2
- package/dist/{search-dialog-jHZ21G4i.js → search-dialog-CaOO1Q4i.js} +2 -2
- package/dist/{search-dialog-Cr7SC8Xt.cjs → search-dialog-CzwvKoLW.cjs} +1 -1
- package/dist/{search-dialog-DBNaG5At.js → search-dialog-DRNJsxOv.js} +1 -1
- package/dist/{search-dialog-e86WPpck.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-kQBonN82.d.ts → sidebar-BtJyWHy4.d.cts} +42 -5
- package/dist/{sidebar---RgTmZD.d.cts → sidebar-C4fuRYYS.d.ts} +42 -5
- 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 +6 -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-Dnv77Lfx.mjs +0 -28
- package/dist/doctor-VBPlQf7d.cjs +0 -28
- package/dist/node-JM9bx0mO.cjs +0 -160
- package/dist/node-q-Y2mdLX.mjs +0 -160
- package/dist/routes-3sAccArX.cjs +0 -6
- package/dist/routes-DZpXqq1p.mjs +0 -6
- package/dist/routes-DjoxNeef.mjs +0 -6
- package/dist/routes-DpJnb2VS.cjs +0 -6
- package/dist/worker-pool-DXLyeHJg.cjs +0 -6
- package/dist/worker-pool-Kn4F9gDq.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,116 +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
|
-
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
|
|
623
|
-
const getCleanDirectoryMeta = (directoryMeta) => {
|
|
624
|
-
const meta = {};
|
|
625
|
-
if (!directoryMeta) return meta;
|
|
626
|
-
for (const [key, value] of Object.entries(directoryMeta)) {
|
|
627
|
-
const cleanKey = key.split("/").filter((part) => !part.startsWith("(") || !part.endsWith(")")).map((part) => part.replace(/^\d+-/, "")).join("/");
|
|
628
|
-
meta[cleanKey === "" ? "." : cleanKey] = value;
|
|
629
|
-
}
|
|
630
|
-
return meta;
|
|
631
|
-
};
|
|
632
|
-
const getOrCreateNode = (parts, rootMap, directoryMeta) => {
|
|
633
|
-
let currentMap = rootMap;
|
|
634
|
-
let parentPath = "";
|
|
635
|
-
let lastNode;
|
|
636
|
-
for (const segment of parts) {
|
|
637
|
-
const currentRelPath = parentPath ? `${parentPath}/${segment}` : segment;
|
|
638
|
-
if (!currentMap.has(segment)) {
|
|
639
|
-
const meta = directoryMeta[currentRelPath] || {};
|
|
640
|
-
const newNode = {
|
|
641
|
-
path: "#",
|
|
642
|
-
title: meta.title || capitalize(segment),
|
|
643
|
-
componentPath: "",
|
|
644
|
-
filePath: "",
|
|
645
|
-
icon: meta.icon,
|
|
646
|
-
groupPosition: typeof meta.order === "number" ? meta.order : 999,
|
|
647
|
-
subRoutes: [],
|
|
648
|
-
childrenMap: /* @__PURE__ */ new Map()
|
|
649
|
-
};
|
|
650
|
-
currentMap.set(segment, newNode);
|
|
651
|
-
}
|
|
652
|
-
lastNode = currentMap.get(segment);
|
|
653
|
-
currentMap = lastNode.childrenMap;
|
|
654
|
-
parentPath = currentRelPath;
|
|
655
|
-
}
|
|
656
|
-
return lastNode;
|
|
657
|
-
};
|
|
658
|
-
const getRoutePosition = (r) => r.sidebarPosition ?? r.order ?? 999;
|
|
659
|
-
const getNodePosition = (n) => n.sidebarPosition ?? n.groupPosition ?? 999;
|
|
660
|
-
const finalizeTree = (nodes) => {
|
|
661
|
-
return nodes.map((node) => {
|
|
662
|
-
if (node.childrenMap && node.childrenMap.size > 0) {
|
|
663
|
-
const childDirs = Array.from(node.childrenMap.values());
|
|
664
|
-
node.subRoutes = [...node.subRoutes || [], ...childDirs];
|
|
665
|
-
}
|
|
666
|
-
const { childrenMap, ...restNode } = node;
|
|
667
|
-
if (restNode.subRoutes && restNode.subRoutes.length > 0) restNode.subRoutes = finalizeTree(restNode.subRoutes);
|
|
668
|
-
return restNode;
|
|
669
|
-
}).sort((a, b) => {
|
|
670
|
-
const posA = getNodePosition(a);
|
|
671
|
-
const posB = getNodePosition(b);
|
|
672
|
-
return posA !== posB ? posA - posB : a.title.localeCompare(b.title);
|
|
673
|
-
});
|
|
674
|
-
};
|
|
675
|
-
function useSidebar(routes) {
|
|
676
|
-
const config = useConfig();
|
|
677
|
-
const { pathname } = useLocation();
|
|
678
|
-
return useMemo(() => {
|
|
679
|
-
const currentPath = normalizePath(pathname);
|
|
680
|
-
const activeRoute = routes.find((r) => normalizePath(r.path) === currentPath);
|
|
681
|
-
const activeTabId = activeRoute?.tab?.toLowerCase();
|
|
682
|
-
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));
|
|
683
|
-
const directoryMeta = getCleanDirectoryMeta(config.directoryMeta);
|
|
684
|
-
const rootNodesMap = /* @__PURE__ */ new Map();
|
|
685
|
-
const ungrouped = [];
|
|
686
|
-
for (const route of filteredRoutes) {
|
|
687
|
-
const parts = route.slugParts || [];
|
|
688
|
-
const isIndex = /^index\.mdx?$/.test(route.filePath.split("/").pop() || "");
|
|
689
|
-
if (parts.length === 0) {
|
|
690
|
-
if (route.filePath) ungrouped.push(route);
|
|
691
|
-
continue;
|
|
692
|
-
}
|
|
693
|
-
const containerNode = getOrCreateNode(parts, rootNodesMap, directoryMeta);
|
|
694
|
-
if (isIndex) Object.assign(containerNode, {
|
|
695
|
-
path: route.path,
|
|
696
|
-
title: route.title || containerNode.title,
|
|
697
|
-
icon: route.icon || containerNode.icon,
|
|
698
|
-
badge: route.badge,
|
|
699
|
-
sidebarPosition: route.sidebarPosition,
|
|
700
|
-
frontmatter: route.frontmatter,
|
|
701
|
-
filePath: route.filePath
|
|
702
|
-
});
|
|
703
|
-
else containerNode.subRoutes.push(route);
|
|
704
|
-
}
|
|
705
|
-
const finalizedTopNodes = finalizeTree(Array.from(rootNodesMap.values()));
|
|
706
|
-
const groups = [];
|
|
707
|
-
for (const node of finalizedTopNodes) if (node.subRoutes && node.subRoutes.length > 0) groups.push({
|
|
708
|
-
slug: node.title.toLowerCase().replace(/\s+/g, "-"),
|
|
709
|
-
title: node.title,
|
|
710
|
-
icon: node.icon,
|
|
711
|
-
path: node.path,
|
|
712
|
-
filePath: node.filePath,
|
|
713
|
-
routes: node.subRoutes
|
|
714
|
-
});
|
|
715
|
-
else ungrouped.push(node);
|
|
716
|
-
return {
|
|
717
|
-
groups,
|
|
718
|
-
ungrouped: finalizeTree(ungrouped),
|
|
719
|
-
activeRoute,
|
|
720
|
-
activePath: currentPath,
|
|
721
|
-
config
|
|
722
|
-
};
|
|
723
|
-
}, [
|
|
724
|
-
routes,
|
|
725
|
-
config,
|
|
726
|
-
pathname
|
|
727
|
-
]);
|
|
728
|
-
}
|
|
729
|
-
|
|
730
849
|
//#endregion
|
|
731
850
|
//#region src/client/components/primitives/sidebar.tsx
|
|
732
851
|
let sidebarScrollPos = 0;
|
|
@@ -820,13 +939,29 @@ function SidebarContent({ children, className }) {
|
|
|
820
939
|
/**
|
|
821
940
|
* Navigation Group
|
|
822
941
|
*/
|
|
823
|
-
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
|
+
}
|
|
824
949
|
return /* @__PURE__ */ jsxs("div", {
|
|
825
950
|
className,
|
|
826
|
-
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", {
|
|
827
962
|
className: "px-2 mb-2 flex items-center gap-2 text-[11px] font-bold uppercase tracking-widest text-muted/50",
|
|
828
963
|
children: [Icon && /* @__PURE__ */ jsx(Icon, { size: 12 }), title]
|
|
829
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
964
|
+
})), (!collapsible || isOpen) && /* @__PURE__ */ jsx("div", {
|
|
830
965
|
className: "flex flex-col gap-0.5",
|
|
831
966
|
children
|
|
832
967
|
})]
|
|
@@ -917,23 +1052,65 @@ function SidebarItem({ route, activePath, activeRoute, className }) {
|
|
|
917
1052
|
className
|
|
918
1053
|
});
|
|
919
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
|
+
};
|
|
920
1063
|
function SidebarItems({ routes, className }) {
|
|
921
1064
|
const { groups, ungrouped, activePath, activeRoute } = useSidebar(routes);
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
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, {
|
|
932
1104
|
route,
|
|
933
1105
|
activePath,
|
|
934
1106
|
activeRoute
|
|
935
1107
|
}, route.path))
|
|
936
|
-
}, 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
|
|
937
1114
|
});
|
|
938
1115
|
}
|
|
939
1116
|
/**
|
|
@@ -951,119 +1128,6 @@ const Sidebar = Object.assign(SidebarRoot, {
|
|
|
951
1128
|
Items: SidebarItems
|
|
952
1129
|
});
|
|
953
1130
|
|
|
954
|
-
//#endregion
|
|
955
|
-
//#region src/client/hooks/use-location.ts
|
|
956
|
-
const useLocation$1 = () => {
|
|
957
|
-
return useLocation();
|
|
958
|
-
};
|
|
959
|
-
|
|
960
|
-
//#endregion
|
|
961
|
-
//#region src/client/hooks/use-search-highlight.ts
|
|
962
|
-
/**
|
|
963
|
-
* Hook to highlight search terms based on the 'hl' query parameter.
|
|
964
|
-
*/
|
|
965
|
-
function useSearchHighlight(containerSelector = ".boltdocs-page") {
|
|
966
|
-
const { search } = useLocation$1();
|
|
967
|
-
const query = new URLSearchParams(search).get("hl");
|
|
968
|
-
useEffect(() => {
|
|
969
|
-
if (!query) {
|
|
970
|
-
clearHighlights(containerSelector);
|
|
971
|
-
return;
|
|
972
|
-
}
|
|
973
|
-
const container = document.querySelector(containerSelector);
|
|
974
|
-
if (!container) return;
|
|
975
|
-
let rafId;
|
|
976
|
-
const observer = new MutationObserver((mutations) => {
|
|
977
|
-
if (mutations.some((m) => {
|
|
978
|
-
const addedNodes = Array.from(m.addedNodes);
|
|
979
|
-
const removedNodes = Array.from(m.removedNodes);
|
|
980
|
-
return addedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight"))) || removedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight")));
|
|
981
|
-
})) run();
|
|
982
|
-
});
|
|
983
|
-
function run() {
|
|
984
|
-
cancelAnimationFrame(rafId);
|
|
985
|
-
rafId = requestAnimationFrame(() => {
|
|
986
|
-
observer.disconnect();
|
|
987
|
-
clearHighlights(containerSelector);
|
|
988
|
-
const terms = query.split(/\s+/).map((t) => t.trim()).filter((t) => t.length >= 2);
|
|
989
|
-
if (terms.length > 0) highlightTerms(container, terms);
|
|
990
|
-
observer.observe(container, {
|
|
991
|
-
childList: true,
|
|
992
|
-
subtree: true
|
|
993
|
-
});
|
|
994
|
-
});
|
|
995
|
-
}
|
|
996
|
-
run();
|
|
997
|
-
return () => {
|
|
998
|
-
cancelAnimationFrame(rafId);
|
|
999
|
-
observer.disconnect();
|
|
1000
|
-
clearHighlights(containerSelector);
|
|
1001
|
-
};
|
|
1002
|
-
}, [
|
|
1003
|
-
query,
|
|
1004
|
-
search,
|
|
1005
|
-
containerSelector
|
|
1006
|
-
]);
|
|
1007
|
-
}
|
|
1008
|
-
function clearHighlights(selector) {
|
|
1009
|
-
document.querySelectorAll(`${selector} mark[data-search-highlight]`).forEach((mark) => {
|
|
1010
|
-
try {
|
|
1011
|
-
const parent = mark.parentNode;
|
|
1012
|
-
if (parent && parent.contains(mark)) {
|
|
1013
|
-
const text = mark.textContent || "";
|
|
1014
|
-
parent.replaceChild(document.createTextNode(text), mark);
|
|
1015
|
-
}
|
|
1016
|
-
} catch (e) {}
|
|
1017
|
-
});
|
|
1018
|
-
}
|
|
1019
|
-
function highlightTerms(container, terms) {
|
|
1020
|
-
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, { acceptNode: (node) => {
|
|
1021
|
-
const parent = node.parentElement;
|
|
1022
|
-
if (parent && (parent.tagName === "SCRIPT" || parent.tagName === "STYLE" || parent.tagName === "MARK" || parent.closest("pre") || parent.closest("code"))) return NodeFilter.FILTER_REJECT;
|
|
1023
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
1024
|
-
} });
|
|
1025
|
-
const nodes = [];
|
|
1026
|
-
let node;
|
|
1027
|
-
while (node = walker.nextNode()) nodes.push(node);
|
|
1028
|
-
const accentMap = {
|
|
1029
|
-
a: "[aáàäâã]",
|
|
1030
|
-
e: "[eéèëê]",
|
|
1031
|
-
i: "[iíìïî]",
|
|
1032
|
-
o: "[oóòöôõ]",
|
|
1033
|
-
u: "[uúùüû]",
|
|
1034
|
-
n: "[nñ]",
|
|
1035
|
-
c: "[cç]"
|
|
1036
|
-
};
|
|
1037
|
-
const prepareRegex = (term) => {
|
|
1038
|
-
let pattern = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1039
|
-
pattern = pattern.split("").map((char) => {
|
|
1040
|
-
return accentMap[char.toLowerCase()] || char;
|
|
1041
|
-
}).join("");
|
|
1042
|
-
return pattern;
|
|
1043
|
-
};
|
|
1044
|
-
const combinedPattern = terms.map(prepareRegex).join("|");
|
|
1045
|
-
const regex = new RegExp(`(${combinedPattern})`, "gi");
|
|
1046
|
-
const matchRegexes = terms.map((term) => {
|
|
1047
|
-
const p = prepareRegex(term);
|
|
1048
|
-
return new RegExp(`^${p}$`, "i");
|
|
1049
|
-
});
|
|
1050
|
-
nodes.forEach((textNode) => {
|
|
1051
|
-
const text = textNode.textContent;
|
|
1052
|
-
if (text && regex.test(text)) {
|
|
1053
|
-
const fragment = document.createDocumentFragment();
|
|
1054
|
-
text.split(regex).forEach((part) => {
|
|
1055
|
-
if (matchRegexes.some((rx) => rx.test(part))) {
|
|
1056
|
-
const mark = document.createElement("mark");
|
|
1057
|
-
mark.textContent = part;
|
|
1058
|
-
mark.setAttribute("data-search-highlight", "true");
|
|
1059
|
-
fragment.appendChild(mark);
|
|
1060
|
-
} else if (part) fragment.appendChild(document.createTextNode(part));
|
|
1061
|
-
});
|
|
1062
|
-
if (textNode.parentNode) textNode.parentNode.replaceChild(fragment, textNode);
|
|
1063
|
-
}
|
|
1064
|
-
});
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
1131
|
//#endregion
|
|
1068
1132
|
//#region src/client/components/ui-base/search-highlight.tsx
|
|
1069
1133
|
/**
|
|
@@ -1154,4 +1218,4 @@ const DocsLayout = Object.assign(DocsLayoutRoot, {
|
|
|
1154
1218
|
});
|
|
1155
1219
|
|
|
1156
1220
|
//#endregion
|
|
1157
|
-
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 };
|