boltdocs 2.5.6 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/boltdocs.js +2 -2
- package/dist/client/index.cjs +6 -0
- package/dist/client/{index.d.mts → index.d.cts} +134 -252
- package/dist/client/index.d.ts +135 -253
- package/dist/client/index.js +1 -1
- package/dist/client/theme/neutral.css +90 -50
- package/dist/node/cli-entry.cjs +2 -2
- package/dist/node/cli-entry.mjs +2 -2
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +150 -205
- package/dist/node/index.d.mts +150 -205
- package/dist/node/index.mjs +1 -1
- package/dist/node-BgvNl2Ay.mjs +89 -0
- package/dist/node-vkbb0MK7.cjs +89 -0
- package/dist/{package-OFZf0s2j.mjs → package-CR0HF9x3.mjs} +1 -1
- package/dist/{package-BY8Jd2j4.cjs → package-Dgmsc_l5.cjs} +1 -1
- package/dist/search-dialog-3lvKsbVG.js +6 -0
- package/dist/search-dialog-DMK5OpgH.cjs +6 -0
- package/dist/use-search-C9bxCqfF.js +6 -0
- package/dist/use-search-DcfZSunO.cjs +6 -0
- package/package.json +19 -22
- package/src/client/app/config-context.tsx +38 -5
- package/src/client/app/doc-page.tsx +34 -0
- package/src/client/app/mdx-component.tsx +2 -3
- package/src/client/app/mdx-components-context.tsx +27 -2
- package/src/client/app/routes-context.tsx +34 -0
- package/src/client/app/scroll-handler.tsx +7 -4
- package/src/client/app/theme-context.tsx +71 -67
- package/src/client/components/default-layout.tsx +13 -14
- package/src/client/components/docs-layout.tsx +1 -2
- package/src/client/components/icons-dev.tsx +36 -5
- package/src/client/components/mdx/admonition.tsx +11 -27
- package/src/client/components/mdx/badge.tsx +1 -1
- package/src/client/components/mdx/button.tsx +3 -3
- package/src/client/components/mdx/card.tsx +1 -1
- package/src/client/components/mdx/code-block.tsx +90 -80
- package/src/client/components/mdx/component-preview.tsx +1 -5
- package/src/client/components/mdx/component-props.tsx +1 -1
- package/src/client/components/mdx/field.tsx +4 -5
- package/src/client/components/mdx/file-tree.tsx +6 -3
- package/src/client/components/mdx/hooks/use-code-block.ts +2 -2
- package/src/client/components/mdx/image.tsx +1 -1
- package/src/client/components/mdx/link.tsx +2 -2
- package/src/client/components/mdx/list.tsx +1 -1
- package/src/client/components/mdx/table.tsx +1 -1
- package/src/client/components/mdx/tabs.tsx +1 -1
- package/src/client/components/primitives/breadcrumbs.tsx +1 -7
- package/src/client/components/primitives/button-group.tsx +1 -1
- package/src/client/components/primitives/button.tsx +1 -1
- package/src/client/components/primitives/code-block.tsx +113 -0
- package/src/client/components/primitives/link.tsx +23 -41
- package/src/client/components/primitives/menu.tsx +5 -6
- package/src/client/components/primitives/navbar.tsx +6 -18
- package/src/client/components/primitives/navigation-menu.tsx +4 -4
- package/src/client/components/primitives/on-this-page.tsx +6 -10
- package/src/client/components/primitives/page-nav.tsx +4 -9
- package/src/client/components/primitives/popover.tsx +1 -1
- package/src/client/components/primitives/search-dialog.tsx +3 -6
- package/src/client/components/primitives/sidebar.tsx +80 -22
- package/src/client/components/primitives/skeleton.tsx +1 -1
- package/src/client/components/primitives/tabs.tsx +4 -11
- package/src/client/components/primitives/tooltip.tsx +3 -3
- package/src/client/components/ui-base/breadcrumbs.tsx +4 -6
- package/src/client/components/ui-base/copy-markdown.tsx +2 -7
- package/src/client/components/ui-base/github-stars.tsx +2 -2
- package/src/client/components/ui-base/head.tsx +58 -51
- package/src/client/components/ui-base/loading.tsx +2 -2
- package/src/client/components/ui-base/navbar.tsx +12 -14
- package/src/client/components/ui-base/not-found.tsx +1 -1
- package/src/client/components/ui-base/on-this-page.tsx +6 -6
- package/src/client/components/ui-base/page-nav.tsx +4 -8
- package/src/client/components/ui-base/search-dialog.tsx +10 -8
- package/src/client/components/ui-base/sidebar.tsx +76 -23
- package/src/client/components/ui-base/tabs.tsx +9 -8
- package/src/client/components/ui-base/theme-toggle.tsx +2 -2
- package/src/client/hooks/use-i18n.ts +3 -3
- package/src/client/hooks/use-localized-to.ts +1 -1
- package/src/client/hooks/use-navbar.ts +8 -6
- package/src/client/hooks/use-routes.ts +19 -11
- package/src/client/hooks/use-search.ts +1 -1
- package/src/client/hooks/use-sidebar.ts +48 -2
- package/src/client/hooks/use-tabs.ts +6 -2
- package/src/client/hooks/use-version.ts +3 -3
- package/src/client/index.ts +22 -22
- package/src/client/ssg/boltdocs-shell.tsx +127 -0
- package/src/client/ssg/create-routes.tsx +179 -0
- package/src/client/ssg/index.ts +3 -0
- package/src/client/ssg/mdx-page.tsx +37 -0
- package/src/client/store/boltdocs-context.tsx +46 -99
- package/src/client/theme/neutral.css +90 -50
- package/src/client/types.ts +5 -33
- package/src/client/utils/react-to-text.ts +34 -0
- package/dist/cache-Cr8W2zgZ.cjs +0 -6
- package/dist/cache-DFdakSmR.mjs +0 -6
- package/dist/client/index.mjs +0 -6
- package/dist/client/ssr.cjs +0 -6
- package/dist/client/ssr.d.cts +0 -80
- package/dist/client/ssr.d.mts +0 -80
- package/dist/client/ssr.mjs +0 -6
- package/dist/node-CWXme96p.mjs +0 -73
- package/dist/node-VYfhzGrh.cjs +0 -73
- package/dist/search-dialog-BeNyI_KQ.mjs +0 -6
- package/dist/search-dialog-dYsCAk5S.js +0 -6
- package/dist/use-search-D25n0PrV.mjs +0 -6
- package/dist/use-search-WuzdH1cJ.js +0 -6
- package/src/client/app/index.tsx +0 -348
- package/src/client/app/mdx-page.tsx +0 -15
- package/src/client/app/preload.tsx +0 -66
- package/src/client/app/router.tsx +0 -30
- package/src/client/integrations/codesandbox.ts +0 -179
- package/src/client/integrations/index.ts +0 -1
- package/src/client/ssr.tsx +0 -65
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "boltdocs",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "A lightweight documentation generator for React projects.",
|
|
5
|
-
"main": "dist/node/index.
|
|
5
|
+
"main": "dist/node/index.mjs",
|
|
6
6
|
"module": "dist/node/index.mjs",
|
|
7
7
|
"types": "dist/node/index.d.ts",
|
|
8
8
|
"bin": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
14
|
-
"type": "
|
|
14
|
+
"type": "module",
|
|
15
15
|
"sideEffects": [
|
|
16
16
|
"**/*.css"
|
|
17
17
|
],
|
|
@@ -19,17 +19,12 @@
|
|
|
19
19
|
".": {
|
|
20
20
|
"types": "./dist/node/index.d.ts",
|
|
21
21
|
"import": "./dist/node/index.mjs",
|
|
22
|
-
"require": "./dist/node/index.
|
|
22
|
+
"require": "./dist/node/index.cjs"
|
|
23
23
|
},
|
|
24
24
|
"./client": {
|
|
25
25
|
"types": "./dist/client/index.d.ts",
|
|
26
|
-
"import": "./dist/client/index.
|
|
27
|
-
"require": "./dist/client/index.
|
|
28
|
-
},
|
|
29
|
-
"./ssr": {
|
|
30
|
-
"types": "./dist/client/ssr.d.ts",
|
|
31
|
-
"import": "./dist/client/ssr.mjs",
|
|
32
|
-
"require": "./dist/client/ssr.js"
|
|
26
|
+
"import": "./dist/client/index.js",
|
|
27
|
+
"require": "./dist/client/index.cjs"
|
|
33
28
|
},
|
|
34
29
|
"./theme/neutral.css": "./dist/client/theme/neutral.css"
|
|
35
30
|
},
|
|
@@ -54,7 +49,7 @@
|
|
|
54
49
|
"dependencies": {
|
|
55
50
|
"@mdx-js/rollup": "3.1.1",
|
|
56
51
|
"@tailwindcss/vite": "4.2.2",
|
|
57
|
-
"@vitejs/plugin-react": "
|
|
52
|
+
"@vitejs/plugin-react": "6.0.1",
|
|
58
53
|
"cac": "7.0.0",
|
|
59
54
|
"class-variance-authority": "0.7.1",
|
|
60
55
|
"clsx": "2.1.1",
|
|
@@ -65,7 +60,8 @@
|
|
|
65
60
|
"isomorphic-dompurify": "3.7.1",
|
|
66
61
|
"lucide-react": "0.575.0",
|
|
67
62
|
"react-aria-components": "1.16.0",
|
|
68
|
-
"react-
|
|
63
|
+
"react-helmet-async": "^2.0.1",
|
|
64
|
+
"react-router-dom": "^7.0.0",
|
|
69
65
|
"rehype-slug": "6.0.0",
|
|
70
66
|
"remark-frontmatter": "5.0.0",
|
|
71
67
|
"remark-gfm": "4.0.1",
|
|
@@ -75,22 +71,23 @@
|
|
|
75
71
|
"svgo": "4.0.1",
|
|
76
72
|
"tailwind-merge": "3.5.0",
|
|
77
73
|
"unist-util-visit": "5.1.0",
|
|
78
|
-
"vite": "7.
|
|
74
|
+
"vite": "7.0.0 || 8.0.0",
|
|
79
75
|
"vite-plugin-image-optimizer": "2.0.3",
|
|
80
|
-
"zod": "4.3.6"
|
|
76
|
+
"zod": "4.3.6",
|
|
77
|
+
"@bdocs/ssg": "0.0.1"
|
|
81
78
|
},
|
|
82
79
|
"peerDependencies": {
|
|
83
|
-
"react": "19.
|
|
84
|
-
"react-dom": "19.
|
|
80
|
+
"react": "19.0.0",
|
|
81
|
+
"react-dom": "19.0.0"
|
|
85
82
|
},
|
|
86
83
|
"devDependencies": {
|
|
87
|
-
"@types/node": "
|
|
88
|
-
"@types/react": "
|
|
89
|
-
"@types/react-dom": "
|
|
84
|
+
"@types/node": "22.0.0",
|
|
85
|
+
"@types/react": "19.0.0",
|
|
86
|
+
"@types/react-dom": "19.0.0",
|
|
90
87
|
"@types/react-router-dom": "5.3.3",
|
|
91
88
|
"@types/semver": "7.7.1",
|
|
92
|
-
"tsdown": "
|
|
93
|
-
"typescript": "
|
|
89
|
+
"tsdown": "0.21.7",
|
|
90
|
+
"typescript": "5.9.3"
|
|
94
91
|
},
|
|
95
92
|
"scripts": {
|
|
96
93
|
"build": "tsdown --config-loader unrun",
|
|
@@ -1,18 +1,51 @@
|
|
|
1
1
|
import { createContext, use } from 'react'
|
|
2
|
-
import type { BoltdocsConfig } from '
|
|
2
|
+
import type { BoltdocsConfig } from '../../shared/types'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Context for the global documentation configuration.
|
|
6
|
+
* Using a global singleton pattern to survive dual-package or duplicated-code hazards.
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
+
const CONFIG_CONTEXT_SYMBOL = Symbol.for('__BDOCS_CONFIG_CONTEXT__')
|
|
9
|
+
const CONFIG_INSTANCE_SYMBOL = Symbol.for('__BDOCS_CONFIG_INSTANCE__')
|
|
10
|
+
|
|
11
|
+
export const ConfigContext =
|
|
12
|
+
(globalThis as any)[CONFIG_CONTEXT_SYMBOL] ||
|
|
13
|
+
((globalThis as any)[CONFIG_CONTEXT_SYMBOL] =
|
|
14
|
+
createContext<BoltdocsConfig | null>(null))
|
|
15
|
+
|
|
16
|
+
export function ConfigProvider({
|
|
17
|
+
config,
|
|
18
|
+
children,
|
|
19
|
+
}: {
|
|
20
|
+
config: BoltdocsConfig
|
|
21
|
+
children: React.ReactNode
|
|
22
|
+
}) {
|
|
23
|
+
// Sync with global registry for dual-package fallback
|
|
24
|
+
if (typeof globalThis !== 'undefined') {
|
|
25
|
+
;(globalThis as any)[CONFIG_INSTANCE_SYMBOL] = config
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
8
32
|
|
|
9
33
|
/**
|
|
10
34
|
* Hook to access the Boltdocs configuration.
|
|
11
35
|
*/
|
|
12
36
|
export function useConfig() {
|
|
13
37
|
const context = use(ConfigContext)
|
|
14
|
-
|
|
15
|
-
|
|
38
|
+
|
|
39
|
+
// Fallback to global registry if context is missing (dual-package hazard safety net)
|
|
40
|
+
if (
|
|
41
|
+
!context &&
|
|
42
|
+
typeof globalThis !== 'undefined' &&
|
|
43
|
+
(globalThis as any)[CONFIG_INSTANCE_SYMBOL]
|
|
44
|
+
) {
|
|
45
|
+
return (globalThis as any)[CONFIG_INSTANCE_SYMBOL] as BoltdocsConfig
|
|
16
46
|
}
|
|
17
|
-
|
|
47
|
+
|
|
48
|
+
if (!context)
|
|
49
|
+
throw new Error('useConfig must be used within a ConfigProvider')
|
|
50
|
+
return context as BoltdocsConfig
|
|
18
51
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import UserLayout from 'virtual:boltdocs-layout'
|
|
2
|
+
import { useMdxComponents } from './mdx-components-context'
|
|
3
|
+
import { useMemo } from 'react'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* DocPage is a layout wrapper for documentation content during SSG.
|
|
7
|
+
* It renders the user-defined layout (or default) around the MDX content.
|
|
8
|
+
*/
|
|
9
|
+
export function DocPage({
|
|
10
|
+
route,
|
|
11
|
+
content: Content,
|
|
12
|
+
mdxComponents: propComponents,
|
|
13
|
+
}: any) {
|
|
14
|
+
// Access global MDX components (defaults + plugins + virtuals) from context
|
|
15
|
+
const contextComponents = useMdxComponents()
|
|
16
|
+
|
|
17
|
+
// Merge components: Prop components (from loader) take priority,
|
|
18
|
+
// then context components (globals).
|
|
19
|
+
const allComponents = useMemo(
|
|
20
|
+
() => ({
|
|
21
|
+
...contextComponents,
|
|
22
|
+
...propComponents,
|
|
23
|
+
}),
|
|
24
|
+
[contextComponents, propComponents],
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if (!Content) return null
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<UserLayout route={route}>
|
|
31
|
+
<Content components={allComponents} />
|
|
32
|
+
</UserLayout>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type React from 'react'
|
|
2
1
|
import { Link as LucideLink } from 'lucide-react'
|
|
3
|
-
import * as MdxComponents from '
|
|
2
|
+
import * as MdxComponents from '../components/mdx'
|
|
4
3
|
|
|
5
4
|
const Heading = ({
|
|
6
5
|
level,
|
|
@@ -25,7 +24,7 @@ const Heading = ({
|
|
|
25
24
|
)
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
import { Loading } from '
|
|
27
|
+
import { Loading } from '../components/ui-base/loading'
|
|
29
28
|
|
|
30
29
|
export const mdxComponentsDefault = {
|
|
31
30
|
...MdxComponents,
|
|
@@ -2,10 +2,30 @@ import { createContext, use } from 'react'
|
|
|
2
2
|
|
|
3
3
|
export type MdxComponentsType = Record<string, React.ComponentType<any>>
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const MDX_COMPONENTS_CONTEXT_SYMBOL = Symbol.for(
|
|
6
|
+
'__BDOCS_MDX_COMPONENTS_CONTEXT__',
|
|
7
|
+
)
|
|
8
|
+
const MDX_COMPONENTS_INSTANCE_SYMBOL = Symbol.for(
|
|
9
|
+
'__BDOCS_MDX_COMPONENTS_INSTANCE__',
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
const MdxComponentsContext =
|
|
13
|
+
(globalThis as any)[MDX_COMPONENTS_CONTEXT_SYMBOL] ||
|
|
14
|
+
((globalThis as any)[MDX_COMPONENTS_CONTEXT_SYMBOL] =
|
|
15
|
+
createContext<MdxComponentsType>({}))
|
|
6
16
|
|
|
7
17
|
export function useMdxComponents() {
|
|
8
|
-
|
|
18
|
+
const context = use(MdxComponentsContext)
|
|
19
|
+
|
|
20
|
+
// Fallback to global registry for dual-package hazards
|
|
21
|
+
if (
|
|
22
|
+
(!context || Object.keys(context).length === 0) &&
|
|
23
|
+
(globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL]
|
|
24
|
+
) {
|
|
25
|
+
return (globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return context
|
|
9
29
|
}
|
|
10
30
|
|
|
11
31
|
export function MdxComponentsProvider({
|
|
@@ -15,6 +35,11 @@ export function MdxComponentsProvider({
|
|
|
15
35
|
components: MdxComponentsType
|
|
16
36
|
children: React.ReactNode
|
|
17
37
|
}) {
|
|
38
|
+
// Sync with global registry
|
|
39
|
+
if (typeof globalThis !== 'undefined') {
|
|
40
|
+
;(globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL] = components
|
|
41
|
+
}
|
|
42
|
+
|
|
18
43
|
return (
|
|
19
44
|
<MdxComponentsContext.Provider value={components}>
|
|
20
45
|
{children}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react'
|
|
2
|
+
import type { ComponentRoute } from '../types'
|
|
3
|
+
|
|
4
|
+
interface RoutesContextType {
|
|
5
|
+
routes: ComponentRoute[]
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const RoutesContext = createContext<RoutesContextType>({
|
|
9
|
+
routes: [],
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Hook to access the processed routes list from the closest provider.
|
|
14
|
+
*/
|
|
15
|
+
export function useRoutesContext() {
|
|
16
|
+
return useContext(RoutesContext)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Provider component for the documentation routes.
|
|
21
|
+
*/
|
|
22
|
+
export function RoutesProvider({
|
|
23
|
+
routes,
|
|
24
|
+
children,
|
|
25
|
+
}: {
|
|
26
|
+
routes: ComponentRoute[]
|
|
27
|
+
children: React.ReactNode
|
|
28
|
+
}) {
|
|
29
|
+
return (
|
|
30
|
+
<RoutesContext.Provider value={{ routes }}>
|
|
31
|
+
{children}
|
|
32
|
+
</RoutesContext.Provider>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
@@ -12,19 +12,19 @@ export function ScrollHandler() {
|
|
|
12
12
|
// biome-ignore lint/correctness/useExhaustiveDependencies: pathname is used as a trigger for scroll-to-top on navigation
|
|
13
13
|
useLayoutEffect(() => {
|
|
14
14
|
const container = document.querySelector('.boltdocs-content') || window
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
// Helper to get scroll top
|
|
17
17
|
const getScrollTop = () => {
|
|
18
18
|
if (container === window) return window.scrollY
|
|
19
19
|
return (container as HTMLElement).scrollTop
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
// Helper to scroll
|
|
23
23
|
const scrollTo = (top: number, behavior: ScrollBehavior = 'auto') => {
|
|
24
24
|
if (container === window) {
|
|
25
25
|
window.scrollTo({ top, behavior })
|
|
26
26
|
} else {
|
|
27
|
-
(container as HTMLElement).scrollTo({ top, behavior })
|
|
27
|
+
;(container as HTMLElement).scrollTo({ top, behavior })
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -33,7 +33,10 @@ export function ScrollHandler() {
|
|
|
33
33
|
const element = document.getElementById(id)
|
|
34
34
|
if (element) {
|
|
35
35
|
const offset = 80
|
|
36
|
-
const containerTop =
|
|
36
|
+
const containerTop =
|
|
37
|
+
container === window
|
|
38
|
+
? 0
|
|
39
|
+
: (container as HTMLElement).getBoundingClientRect().top
|
|
37
40
|
const elementRect = element.getBoundingClientRect().top
|
|
38
41
|
const elementPosition = elementRect - containerTop
|
|
39
42
|
const offsetPosition = elementPosition - offset + getScrollTop()
|
|
@@ -1,99 +1,103 @@
|
|
|
1
|
-
import { createContext, use,
|
|
1
|
+
import { createContext, use, useState, useEffect } from 'react'
|
|
2
2
|
|
|
3
|
-
type Theme = 'light' | 'dark' | 'system'
|
|
3
|
+
export type Theme = 'light' | 'dark' | 'system'
|
|
4
|
+
export type ResolvedTheme = 'light' | 'dark'
|
|
4
5
|
|
|
5
6
|
interface ThemeContextType {
|
|
6
7
|
theme: Theme
|
|
7
|
-
resolvedTheme:
|
|
8
|
+
resolvedTheme: ResolvedTheme
|
|
8
9
|
setTheme: (theme: Theme) => void
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
+
const THEME_CONTEXT_SYMBOL = Symbol.for('__BDOCS_THEME_CONTEXT__')
|
|
13
|
+
const THEME_INSTANCE_SYMBOL = Symbol.for('__BDOCS_THEME_INSTANCE__')
|
|
14
|
+
const THEME_EVENT = 'boltdocs-theme-change'
|
|
15
|
+
|
|
16
|
+
const ThemeContext =
|
|
17
|
+
(globalThis as any)[THEME_CONTEXT_SYMBOL] ||
|
|
18
|
+
((globalThis as any)[THEME_CONTEXT_SYMBOL] = createContext<
|
|
19
|
+
ThemeContextType | undefined
|
|
20
|
+
>(undefined))
|
|
12
21
|
|
|
13
22
|
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
|
14
23
|
const [theme, setThemeState] = useState<Theme>('system')
|
|
15
|
-
const [resolvedTheme, setResolvedTheme] = useState<
|
|
16
|
-
const [mounted, setMounted] = useState(false)
|
|
17
|
-
|
|
18
|
-
// Initialize theme from localStorage and set internal resolved theme
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
setMounted(true)
|
|
21
|
-
const stored = localStorage.getItem('boltdocs-theme') as Theme | null
|
|
22
|
-
const initialTheme =
|
|
23
|
-
stored === 'light' || stored === 'dark' || stored === 'system'
|
|
24
|
-
? stored
|
|
25
|
-
: 'system'
|
|
26
|
-
|
|
27
|
-
setThemeState(initialTheme)
|
|
24
|
+
const [resolvedTheme, setResolvedTheme] = useState<ResolvedTheme>('dark')
|
|
28
25
|
|
|
26
|
+
const applyTheme = (targetTheme: Theme) => {
|
|
29
27
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
|
28
|
+
const isDark =
|
|
29
|
+
targetTheme === 'dark' ||
|
|
30
|
+
(targetTheme === 'system' && mediaQuery.matches)
|
|
31
|
+
|
|
32
|
+
const root = window.document.documentElement
|
|
33
|
+
root.classList.toggle('dark', isDark)
|
|
34
|
+
root.dataset.theme = isDark ? 'dark' : 'light'
|
|
35
|
+
setResolvedTheme(isDark ? 'dark' : 'light')
|
|
36
|
+
}
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const savedTheme = localStorage.getItem('boltdocs-theme') as Theme | null
|
|
40
|
+
if (savedTheme) {
|
|
41
|
+
setThemeState(savedTheme)
|
|
42
|
+
applyTheme(savedTheme)
|
|
43
|
+
} else {
|
|
44
|
+
applyTheme('system')
|
|
37
45
|
}
|
|
38
46
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// actually, the second useEffect will handle the source of truth,
|
|
44
|
-
// but this listener ensures 'system' updates instantly.
|
|
45
|
-
setResolvedTheme((prevResolved) => {
|
|
46
|
-
const currentTheme =
|
|
47
|
-
(localStorage.getItem('boltdocs-theme') as Theme) || 'system'
|
|
48
|
-
if (currentTheme === 'system') {
|
|
49
|
-
return e.matches ? 'dark' : 'light'
|
|
50
|
-
}
|
|
51
|
-
return prevResolved
|
|
52
|
-
})
|
|
47
|
+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
|
48
|
+
const listener = () => {
|
|
49
|
+
const current = (localStorage.getItem('boltdocs-theme') as Theme) || 'system'
|
|
50
|
+
if (current === 'system') applyTheme('system')
|
|
53
51
|
}
|
|
54
52
|
|
|
55
|
-
mediaQuery.addEventListener('change',
|
|
56
|
-
return () => mediaQuery.removeEventListener('change',
|
|
53
|
+
mediaQuery.addEventListener('change', listener)
|
|
54
|
+
return () => mediaQuery.removeEventListener('change', listener)
|
|
57
55
|
}, [])
|
|
58
56
|
|
|
59
|
-
// Sync with DOM and resolved theme when theme preference changes
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
if (!mounted) return
|
|
62
|
-
|
|
63
|
-
const isSystemDark = window.matchMedia(
|
|
64
|
-
'(prefers-color-scheme: dark)',
|
|
65
|
-
).matches
|
|
66
|
-
const nextResolved =
|
|
67
|
-
theme === 'system' ? (isSystemDark ? 'dark' : 'light') : theme
|
|
68
|
-
|
|
69
|
-
setResolvedTheme(nextResolved as 'light' | 'dark')
|
|
70
|
-
|
|
71
|
-
const root = document.documentElement
|
|
72
|
-
if (nextResolved === 'light') {
|
|
73
|
-
root.classList.add('theme-light')
|
|
74
|
-
root.dataset.theme = 'light'
|
|
75
|
-
} else {
|
|
76
|
-
root.classList.remove('theme-light')
|
|
77
|
-
root.dataset.theme = 'dark'
|
|
78
|
-
}
|
|
79
|
-
}, [theme, mounted])
|
|
80
|
-
|
|
81
57
|
const setTheme = (newTheme: Theme) => {
|
|
82
58
|
setThemeState(newTheme)
|
|
83
59
|
localStorage.setItem('boltdocs-theme', newTheme)
|
|
60
|
+
applyTheme(newTheme)
|
|
61
|
+
|
|
62
|
+
// Notify external listeners (dual-package hazard)
|
|
63
|
+
if (typeof window !== 'undefined') {
|
|
64
|
+
window.dispatchEvent(new CustomEvent(THEME_EVENT, { detail: newTheme }))
|
|
65
|
+
}
|
|
84
66
|
}
|
|
85
67
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
68
|
+
const value = { theme, resolvedTheme, setTheme }
|
|
69
|
+
|
|
70
|
+
// Sync with global registry
|
|
71
|
+
if (typeof globalThis !== 'undefined') {
|
|
72
|
+
;(globalThis as any)[THEME_INSTANCE_SYMBOL] = value
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
|
|
91
76
|
}
|
|
92
77
|
|
|
93
78
|
export function useTheme() {
|
|
94
79
|
const context = use(ThemeContext)
|
|
80
|
+
const [, forceUpdate] = useState({})
|
|
81
|
+
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (context) return
|
|
84
|
+
|
|
85
|
+
const handler = () => forceUpdate({})
|
|
86
|
+
window.addEventListener(THEME_EVENT, handler)
|
|
87
|
+
return () => window.removeEventListener(THEME_EVENT, handler)
|
|
88
|
+
}, [context])
|
|
89
|
+
|
|
90
|
+
// Fallback to global registry for dual-package hazards
|
|
91
|
+
if (
|
|
92
|
+
!context &&
|
|
93
|
+
typeof globalThis !== 'undefined' &&
|
|
94
|
+
(globalThis as any)[THEME_INSTANCE_SYMBOL]
|
|
95
|
+
) {
|
|
96
|
+
return (globalThis as any)[THEME_INSTANCE_SYMBOL] as ThemeContextType
|
|
97
|
+
}
|
|
98
|
+
|
|
95
99
|
if (context === undefined) {
|
|
96
100
|
throw new Error('useTheme must be used within a ThemeProvider')
|
|
97
101
|
}
|
|
98
|
-
return context
|
|
102
|
+
return context as ThemeContextType
|
|
99
103
|
}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
import { DocsLayout } from '
|
|
2
|
-
import { Navbar } from '
|
|
3
|
-
import { Sidebar } from '
|
|
4
|
-
import { OnThisPage } from '
|
|
5
|
-
import { Head } from '
|
|
6
|
-
import { Breadcrumbs } from '
|
|
7
|
-
import { PageNav } from '
|
|
8
|
-
import { ErrorBoundary } from '
|
|
9
|
-
import { CopyMarkdown } from '
|
|
10
|
-
import { useRoutes } from '
|
|
11
|
-
import { useConfig } from '
|
|
12
|
-
import { useMdxComponents } from '
|
|
13
|
-
|
|
1
|
+
import { DocsLayout } from './docs-layout'
|
|
2
|
+
import { Navbar } from './ui-base/navbar'
|
|
3
|
+
import { Sidebar } from './ui-base/sidebar'
|
|
4
|
+
import { OnThisPage } from './ui-base/on-this-page'
|
|
5
|
+
import { Head } from './ui-base/head'
|
|
6
|
+
import { Breadcrumbs } from './ui-base/breadcrumbs'
|
|
7
|
+
import { PageNav } from './ui-base/page-nav'
|
|
8
|
+
import { ErrorBoundary } from './ui-base/error-boundary'
|
|
9
|
+
import { CopyMarkdown } from './ui-base/copy-markdown'
|
|
10
|
+
import { useRoutes } from '../hooks/use-routes'
|
|
11
|
+
import { useConfig } from '../app/config-context'
|
|
12
|
+
import { useMdxComponents } from '../app/mdx-components-context'
|
|
14
13
|
import { useLocation } from 'react-router-dom'
|
|
15
|
-
import { getTranslated } from '
|
|
14
|
+
import { getTranslated } from '../utils/i18n'
|
|
16
15
|
|
|
17
16
|
export interface LayoutProps {
|
|
18
17
|
children: React.ReactNode
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
type WrapperProps = SVGProps<SVGSVGElement> & {
|
|
1
|
+
type WrapperProps = React.SVGProps<SVGSVGElement> & {
|
|
4
2
|
size?: number
|
|
5
3
|
}
|
|
6
4
|
|
|
@@ -150,7 +148,6 @@ export const BracketsOrange = (props: WrapperProps) => (
|
|
|
150
148
|
</svg>
|
|
151
149
|
)
|
|
152
150
|
|
|
153
|
-
export default BracketsOrange
|
|
154
151
|
|
|
155
152
|
export const React = (props: WrapperProps) => (
|
|
156
153
|
<svg
|
|
@@ -219,10 +216,44 @@ export const Yaml = (props: WrapperProps) => (
|
|
|
219
216
|
viewBox="0 0 24 24"
|
|
220
217
|
{...wrapperProps(props)}
|
|
221
218
|
>
|
|
222
|
-
<title>
|
|
219
|
+
<title>YAML</title>
|
|
223
220
|
<path
|
|
224
221
|
fill="#A78BFA"
|
|
225
222
|
d="M6.533 5.864h2.755l2.654 5.011h.113l2.654-5.011h2.756l-4.245 7.522V17.5h-2.443v-4.114L6.533 5.864z"
|
|
226
223
|
></path>
|
|
227
224
|
</svg>
|
|
228
225
|
)
|
|
226
|
+
|
|
227
|
+
export const Rust = (props: WrapperProps) => (
|
|
228
|
+
<svg
|
|
229
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
230
|
+
fill="none"
|
|
231
|
+
viewBox="0 0 25 24"
|
|
232
|
+
{...wrapperProps(props)}
|
|
233
|
+
>
|
|
234
|
+
<title>Rust</title>
|
|
235
|
+
<path
|
|
236
|
+
fill="#EA580C"
|
|
237
|
+
fillRule="evenodd"
|
|
238
|
+
d="M12.58 2.136a.287.287 0 00-.488 0l-.526.85a8.974 8.974 0 00-.232.022l-.683-.73a.287.287 0 00-.478.096l-.35.935c-.075.021-.15.044-.224.067l-.812-.583a.287.287 0 00-.45.187l-.162.989a9.088 9.088 0 00-.204.11l-.913-.417a.287.287 0 00-.406.272l.036 1.005a9.099 9.099 0 00-.175.144l-.98-.231a.287.287 0 00-.345.345l.231.98a9.125 9.125 0 00-.144.175L4.27 6.316a.287.287 0 00-.271.406l.416.913a9.036 9.036 0 00-.11.203L3.317 8a.287.287 0 00-.187.45l.584.813a8.953 8.953 0 00-.068.223l-.935.35a.287.287 0 00-.095.479l.73.682a8.966 8.966 0 00-.023.233l-.85.526a.287.287 0 000 .488l.85.526c.007.078.014.156.023.233l-.73.682a.287.287 0 00.095.479l.935.35.068.223-.584.812a.287.287 0 00.187.451l.99.162c.035.068.072.135.109.203l-.416.913a.287.287 0 00.271.406l1.006-.036c.047.059.095.117.143.174l-.23.981a.287.287 0 00.344.345l.981-.23c.057.048.115.095.174.142l-.036 1.006a.287.287 0 00.406.272l.914-.417c.067.038.135.074.203.11l.161.99a.287.287 0 00.451.186l.813-.584c.074.024.148.046.223.068l.35.935a.287.287 0 00.478.095l.683-.73c.077.01.154.017.232.023l.526.85a.287.287 0 00.489 0l.526-.85c.078-.006.155-.014.232-.023l.682.73a.287.287 0 00.479-.095l.35-.935c.075-.022.15-.044.223-.068l.813.584a.287.287 0 00.45-.187l.162-.99a8.77 8.77 0 00.203-.109l.913.417a.287.287 0 00.406-.272l-.035-1.006c.058-.047.116-.094.174-.143l.98.231a.287.287 0 00.346-.345l-.231-.98.143-.175 1.006.036a.287.287 0 00.271-.406l-.416-.913a9.4 9.4 0 00.109-.203l.99-.162a.287.287 0 00.187-.45l-.584-.813a8.43 8.43 0 00.067-.223l.935-.35a.287.287 0 00.096-.479l-.73-.682c.009-.077.016-.155.023-.233l.85-.526a.287.287 0 000-.488l-.85-.526a8.844 8.844 0 00-.023-.233l.73-.682a.287.287 0 00-.096-.479l-.934-.35a9.246 9.246 0 00-.068-.223l.584-.812A.287.287 0 0021.357 8l-.99-.162a8.92 8.92 0 00-.11-.203l.417-.913a.287.287 0 00-.271-.406l-1.006.036a9.178 9.178 0 00-.143-.174l.23-.981a.287.287 0 00-.345-.345l-.98.23a9.43 9.43 0 00-.174-.142l.035-1.006a.287.287 0 00-.405-.272l-.914.417a9.11 9.11 0 00-.203-.11l-.162-.99a.287.287 0 00-.45-.186l-.813.584a9.088 9.088 0 00-.223-.068l-.35-.935a.287.287 0 00-.479-.095l-.682.73a9.062 9.062 0 00-.232-.023l-.526-.85zm-.257 1.62a.592.592 0 01.578.596.595.595 0 11-.578-.595zm1.363.98A7.324 7.324 0 0118.7 8.309l-.702 1.585a.547.547 0 00.275.717l1.352.6c.041.422.047.847.015 1.27h-.752c-.075 0-.106.05-.106.123v.344c0 .812-.457.99-.859 1.034-.383.044-.806-.161-.86-.394-.22-1.24-.583-1.526-1.152-1.975l-.041-.033c.736-.467 1.502-1.158 1.502-2.08 0-.998-.683-1.625-1.148-1.934-.655-.43-1.379-.516-1.574-.516H6.88a7.324 7.324 0 014.098-2.312l.916.96a.54.54 0 00.766.018l1.026-.978zm-8.46 4.407a.595.595 0 11-.034 1.19.595.595 0 01.034-1.19zm14.192.026a.595.595 0 11-.035 1.19.595.595 0 01.035-1.19zm-13.07.096h1.037v4.678H5.291a7.324 7.324 0 01-.237-2.797l1.282-.57a.542.542 0 00.276-.716l-.264-.595zm4.33.05h2.47c.128 0 .901.147.901.727 0 .48-.593.653-1.081.653h-2.293l.002-1.38zm0 3.36h1.892c.172 0 .924.05 1.164 1.011.026.104.064.291.107.503.078.389.174.861.247 1.06.113.345.57 1.034 1.058 1.034h3.089c-.207.277-.433.54-.677.785l-1.258-.27a.544.544 0 00-.645.417l-.298 1.394a7.323 7.323 0 01-6.108-.03l-.298-1.392a.542.542 0 00-.643-.418l-1.23.264a7.32 7.32 0 01-.636-.75h5.984c.067 0 .113-.011.113-.074v-2.117c0-.061-.046-.075-.113-.075h-1.75l.001-1.341zm-2.763 4.848a.595.595 0 11-.034 1.19.595.595 0 01.034-1.19zm8.814.027a.596.596 0 11-.035 1.19.596.596 0 01.035-1.19z"
|
|
239
|
+
clipRule="evenodd"
|
|
240
|
+
></path>
|
|
241
|
+
</svg>
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
export const BracketsRed = (props: WrapperProps) => (
|
|
246
|
+
<svg
|
|
247
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
248
|
+
fill="none"
|
|
249
|
+
viewBox="0 0 24 24"
|
|
250
|
+
{...wrapperProps(props)}
|
|
251
|
+
>
|
|
252
|
+
<title>Rust</title>
|
|
253
|
+
<path
|
|
254
|
+
fill="#F87171"
|
|
255
|
+
d="M4.778 6.667A2.667 2.667 0 017.444 4a.889.889 0 010 1.778.889.889 0 00-.888.889v3.5c0 .701-.273 1.35-.73 1.833.457.483.73 1.132.73 1.832v3.501c0 .491.398.89.888.89a.889.889 0 010 1.777 2.667 2.667 0 01-2.666-2.667v-3.5a.889.889 0 00-.674-.863l-.43-.108a.889.889 0 010-1.724l.43-.108a.889.889 0 00.674-.862V6.667zm14.222 0A2.667 2.667 0 0016.333 4a.889.889 0 000 1.778c.491 0 .89.398.89.889v3.5c0 .701.272 1.35.729 1.833a2.664 2.664 0 00-.73 1.832v3.501a.889.889 0 01-.889.89.889.889 0 000 1.777A2.667 2.667 0 0019 17.333v-3.5c0-.408.278-.764.673-.863l.431-.108a.889.889 0 000-1.724l-.43-.108a.889.889 0 01-.674-.862V6.667z"
|
|
256
|
+
></path>
|
|
257
|
+
</svg>
|
|
258
|
+
);
|
|
259
|
+
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
Zap,
|
|
8
8
|
Flame,
|
|
9
9
|
} from 'lucide-react'
|
|
10
|
-
import { cn } from '
|
|
10
|
+
import { cn } from '../../utils/cn'
|
|
11
11
|
import { cva } from 'class-variance-authority'
|
|
12
12
|
import type { VariantProps } from 'class-variance-authority'
|
|
13
13
|
|
|
@@ -21,26 +21,17 @@ const ICON_MAP: Record<string, React.ReactNode> = {
|
|
|
21
21
|
caution: <Zap size={18} />,
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const LABEL_MAP: Record<string, string> = {
|
|
25
|
-
note: 'Note',
|
|
26
|
-
tip: 'Tip',
|
|
27
|
-
info: 'Info',
|
|
28
|
-
warning: 'Warning',
|
|
29
|
-
danger: 'Danger',
|
|
30
|
-
important: 'Important',
|
|
31
|
-
caution: 'Caution',
|
|
32
|
-
}
|
|
33
24
|
|
|
34
|
-
const admonitionVariants = cva('py-4 px-4 rounded-lg', {
|
|
25
|
+
const admonitionVariants = cva('py-4 px-4 rounded-lg flex items-center gap-3 border-[1px] flex-row', {
|
|
35
26
|
variants: {
|
|
36
27
|
type: {
|
|
37
|
-
note: 'border-primary-
|
|
38
|
-
tip: 'border-emerald-
|
|
39
|
-
info: 'border-sky-
|
|
40
|
-
warning: 'border-amber-
|
|
41
|
-
danger: 'border-red-
|
|
42
|
-
important: 'border-orange-
|
|
43
|
-
caution: 'border-yellow-
|
|
28
|
+
note: 'border-primary-200 dark:border-primary-800 bg-primary-500/5 text-primary-400',
|
|
29
|
+
tip: 'border-emerald-200 dark:border-emerald-800 bg-emerald-500/5 text-emerald-500',
|
|
30
|
+
info: 'border-sky-200 dark:border-sky-800 bg-sky-500/5 text-sky-500',
|
|
31
|
+
warning: 'border-amber-200 dark:border-amber-800 bg-amber-500/5 text-amber-500',
|
|
32
|
+
danger: 'border-red-200 dark:border-red-800/70 bg-red-500/5 text-red-500',
|
|
33
|
+
important: 'border-orange-200 dark:border-orange-800/70 bg-orange-500/5 text-orange-500',
|
|
34
|
+
caution: 'border-yellow-200 dark:border-yellow-800/70 bg-yellow-500/5 text-yellow-500',
|
|
44
35
|
},
|
|
45
36
|
},
|
|
46
37
|
defaultVariants: {
|
|
@@ -51,7 +42,7 @@ type AdmonitionVariants = VariantProps<typeof admonitionVariants>
|
|
|
51
42
|
|
|
52
43
|
export interface AdmonitionProps
|
|
53
44
|
extends React.HTMLAttributes<HTMLDivElement>,
|
|
54
|
-
|
|
45
|
+
AdmonitionVariants {
|
|
55
46
|
title?: string
|
|
56
47
|
children: React.ReactNode
|
|
57
48
|
}
|
|
@@ -69,14 +60,7 @@ export function Admonition({
|
|
|
69
60
|
role={type === 'warning' || type === 'danger' ? 'alert' : 'note'}
|
|
70
61
|
{...rest}
|
|
71
62
|
>
|
|
72
|
-
|
|
73
|
-
<span className={cn('shrink-0', admonitionVariants({ type }))}>
|
|
74
|
-
{ICON_MAP[type as keyof typeof ICON_MAP]}
|
|
75
|
-
</span>
|
|
76
|
-
<span className="text-sm font-bold tracking-tight text-text-main">
|
|
77
|
-
{title || LABEL_MAP[type as keyof typeof LABEL_MAP]}
|
|
78
|
-
</span>
|
|
79
|
-
</div>
|
|
63
|
+
{ICON_MAP[type as keyof typeof ICON_MAP]}
|
|
80
64
|
<div className="text-sm text-text-muted leading-relaxed [&>p]:m-0 [&>p]:mb-2 [&>p:last-child]:mb-0">
|
|
81
65
|
{children}
|
|
82
66
|
</div>
|