boltdocs 2.8.4 → 2.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-B19MLTpN.cjs +6 -0
- package/dist/cache-CfhOTR3Q.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/config-BqZUYono.cjs +7 -0
- package/dist/config-DBKBEj3j.mjs +7 -0
- package/dist/config-GPVEdeon.mjs +6 -0
- package/dist/config-kIQOJHXC.cjs +6 -0
- package/dist/csp-CBysWlAf.cjs +6 -0
- package/dist/csp-RJyh0nHV.mjs +6 -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-C19DsI1e.mjs +7 -0
- package/dist/{doctor-DT4jh07O.cjs → doctor-D8fl3Sbg.cjs} +1 -1
- package/dist/doctor-DzEgMMRo.cjs +7 -0
- package/dist/errors-C0Hx15Ag.mjs +6 -0
- package/dist/errors-Dx6JHoKE.cjs +6 -0
- package/dist/{generator-BHCrLU6h.mjs → generator-B6lrnDZ-.mjs} +1 -1
- package/dist/{generator-CC2yHzhZ.cjs → generator-DtUU3Cfk.cjs} +2 -2
- package/dist/handler-1LRMYeI4.cjs +28 -0
- package/dist/handler-CyIBbZdb.mjs +28 -0
- package/dist/{doctor-BGPdO1Ah.mjs → handler-eNNcucnf.mjs} +1 -1
- package/dist/headers-BJ4jJAhU.cjs +6 -0
- package/dist/headers-HD_qTVVW.mjs +6 -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-C9MKjAs0.cjs} +1 -1
- package/dist/{meta-loader-DzwDFtdT.mjs → meta-loader-CxAoQthW.mjs} +1 -1
- package/dist/node/cli-entry.cjs +8 -2
- package/dist/node/cli-entry.mjs +8 -2
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +362 -18
- package/dist/node/index.d.mts +364 -19
- 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-B7qbjtLl.mjs +105 -0
- package/dist/node-Dj3-2YYP.cjs +105 -0
- package/dist/{package-CwNjt3Sd.cjs → package-ByXh2JHp.cjs} +1 -1
- package/dist/{package-DlgexgpQ.mjs → package-DQBAV8uo.mjs} +1 -1
- package/dist/{parser-BzB-zCkF.cjs → parser-B8naUXl2.cjs} +1 -1
- package/dist/parser-D4oEyuP-.cjs +6 -0
- package/dist/parser-IR9tfyGE.mjs +6 -0
- package/dist/plugin-BkquLpOI.mjs +61 -0
- package/dist/plugin-CL1LsQXk.cjs +61 -0
- package/dist/routes-DR13Y1em.mjs +6 -0
- package/dist/routes-DX8ryKjs.cjs +6 -0
- package/dist/routes-DgTQxpZi.cjs +6 -0
- package/dist/routes-TUSK5wD7.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-BB71nVsG.cjs +6 -0
- package/dist/shiki-adapter-CL-IQwKI.cjs +6 -0
- package/dist/shiki-adapter-CxTLkjew.mjs +6 -0
- package/dist/shiki-adapter-rQ087Lx3.mjs +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/types-generator-BRyf4o9F.mjs +26 -0
- package/dist/types-generator-BqNKCbrx.cjs +26 -0
- package/dist/types-generator-Cu2jQP-V.mjs +6 -0
- package/dist/utils-BWy_8ASj.cjs +7 -0
- package/dist/utils-DexBrwiP.mjs +7 -0
- package/dist/worker-pool-C6r6V05j.mjs +6 -0
- package/dist/worker-pool-m81xuM5v.cjs +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/parser-9LqyiEnB.mjs +0 -6
- package/dist/parser-B7-6PyQz.cjs +0 -6
- 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/utils-BYITg7T5.mjs +0 -7
- package/dist/utils-Cjmx1hhk.cjs +0 -7
- package/dist/worker-pool-DXLyeHJg.cjs +0 -6
- package/dist/worker-pool-Kn4F9gDq.mjs +0 -6
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright (c) 2026 Jesus Alcala
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
const require_icons_dev = require('./icons-dev-
|
|
6
|
+
const require_icons_dev = require('./icons-dev-BryEFkJu.cjs');
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let react_router_dom = require("react-router-dom");
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -244,6 +244,235 @@ Tabs.Item = TabsItem;
|
|
|
244
244
|
Tabs.Content = TabsContent;
|
|
245
245
|
Tabs.Indicator = TabsIndicator;
|
|
246
246
|
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/client/hooks/use-sidebar.ts
|
|
249
|
+
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
|
|
250
|
+
const getCleanDirectoryMeta = (directoryMeta) => {
|
|
251
|
+
const meta = {};
|
|
252
|
+
if (!directoryMeta) return meta;
|
|
253
|
+
for (const [key, value] of Object.entries(directoryMeta)) {
|
|
254
|
+
const cleanKey = key.split("/").filter((part) => !part.startsWith("(") || !part.endsWith(")")).map((part) => part.replace(/^\d+-/, "")).join("/");
|
|
255
|
+
meta[cleanKey === "" ? "." : cleanKey] = value;
|
|
256
|
+
}
|
|
257
|
+
return meta;
|
|
258
|
+
};
|
|
259
|
+
const getOrCreateNode = (parts, rootMap, directoryMeta) => {
|
|
260
|
+
let currentMap = rootMap;
|
|
261
|
+
let parentPath = "";
|
|
262
|
+
let lastNode;
|
|
263
|
+
for (const segment of parts) {
|
|
264
|
+
const currentRelPath = parentPath ? `${parentPath}/${segment}` : segment;
|
|
265
|
+
if (!currentMap.has(segment)) {
|
|
266
|
+
const meta = directoryMeta[currentRelPath] || {};
|
|
267
|
+
const newNode = {
|
|
268
|
+
path: "#",
|
|
269
|
+
title: meta.title || capitalize(segment),
|
|
270
|
+
componentPath: "",
|
|
271
|
+
filePath: "",
|
|
272
|
+
icon: meta.icon,
|
|
273
|
+
groupPosition: typeof meta.order === "number" ? meta.order : 999,
|
|
274
|
+
collapsible: meta.collapsible,
|
|
275
|
+
collapsed: meta.collapsed,
|
|
276
|
+
hasCustomTitle: meta.title !== void 0,
|
|
277
|
+
subRoutes: [],
|
|
278
|
+
childrenMap: /* @__PURE__ */ new Map()
|
|
279
|
+
};
|
|
280
|
+
currentMap.set(segment, newNode);
|
|
281
|
+
}
|
|
282
|
+
lastNode = currentMap.get(segment);
|
|
283
|
+
currentMap = lastNode.childrenMap;
|
|
284
|
+
parentPath = currentRelPath;
|
|
285
|
+
}
|
|
286
|
+
return lastNode;
|
|
287
|
+
};
|
|
288
|
+
const getRoutePosition = (r) => r.sidebarPosition ?? r.order ?? 999;
|
|
289
|
+
const getNodePosition = (n) => n.sidebarPosition ?? n.groupPosition ?? 999;
|
|
290
|
+
const finalizeTree = (nodes) => {
|
|
291
|
+
return nodes.map((node) => {
|
|
292
|
+
if (node.childrenMap && node.childrenMap.size > 0) {
|
|
293
|
+
const childDirs = Array.from(node.childrenMap.values());
|
|
294
|
+
node.subRoutes = [...node.subRoutes || [], ...childDirs];
|
|
295
|
+
}
|
|
296
|
+
const { childrenMap, ...restNode } = node;
|
|
297
|
+
if (restNode.subRoutes && restNode.subRoutes.length > 0) restNode.subRoutes = finalizeTree(restNode.subRoutes);
|
|
298
|
+
return restNode;
|
|
299
|
+
}).sort((a, b) => {
|
|
300
|
+
const posA = getNodePosition(a);
|
|
301
|
+
const posB = getNodePosition(b);
|
|
302
|
+
return posA !== posB ? posA - posB : a.title.localeCompare(b.title);
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
function useSidebar(routes) {
|
|
306
|
+
const config = require_icons_dev.useConfig();
|
|
307
|
+
const { pathname } = (0, react_router_dom.useLocation)();
|
|
308
|
+
return (0, react.useMemo)(() => {
|
|
309
|
+
const currentPath = require_icons_dev.normalizePath(pathname);
|
|
310
|
+
const activeRoute = routes.find((r) => require_icons_dev.normalizePath(r.path) === currentPath);
|
|
311
|
+
const activeTabId = activeRoute?.tab?.toLowerCase();
|
|
312
|
+
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));
|
|
313
|
+
const directoryMeta = getCleanDirectoryMeta(config.directoryMeta);
|
|
314
|
+
const rootNodesMap = /* @__PURE__ */ new Map();
|
|
315
|
+
const ungrouped = [];
|
|
316
|
+
for (const route of filteredRoutes) {
|
|
317
|
+
const parts = route.slugParts || [];
|
|
318
|
+
const isIndex = /^index\.mdx?$/.test(route.filePath.split("/").pop() || "");
|
|
319
|
+
if (parts.length === 0) {
|
|
320
|
+
if (route.filePath) ungrouped.push(route);
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const containerNode = getOrCreateNode(parts, rootNodesMap, directoryMeta);
|
|
324
|
+
if (isIndex) Object.assign(containerNode, {
|
|
325
|
+
path: route.path,
|
|
326
|
+
title: containerNode.hasCustomTitle ? containerNode.title : route.title || containerNode.title,
|
|
327
|
+
icon: route.icon || containerNode.icon,
|
|
328
|
+
badge: route.badge,
|
|
329
|
+
sidebarPosition: route.sidebarPosition,
|
|
330
|
+
frontmatter: route.frontmatter,
|
|
331
|
+
filePath: route.filePath
|
|
332
|
+
});
|
|
333
|
+
else containerNode.subRoutes.push(route);
|
|
334
|
+
}
|
|
335
|
+
const finalizedTopNodes = finalizeTree(Array.from(rootNodesMap.values()));
|
|
336
|
+
const groups = [];
|
|
337
|
+
for (const node of finalizedTopNodes) if (node.subRoutes && node.subRoutes.length > 0) groups.push({
|
|
338
|
+
slug: node.title.toLowerCase().replace(/\s+/g, "-"),
|
|
339
|
+
title: node.title,
|
|
340
|
+
icon: node.icon,
|
|
341
|
+
path: node.path,
|
|
342
|
+
filePath: node.filePath,
|
|
343
|
+
routes: node.subRoutes,
|
|
344
|
+
sidebarPosition: node.sidebarPosition ?? node.groupPosition ?? 999,
|
|
345
|
+
collapsible: node.collapsible,
|
|
346
|
+
collapsed: node.collapsed
|
|
347
|
+
});
|
|
348
|
+
else ungrouped.push(node);
|
|
349
|
+
return {
|
|
350
|
+
groups,
|
|
351
|
+
ungrouped: finalizeTree(ungrouped),
|
|
352
|
+
activeRoute,
|
|
353
|
+
activePath: currentPath,
|
|
354
|
+
config
|
|
355
|
+
};
|
|
356
|
+
}, [
|
|
357
|
+
routes,
|
|
358
|
+
config,
|
|
359
|
+
pathname
|
|
360
|
+
]);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
//#endregion
|
|
364
|
+
//#region src/client/hooks/use-location.ts
|
|
365
|
+
const useLocation = () => {
|
|
366
|
+
return (0, react_router_dom.useLocation)();
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/client/hooks/use-search-highlight.ts
|
|
371
|
+
/**
|
|
372
|
+
* Hook to highlight search terms based on the 'hl' query parameter.
|
|
373
|
+
*/
|
|
374
|
+
function useSearchHighlight(containerSelector = ".boltdocs-page") {
|
|
375
|
+
const { search } = useLocation();
|
|
376
|
+
const query = new URLSearchParams(search).get("hl");
|
|
377
|
+
(0, react.useEffect)(() => {
|
|
378
|
+
if (!query) {
|
|
379
|
+
clearHighlights(containerSelector);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const container = document.querySelector(containerSelector);
|
|
383
|
+
if (!container) return;
|
|
384
|
+
let rafId;
|
|
385
|
+
const observer = new MutationObserver((mutations) => {
|
|
386
|
+
if (mutations.some((m) => {
|
|
387
|
+
const addedNodes = Array.from(m.addedNodes);
|
|
388
|
+
const removedNodes = Array.from(m.removedNodes);
|
|
389
|
+
return addedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight"))) || removedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight")));
|
|
390
|
+
})) run();
|
|
391
|
+
});
|
|
392
|
+
function run() {
|
|
393
|
+
cancelAnimationFrame(rafId);
|
|
394
|
+
rafId = requestAnimationFrame(() => {
|
|
395
|
+
observer.disconnect();
|
|
396
|
+
clearHighlights(containerSelector);
|
|
397
|
+
const terms = query.split(/\s+/).map((t) => t.trim()).filter((t) => t.length >= 2);
|
|
398
|
+
if (terms.length > 0) highlightTerms(container, terms);
|
|
399
|
+
observer.observe(container, {
|
|
400
|
+
childList: true,
|
|
401
|
+
subtree: true
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
run();
|
|
406
|
+
return () => {
|
|
407
|
+
cancelAnimationFrame(rafId);
|
|
408
|
+
observer.disconnect();
|
|
409
|
+
clearHighlights(containerSelector);
|
|
410
|
+
};
|
|
411
|
+
}, [
|
|
412
|
+
query,
|
|
413
|
+
search,
|
|
414
|
+
containerSelector
|
|
415
|
+
]);
|
|
416
|
+
}
|
|
417
|
+
function clearHighlights(selector) {
|
|
418
|
+
document.querySelectorAll(`${selector} mark[data-search-highlight]`).forEach((mark) => {
|
|
419
|
+
try {
|
|
420
|
+
const parent = mark.parentNode;
|
|
421
|
+
if (parent && parent.contains(mark)) {
|
|
422
|
+
const text = mark.textContent || "";
|
|
423
|
+
parent.replaceChild(document.createTextNode(text), mark);
|
|
424
|
+
}
|
|
425
|
+
} catch (e) {}
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
function highlightTerms(container, terms) {
|
|
429
|
+
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, { acceptNode: (node) => {
|
|
430
|
+
const parent = node.parentElement;
|
|
431
|
+
if (parent && (parent.tagName === "SCRIPT" || parent.tagName === "STYLE" || parent.tagName === "MARK" || parent.closest("pre") || parent.closest("code"))) return NodeFilter.FILTER_REJECT;
|
|
432
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
433
|
+
} });
|
|
434
|
+
const nodes = [];
|
|
435
|
+
let node;
|
|
436
|
+
while (node = walker.nextNode()) nodes.push(node);
|
|
437
|
+
const accentMap = {
|
|
438
|
+
a: "[aáàäâã]",
|
|
439
|
+
e: "[eéèëê]",
|
|
440
|
+
i: "[iíìïî]",
|
|
441
|
+
o: "[oóòöôõ]",
|
|
442
|
+
u: "[uúùüû]",
|
|
443
|
+
n: "[nñ]",
|
|
444
|
+
c: "[cç]"
|
|
445
|
+
};
|
|
446
|
+
const prepareRegex = (term) => {
|
|
447
|
+
let pattern = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
448
|
+
pattern = pattern.split("").map((char) => {
|
|
449
|
+
return accentMap[char.toLowerCase()] || char;
|
|
450
|
+
}).join("");
|
|
451
|
+
return pattern;
|
|
452
|
+
};
|
|
453
|
+
const combinedPattern = terms.map(prepareRegex).join("|");
|
|
454
|
+
const regex = new RegExp(`(${combinedPattern})`, "gi");
|
|
455
|
+
const matchRegexes = terms.map((term) => {
|
|
456
|
+
const p = prepareRegex(term);
|
|
457
|
+
return new RegExp(`^${p}$`, "i");
|
|
458
|
+
});
|
|
459
|
+
nodes.forEach((textNode) => {
|
|
460
|
+
const text = textNode.textContent;
|
|
461
|
+
if (text && regex.test(text)) {
|
|
462
|
+
const fragment = document.createDocumentFragment();
|
|
463
|
+
text.split(regex).forEach((part) => {
|
|
464
|
+
if (matchRegexes.some((rx) => rx.test(part))) {
|
|
465
|
+
const mark = document.createElement("mark");
|
|
466
|
+
mark.textContent = part;
|
|
467
|
+
mark.setAttribute("data-search-highlight", "true");
|
|
468
|
+
fragment.appendChild(mark);
|
|
469
|
+
} else if (part) fragment.appendChild(document.createTextNode(part));
|
|
470
|
+
});
|
|
471
|
+
if (textNode.parentNode) textNode.parentNode.replaceChild(fragment, textNode);
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
|
|
247
476
|
//#endregion
|
|
248
477
|
//#region src/client/components/primitives/helpers/observer.ts
|
|
249
478
|
function getItemId(url) {
|
|
@@ -619,116 +848,6 @@ PageNav.Title = PageNavTitle;
|
|
|
619
848
|
PageNav.Description = PageNavDescription;
|
|
620
849
|
PageNav.Icon = PageNavIcon;
|
|
621
850
|
|
|
622
|
-
//#endregion
|
|
623
|
-
//#region src/client/hooks/use-sidebar.ts
|
|
624
|
-
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1).replace(/-/g, " ");
|
|
625
|
-
const getCleanDirectoryMeta = (directoryMeta) => {
|
|
626
|
-
const meta = {};
|
|
627
|
-
if (!directoryMeta) return meta;
|
|
628
|
-
for (const [key, value] of Object.entries(directoryMeta)) {
|
|
629
|
-
const cleanKey = key.split("/").filter((part) => !part.startsWith("(") || !part.endsWith(")")).map((part) => part.replace(/^\d+-/, "")).join("/");
|
|
630
|
-
meta[cleanKey === "" ? "." : cleanKey] = value;
|
|
631
|
-
}
|
|
632
|
-
return meta;
|
|
633
|
-
};
|
|
634
|
-
const getOrCreateNode = (parts, rootMap, directoryMeta) => {
|
|
635
|
-
let currentMap = rootMap;
|
|
636
|
-
let parentPath = "";
|
|
637
|
-
let lastNode;
|
|
638
|
-
for (const segment of parts) {
|
|
639
|
-
const currentRelPath = parentPath ? `${parentPath}/${segment}` : segment;
|
|
640
|
-
if (!currentMap.has(segment)) {
|
|
641
|
-
const meta = directoryMeta[currentRelPath] || {};
|
|
642
|
-
const newNode = {
|
|
643
|
-
path: "#",
|
|
644
|
-
title: meta.title || capitalize(segment),
|
|
645
|
-
componentPath: "",
|
|
646
|
-
filePath: "",
|
|
647
|
-
icon: meta.icon,
|
|
648
|
-
groupPosition: typeof meta.order === "number" ? meta.order : 999,
|
|
649
|
-
subRoutes: [],
|
|
650
|
-
childrenMap: /* @__PURE__ */ new Map()
|
|
651
|
-
};
|
|
652
|
-
currentMap.set(segment, newNode);
|
|
653
|
-
}
|
|
654
|
-
lastNode = currentMap.get(segment);
|
|
655
|
-
currentMap = lastNode.childrenMap;
|
|
656
|
-
parentPath = currentRelPath;
|
|
657
|
-
}
|
|
658
|
-
return lastNode;
|
|
659
|
-
};
|
|
660
|
-
const getRoutePosition = (r) => r.sidebarPosition ?? r.order ?? 999;
|
|
661
|
-
const getNodePosition = (n) => n.sidebarPosition ?? n.groupPosition ?? 999;
|
|
662
|
-
const finalizeTree = (nodes) => {
|
|
663
|
-
return nodes.map((node) => {
|
|
664
|
-
if (node.childrenMap && node.childrenMap.size > 0) {
|
|
665
|
-
const childDirs = Array.from(node.childrenMap.values());
|
|
666
|
-
node.subRoutes = [...node.subRoutes || [], ...childDirs];
|
|
667
|
-
}
|
|
668
|
-
const { childrenMap, ...restNode } = node;
|
|
669
|
-
if (restNode.subRoutes && restNode.subRoutes.length > 0) restNode.subRoutes = finalizeTree(restNode.subRoutes);
|
|
670
|
-
return restNode;
|
|
671
|
-
}).sort((a, b) => {
|
|
672
|
-
const posA = getNodePosition(a);
|
|
673
|
-
const posB = getNodePosition(b);
|
|
674
|
-
return posA !== posB ? posA - posB : a.title.localeCompare(b.title);
|
|
675
|
-
});
|
|
676
|
-
};
|
|
677
|
-
function useSidebar(routes) {
|
|
678
|
-
const config = require_icons_dev.useConfig();
|
|
679
|
-
const { pathname } = (0, react_router_dom.useLocation)();
|
|
680
|
-
return (0, react.useMemo)(() => {
|
|
681
|
-
const currentPath = require_icons_dev.normalizePath(pathname);
|
|
682
|
-
const activeRoute = routes.find((r) => require_icons_dev.normalizePath(r.path) === currentPath);
|
|
683
|
-
const activeTabId = activeRoute?.tab?.toLowerCase();
|
|
684
|
-
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));
|
|
685
|
-
const directoryMeta = getCleanDirectoryMeta(config.directoryMeta);
|
|
686
|
-
const rootNodesMap = /* @__PURE__ */ new Map();
|
|
687
|
-
const ungrouped = [];
|
|
688
|
-
for (const route of filteredRoutes) {
|
|
689
|
-
const parts = route.slugParts || [];
|
|
690
|
-
const isIndex = /^index\.mdx?$/.test(route.filePath.split("/").pop() || "");
|
|
691
|
-
if (parts.length === 0) {
|
|
692
|
-
if (route.filePath) ungrouped.push(route);
|
|
693
|
-
continue;
|
|
694
|
-
}
|
|
695
|
-
const containerNode = getOrCreateNode(parts, rootNodesMap, directoryMeta);
|
|
696
|
-
if (isIndex) Object.assign(containerNode, {
|
|
697
|
-
path: route.path,
|
|
698
|
-
title: route.title || containerNode.title,
|
|
699
|
-
icon: route.icon || containerNode.icon,
|
|
700
|
-
badge: route.badge,
|
|
701
|
-
sidebarPosition: route.sidebarPosition,
|
|
702
|
-
frontmatter: route.frontmatter,
|
|
703
|
-
filePath: route.filePath
|
|
704
|
-
});
|
|
705
|
-
else containerNode.subRoutes.push(route);
|
|
706
|
-
}
|
|
707
|
-
const finalizedTopNodes = finalizeTree(Array.from(rootNodesMap.values()));
|
|
708
|
-
const groups = [];
|
|
709
|
-
for (const node of finalizedTopNodes) if (node.subRoutes && node.subRoutes.length > 0) groups.push({
|
|
710
|
-
slug: node.title.toLowerCase().replace(/\s+/g, "-"),
|
|
711
|
-
title: node.title,
|
|
712
|
-
icon: node.icon,
|
|
713
|
-
path: node.path,
|
|
714
|
-
filePath: node.filePath,
|
|
715
|
-
routes: node.subRoutes
|
|
716
|
-
});
|
|
717
|
-
else ungrouped.push(node);
|
|
718
|
-
return {
|
|
719
|
-
groups,
|
|
720
|
-
ungrouped: finalizeTree(ungrouped),
|
|
721
|
-
activeRoute,
|
|
722
|
-
activePath: currentPath,
|
|
723
|
-
config
|
|
724
|
-
};
|
|
725
|
-
}, [
|
|
726
|
-
routes,
|
|
727
|
-
config,
|
|
728
|
-
pathname
|
|
729
|
-
]);
|
|
730
|
-
}
|
|
731
|
-
|
|
732
851
|
//#endregion
|
|
733
852
|
//#region src/client/components/primitives/sidebar.tsx
|
|
734
853
|
let sidebarScrollPos = 0;
|
|
@@ -822,13 +941,29 @@ function SidebarContent({ children, className }) {
|
|
|
822
941
|
/**
|
|
823
942
|
* Navigation Group
|
|
824
943
|
*/
|
|
825
|
-
function SidebarGroup({ title, icon: Icon, children, className }) {
|
|
944
|
+
function SidebarGroup({ title, icon: Icon, children, className, collapsible = false, collapsed = false, active = false }) {
|
|
945
|
+
const [isOpen, setIsOpen] = (0, react.useState)(() => active || !collapsed);
|
|
946
|
+
const [prevActive, setPrevActive] = (0, react.useState)(active);
|
|
947
|
+
if (active !== prevActive) {
|
|
948
|
+
setPrevActive(active);
|
|
949
|
+
if (active) setIsOpen(true);
|
|
950
|
+
}
|
|
826
951
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
827
952
|
className,
|
|
828
|
-
children: [title && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
953
|
+
children: [title && (collapsible ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
954
|
+
onClick: () => setIsOpen(!isOpen),
|
|
955
|
+
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",
|
|
956
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
957
|
+
className: "flex items-center gap-2",
|
|
958
|
+
children: [Icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { size: 12 }), title]
|
|
959
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_icons_dev.ChevronRight, {
|
|
960
|
+
size: 12,
|
|
961
|
+
className: require_icons_dev.cn("transition-transform duration-200 text-muted/40 group-hover:text-body", isOpen && "rotate-90")
|
|
962
|
+
})]
|
|
963
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h4", {
|
|
829
964
|
className: "px-2 mb-2 flex items-center gap-2 text-[11px] font-bold uppercase tracking-widest text-muted/50",
|
|
830
965
|
children: [Icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { size: 12 }), title]
|
|
831
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
966
|
+
})), (!collapsible || isOpen) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
832
967
|
className: "flex flex-col gap-0.5",
|
|
833
968
|
children
|
|
834
969
|
})]
|
|
@@ -919,23 +1054,65 @@ function SidebarItem({ route, activePath, activeRoute, className }) {
|
|
|
919
1054
|
className
|
|
920
1055
|
});
|
|
921
1056
|
}
|
|
1057
|
+
const isRouteActive = (route, activePath, activeRoute) => {
|
|
1058
|
+
const normalizedPath = route.path.endsWith("/") ? route.path.slice(0, -1) : route.path;
|
|
1059
|
+
if ((activePath.endsWith("/") ? activePath.slice(0, -1) : activePath) === normalizedPath) return true;
|
|
1060
|
+
if (activeRoute?.filePath && route.filePath && activeRoute.filePath === route.filePath) return true;
|
|
1061
|
+
if (route.routes && route.routes.some((r) => isRouteActive(r, activePath, activeRoute))) return true;
|
|
1062
|
+
if (route.subRoutes && route.subRoutes.some((r) => isRouteActive(r, activePath, activeRoute))) return true;
|
|
1063
|
+
return false;
|
|
1064
|
+
};
|
|
922
1065
|
function SidebarItems({ routes, className }) {
|
|
923
1066
|
const { groups, ungrouped, activePath, activeRoute } = useSidebar(routes);
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
1067
|
+
const mergedItems = [...ungrouped.map((route) => ({
|
|
1068
|
+
type: "link",
|
|
1069
|
+
position: route.sidebarPosition ?? 999,
|
|
1070
|
+
title: route.title,
|
|
1071
|
+
route
|
|
1072
|
+
})), ...groups.map((group) => ({
|
|
1073
|
+
type: "group",
|
|
1074
|
+
position: group.sidebarPosition ?? 999,
|
|
1075
|
+
title: group.title,
|
|
1076
|
+
group
|
|
1077
|
+
}))].sort((a, b) => {
|
|
1078
|
+
if (a.position !== b.position) return a.position - b.position;
|
|
1079
|
+
if (a.type !== b.type) return a.type === "link" ? -1 : 1;
|
|
1080
|
+
return a.title.localeCompare(b.title);
|
|
1081
|
+
});
|
|
1082
|
+
const renderedElements = [];
|
|
1083
|
+
let currentUngrouped = [];
|
|
1084
|
+
const pushUngrouped = () => {
|
|
1085
|
+
if (currentUngrouped.length > 0) {
|
|
1086
|
+
const routesToRender = [...currentUngrouped];
|
|
1087
|
+
renderedElements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarGroup, { children: routesToRender.map((route) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarItem, {
|
|
1088
|
+
route,
|
|
1089
|
+
activePath,
|
|
1090
|
+
activeRoute
|
|
1091
|
+
}, route.path)) }, `ungrouped-${routesToRender[0].path}`));
|
|
1092
|
+
currentUngrouped = [];
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
for (const item of mergedItems) if (item.type === "link") currentUngrouped.push(item.route);
|
|
1096
|
+
else {
|
|
1097
|
+
pushUngrouped();
|
|
1098
|
+
const isGroupActive = item.group.routes.some((route) => isRouteActive(route, activePath, activeRoute));
|
|
1099
|
+
renderedElements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarGroup, {
|
|
1100
|
+
title: item.group.title,
|
|
1101
|
+
icon: getIcon(item.group.icon),
|
|
1102
|
+
collapsible: item.group.collapsible,
|
|
1103
|
+
collapsed: item.group.collapsed,
|
|
1104
|
+
active: isGroupActive,
|
|
1105
|
+
children: item.group.routes.map((route) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarItem, {
|
|
934
1106
|
route,
|
|
935
1107
|
activePath,
|
|
936
1108
|
activeRoute
|
|
937
1109
|
}, route.path))
|
|
938
|
-
}, group.title))
|
|
1110
|
+
}, item.group.title));
|
|
1111
|
+
}
|
|
1112
|
+
pushUngrouped();
|
|
1113
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1114
|
+
className: require_icons_dev.cn("flex flex-col gap-6", className),
|
|
1115
|
+
children: renderedElements
|
|
939
1116
|
});
|
|
940
1117
|
}
|
|
941
1118
|
/**
|
|
@@ -953,119 +1130,6 @@ const Sidebar = Object.assign(SidebarRoot, {
|
|
|
953
1130
|
Items: SidebarItems
|
|
954
1131
|
});
|
|
955
1132
|
|
|
956
|
-
//#endregion
|
|
957
|
-
//#region src/client/hooks/use-location.ts
|
|
958
|
-
const useLocation = () => {
|
|
959
|
-
return (0, react_router_dom.useLocation)();
|
|
960
|
-
};
|
|
961
|
-
|
|
962
|
-
//#endregion
|
|
963
|
-
//#region src/client/hooks/use-search-highlight.ts
|
|
964
|
-
/**
|
|
965
|
-
* Hook to highlight search terms based on the 'hl' query parameter.
|
|
966
|
-
*/
|
|
967
|
-
function useSearchHighlight(containerSelector = ".boltdocs-page") {
|
|
968
|
-
const { search } = useLocation();
|
|
969
|
-
const query = new URLSearchParams(search).get("hl");
|
|
970
|
-
(0, react.useEffect)(() => {
|
|
971
|
-
if (!query) {
|
|
972
|
-
clearHighlights(containerSelector);
|
|
973
|
-
return;
|
|
974
|
-
}
|
|
975
|
-
const container = document.querySelector(containerSelector);
|
|
976
|
-
if (!container) return;
|
|
977
|
-
let rafId;
|
|
978
|
-
const observer = new MutationObserver((mutations) => {
|
|
979
|
-
if (mutations.some((m) => {
|
|
980
|
-
const addedNodes = Array.from(m.addedNodes);
|
|
981
|
-
const removedNodes = Array.from(m.removedNodes);
|
|
982
|
-
return addedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight"))) || removedNodes.some((n) => !(n instanceof HTMLElement && n.hasAttribute("data-search-highlight")));
|
|
983
|
-
})) run();
|
|
984
|
-
});
|
|
985
|
-
function run() {
|
|
986
|
-
cancelAnimationFrame(rafId);
|
|
987
|
-
rafId = requestAnimationFrame(() => {
|
|
988
|
-
observer.disconnect();
|
|
989
|
-
clearHighlights(containerSelector);
|
|
990
|
-
const terms = query.split(/\s+/).map((t) => t.trim()).filter((t) => t.length >= 2);
|
|
991
|
-
if (terms.length > 0) highlightTerms(container, terms);
|
|
992
|
-
observer.observe(container, {
|
|
993
|
-
childList: true,
|
|
994
|
-
subtree: true
|
|
995
|
-
});
|
|
996
|
-
});
|
|
997
|
-
}
|
|
998
|
-
run();
|
|
999
|
-
return () => {
|
|
1000
|
-
cancelAnimationFrame(rafId);
|
|
1001
|
-
observer.disconnect();
|
|
1002
|
-
clearHighlights(containerSelector);
|
|
1003
|
-
};
|
|
1004
|
-
}, [
|
|
1005
|
-
query,
|
|
1006
|
-
search,
|
|
1007
|
-
containerSelector
|
|
1008
|
-
]);
|
|
1009
|
-
}
|
|
1010
|
-
function clearHighlights(selector) {
|
|
1011
|
-
document.querySelectorAll(`${selector} mark[data-search-highlight]`).forEach((mark) => {
|
|
1012
|
-
try {
|
|
1013
|
-
const parent = mark.parentNode;
|
|
1014
|
-
if (parent && parent.contains(mark)) {
|
|
1015
|
-
const text = mark.textContent || "";
|
|
1016
|
-
parent.replaceChild(document.createTextNode(text), mark);
|
|
1017
|
-
}
|
|
1018
|
-
} catch (e) {}
|
|
1019
|
-
});
|
|
1020
|
-
}
|
|
1021
|
-
function highlightTerms(container, terms) {
|
|
1022
|
-
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, { acceptNode: (node) => {
|
|
1023
|
-
const parent = node.parentElement;
|
|
1024
|
-
if (parent && (parent.tagName === "SCRIPT" || parent.tagName === "STYLE" || parent.tagName === "MARK" || parent.closest("pre") || parent.closest("code"))) return NodeFilter.FILTER_REJECT;
|
|
1025
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
1026
|
-
} });
|
|
1027
|
-
const nodes = [];
|
|
1028
|
-
let node;
|
|
1029
|
-
while (node = walker.nextNode()) nodes.push(node);
|
|
1030
|
-
const accentMap = {
|
|
1031
|
-
a: "[aáàäâã]",
|
|
1032
|
-
e: "[eéèëê]",
|
|
1033
|
-
i: "[iíìïî]",
|
|
1034
|
-
o: "[oóòöôõ]",
|
|
1035
|
-
u: "[uúùüû]",
|
|
1036
|
-
n: "[nñ]",
|
|
1037
|
-
c: "[cç]"
|
|
1038
|
-
};
|
|
1039
|
-
const prepareRegex = (term) => {
|
|
1040
|
-
let pattern = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1041
|
-
pattern = pattern.split("").map((char) => {
|
|
1042
|
-
return accentMap[char.toLowerCase()] || char;
|
|
1043
|
-
}).join("");
|
|
1044
|
-
return pattern;
|
|
1045
|
-
};
|
|
1046
|
-
const combinedPattern = terms.map(prepareRegex).join("|");
|
|
1047
|
-
const regex = new RegExp(`(${combinedPattern})`, "gi");
|
|
1048
|
-
const matchRegexes = terms.map((term) => {
|
|
1049
|
-
const p = prepareRegex(term);
|
|
1050
|
-
return new RegExp(`^${p}$`, "i");
|
|
1051
|
-
});
|
|
1052
|
-
nodes.forEach((textNode) => {
|
|
1053
|
-
const text = textNode.textContent;
|
|
1054
|
-
if (text && regex.test(text)) {
|
|
1055
|
-
const fragment = document.createDocumentFragment();
|
|
1056
|
-
text.split(regex).forEach((part) => {
|
|
1057
|
-
if (matchRegexes.some((rx) => rx.test(part))) {
|
|
1058
|
-
const mark = document.createElement("mark");
|
|
1059
|
-
mark.textContent = part;
|
|
1060
|
-
mark.setAttribute("data-search-highlight", "true");
|
|
1061
|
-
fragment.appendChild(mark);
|
|
1062
|
-
} else if (part) fragment.appendChild(document.createTextNode(part));
|
|
1063
|
-
});
|
|
1064
|
-
if (textNode.parentNode) textNode.parentNode.replaceChild(fragment, textNode);
|
|
1065
|
-
}
|
|
1066
|
-
});
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
1133
|
//#endregion
|
|
1070
1134
|
//#region src/client/components/ui-base/search-highlight.tsx
|
|
1071
1135
|
/**
|