boltdocs 1.6.0 → 1.7.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-3QICRMWF.css → SearchDialog-UOAW6IR3.css} +270 -113
- package/dist/{SearchDialog-J3KNRGNO.mjs → SearchDialog-YOXMFGH6.mjs} +1 -1
- package/dist/{chunk-HSPDIRTW.mjs → chunk-MULKZFVN.mjs} +872 -758
- package/dist/client/index.css +270 -113
- package/dist/client/index.d.mts +21 -7
- package/dist/client/index.d.ts +21 -7
- package/dist/client/index.js +637 -499
- package/dist/client/index.mjs +17 -1
- package/dist/client/ssr.css +270 -113
- package/dist/client/ssr.d.mts +3 -1
- package/dist/client/ssr.d.ts +3 -1
- package/dist/client/ssr.js +533 -412
- package/dist/client/ssr.mjs +3 -2
- package/dist/{config-DkZg5aCf.d.ts → config-D68h41CA.d.mts} +21 -2
- package/dist/{config-DkZg5aCf.d.mts → config-D68h41CA.d.ts} +21 -2
- package/dist/node/index.d.mts +10 -2
- package/dist/node/index.d.ts +10 -2
- package/dist/node/index.js +45 -21
- package/dist/node/index.mjs +45 -21
- package/dist/{types-DGIo1VKD.d.mts → types-CviV0GbX.d.mts} +13 -0
- package/dist/{types-DGIo1VKD.d.ts → types-CviV0GbX.d.ts} +13 -0
- package/package.json +1 -1
- package/src/client/app/index.tsx +8 -4
- package/src/client/index.ts +2 -0
- package/src/client/ssr.tsx +4 -1
- package/src/client/theme/components/mdx/Table.tsx +53 -0
- package/src/client/theme/components/mdx/index.ts +3 -0
- package/src/client/theme/components/mdx/mdx-components.css +49 -0
- package/src/client/theme/styles/markdown.css +8 -3
- package/src/client/theme/styles/variables.css +10 -9
- package/src/client/theme/ui/Layout/Layout.tsx +2 -10
- package/src/client/theme/ui/Layout/base.css +15 -3
- package/src/client/theme/ui/Link/Link.tsx +2 -2
- package/src/client/theme/ui/Link/LinkPreview.tsx +9 -14
- package/src/client/theme/ui/Link/link-preview.css +30 -27
- package/src/client/theme/ui/Navbar/Navbar.tsx +65 -17
- package/src/client/theme/ui/Navbar/Tabs.tsx +74 -0
- package/src/client/theme/ui/Navbar/navbar.css +111 -5
- package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +65 -49
- package/src/client/theme/ui/OnThisPage/toc.css +30 -10
- package/src/client/theme/ui/Sidebar/Sidebar.tsx +97 -57
- package/src/client/theme/ui/Sidebar/sidebar.css +61 -67
- package/src/client/types.ts +10 -0
- package/src/node/config.ts +19 -1
- package/src/node/plugin/entry.ts +5 -1
- package/src/node/plugin/index.ts +2 -1
- package/src/node/routes/index.ts +12 -1
- package/src/node/routes/parser.ts +21 -7
- package/src/node/routes/types.ts +9 -1
- package/src/node/ssg/index.ts +2 -1
- package/src/node/ssg/options.ts +2 -0
|
@@ -8,72 +8,44 @@
|
|
|
8
8
|
backdrop-filter: blur(var(--ld-sidebar-blur));
|
|
9
9
|
-webkit-backdrop-filter: blur(var(--ld-sidebar-blur));
|
|
10
10
|
border-right: 1px solid var(--ld-border-subtle);
|
|
11
|
-
padding:
|
|
11
|
+
padding: 1.5rem 0.6rem;
|
|
12
12
|
overflow-y: auto;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
height: calc(100vh - var(--ld-navbar-height));
|
|
16
|
-
scrollbar-width: thin;
|
|
17
|
-
scrollbar-color: var(--ld-bg-mute) transparent;
|
|
13
|
+
height: 100%;
|
|
14
|
+
scrollbar-width: none;
|
|
18
15
|
display: flex;
|
|
19
16
|
flex-direction: column;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
opacity 0.2s ease;
|
|
17
|
+
/* Hardware acceleration */
|
|
18
|
+
transform: translate3d(0, 0, 0);
|
|
19
|
+
backface-visibility: hidden;
|
|
24
20
|
}
|
|
25
21
|
|
|
26
|
-
.
|
|
27
|
-
flex:
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/* ─── Collapsible Sidebar ────────────────────────────────── */
|
|
31
|
-
.boltdocs-main-container.sidebar-collapsed .boltdocs-sidebar {
|
|
32
|
-
width: 54px;
|
|
33
|
-
padding: 1rem 0;
|
|
34
|
-
border-right: 1px solid var(--ld-border-subtle);
|
|
35
|
-
opacity: 1;
|
|
36
|
-
pointer-events: auto;
|
|
37
|
-
overflow: hidden;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.sidebar-collapse {
|
|
41
|
-
width: 100%;
|
|
22
|
+
.sidebar-icon {
|
|
23
|
+
flex-shrink: 0;
|
|
42
24
|
display: flex;
|
|
43
25
|
align-items: center;
|
|
44
|
-
justify-content: flex-end;
|
|
45
|
-
padding: 0 0.75rem 1rem;
|
|
46
|
-
transition: justify-content 0.3s ease;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.boltdocs-main-container.sidebar-collapsed .sidebar-collapse {
|
|
50
26
|
justify-content: center;
|
|
51
|
-
padding: 0 0 1rem;
|
|
52
27
|
}
|
|
53
28
|
|
|
54
|
-
.sidebar-
|
|
29
|
+
.sidebar-icon.lucide-icon,
|
|
30
|
+
.sidebar-icon.svg-icon svg {
|
|
55
31
|
color: var(--ld-text-muted);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
display: flex;
|
|
61
|
-
align-items: center;
|
|
62
|
-
justify-content: center;
|
|
63
|
-
width: 32px;
|
|
64
|
-
height: 32px;
|
|
65
|
-
border-radius: var(--ld-radius-md);
|
|
66
|
-
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
|
32
|
+
width: 18px;
|
|
33
|
+
height: 18px;
|
|
34
|
+
stroke-width: 2px;
|
|
35
|
+
transition: color 0.2s ease;
|
|
67
36
|
}
|
|
68
37
|
|
|
69
|
-
.sidebar-
|
|
70
|
-
|
|
71
|
-
color: var(--ld-
|
|
72
|
-
|
|
38
|
+
.sidebar-link:hover .sidebar-icon.lucide-icon,
|
|
39
|
+
.sidebar-link.active .sidebar-icon.lucide-icon {
|
|
40
|
+
color: var(--ld-color-primary);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.boltdocs-sidebar > nav {
|
|
44
|
+
flex: 1;
|
|
73
45
|
}
|
|
74
46
|
|
|
75
47
|
.boltdocs-sidebar::-webkit-scrollbar {
|
|
76
|
-
|
|
48
|
+
display: none;
|
|
77
49
|
}
|
|
78
50
|
|
|
79
51
|
.boltdocs-sidebar::-webkit-scrollbar-track {
|
|
@@ -92,23 +64,29 @@
|
|
|
92
64
|
}
|
|
93
65
|
|
|
94
66
|
.sidebar-list li {
|
|
95
|
-
margin-bottom:
|
|
67
|
+
margin-bottom: 2px;
|
|
96
68
|
}
|
|
97
69
|
|
|
98
70
|
.sidebar-link {
|
|
99
71
|
display: flex;
|
|
100
72
|
align-items: center;
|
|
101
73
|
justify-content: space-between;
|
|
102
|
-
padding: 0.
|
|
74
|
+
padding: 0.5rem 0.75rem;
|
|
103
75
|
color: var(--ld-text-muted);
|
|
104
76
|
text-decoration: none;
|
|
105
|
-
border-radius:
|
|
77
|
+
border-radius: 0.75rem; /* Large rounded corners */
|
|
106
78
|
font-size: 0.875rem;
|
|
107
79
|
font-weight: 500;
|
|
108
80
|
transition: all 0.2s ease;
|
|
109
81
|
margin: 0.15rem 0;
|
|
110
82
|
}
|
|
111
83
|
|
|
84
|
+
.sidebar-link-title-container {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
gap: 0.75rem;
|
|
88
|
+
}
|
|
89
|
+
|
|
112
90
|
.sidebar-link-content {
|
|
113
91
|
display: flex;
|
|
114
92
|
align-items: center;
|
|
@@ -117,7 +95,7 @@
|
|
|
117
95
|
gap: 0.5rem;
|
|
118
96
|
}
|
|
119
97
|
|
|
120
|
-
.sidebar-link-content > span:
|
|
98
|
+
.sidebar-link-content > span:last-child {
|
|
121
99
|
flex: 1;
|
|
122
100
|
word-wrap: break-word;
|
|
123
101
|
}
|
|
@@ -162,11 +140,13 @@
|
|
|
162
140
|
|
|
163
141
|
.sidebar-link:hover {
|
|
164
142
|
color: var(--ld-color-primary-hover);
|
|
143
|
+
background-color: var(--ld-bg-soft);
|
|
165
144
|
}
|
|
166
145
|
|
|
167
146
|
.sidebar-link.active {
|
|
168
147
|
color: var(--ld-color-primary);
|
|
169
148
|
font-weight: 600;
|
|
149
|
+
background-color: var(--ld-bg-soft);
|
|
170
150
|
}
|
|
171
151
|
|
|
172
152
|
/* ─── Sidebar Groups ─────────────────────────────────────── */
|
|
@@ -183,29 +163,32 @@
|
|
|
183
163
|
align-items: center;
|
|
184
164
|
justify-content: space-between;
|
|
185
165
|
width: 100%;
|
|
186
|
-
padding: 0.
|
|
166
|
+
padding: 0.5rem 0.75rem;
|
|
187
167
|
background: none;
|
|
188
168
|
border: none;
|
|
189
169
|
border-radius: var(--ld-radius-md);
|
|
190
|
-
color: var(--ld-text-
|
|
170
|
+
color: var(--ld-text-muted);
|
|
191
171
|
font-family: var(--ld-font-sans);
|
|
192
|
-
font-size: 0.
|
|
193
|
-
font-weight:
|
|
194
|
-
text-transform: uppercase;
|
|
195
|
-
letter-spacing: 0.08em;
|
|
172
|
+
font-size: 0.8125rem;
|
|
173
|
+
font-weight: 600;
|
|
196
174
|
cursor: pointer;
|
|
197
175
|
transition:
|
|
198
176
|
color 0.2s,
|
|
199
177
|
background-color 0.2s;
|
|
200
178
|
}
|
|
201
179
|
|
|
180
|
+
.sidebar-group-header-content {
|
|
181
|
+
display: flex;
|
|
182
|
+
align-items: center;
|
|
183
|
+
gap: 0.75rem;
|
|
184
|
+
}
|
|
185
|
+
|
|
202
186
|
.sidebar-group-header:hover {
|
|
203
|
-
color: var(--ld-text-
|
|
204
|
-
background-color: rgba(255, 255, 255, 0.03);
|
|
187
|
+
color: var(--ld-text-main);
|
|
205
188
|
}
|
|
206
189
|
|
|
207
190
|
.sidebar-group-header.active {
|
|
208
|
-
color: var(--ld-
|
|
191
|
+
color: var(--ld-text-main);
|
|
209
192
|
}
|
|
210
193
|
|
|
211
194
|
.sidebar-group-chevron {
|
|
@@ -223,14 +206,25 @@
|
|
|
223
206
|
.sidebar-group-list {
|
|
224
207
|
list-style: none;
|
|
225
208
|
padding: 0;
|
|
226
|
-
margin: 0.35rem 0 0;
|
|
227
|
-
|
|
209
|
+
margin: 0.35rem 0 0.5rem 0;
|
|
210
|
+
position: relative;
|
|
228
211
|
}
|
|
229
212
|
|
|
230
213
|
.sidebar-group-list li {
|
|
231
|
-
margin-bottom:
|
|
214
|
+
margin-bottom: 2px;
|
|
232
215
|
}
|
|
233
216
|
|
|
234
217
|
.sidebar-link-nested {
|
|
235
|
-
padding-left:
|
|
218
|
+
padding-left: 0.75rem;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.sidebar-group-list {
|
|
222
|
+
list-style: none;
|
|
223
|
+
padding: 0;
|
|
224
|
+
margin: 0.35rem 0 0.5rem 0;
|
|
225
|
+
position: relative;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.sidebar-group-list li {
|
|
229
|
+
margin-bottom: 2px;
|
|
236
230
|
}
|
package/src/client/types.ts
CHANGED
|
@@ -29,6 +29,14 @@ export interface ComponentRoute {
|
|
|
29
29
|
locale?: string;
|
|
30
30
|
/** The version this route belongs to, if versioning is configured */
|
|
31
31
|
version?: string;
|
|
32
|
+
/** Optional icon to display (Lucide icon name or raw SVG) */
|
|
33
|
+
icon?: string;
|
|
34
|
+
/** The tab this route belongs to, if tabs are configured */
|
|
35
|
+
tab?: string;
|
|
36
|
+
/** Optional badge to display next to the sidebar item */
|
|
37
|
+
badge?: string | { text: string; expires?: string };
|
|
38
|
+
/** Optional icon for the route's group */
|
|
39
|
+
groupIcon?: string;
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
/**
|
|
@@ -39,6 +47,8 @@ export interface CreateBoltdocsAppOptions {
|
|
|
39
47
|
target: string;
|
|
40
48
|
/** Initial routes generated by the Vite plugin (`virtual:boltdocs-routes`) */
|
|
41
49
|
routes: ComponentRoute[];
|
|
50
|
+
/** The name of the documentation directory (e.g. 'docs') */
|
|
51
|
+
docsDirName: string;
|
|
42
52
|
/** Site configuration (`virtual:boltdocs-config`) */
|
|
43
53
|
config: any;
|
|
44
54
|
/** Dynamic import mapping from `import.meta.glob` for the documentation pages */
|
package/src/node/config.ts
CHANGED
|
@@ -32,7 +32,20 @@ export interface BoltdocsThemeConfig {
|
|
|
32
32
|
/** URL path to the site logo */
|
|
33
33
|
logo?: string;
|
|
34
34
|
/** Items to display in the top navigation bar */
|
|
35
|
-
navbar?: Array<{
|
|
35
|
+
navbar?: Array<{
|
|
36
|
+
/** Text to display (alias for text) */
|
|
37
|
+
label?: string;
|
|
38
|
+
/** Text to display */
|
|
39
|
+
text?: string;
|
|
40
|
+
/** URL path or external link (alias for link) */
|
|
41
|
+
to?: string;
|
|
42
|
+
/** URL path or external link (alias for link) */
|
|
43
|
+
href?: string;
|
|
44
|
+
/** URL path or external link */
|
|
45
|
+
link?: string;
|
|
46
|
+
/** Alignment of the item in the navbar */
|
|
47
|
+
position?: "left" | "right";
|
|
48
|
+
}>;
|
|
36
49
|
/** Items to display in the sidebar, organized optionally by group URLs */
|
|
37
50
|
sidebar?: Record<string, Array<{ text: string; link: string }>>;
|
|
38
51
|
/** Social links to display in the navigation bar */
|
|
@@ -66,6 +79,11 @@ export interface BoltdocsThemeConfig {
|
|
|
66
79
|
className?: string;
|
|
67
80
|
style?: any;
|
|
68
81
|
};
|
|
82
|
+
/**
|
|
83
|
+
* Top-level tabs for organizing documentation groups.
|
|
84
|
+
* Tab discovery uses the (tab-id) directory syntax.
|
|
85
|
+
*/
|
|
86
|
+
tabs?: Array<{ id: string; text: string; icon?: string }>;
|
|
69
87
|
/**
|
|
70
88
|
* The syntax highlighting theme for code blocks.
|
|
71
89
|
* Supports any Shiki theme name (e.g., 'github-dark', 'one-dark-pro', 'aurora-x').
|
package/src/node/plugin/entry.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { normalizePath } from "../utils";
|
|
2
2
|
import type { BoltdocsConfig } from "../config";
|
|
3
3
|
import type { BoltdocsPluginOptions } from "./types";
|
|
4
|
+
import path from "path";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Generates the raw source code for the virtual entry file (`\0virtual:boltdocs-entry`).
|
|
@@ -36,6 +37,8 @@ const ${name} = _comp_${name}.default || _comp_${name}['${name}'] || _comp_${nam
|
|
|
36
37
|
.join("\n");
|
|
37
38
|
const componentMap = pluginComponents.map(([name]) => name).join(", ");
|
|
38
39
|
|
|
40
|
+
const docsDirName = path.basename(options.docsDir || "docs");
|
|
41
|
+
|
|
39
42
|
return `
|
|
40
43
|
import { createBoltdocsApp as _createApp } from 'boltdocs/client';
|
|
41
44
|
import 'boltdocs/style.css';
|
|
@@ -48,8 +51,9 @@ ${componentImports}
|
|
|
48
51
|
_createApp({
|
|
49
52
|
target: '#root',
|
|
50
53
|
routes: _routes,
|
|
54
|
+
docsDirName: '${docsDirName}',
|
|
51
55
|
config: _config,
|
|
52
|
-
modules: import.meta.glob('
|
|
56
|
+
modules: import.meta.glob('/${docsDirName}/**/*.{md,mdx}'),
|
|
53
57
|
hot: import.meta.hot,
|
|
54
58
|
${homeOption}
|
|
55
59
|
components: { ${componentMap} },
|
package/src/node/plugin/index.ts
CHANGED
|
@@ -165,7 +165,8 @@ export function boltdocsPlugin(
|
|
|
165
165
|
? path.resolve(viteConfig.root, viteConfig.build.outDir)
|
|
166
166
|
: path.resolve(process.cwd(), "dist");
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
const docsDirName = path.basename(docsDir || "docs");
|
|
169
|
+
await generateStaticPages({ docsDir, docsDirName, outDir, config });
|
|
169
170
|
|
|
170
171
|
const { flushCache } = await import("../cache");
|
|
171
172
|
await flushCache();
|
package/src/node/routes/index.ts
CHANGED
|
@@ -69,13 +69,17 @@ export async function generateRoutes(
|
|
|
69
69
|
docCache.save();
|
|
70
70
|
|
|
71
71
|
// Collect group metadata from directory names and index files
|
|
72
|
-
const groupMeta = new Map<
|
|
72
|
+
const groupMeta = new Map<
|
|
73
|
+
string,
|
|
74
|
+
{ title: string; position?: number; icon?: string }
|
|
75
|
+
>();
|
|
73
76
|
for (const p of parsed) {
|
|
74
77
|
if (p.relativeDir) {
|
|
75
78
|
if (!groupMeta.has(p.relativeDir)) {
|
|
76
79
|
groupMeta.set(p.relativeDir, {
|
|
77
80
|
title: capitalize(p.relativeDir),
|
|
78
81
|
position: p.inferredGroupPosition,
|
|
82
|
+
icon: p.route.icon,
|
|
79
83
|
});
|
|
80
84
|
} else {
|
|
81
85
|
const entry = groupMeta.get(p.relativeDir)!;
|
|
@@ -85,6 +89,9 @@ export async function generateRoutes(
|
|
|
85
89
|
) {
|
|
86
90
|
entry.position = p.inferredGroupPosition;
|
|
87
91
|
}
|
|
92
|
+
if (!entry.icon && p.route.icon) {
|
|
93
|
+
entry.icon = p.route.icon;
|
|
94
|
+
}
|
|
88
95
|
}
|
|
89
96
|
}
|
|
90
97
|
|
|
@@ -94,6 +101,9 @@ export async function generateRoutes(
|
|
|
94
101
|
if (p.groupMeta.position !== undefined) {
|
|
95
102
|
entry.position = p.groupMeta.position;
|
|
96
103
|
}
|
|
104
|
+
if (p.groupMeta.icon) {
|
|
105
|
+
entry.icon = p.groupMeta.icon;
|
|
106
|
+
}
|
|
97
107
|
}
|
|
98
108
|
}
|
|
99
109
|
|
|
@@ -107,6 +117,7 @@ export async function generateRoutes(
|
|
|
107
117
|
group: dir,
|
|
108
118
|
groupTitle: meta?.title || (dir ? capitalize(dir) : undefined),
|
|
109
119
|
groupPosition: meta?.position,
|
|
120
|
+
groupIcon: meta?.icon,
|
|
110
121
|
};
|
|
111
122
|
});
|
|
112
123
|
|
|
@@ -69,6 +69,16 @@ export function parseDocFile(
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// Level 3: Check for Tab hierarchy (name)
|
|
73
|
+
let inferredTab: string | undefined;
|
|
74
|
+
if (parts.length > 0) {
|
|
75
|
+
const tabMatch = parts[0].match(/^\((.+)\)$/);
|
|
76
|
+
if (tabMatch) {
|
|
77
|
+
inferredTab = tabMatch[1].toLowerCase();
|
|
78
|
+
parts = parts.slice(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
72
82
|
const cleanRelativePath = parts.join("/");
|
|
73
83
|
|
|
74
84
|
let cleanRoutePath: string;
|
|
@@ -118,12 +128,12 @@ export function parseDocFile(
|
|
|
118
128
|
.trim();
|
|
119
129
|
const id = slugger.slug(text);
|
|
120
130
|
// Security: Sanitize heading text for XSS
|
|
121
|
-
headings.push({ level, text
|
|
131
|
+
headings.push({ level, text, id });
|
|
122
132
|
}
|
|
123
133
|
|
|
124
|
-
const sanitizedTitle = data.title ?
|
|
134
|
+
const sanitizedTitle = data.title ? data.title : inferredTitle;
|
|
125
135
|
let sanitizedDescription = data.description
|
|
126
|
-
?
|
|
136
|
+
? data.description
|
|
127
137
|
: "";
|
|
128
138
|
|
|
129
139
|
// If no description is provided, extract a summary from the content
|
|
@@ -135,10 +145,11 @@ export function parseDocFile(
|
|
|
135
145
|
.replace(/\n+/g, " ") // Normalize whitespace
|
|
136
146
|
.trim()
|
|
137
147
|
.slice(0, 160);
|
|
138
|
-
sanitizedDescription =
|
|
148
|
+
sanitizedDescription = summary;
|
|
139
149
|
}
|
|
140
150
|
|
|
141
|
-
const sanitizedBadge = data.badge ?
|
|
151
|
+
const sanitizedBadge = data.badge ? data.badge : undefined;
|
|
152
|
+
const icon = data.icon ? String(data.icon) : undefined;
|
|
142
153
|
|
|
143
154
|
return {
|
|
144
155
|
route: {
|
|
@@ -152,20 +163,23 @@ export function parseDocFile(
|
|
|
152
163
|
locale,
|
|
153
164
|
version,
|
|
154
165
|
badge: sanitizedBadge,
|
|
166
|
+
icon,
|
|
167
|
+
tab: inferredTab,
|
|
155
168
|
},
|
|
156
169
|
relativeDir: cleanDirName,
|
|
157
170
|
isGroupIndex,
|
|
171
|
+
inferredTab,
|
|
158
172
|
groupMeta: isGroupIndex
|
|
159
173
|
? {
|
|
160
|
-
title:
|
|
174
|
+
title:
|
|
161
175
|
data.groupTitle ||
|
|
162
176
|
data.title ||
|
|
163
177
|
(cleanDirName ? capitalize(cleanDirName) : ""),
|
|
164
|
-
),
|
|
165
178
|
position:
|
|
166
179
|
data.groupPosition ??
|
|
167
180
|
data.sidebarPosition ??
|
|
168
181
|
(rawDirName ? extractNumberPrefix(rawDirName) : undefined),
|
|
182
|
+
icon,
|
|
169
183
|
}
|
|
170
184
|
: undefined,
|
|
171
185
|
inferredGroupPosition: rawDirName
|
package/src/node/routes/types.ts
CHANGED
|
@@ -21,6 +21,8 @@ export interface RouteMeta {
|
|
|
21
21
|
groupTitle?: string;
|
|
22
22
|
/** Optional explicit position for ordering the group itself */
|
|
23
23
|
groupPosition?: number;
|
|
24
|
+
/** Optional icon for the route's group */
|
|
25
|
+
groupIcon?: string;
|
|
24
26
|
/** Extracted markdown headings for search indexing */
|
|
25
27
|
headings?: { level: number; text: string; id: string }[];
|
|
26
28
|
/** The locale this route belongs to, if i18n is configured */
|
|
@@ -29,6 +31,10 @@ export interface RouteMeta {
|
|
|
29
31
|
version?: string;
|
|
30
32
|
/** Optional badge to display next to the sidebar item (e.g., 'New', 'Experimental') */
|
|
31
33
|
badge?: string | { text: string; expires?: string };
|
|
34
|
+
/** Optional icon to display (Lucide icon name or raw SVG) */
|
|
35
|
+
icon?: string;
|
|
36
|
+
/** The tab this route belongs to, if tabs are configured */
|
|
37
|
+
tab?: string;
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
/**
|
|
@@ -43,7 +49,9 @@ export interface ParsedDocFile {
|
|
|
43
49
|
/** Whether this file is the index file for its directory group */
|
|
44
50
|
isGroupIndex: boolean;
|
|
45
51
|
/** If this is a group index, any specific frontmatter metadata dictating the group's title and position */
|
|
46
|
-
groupMeta?: { title: string; position?: number };
|
|
52
|
+
groupMeta?: { title: string; position?: number; icon?: string };
|
|
47
53
|
/** Extracted group position from the directory name if it has a numeric prefix */
|
|
48
54
|
inferredGroupPosition?: number;
|
|
55
|
+
/** Extracted tab name from the directory name if it follows the (tab-name) syntax */
|
|
56
|
+
inferredTab?: string;
|
|
49
57
|
}
|
package/src/node/ssg/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ const _require = createRequire(import.meta.url);
|
|
|
24
24
|
* @param options - Configuration for paths and site metadata
|
|
25
25
|
*/
|
|
26
26
|
export async function generateStaticPages(options: SSGOptions): Promise<void> {
|
|
27
|
-
const { docsDir, outDir, config } = options;
|
|
27
|
+
const { docsDir, docsDirName, outDir, config } = options;
|
|
28
28
|
const routes = await generateRoutes(docsDir, config);
|
|
29
29
|
const siteTitle = config?.themeConfig?.title || "Boltdocs";
|
|
30
30
|
const siteDescription = config?.themeConfig?.description || "";
|
|
@@ -64,6 +64,7 @@ export async function generateStaticPages(options: SSGOptions): Promise<void> {
|
|
|
64
64
|
path: route.path,
|
|
65
65
|
routes: routes,
|
|
66
66
|
config: config || {},
|
|
67
|
+
docsDirName: docsDirName,
|
|
67
68
|
modules: fakeModules,
|
|
68
69
|
homePage: undefined, // No custom home page for now
|
|
69
70
|
});
|
package/src/node/ssg/options.ts
CHANGED
|
@@ -6,6 +6,8 @@ import { BoltdocsConfig } from "../config";
|
|
|
6
6
|
export interface SSGOptions {
|
|
7
7
|
/** The root directory containing markdown documentation files */
|
|
8
8
|
docsDir: string;
|
|
9
|
+
/** The name of the documentation directory (e.g. 'docs') */
|
|
10
|
+
docsDirName: string;
|
|
9
11
|
/** The output directory where Vite placed the compiled `index.html` and assets */
|
|
10
12
|
outDir: string;
|
|
11
13
|
/** Pre-resolved config (avoids re-resolving during the SSG phase) */
|