boltdocs 1.0.1 → 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/{CodeBlock-37XMKCYY.mjs → CodeBlock-V3Z5EKGR.mjs} +0 -1
- package/dist/{PackageManagerTabs-4NWXLXQO.mjs → PackageManagerTabs-XEKI3L7P.mjs} +0 -2
- package/dist/{SearchDialog-FTOQZ763.mjs → SearchDialog-5EDRACEG.mjs} +1 -2
- package/dist/{SearchDialog-ZAZXYIFX.css → SearchDialog-X57WPTNN.css} +57 -129
- package/dist/{Video-I6QY4X7J.mjs → Video-KNTY5BNO.mjs} +0 -1
- package/dist/cache-EHR7SXRU.mjs +12 -0
- package/dist/chunk-GSYECEZY.mjs +381 -0
- package/dist/{chunk-ZFCOLEXN.mjs → chunk-NS7WHDYA.mjs} +234 -426
- package/dist/client/index.css +57 -129
- package/dist/client/index.d.mts +39 -8
- package/dist/client/index.d.ts +39 -8
- package/dist/client/index.js +557 -564
- package/dist/client/index.mjs +305 -18
- package/dist/client/ssr.css +57 -129
- package/dist/client/ssr.d.mts +1 -1
- package/dist/client/ssr.d.ts +1 -1
- package/dist/client/ssr.js +257 -558
- package/dist/client/ssr.mjs +1 -2
- 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 +144 -147
- package/dist/{index-CRQKWAeo.d.mts → types-CvrzTbEX.d.mts} +1 -28
- package/dist/{index-CRQKWAeo.d.ts → types-CvrzTbEX.d.ts} +1 -28
- package/package.json +2 -2
- package/src/client/app/index.tsx +32 -110
- package/src/client/app/preload.tsx +1 -1
- package/src/client/index.ts +1 -1
- package/src/client/ssr.tsx +2 -1
- package/src/client/theme/components/Playground/Playground.tsx +40 -2
- package/src/client/theme/components/mdx/mdx-components.css +39 -20
- package/src/client/theme/styles/markdown.css +4 -4
- package/src/client/theme/styles.css +0 -1
- package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +1 -1
- package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +1 -1
- package/src/client/theme/ui/Layout/Layout.tsx +3 -14
- 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/Navbar/Navbar.tsx +1 -1
- 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/SearchDialog/SearchDialog.tsx +1 -1
- package/src/client/theme/ui/Sidebar/Sidebar.tsx +44 -40
- package/src/client/theme/ui/Sidebar/sidebar.css +25 -58
- package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +1 -1
- package/src/client/types.ts +50 -0
- 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-OE2OE6B6.mjs +0 -7
- package/dist/chunk-PN4GCTYG.mjs +0 -67
- package/dist/chunk-X2TDGMTR.mjs +0 -64
- package/dist/chunk-X6BYQHVC.mjs +0 -12
- package/dist/node/cli/index.d.mts +0 -1
- package/dist/node/cli/index.d.ts +0 -1
- package/dist/node/cli/index.js +0 -199
- package/dist/node/cli/index.mjs +0 -154
- package/src/client/theme/styles/home.css +0 -60
package/src/client/app/index.tsx
CHANGED
|
@@ -11,6 +11,7 @@ import { ThemeLayout } from "../theme/ui/Layout";
|
|
|
11
11
|
import { NotFound } from "../theme/ui/NotFound";
|
|
12
12
|
import { Loading } from "../theme/ui/Loading";
|
|
13
13
|
import { MDXProvider } from "@mdx-js/react";
|
|
14
|
+
import { ComponentRoute, CreateBoltdocsAppOptions } from "../types";
|
|
14
15
|
import {
|
|
15
16
|
createContext,
|
|
16
17
|
useContext,
|
|
@@ -39,27 +40,6 @@ const PackageManagerTabs = lazy(() =>
|
|
|
39
40
|
default: m.PackageManagerTabs,
|
|
40
41
|
})),
|
|
41
42
|
);
|
|
42
|
-
const Playground = lazy(() =>
|
|
43
|
-
import("../theme/components/Playground").then((m) => ({
|
|
44
|
-
default: m.Playground,
|
|
45
|
-
})),
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
import {
|
|
49
|
-
Button,
|
|
50
|
-
Badge,
|
|
51
|
-
Card,
|
|
52
|
-
Cards,
|
|
53
|
-
Tabs,
|
|
54
|
-
Tab,
|
|
55
|
-
Admonition,
|
|
56
|
-
Note,
|
|
57
|
-
Tip,
|
|
58
|
-
Warning,
|
|
59
|
-
Danger,
|
|
60
|
-
InfoBox,
|
|
61
|
-
List,
|
|
62
|
-
} from "../theme/components/mdx";
|
|
63
43
|
declare global {
|
|
64
44
|
interface ImportMeta {
|
|
65
45
|
env: Record<string, any>;
|
|
@@ -114,75 +94,8 @@ const mdxComponents = {
|
|
|
114
94
|
<PackageManagerTabs {...props} />
|
|
115
95
|
</Suspense>
|
|
116
96
|
),
|
|
117
|
-
Playground: (props: any) => (
|
|
118
|
-
<Suspense fallback={<div className="playground-skeleton" />}>
|
|
119
|
-
<Playground {...props} />
|
|
120
|
-
</Suspense>
|
|
121
|
-
),
|
|
122
|
-
Button,
|
|
123
|
-
Badge,
|
|
124
|
-
Card,
|
|
125
|
-
Cards,
|
|
126
|
-
Tabs,
|
|
127
|
-
Tab,
|
|
128
|
-
Admonition,
|
|
129
|
-
Note,
|
|
130
|
-
Tip,
|
|
131
|
-
Warning,
|
|
132
|
-
Danger,
|
|
133
|
-
InfoBox,
|
|
134
|
-
List,
|
|
135
97
|
};
|
|
136
98
|
|
|
137
|
-
/**
|
|
138
|
-
* Metadata provided by the server for a specific route.
|
|
139
|
-
* Maps closely to the `RouteMeta` type in the Node environment.
|
|
140
|
-
*/
|
|
141
|
-
export interface ComponentRoute {
|
|
142
|
-
/** The final URL path */
|
|
143
|
-
path: string;
|
|
144
|
-
/** The absolute filesystem path of the source file */
|
|
145
|
-
componentPath: string;
|
|
146
|
-
/** The page title */
|
|
147
|
-
title: string;
|
|
148
|
-
/** Explicit order in the sidebar */
|
|
149
|
-
sidebarPosition?: number;
|
|
150
|
-
/** The relative path from the docs directory */
|
|
151
|
-
filePath: string;
|
|
152
|
-
/** The group directory name */
|
|
153
|
-
group?: string;
|
|
154
|
-
/** The display title of the group */
|
|
155
|
-
groupTitle?: string;
|
|
156
|
-
/** Explicit order of the group in the sidebar */
|
|
157
|
-
groupPosition?: number;
|
|
158
|
-
/** Extracted markdown headings for search indexing */
|
|
159
|
-
headings?: { level: number; text: string; id: string }[];
|
|
160
|
-
/** The locale this route belongs to, if i18n is configured */
|
|
161
|
-
locale?: string;
|
|
162
|
-
/** The version this route belongs to, if versioning is configured */
|
|
163
|
-
version?: string;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Configuration options for initializing the Boltdocs client app.
|
|
168
|
-
*/
|
|
169
|
-
export interface CreateBoltdocsAppOptions {
|
|
170
|
-
/** CSS selector for the DOM element where the app should mount (e.g. '#root') */
|
|
171
|
-
target: string;
|
|
172
|
-
/** Initial routes generated by the Vite plugin (`virtual:boltdocs-routes`) */
|
|
173
|
-
routes: ComponentRoute[];
|
|
174
|
-
/** Site configuration (`virtual:boltdocs-config`) */
|
|
175
|
-
config: any;
|
|
176
|
-
/** Dynamic import mapping from `import.meta.glob` for the documentation pages */
|
|
177
|
-
modules: Record<string, () => Promise<any>>;
|
|
178
|
-
/** The `import.meta.hot` instance necessary for fast refresh/HMR updates */
|
|
179
|
-
hot?: any;
|
|
180
|
-
/** Optional custom React component to render when visiting the root path ('/') */
|
|
181
|
-
homePage?: React.ComponentType;
|
|
182
|
-
/** Optional custom MDX components provided by plugins */
|
|
183
|
-
components?: Record<string, React.ComponentType<any>>;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
99
|
export function AppShell({
|
|
187
100
|
initialRoutes,
|
|
188
101
|
initialConfig,
|
|
@@ -200,20 +113,9 @@ export function AppShell({
|
|
|
200
113
|
}) {
|
|
201
114
|
const [routesInfo, setRoutesInfo] = useState<ComponentRoute[]>(initialRoutes);
|
|
202
115
|
const [config] = useState(initialConfig);
|
|
203
|
-
const [resolvedRoutes, setResolvedRoutes] = useState<any[]>([]);
|
|
204
|
-
|
|
205
|
-
// Subscribe to HMR events
|
|
206
|
-
useEffect(() => {
|
|
207
|
-
if (hot) {
|
|
208
|
-
hot.on("boltdocs:routes-update", (newRoutes: ComponentRoute[]) => {
|
|
209
|
-
setRoutesInfo(newRoutes);
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
}, [hot]);
|
|
213
116
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const mapped = routesInfo
|
|
117
|
+
const resolveRoutes = (infos: ComponentRoute[]) => {
|
|
118
|
+
return infos
|
|
217
119
|
.filter(
|
|
218
120
|
(route) => !(HomePage && (route.path === "/" || route.path === "")),
|
|
219
121
|
)
|
|
@@ -232,8 +134,24 @@ export function AppShell({
|
|
|
232
134
|
}),
|
|
233
135
|
};
|
|
234
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]);
|
|
235
151
|
|
|
236
|
-
|
|
152
|
+
// Sync resolved routes when info or modules change
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
setResolvedRoutes(resolveRoutes(routesInfo));
|
|
237
155
|
}, [routesInfo, modules]);
|
|
238
156
|
|
|
239
157
|
return (
|
|
@@ -261,7 +179,10 @@ export function AppShell({
|
|
|
261
179
|
)}
|
|
262
180
|
|
|
263
181
|
{/* Documentation pages WITH sidebar + TOC layout */}
|
|
264
|
-
<Route
|
|
182
|
+
<Route
|
|
183
|
+
key="docs-layout"
|
|
184
|
+
element={<DocsLayout config={config} routes={routesInfo} />}
|
|
185
|
+
>
|
|
265
186
|
{resolvedRoutes.map((route: any) => (
|
|
266
187
|
<Route
|
|
267
188
|
key={route.path}
|
|
@@ -303,6 +224,8 @@ function ScrollHandler() {
|
|
|
303
224
|
const { pathname, hash } = useLocation();
|
|
304
225
|
|
|
305
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.
|
|
306
229
|
if (hash) {
|
|
307
230
|
const id = hash.replace("#", "");
|
|
308
231
|
const element = document.getElementById(id);
|
|
@@ -412,11 +335,10 @@ export function createBoltdocsApp(options: CreateBoltdocsAppOptions) {
|
|
|
412
335
|
</React.StrictMode>
|
|
413
336
|
);
|
|
414
337
|
|
|
415
|
-
//
|
|
416
|
-
//
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
338
|
+
// SSG pre-renders a shell with mock components for SEO crawlers.
|
|
339
|
+
// We always use createRoot because the SSG output doesn't match the
|
|
340
|
+
// real client-side component tree (components are lazy/dynamic).
|
|
341
|
+
// Clear any SSG placeholder content before mounting.
|
|
342
|
+
container.innerHTML = "";
|
|
343
|
+
ReactDOM.createRoot(container as HTMLElement).render(app);
|
|
422
344
|
}
|
package/src/client/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { BoltdocsConfig, BoltdocsThemeConfig } from "../node/config";
|
|
2
|
-
export type { ComponentRoute, CreateBoltdocsAppOptions } from "./
|
|
2
|
+
export type { ComponentRoute, CreateBoltdocsAppOptions } from "./types";
|
|
3
3
|
export { createBoltdocsApp } from "./app";
|
|
4
4
|
export { ThemeLayout } from "./theme/ui/Layout";
|
|
5
5
|
export { Navbar } from "./theme/ui/Navbar";
|
package/src/client/ssr.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import ReactDOMServer from "react-dom/server";
|
|
3
3
|
import { StaticRouter } from "react-router-dom/server";
|
|
4
|
-
import { AppShell
|
|
4
|
+
import { AppShell } from "./app";
|
|
5
|
+
import { ComponentRoute } from "./types";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Options for rendering the Boltdocs application on the server (SSG).
|
|
@@ -7,17 +7,52 @@ interface PlaygroundProps {
|
|
|
7
7
|
children?: string | React.ReactNode;
|
|
8
8
|
scope?: Record<string, any>;
|
|
9
9
|
readonly?: boolean;
|
|
10
|
+
noInline?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Transforms code that uses `export default` into a format compatible
|
|
15
|
+
* with react-live's `noInline` mode by stripping the export and
|
|
16
|
+
* appending a `render(<ComponentName />)` call.
|
|
17
|
+
*/
|
|
18
|
+
function prepareCode(raw: string): { code: string; noInline: boolean } {
|
|
19
|
+
const trimmed = raw.trim();
|
|
20
|
+
|
|
21
|
+
// Match: export default function Name(...)
|
|
22
|
+
const fnMatch = trimmed.match(/export\s+default\s+function\s+(\w+)/);
|
|
23
|
+
if (fnMatch) {
|
|
24
|
+
const name = fnMatch[1];
|
|
25
|
+
const code =
|
|
26
|
+
trimmed.replace(/export\s+default\s+/, "") + `\n\nrender(<${name} />);`;
|
|
27
|
+
return { code, noInline: true };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Match: export default ComponentName (at the end)
|
|
31
|
+
const varMatch = trimmed.match(/export\s+default\s+(\w+)\s*;?\s*$/);
|
|
32
|
+
if (varMatch) {
|
|
33
|
+
const name = varMatch[1];
|
|
34
|
+
const code =
|
|
35
|
+
trimmed.replace(/export\s+default\s+\w+\s*;?\s*$/, "") +
|
|
36
|
+
`\nrender(<${name} />);`;
|
|
37
|
+
return { code, noInline: true };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// No export default — use inline mode (simple JSX expression)
|
|
41
|
+
return { code: trimmed, noInline: false };
|
|
10
42
|
}
|
|
11
43
|
|
|
12
44
|
/**
|
|
13
45
|
* A live React playground component.
|
|
14
46
|
* Features a split layout with a live editor and a preview section.
|
|
47
|
+
*
|
|
48
|
+
* Supports `export default function App()` style code out of the box.
|
|
15
49
|
*/
|
|
16
50
|
export function Playground({
|
|
17
51
|
code,
|
|
18
52
|
children,
|
|
19
53
|
scope = {},
|
|
20
54
|
readonly = false,
|
|
55
|
+
noInline: forceNoInline,
|
|
21
56
|
}: PlaygroundProps) {
|
|
22
57
|
// Extract code from either `code` prop or `children`
|
|
23
58
|
let initialCode = code || "";
|
|
@@ -25,8 +60,11 @@ export function Playground({
|
|
|
25
60
|
initialCode = children;
|
|
26
61
|
}
|
|
27
62
|
|
|
63
|
+
const prepared = prepareCode(initialCode);
|
|
64
|
+
const useNoInline = forceNoInline ?? prepared.noInline;
|
|
65
|
+
|
|
28
66
|
const [copied, setCopied] = useState(false);
|
|
29
|
-
const [activeCode, setActiveCode] = useState(
|
|
67
|
+
const [activeCode, setActiveCode] = useState(prepared.code);
|
|
30
68
|
|
|
31
69
|
const handleCopy = () => {
|
|
32
70
|
navigator.clipboard.writeText(activeCode);
|
|
@@ -43,7 +81,7 @@ export function Playground({
|
|
|
43
81
|
code={activeCode}
|
|
44
82
|
scope={extendedScope}
|
|
45
83
|
theme={undefined}
|
|
46
|
-
noInline={
|
|
84
|
+
noInline={useNoInline}
|
|
47
85
|
>
|
|
48
86
|
<div className="playground-split-container">
|
|
49
87
|
{/* Editor Side */}
|
|
@@ -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 {
|
|
@@ -265,12 +265,12 @@
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
.code-block-wrapper pre > code {
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
display: grid !important;
|
|
269
|
+
padding: 1.25rem 1rem !important;
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
.code-block-wrapper pre > code .line {
|
|
273
|
-
padding: 0;
|
|
273
|
+
padding: 0 1.25rem;
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
/* Default pre (without wrapper) */
|
|
@@ -288,7 +288,7 @@
|
|
|
288
288
|
|
|
289
289
|
.boltdocs-page pre > code {
|
|
290
290
|
display: grid;
|
|
291
|
-
padding: 1rem
|
|
291
|
+
padding: 1rem 1rem;
|
|
292
292
|
background-color: transparent;
|
|
293
293
|
border: none;
|
|
294
294
|
color: inherit;
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { useLocation } from "react-router-dom";
|
|
3
3
|
import { Link } from "../Link";
|
|
4
4
|
import { Home, ChevronRight } from "lucide-react";
|
|
5
|
-
import { ComponentRoute } from "../../../
|
|
5
|
+
import { ComponentRoute } from "../../../types";
|
|
6
6
|
import { BoltdocsConfig } from "../../../../node/config";
|
|
7
7
|
|
|
8
8
|
export interface BreadcrumbsProps {
|
|
@@ -2,7 +2,7 @@ import React, { useState, useRef, useEffect } from "react";
|
|
|
2
2
|
import { Globe, ChevronDown } from "lucide-react";
|
|
3
3
|
import { useNavigate, useLocation } from "react-router-dom";
|
|
4
4
|
import { BoltdocsI18nConfig } from "../../../../node/config";
|
|
5
|
-
import { ComponentRoute } from "../../../
|
|
5
|
+
import { ComponentRoute } from "../../../types";
|
|
6
6
|
|
|
7
7
|
function getBaseFilePath(
|
|
8
8
|
filePath: string,
|
|
@@ -4,7 +4,7 @@ import { Link } from "../Link";
|
|
|
4
4
|
import { ChevronLeft, ChevronRight, Menu } from "lucide-react";
|
|
5
5
|
import { usePreload } from "../../../app/preload";
|
|
6
6
|
import { BoltdocsConfig } from "../../../../node/config";
|
|
7
|
-
import { ComponentRoute } from "../../../
|
|
7
|
+
import { ComponentRoute } from "../../../types";
|
|
8
8
|
export { Navbar } from "../Navbar";
|
|
9
9
|
export { Sidebar } from "../Sidebar";
|
|
10
10
|
export { OnThisPage } from "../OnThisPage";
|
|
@@ -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
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
LinkProps as RouterLinkProps,
|
|
6
6
|
NavLinkProps as RouterNavLinkProps,
|
|
7
7
|
useLocation,
|
|
8
|
+
useNavigate,
|
|
8
9
|
} from "react-router-dom";
|
|
9
10
|
import { usePreload } from "../../../app/preload";
|
|
10
11
|
import { useConfig } from "../../../app";
|
|
@@ -107,11 +108,13 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
|
|
|
107
108
|
boltdocsPrefetch = "hover",
|
|
108
109
|
onMouseEnter,
|
|
109
110
|
onFocus,
|
|
111
|
+
onClick,
|
|
110
112
|
to,
|
|
111
113
|
...rest
|
|
112
114
|
} = props;
|
|
113
115
|
const localizedTo = useLocalizedTo(to);
|
|
114
116
|
const { preload } = usePreload();
|
|
117
|
+
const navigate = useNavigate();
|
|
115
118
|
|
|
116
119
|
const handleMouseEnter = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
117
120
|
onMouseEnter?.(e);
|
|
@@ -135,12 +138,38 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
|
|
|
135
138
|
}
|
|
136
139
|
};
|
|
137
140
|
|
|
141
|
+
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
142
|
+
// Allow user onClick to handle defaults or custom logic
|
|
143
|
+
onClick?.(e);
|
|
144
|
+
|
|
145
|
+
// If default prevented or not a simple left click, don't handle
|
|
146
|
+
if (
|
|
147
|
+
e.defaultPrevented ||
|
|
148
|
+
e.button !== 0 ||
|
|
149
|
+
e.metaKey ||
|
|
150
|
+
e.ctrlKey ||
|
|
151
|
+
e.shiftKey ||
|
|
152
|
+
e.altKey
|
|
153
|
+
) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Intercept navigation to wrap in startTransition
|
|
158
|
+
if (typeof localizedTo === "string" && !localizedTo.startsWith("http")) {
|
|
159
|
+
e.preventDefault();
|
|
160
|
+
React.startTransition(() => {
|
|
161
|
+
navigate(localizedTo);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
138
166
|
return (
|
|
139
167
|
<RouterLink
|
|
140
168
|
ref={ref}
|
|
141
169
|
to={localizedTo}
|
|
142
170
|
onMouseEnter={handleMouseEnter}
|
|
143
171
|
onFocus={handleFocus}
|
|
172
|
+
onClick={handleClick}
|
|
144
173
|
{...rest}
|
|
145
174
|
/>
|
|
146
175
|
);
|
|
@@ -159,12 +188,14 @@ export const NavLink = React.forwardRef<HTMLAnchorElement, NavLinkProps>(
|
|
|
159
188
|
boltdocsPrefetch = "hover",
|
|
160
189
|
onMouseEnter,
|
|
161
190
|
onFocus,
|
|
191
|
+
onClick,
|
|
162
192
|
to,
|
|
163
193
|
...rest
|
|
164
194
|
} = props;
|
|
165
195
|
|
|
166
196
|
const localizedTo = useLocalizedTo(to);
|
|
167
197
|
const { preload } = usePreload();
|
|
198
|
+
const navigate = useNavigate();
|
|
168
199
|
|
|
169
200
|
const handleMouseEnter = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
170
201
|
onMouseEnter?.(e);
|
|
@@ -188,12 +219,33 @@ export const NavLink = React.forwardRef<HTMLAnchorElement, NavLinkProps>(
|
|
|
188
219
|
}
|
|
189
220
|
};
|
|
190
221
|
|
|
222
|
+
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
223
|
+
onClick?.(e);
|
|
224
|
+
if (
|
|
225
|
+
e.defaultPrevented ||
|
|
226
|
+
e.button !== 0 ||
|
|
227
|
+
e.metaKey ||
|
|
228
|
+
e.ctrlKey ||
|
|
229
|
+
e.shiftKey ||
|
|
230
|
+
e.altKey
|
|
231
|
+
) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (typeof localizedTo === "string" && !localizedTo.startsWith("http")) {
|
|
235
|
+
e.preventDefault();
|
|
236
|
+
React.startTransition(() => {
|
|
237
|
+
navigate(localizedTo);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
191
242
|
return (
|
|
192
243
|
<RouterNavLink
|
|
193
244
|
ref={ref}
|
|
194
245
|
to={localizedTo}
|
|
195
246
|
onMouseEnter={handleMouseEnter}
|
|
196
247
|
onFocus={handleFocus}
|
|
248
|
+
onClick={handleClick}
|
|
197
249
|
{...rest}
|
|
198
250
|
/>
|
|
199
251
|
);
|
|
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
|
|
|
2
2
|
import { Link } from "../Link";
|
|
3
3
|
import { Book, ChevronDown } from "lucide-react";
|
|
4
4
|
import { BoltdocsConfig } from "../../../../node/config";
|
|
5
|
-
import { ComponentRoute } from "../../../
|
|
5
|
+
import { ComponentRoute } from "../../../types";
|
|
6
6
|
import { LanguageSwitcher } from "../LanguageSwitcher";
|
|
7
7
|
import { VersionSwitcher } from "../VersionSwitcher";
|
|
8
8
|
import { ThemeToggle } from "../ThemeToggle";
|