boltdocs 1.0.4 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{SearchDialog-R36WKAQ7.mjs → SearchDialog-5EDRACEG.mjs} +1 -1
- package/dist/{SearchDialog-PYF3QMYG.css → SearchDialog-X57WPTNN.css} +54 -126
- package/dist/cache-EHR7SXRU.mjs +12 -0
- package/dist/chunk-GSYECEZY.mjs +381 -0
- package/dist/{chunk-TWSRXUFF.mjs → chunk-NS7WHDYA.mjs} +229 -418
- package/dist/client/index.css +54 -126
- package/dist/client/index.d.mts +5 -4
- package/dist/client/index.d.ts +5 -4
- package/dist/client/index.js +555 -580
- package/dist/client/index.mjs +304 -16
- package/dist/client/ssr.css +54 -126
- package/dist/client/ssr.js +257 -580
- package/dist/client/ssr.mjs +1 -1
- package/dist/{config-D2XmHJYe.d.mts → config-BD5ZHz15.d.mts} +7 -0
- package/dist/{config-D2XmHJYe.d.ts → config-BD5ZHz15.d.ts} +7 -0
- package/dist/node/index.d.mts +2 -2
- package/dist/node/index.d.ts +2 -2
- package/dist/node/index.js +457 -118
- package/dist/node/index.mjs +93 -136
- package/package.json +2 -2
- package/src/client/app/index.tsx +25 -54
- package/src/client/theme/components/mdx/mdx-components.css +39 -20
- package/src/client/theme/styles/markdown.css +1 -1
- package/src/client/theme/styles.css +0 -1
- package/src/client/theme/ui/Layout/Layout.tsx +2 -13
- package/src/client/theme/ui/Layout/responsive.css +0 -4
- package/src/client/theme/ui/Link/Link.tsx +52 -0
- package/src/client/theme/ui/NotFound/NotFound.tsx +0 -1
- package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +45 -2
- package/src/client/theme/ui/Sidebar/Sidebar.tsx +44 -40
- package/src/client/theme/ui/Sidebar/sidebar.css +25 -58
- package/src/node/cache.ts +360 -46
- package/src/node/config.ts +7 -0
- package/src/node/mdx.ts +83 -4
- package/src/node/plugin/index.ts +3 -0
- package/src/node/routes/cache.ts +5 -1
- package/src/node/routes/index.ts +17 -2
- package/src/node/ssg/index.ts +4 -0
- package/dist/Playground-B2FA34BC.mjs +0 -6
- package/dist/chunk-WPT4MWTQ.mjs +0 -89
- package/src/client/theme/styles/home.css +0 -60
package/dist/node/index.mjs
CHANGED
|
@@ -1,133 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FileCache,
|
|
3
|
+
TransformCache,
|
|
4
|
+
capitalize,
|
|
5
|
+
escapeHtml,
|
|
6
|
+
extractNumberPrefix,
|
|
7
|
+
fileToRoutePath,
|
|
8
|
+
isDocFile,
|
|
9
|
+
normalizePath,
|
|
10
|
+
parseFrontmatter,
|
|
11
|
+
stripNumberPrefix
|
|
12
|
+
} from "../chunk-GSYECEZY.mjs";
|
|
13
|
+
|
|
1
14
|
// src/node/plugin/index.ts
|
|
2
15
|
import { loadEnv } from "vite";
|
|
3
16
|
|
|
4
17
|
// src/node/routes/index.ts
|
|
5
18
|
import fastGlob from "fast-glob";
|
|
6
19
|
|
|
7
|
-
// src/node/utils.ts
|
|
8
|
-
import fs from "fs";
|
|
9
|
-
import matter from "gray-matter";
|
|
10
|
-
function normalizePath(p) {
|
|
11
|
-
return p.replace(/\\/g, "/");
|
|
12
|
-
}
|
|
13
|
-
function stripNumberPrefix(name) {
|
|
14
|
-
return name.replace(/^\d+\./, "");
|
|
15
|
-
}
|
|
16
|
-
function extractNumberPrefix(name) {
|
|
17
|
-
const match = name.match(/^(\d+)\./);
|
|
18
|
-
return match ? parseInt(match[1], 10) : void 0;
|
|
19
|
-
}
|
|
20
|
-
function isDocFile(filePath) {
|
|
21
|
-
return /\.mdx?$/.test(filePath);
|
|
22
|
-
}
|
|
23
|
-
function getFileMtime(filePath) {
|
|
24
|
-
try {
|
|
25
|
-
return fs.statSync(filePath).mtimeMs;
|
|
26
|
-
} catch {
|
|
27
|
-
return 0;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function parseFrontmatter(filePath) {
|
|
31
|
-
const raw = fs.readFileSync(filePath, "utf-8");
|
|
32
|
-
const { data, content } = matter(raw);
|
|
33
|
-
return { data, content };
|
|
34
|
-
}
|
|
35
|
-
function escapeHtml(str) {
|
|
36
|
-
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
37
|
-
}
|
|
38
|
-
function fileToRoutePath(relativePath) {
|
|
39
|
-
let cleanedPath = relativePath.split("/").map(stripNumberPrefix).join("/");
|
|
40
|
-
let routePath = cleanedPath.replace(/\.mdx?$/, "");
|
|
41
|
-
if (routePath === "index" || routePath.endsWith("/index")) {
|
|
42
|
-
routePath = routePath.replace(/index$/, "");
|
|
43
|
-
}
|
|
44
|
-
if (!routePath.startsWith("/")) {
|
|
45
|
-
routePath = "/" + routePath;
|
|
46
|
-
}
|
|
47
|
-
if (routePath.length > 1 && routePath.endsWith("/")) {
|
|
48
|
-
routePath = routePath.slice(0, -1);
|
|
49
|
-
}
|
|
50
|
-
return routePath;
|
|
51
|
-
}
|
|
52
|
-
function capitalize(str) {
|
|
53
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// src/node/cache.ts
|
|
57
|
-
var FileCache = class {
|
|
58
|
-
entries = /* @__PURE__ */ new Map();
|
|
59
|
-
/**
|
|
60
|
-
* Retrieves parsed data for a file from the cache.
|
|
61
|
-
* Compares the current filesystem mtime with the cached mtime.
|
|
62
|
-
*
|
|
63
|
-
* @param filePath - The absolute path of the file
|
|
64
|
-
* @returns The cached data if valid, or `null` if the file has changed or doesn't exist
|
|
65
|
-
*/
|
|
66
|
-
get(filePath) {
|
|
67
|
-
const entry = this.entries.get(filePath);
|
|
68
|
-
if (!entry) return null;
|
|
69
|
-
const currentMtime = getFileMtime(filePath);
|
|
70
|
-
if (currentMtime !== entry.mtime) return null;
|
|
71
|
-
return entry.data;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Stores parsed data for a file in the cache, recording its current mtime.
|
|
75
|
-
*
|
|
76
|
-
* @param filePath - The absolute path to the file
|
|
77
|
-
* @param data - The parsed data to store
|
|
78
|
-
*/
|
|
79
|
-
set(filePath, data) {
|
|
80
|
-
this.entries.set(filePath, {
|
|
81
|
-
data,
|
|
82
|
-
mtime: getFileMtime(filePath)
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Checks if a specific file's cache is still valid (based on its mtime).
|
|
87
|
-
*
|
|
88
|
-
* @param filePath - The absolute path to the file
|
|
89
|
-
* @returns `true` if the cache is valid, `false` otherwise
|
|
90
|
-
*/
|
|
91
|
-
isValid(filePath) {
|
|
92
|
-
return this.get(filePath) !== null;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Manually removes a specific file from the cache.
|
|
96
|
-
* Useful when forcefully invalidating a single updated file.
|
|
97
|
-
*
|
|
98
|
-
* @param filePath - The absolute path to the file
|
|
99
|
-
*/
|
|
100
|
-
invalidate(filePath) {
|
|
101
|
-
this.entries.delete(filePath);
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Clears the entire cache, forcing all files to be re-parsed on the next request.
|
|
105
|
-
* Useful when global dependencies (like config) change.
|
|
106
|
-
*/
|
|
107
|
-
invalidateAll() {
|
|
108
|
-
this.entries.clear();
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Removes cached entries for files that no longer exist on the filesystem.
|
|
112
|
-
* Prevents memory leaks from deleted files.
|
|
113
|
-
*
|
|
114
|
-
* @param currentFiles - A Set of absolute file paths currently discovered on the disk
|
|
115
|
-
*/
|
|
116
|
-
pruneStale(currentFiles) {
|
|
117
|
-
for (const key of this.entries.keys()) {
|
|
118
|
-
if (!currentFiles.has(key)) {
|
|
119
|
-
this.entries.delete(key);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
/** Number of cached entries */
|
|
124
|
-
get size() {
|
|
125
|
-
return this.entries.size;
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
20
|
// src/node/routes/cache.ts
|
|
130
|
-
var docCache = new FileCache();
|
|
21
|
+
var docCache = new FileCache({ name: "routes" });
|
|
131
22
|
function invalidateRouteCache() {
|
|
132
23
|
docCache.invalidateAll();
|
|
133
24
|
}
|
|
@@ -240,6 +131,7 @@ function compareByGroupPosition(a, b) {
|
|
|
240
131
|
|
|
241
132
|
// src/node/routes/index.ts
|
|
242
133
|
async function generateRoutes(docsDir, config, basePath = "/docs") {
|
|
134
|
+
docCache.load();
|
|
243
135
|
const files = await fastGlob(["**/*.md", "**/*.mdx"], {
|
|
244
136
|
cwd: docsDir,
|
|
245
137
|
absolute: true
|
|
@@ -248,15 +140,25 @@ async function generateRoutes(docsDir, config, basePath = "/docs") {
|
|
|
248
140
|
if (config?.i18n) {
|
|
249
141
|
docCache.invalidateAll();
|
|
250
142
|
}
|
|
143
|
+
let cacheHits = 0;
|
|
251
144
|
const parsed = await Promise.all(
|
|
252
145
|
files.map(async (file) => {
|
|
253
146
|
const cached = docCache.get(file);
|
|
254
|
-
if (cached)
|
|
147
|
+
if (cached) {
|
|
148
|
+
cacheHits++;
|
|
149
|
+
return cached;
|
|
150
|
+
}
|
|
255
151
|
const result = parseDocFile(file, docsDir, basePath, config);
|
|
256
152
|
docCache.set(file, result);
|
|
257
153
|
return result;
|
|
258
154
|
})
|
|
259
155
|
);
|
|
156
|
+
if (files.length > 0) {
|
|
157
|
+
console.log(
|
|
158
|
+
`[boltdocs] Routes generated: ${files.length} files (${cacheHits} from cache, ${files.length - cacheHits} parsed)`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
docCache.save();
|
|
260
162
|
const groupMeta = /* @__PURE__ */ new Map();
|
|
261
163
|
for (const p of parsed) {
|
|
262
164
|
if (p.relativeDir) {
|
|
@@ -336,7 +238,7 @@ import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
|
|
|
336
238
|
// src/node/config.ts
|
|
337
239
|
import path2 from "path";
|
|
338
240
|
import { pathToFileURL } from "url";
|
|
339
|
-
import
|
|
241
|
+
import fs from "fs";
|
|
340
242
|
var CONFIG_FILES = [
|
|
341
243
|
"boltdocs.config.js",
|
|
342
244
|
"boltdocs.config.mjs",
|
|
@@ -357,7 +259,7 @@ async function resolveConfig(docsDir) {
|
|
|
357
259
|
};
|
|
358
260
|
for (const filename of CONFIG_FILES) {
|
|
359
261
|
const configPath = path2.resolve(projectRoot, filename);
|
|
360
|
-
if (
|
|
262
|
+
if (fs.existsSync(configPath)) {
|
|
361
263
|
try {
|
|
362
264
|
const fileUrl = pathToFileURL(configPath).href + "?t=" + Date.now();
|
|
363
265
|
const mod = await import(fileUrl);
|
|
@@ -383,7 +285,7 @@ async function resolveConfig(docsDir) {
|
|
|
383
285
|
}
|
|
384
286
|
|
|
385
287
|
// src/node/ssg/index.ts
|
|
386
|
-
import
|
|
288
|
+
import fs2 from "fs";
|
|
387
289
|
import path3 from "path";
|
|
388
290
|
import { fileURLToPath } from "url";
|
|
389
291
|
import { createRequire } from "module";
|
|
@@ -456,7 +358,7 @@ async function generateStaticPages(options) {
|
|
|
456
358
|
const siteTitle = config?.themeConfig?.title || "Boltdocs";
|
|
457
359
|
const siteDescription = config?.themeConfig?.description || "";
|
|
458
360
|
const ssrModulePath = path3.resolve(_dirname, "../client/ssr.js");
|
|
459
|
-
if (!
|
|
361
|
+
if (!fs2.existsSync(ssrModulePath)) {
|
|
460
362
|
console.error(
|
|
461
363
|
"[boltdocs] SSR module not found at",
|
|
462
364
|
ssrModulePath,
|
|
@@ -466,11 +368,11 @@ async function generateStaticPages(options) {
|
|
|
466
368
|
}
|
|
467
369
|
const { render } = _require(ssrModulePath);
|
|
468
370
|
const templatePath = path3.join(outDir, "index.html");
|
|
469
|
-
if (!
|
|
371
|
+
if (!fs2.existsSync(templatePath)) {
|
|
470
372
|
console.warn("[boltdocs] No index.html found in outDir, skipping SSG.");
|
|
471
373
|
return;
|
|
472
374
|
}
|
|
473
|
-
const template =
|
|
375
|
+
const template = fs2.readFileSync(templatePath, "utf-8");
|
|
474
376
|
let homePageComp;
|
|
475
377
|
if (config?._homePagePath) {
|
|
476
378
|
try {
|
|
@@ -497,8 +399,8 @@ async function generateStaticPages(options) {
|
|
|
497
399
|
description: escapeHtml(pageDescription)
|
|
498
400
|
}).replace("<!--app-html-->", appHtml).replace(`<div id="root"></div>`, `<div id="root">${appHtml}</div>`);
|
|
499
401
|
const routeDir = path3.join(outDir, route.path);
|
|
500
|
-
await
|
|
501
|
-
await
|
|
402
|
+
await fs2.promises.mkdir(routeDir, { recursive: true });
|
|
403
|
+
await fs2.promises.writeFile(
|
|
502
404
|
path3.join(routeDir, "index.html"),
|
|
503
405
|
html,
|
|
504
406
|
"utf-8"
|
|
@@ -512,10 +414,12 @@ async function generateStaticPages(options) {
|
|
|
512
414
|
routes.map((r) => r.path),
|
|
513
415
|
config
|
|
514
416
|
);
|
|
515
|
-
|
|
417
|
+
fs2.writeFileSync(path3.join(outDir, "sitemap.xml"), sitemap, "utf-8");
|
|
516
418
|
console.log(
|
|
517
419
|
`[boltdocs] Generated ${routes.length} static pages + sitemap.xml`
|
|
518
420
|
);
|
|
421
|
+
const { flushCache } = await import("../cache-EHR7SXRU.mjs");
|
|
422
|
+
await flushCache();
|
|
519
423
|
}
|
|
520
424
|
|
|
521
425
|
// src/node/plugin/index.ts
|
|
@@ -696,6 +600,8 @@ function boltdocsPlugin(options = {}, passedConfig) {
|
|
|
696
600
|
if (!isBuild) return;
|
|
697
601
|
const outDir = viteConfig?.build?.outDir ? path4.resolve(viteConfig.root, viteConfig.build.outDir) : path4.resolve(process.cwd(), "dist");
|
|
698
602
|
await generateStaticPages({ docsDir, outDir, config });
|
|
603
|
+
const { flushCache } = await import("../cache-EHR7SXRU.mjs");
|
|
604
|
+
await flushCache();
|
|
699
605
|
}
|
|
700
606
|
},
|
|
701
607
|
ViteImageOptimizer({
|
|
@@ -725,10 +631,13 @@ import remarkGfm from "remark-gfm";
|
|
|
725
631
|
import remarkFrontmatter from "remark-frontmatter";
|
|
726
632
|
import rehypeSlug from "rehype-slug";
|
|
727
633
|
import rehypePrettyCode from "rehype-pretty-code";
|
|
634
|
+
import crypto from "crypto";
|
|
635
|
+
var mdxCache = new TransformCache("mdx");
|
|
636
|
+
var mdxCacheLoaded = false;
|
|
728
637
|
function boltdocsMdxPlugin(config) {
|
|
729
638
|
const extraRemarkPlugins = config?.plugins?.flatMap((p) => p.remarkPlugins || []) || [];
|
|
730
639
|
const extraRehypePlugins = config?.plugins?.flatMap((p) => p.rehypePlugins || []) || [];
|
|
731
|
-
|
|
640
|
+
const baseMdxPlugin = mdxPlugin({
|
|
732
641
|
remarkPlugins: [remarkGfm, remarkFrontmatter, ...extraRemarkPlugins],
|
|
733
642
|
rehypePlugins: [
|
|
734
643
|
rehypeSlug,
|
|
@@ -736,16 +645,64 @@ function boltdocsMdxPlugin(config) {
|
|
|
736
645
|
[
|
|
737
646
|
rehypePrettyCode,
|
|
738
647
|
{
|
|
739
|
-
theme: "one-dark-pro",
|
|
648
|
+
theme: config?.themeConfig?.codeTheme || "one-dark-pro",
|
|
740
649
|
keepBackground: false
|
|
741
650
|
}
|
|
742
651
|
]
|
|
743
652
|
],
|
|
744
|
-
// Provide React as default for JSX
|
|
745
653
|
jsxRuntime: "automatic",
|
|
746
654
|
providerImportSource: "@mdx-js/react"
|
|
747
655
|
});
|
|
656
|
+
return {
|
|
657
|
+
...baseMdxPlugin,
|
|
658
|
+
name: "vite-plugin-boltdocs-mdx",
|
|
659
|
+
async buildStart() {
|
|
660
|
+
hits = 0;
|
|
661
|
+
total = 0;
|
|
662
|
+
if (!mdxCacheLoaded) {
|
|
663
|
+
mdxCache.load();
|
|
664
|
+
mdxCacheLoaded = true;
|
|
665
|
+
}
|
|
666
|
+
if (baseMdxPlugin.buildStart) {
|
|
667
|
+
await baseMdxPlugin.buildStart.call(this);
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
async transform(code, id, options) {
|
|
671
|
+
if (!id.endsWith(".md") && !id.endsWith(".mdx")) {
|
|
672
|
+
return baseMdxPlugin.transform?.call(this, code, id, options);
|
|
673
|
+
}
|
|
674
|
+
total++;
|
|
675
|
+
const contentHash = crypto.createHash("md5").update(code).digest("hex");
|
|
676
|
+
const cacheKey = `${id}:${contentHash}`;
|
|
677
|
+
const cached = mdxCache.get(cacheKey);
|
|
678
|
+
if (cached) {
|
|
679
|
+
hits++;
|
|
680
|
+
return { code: cached, map: null };
|
|
681
|
+
}
|
|
682
|
+
const result = await baseMdxPlugin.transform.call(
|
|
683
|
+
this,
|
|
684
|
+
code,
|
|
685
|
+
id,
|
|
686
|
+
options
|
|
687
|
+
);
|
|
688
|
+
if (result && typeof result === "object" && result.code) {
|
|
689
|
+
mdxCache.set(cacheKey, result.code);
|
|
690
|
+
} else if (typeof result === "string") {
|
|
691
|
+
mdxCache.set(cacheKey, result);
|
|
692
|
+
}
|
|
693
|
+
return result;
|
|
694
|
+
},
|
|
695
|
+
async buildEnd() {
|
|
696
|
+
mdxCache.save();
|
|
697
|
+
await mdxCache.flush();
|
|
698
|
+
if (baseMdxPlugin.buildEnd) {
|
|
699
|
+
await baseMdxPlugin.buildEnd.call(this);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
};
|
|
748
703
|
}
|
|
704
|
+
var hits = 0;
|
|
705
|
+
var total = 0;
|
|
749
706
|
|
|
750
707
|
// src/node/index.ts
|
|
751
708
|
async function boltdocs(options) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "boltdocs",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A lightweight documentation generator for React projects.",
|
|
5
5
|
"main": "dist/node/index.js",
|
|
6
6
|
"module": "dist/node/index.mjs",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"remark-gfm": "^4.0.1",
|
|
55
55
|
"sharp": "^0.34.5",
|
|
56
56
|
"shiki": "^3.23.0",
|
|
57
|
-
"svgo": "^4.0.
|
|
57
|
+
"svgo": "^4.0.1",
|
|
58
58
|
"unist-util-visit": "^5.1.0",
|
|
59
59
|
"vite": "^7.3.1",
|
|
60
60
|
"vite-plugin-image-optimizer": "^2.0.3"
|
package/src/client/app/index.tsx
CHANGED
|
@@ -40,27 +40,6 @@ const PackageManagerTabs = lazy(() =>
|
|
|
40
40
|
default: m.PackageManagerTabs,
|
|
41
41
|
})),
|
|
42
42
|
);
|
|
43
|
-
const Playground = lazy(() =>
|
|
44
|
-
import("../theme/components/Playground").then((m) => ({
|
|
45
|
-
default: m.Playground,
|
|
46
|
-
})),
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
import {
|
|
50
|
-
Button,
|
|
51
|
-
Badge,
|
|
52
|
-
Card,
|
|
53
|
-
Cards,
|
|
54
|
-
Tabs,
|
|
55
|
-
Tab,
|
|
56
|
-
Admonition,
|
|
57
|
-
Note,
|
|
58
|
-
Tip,
|
|
59
|
-
Warning,
|
|
60
|
-
Danger,
|
|
61
|
-
InfoBox,
|
|
62
|
-
List,
|
|
63
|
-
} from "../theme/components/mdx";
|
|
64
43
|
declare global {
|
|
65
44
|
interface ImportMeta {
|
|
66
45
|
env: Record<string, any>;
|
|
@@ -115,24 +94,6 @@ const mdxComponents = {
|
|
|
115
94
|
<PackageManagerTabs {...props} />
|
|
116
95
|
</Suspense>
|
|
117
96
|
),
|
|
118
|
-
Playground: (props: any) => (
|
|
119
|
-
<Suspense fallback={<div className="playground-skeleton" />}>
|
|
120
|
-
<Playground {...props} />
|
|
121
|
-
</Suspense>
|
|
122
|
-
),
|
|
123
|
-
Button,
|
|
124
|
-
Badge,
|
|
125
|
-
Card,
|
|
126
|
-
Cards,
|
|
127
|
-
Tabs,
|
|
128
|
-
Tab,
|
|
129
|
-
Admonition,
|
|
130
|
-
Note,
|
|
131
|
-
Tip,
|
|
132
|
-
Warning,
|
|
133
|
-
Danger,
|
|
134
|
-
InfoBox,
|
|
135
|
-
List,
|
|
136
97
|
};
|
|
137
98
|
|
|
138
99
|
export function AppShell({
|
|
@@ -152,20 +113,9 @@ export function AppShell({
|
|
|
152
113
|
}) {
|
|
153
114
|
const [routesInfo, setRoutesInfo] = useState<ComponentRoute[]>(initialRoutes);
|
|
154
115
|
const [config] = useState(initialConfig);
|
|
155
|
-
const [resolvedRoutes, setResolvedRoutes] = useState<any[]>([]);
|
|
156
|
-
|
|
157
|
-
// Subscribe to HMR events
|
|
158
|
-
useEffect(() => {
|
|
159
|
-
if (hot) {
|
|
160
|
-
hot.on("boltdocs:routes-update", (newRoutes: ComponentRoute[]) => {
|
|
161
|
-
setRoutesInfo(newRoutes);
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}, [hot]);
|
|
165
116
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const mapped = routesInfo
|
|
117
|
+
const resolveRoutes = (infos: ComponentRoute[]) => {
|
|
118
|
+
return infos
|
|
169
119
|
.filter(
|
|
170
120
|
(route) => !(HomePage && (route.path === "/" || route.path === "")),
|
|
171
121
|
)
|
|
@@ -184,8 +134,24 @@ export function AppShell({
|
|
|
184
134
|
}),
|
|
185
135
|
};
|
|
186
136
|
});
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const [resolvedRoutes, setResolvedRoutes] = useState<any[]>(() =>
|
|
140
|
+
resolveRoutes(initialRoutes),
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// Subscribe to HMR events
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (hot) {
|
|
146
|
+
hot.on("boltdocs:routes-update", (newRoutes: ComponentRoute[]) => {
|
|
147
|
+
setRoutesInfo(newRoutes);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}, [hot]);
|
|
187
151
|
|
|
188
|
-
|
|
152
|
+
// Sync resolved routes when info or modules change
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
setResolvedRoutes(resolveRoutes(routesInfo));
|
|
189
155
|
}, [routesInfo, modules]);
|
|
190
156
|
|
|
191
157
|
return (
|
|
@@ -213,7 +179,10 @@ export function AppShell({
|
|
|
213
179
|
)}
|
|
214
180
|
|
|
215
181
|
{/* Documentation pages WITH sidebar + TOC layout */}
|
|
216
|
-
<Route
|
|
182
|
+
<Route
|
|
183
|
+
key="docs-layout"
|
|
184
|
+
element={<DocsLayout config={config} routes={routesInfo} />}
|
|
185
|
+
>
|
|
217
186
|
{resolvedRoutes.map((route: any) => (
|
|
218
187
|
<Route
|
|
219
188
|
key={route.path}
|
|
@@ -255,6 +224,8 @@ function ScrollHandler() {
|
|
|
255
224
|
const { pathname, hash } = useLocation();
|
|
256
225
|
|
|
257
226
|
useLayoutEffect(() => {
|
|
227
|
+
// Only scroll if we are not in a pending transition state (if we were using useTransition)
|
|
228
|
+
// For now, we ensure the scroll happens.
|
|
258
229
|
if (hash) {
|
|
259
230
|
const id = hash.replace("#", "");
|
|
260
231
|
const element = document.getElementById(id);
|
|
@@ -6,54 +6,77 @@
|
|
|
6
6
|
|
|
7
7
|
/* ─── Button ──────────────────────────────────────────────── */
|
|
8
8
|
.ld-btn {
|
|
9
|
+
/* Total Reset */
|
|
10
|
+
all: unset;
|
|
11
|
+
box-sizing: border-box !important;
|
|
9
12
|
display: inline-flex;
|
|
10
13
|
align-items: center;
|
|
11
|
-
|
|
14
|
+
justify-content: center;
|
|
15
|
+
gap: 0.5rem;
|
|
16
|
+
|
|
17
|
+
/* Typography */
|
|
18
|
+
font-family: var(--ld-font-sans);
|
|
12
19
|
font-weight: 600;
|
|
20
|
+
font-size: 0.9375rem;
|
|
21
|
+
line-height: normal; /* Essential for flex centering */
|
|
22
|
+
letter-spacing: -0.01em;
|
|
23
|
+
text-align: center;
|
|
24
|
+
text-decoration: none !important;
|
|
25
|
+
white-space: nowrap;
|
|
26
|
+
|
|
27
|
+
/* Appearance */
|
|
13
28
|
border-radius: var(--ld-radius-md);
|
|
14
29
|
cursor: pointer;
|
|
15
|
-
transition: all
|
|
16
|
-
font-family: var(--ld-font-sans);
|
|
30
|
+
transition: all 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
17
31
|
border: 1px solid transparent;
|
|
18
|
-
|
|
19
|
-
|
|
32
|
+
user-select: none;
|
|
33
|
+
position: relative;
|
|
20
34
|
}
|
|
21
35
|
|
|
22
36
|
.ld-btn:hover {
|
|
23
|
-
transform:
|
|
37
|
+
transform: translateY(-1px);
|
|
24
38
|
}
|
|
25
39
|
|
|
26
40
|
.ld-btn:active {
|
|
27
|
-
transform: scale(0.
|
|
41
|
+
transform: translateY(0) scale(0.98);
|
|
28
42
|
}
|
|
29
43
|
|
|
30
44
|
/* sizes */
|
|
31
45
|
.ld-btn--sm {
|
|
32
|
-
|
|
46
|
+
min-height: 2rem;
|
|
47
|
+
padding: 0 1rem;
|
|
33
48
|
font-size: 0.8125rem;
|
|
34
49
|
border-radius: var(--ld-radius-md);
|
|
35
50
|
}
|
|
36
51
|
.ld-btn--md {
|
|
37
|
-
|
|
52
|
+
min-height: 2.625rem;
|
|
53
|
+
padding: 0 1.6rem;
|
|
38
54
|
font-size: 0.9375rem;
|
|
39
55
|
}
|
|
40
56
|
.ld-btn--lg {
|
|
41
|
-
|
|
57
|
+
min-height: 3.25rem;
|
|
58
|
+
padding: 0 2.2rem;
|
|
42
59
|
font-size: 1.05rem;
|
|
43
60
|
}
|
|
44
61
|
|
|
45
62
|
/* variants */
|
|
46
63
|
.ld-btn--primary {
|
|
47
|
-
background-color: var(
|
|
64
|
+
background-color: var(
|
|
65
|
+
--ld-ui-btn-primary-bg,
|
|
66
|
+
var(--ld-btn-primary-bg)
|
|
67
|
+
) !important;
|
|
48
68
|
color: var(--ld-ui-btn-primary-text, var(--ld-btn-primary-text)) !important;
|
|
69
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
49
70
|
}
|
|
50
71
|
.ld-btn--primary:hover {
|
|
51
|
-
|
|
52
|
-
color: var(--ld-ui-btn-primary-text, var(--ld-btn-primary-text)) !important;
|
|
72
|
+
filter: brightness(1.1);
|
|
53
73
|
}
|
|
54
74
|
|
|
55
75
|
.ld-btn--secondary {
|
|
56
|
-
background-color: var(
|
|
76
|
+
background-color: var(
|
|
77
|
+
--ld-ui-btn-secondary-bg,
|
|
78
|
+
var(--ld-btn-secondary-bg)
|
|
79
|
+
) !important;
|
|
57
80
|
color: var(
|
|
58
81
|
--ld-ui-btn-secondary-text,
|
|
59
82
|
var(--ld-btn-secondary-text)
|
|
@@ -63,14 +86,10 @@
|
|
|
63
86
|
.ld-btn--secondary:hover {
|
|
64
87
|
background-color: var(--ld-bg-mute);
|
|
65
88
|
border-color: var(--ld-border-strong);
|
|
66
|
-
color: var(
|
|
67
|
-
--ld-ui-btn-secondary-text,
|
|
68
|
-
var(--ld-btn-secondary-text)
|
|
69
|
-
) !important;
|
|
70
89
|
}
|
|
71
90
|
|
|
72
91
|
.ld-btn--outline {
|
|
73
|
-
background: transparent;
|
|
92
|
+
background: transparent !important;
|
|
74
93
|
color: var(--ld-text-main) !important;
|
|
75
94
|
border-color: var(--ld-border-strong);
|
|
76
95
|
}
|
|
@@ -80,7 +99,7 @@
|
|
|
80
99
|
}
|
|
81
100
|
|
|
82
101
|
.ld-btn--ghost {
|
|
83
|
-
background: transparent;
|
|
102
|
+
background: transparent !important;
|
|
84
103
|
color: var(--ld-text-muted) !important;
|
|
85
104
|
}
|
|
86
105
|
.ld-btn--ghost:hover {
|
|
@@ -139,22 +139,11 @@ export function ThemeLayout({
|
|
|
139
139
|
<Sidebar
|
|
140
140
|
routes={filteredRoutes}
|
|
141
141
|
config={config}
|
|
142
|
-
|
|
142
|
+
isCollapsed={!isSidebarOpen}
|
|
143
|
+
onToggle={() => setIsSidebarOpen(!isSidebarOpen)}
|
|
143
144
|
/>
|
|
144
145
|
)}
|
|
145
146
|
|
|
146
|
-
{/* Floating Expand Button when Sidebar is Collapsed */}
|
|
147
|
-
{sidebar === undefined && (
|
|
148
|
-
<button
|
|
149
|
-
className="sidebar-toggle-floating"
|
|
150
|
-
onClick={() => setIsSidebarOpen(true)}
|
|
151
|
-
aria-label="Expand Sidebar"
|
|
152
|
-
title="Expand Sidebar"
|
|
153
|
-
>
|
|
154
|
-
<Menu size={20} />
|
|
155
|
-
</button>
|
|
156
|
-
)}
|
|
157
|
-
|
|
158
147
|
<main className="boltdocs-content">
|
|
159
148
|
{breadcrumbs !== undefined ? (
|
|
160
149
|
breadcrumbs
|