boltdocs 1.10.2 → 2.0.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.
Files changed (250) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/dist/cache-7G6D532T.mjs +1 -0
  4. package/dist/chunk-A4HQPEPU.mjs +1 -0
  5. package/dist/chunk-BA5NH5HU.mjs +1 -0
  6. package/dist/chunk-BQCD3DWG.mjs +1 -0
  7. package/dist/chunk-H63UMKYF.mjs +1 -0
  8. package/dist/chunk-IWHRQHS7.mjs +1 -0
  9. package/dist/chunk-JZXLCA2E.mjs +1 -0
  10. package/dist/chunk-MFU7Q6WF.mjs +1 -0
  11. package/dist/chunk-QYPNX5UN.mjs +1 -0
  12. package/dist/chunk-XEAPSFMB.mjs +1 -0
  13. package/dist/client/components/mdx/index.d.mts +209 -0
  14. package/dist/client/components/mdx/index.d.ts +209 -0
  15. package/dist/client/components/mdx/index.js +1 -0
  16. package/dist/client/components/mdx/index.mjs +1 -0
  17. package/dist/client/hooks/index.d.mts +133 -0
  18. package/dist/client/hooks/index.d.ts +133 -0
  19. package/dist/client/hooks/index.js +1 -0
  20. package/dist/client/hooks/index.mjs +1 -0
  21. package/dist/client/index.d.mts +138 -298
  22. package/dist/client/index.d.ts +138 -298
  23. package/dist/client/index.js +1 -3630
  24. package/dist/client/index.mjs +1 -697
  25. package/dist/client/ssr.d.mts +7 -3
  26. package/dist/client/ssr.d.ts +7 -3
  27. package/dist/client/ssr.js +1 -2928
  28. package/dist/client/ssr.mjs +1 -33
  29. package/dist/{config-BsFQ-ErD.d.ts → config-CX4l-ZNp.d.mts} +42 -35
  30. package/dist/{config-BsFQ-ErD.d.mts → config-CX4l-ZNp.d.ts} +42 -35
  31. package/dist/node/index.d.mts +2 -4
  32. package/dist/node/index.d.ts +2 -4
  33. package/dist/node/index.js +31 -1161
  34. package/dist/node/index.mjs +31 -736
  35. package/dist/search-dialog-EB3N4TYM.mjs +1 -0
  36. package/dist/types-BuZWFT7r.d.ts +159 -0
  37. package/dist/types-CvT-SGbK.d.mts +159 -0
  38. package/dist/use-routes-5bAtAAYX.d.mts +30 -0
  39. package/dist/use-routes-BefRXY3v.d.ts +30 -0
  40. package/package.json +34 -12
  41. package/src/client/app/config-context.tsx +18 -0
  42. package/src/client/app/docs-layout.tsx +14 -0
  43. package/src/client/app/index.tsx +137 -262
  44. package/src/client/app/mdx-component.tsx +52 -0
  45. package/src/client/app/mdx-components-context.tsx +23 -0
  46. package/src/client/app/mdx-page.tsx +20 -0
  47. package/src/client/app/preload.tsx +38 -30
  48. package/src/client/app/router.tsx +30 -0
  49. package/src/client/app/scroll-handler.tsx +40 -0
  50. package/src/client/app/theme-context.tsx +75 -0
  51. package/src/client/components/default-layout.tsx +80 -0
  52. package/src/client/components/docs-layout.tsx +105 -0
  53. package/src/client/components/icons-dev.tsx +74 -0
  54. package/src/client/components/mdx/admonition.tsx +107 -0
  55. package/src/client/components/mdx/badge.tsx +41 -0
  56. package/src/client/components/mdx/button.tsx +35 -0
  57. package/src/client/components/mdx/card.tsx +124 -0
  58. package/src/client/components/mdx/code-block.tsx +119 -0
  59. package/src/client/components/mdx/component-preview.tsx +47 -0
  60. package/src/client/components/mdx/component-props.tsx +83 -0
  61. package/src/client/components/mdx/field.tsx +66 -0
  62. package/src/client/components/mdx/file-tree.tsx +287 -0
  63. package/src/client/components/mdx/hooks/use-code-block.ts +56 -0
  64. package/src/client/components/mdx/hooks/use-component-preview.ts +16 -0
  65. package/src/client/components/mdx/hooks/useTable.ts +74 -0
  66. package/src/client/components/mdx/hooks/useTabs.ts +68 -0
  67. package/src/client/components/mdx/image.tsx +23 -0
  68. package/src/client/components/mdx/index.ts +53 -0
  69. package/src/client/components/mdx/link.tsx +38 -0
  70. package/src/client/components/mdx/list.tsx +192 -0
  71. package/src/client/components/mdx/table.tsx +156 -0
  72. package/src/client/components/mdx/tabs.tsx +135 -0
  73. package/src/client/components/mdx/video.tsx +68 -0
  74. package/src/client/components/primitives/breadcrumbs.tsx +79 -0
  75. package/src/client/components/primitives/button-group.tsx +54 -0
  76. package/src/client/components/primitives/button.tsx +145 -0
  77. package/src/client/components/primitives/helpers/observer.ts +120 -0
  78. package/src/client/components/primitives/index.ts +17 -0
  79. package/src/client/components/primitives/link.tsx +122 -0
  80. package/src/client/components/primitives/menu.tsx +159 -0
  81. package/src/client/components/primitives/navbar.tsx +359 -0
  82. package/src/client/components/primitives/navigation-menu.tsx +116 -0
  83. package/src/client/components/primitives/on-this-page.tsx +461 -0
  84. package/src/client/components/primitives/page-nav.tsx +87 -0
  85. package/src/client/components/primitives/popover.tsx +47 -0
  86. package/src/client/components/primitives/search-dialog.tsx +183 -0
  87. package/src/client/components/primitives/sidebar.tsx +154 -0
  88. package/src/client/components/primitives/tabs.tsx +90 -0
  89. package/src/client/components/primitives/tooltip.tsx +83 -0
  90. package/src/client/components/primitives/types.ts +11 -0
  91. package/src/client/components/ui-base/breadcrumbs.tsx +42 -0
  92. package/src/client/components/ui-base/copy-markdown.tsx +112 -0
  93. package/src/client/components/ui-base/error-boundary.tsx +52 -0
  94. package/src/client/components/ui-base/github-stars.tsx +27 -0
  95. package/src/client/components/ui-base/head.tsx +69 -0
  96. package/src/client/components/ui-base/loading.tsx +87 -0
  97. package/src/client/components/ui-base/navbar.tsx +138 -0
  98. package/src/client/components/ui-base/not-found.tsx +24 -0
  99. package/src/client/components/ui-base/on-this-page.tsx +152 -0
  100. package/src/client/components/ui-base/page-nav.tsx +39 -0
  101. package/src/client/components/ui-base/powered-by.tsx +19 -0
  102. package/src/client/components/ui-base/progress-bar.tsx +67 -0
  103. package/src/client/components/ui-base/search-dialog.tsx +82 -0
  104. package/src/client/components/ui-base/sidebar.tsx +104 -0
  105. package/src/client/components/ui-base/tabs.tsx +65 -0
  106. package/src/client/components/ui-base/theme-toggle.tsx +32 -0
  107. package/src/client/hooks/index.ts +12 -0
  108. package/src/client/hooks/use-breadcrumbs.ts +22 -0
  109. package/src/client/hooks/use-i18n.ts +84 -0
  110. package/src/client/hooks/use-localized-to.ts +95 -0
  111. package/src/client/hooks/use-location.ts +5 -0
  112. package/src/client/hooks/use-navbar.ts +60 -0
  113. package/src/client/hooks/use-onthispage.ts +23 -0
  114. package/src/client/hooks/use-page-nav.ts +22 -0
  115. package/src/client/hooks/use-routes.ts +72 -0
  116. package/src/client/hooks/use-search.ts +71 -0
  117. package/src/client/hooks/use-sidebar.ts +49 -0
  118. package/src/client/hooks/use-tabs.ts +43 -0
  119. package/src/client/hooks/use-version.ts +78 -0
  120. package/src/client/index.ts +55 -17
  121. package/src/client/integrations/codesandbox.ts +179 -0
  122. package/src/client/ssr.tsx +27 -16
  123. package/src/client/theme/neutral.css +360 -0
  124. package/src/client/types.ts +131 -27
  125. package/src/client/utils/cn.ts +6 -0
  126. package/src/client/utils/copy-clipboard.ts +22 -0
  127. package/src/client/utils/get-base-file-path.ts +21 -0
  128. package/src/client/utils/github.ts +121 -0
  129. package/src/client/utils/use-on-change.ts +15 -0
  130. package/src/client/virtual.d.ts +24 -0
  131. package/src/node/cache.ts +156 -156
  132. package/src/node/config.ts +159 -103
  133. package/src/node/index.ts +13 -13
  134. package/src/node/mdx.ts +213 -61
  135. package/src/node/plugin/entry.ts +29 -18
  136. package/src/node/plugin/html.ts +11 -11
  137. package/src/node/plugin/index.ts +161 -84
  138. package/src/node/plugin/types.ts +2 -4
  139. package/src/node/routes/cache.ts +6 -6
  140. package/src/node/routes/index.ts +206 -113
  141. package/src/node/routes/parser.ts +102 -82
  142. package/src/node/routes/sorter.ts +15 -15
  143. package/src/node/routes/types.ts +24 -24
  144. package/src/node/ssg/index.ts +73 -47
  145. package/src/node/ssg/meta.ts +4 -4
  146. package/src/node/ssg/options.ts +5 -5
  147. package/src/node/ssg/sitemap.ts +14 -14
  148. package/src/node/utils.ts +54 -31
  149. package/tsconfig.json +25 -20
  150. package/tsup.config.ts +23 -14
  151. package/dist/PackageManagerTabs-NVT7G625.mjs +0 -99
  152. package/dist/SearchDialog-AGVF6JBO.mjs +0 -194
  153. package/dist/SearchDialog-YPDOM7Q6.css +0 -2847
  154. package/dist/Video-KNTY5BNO.mjs +0 -6
  155. package/dist/cache-KNL5B4EE.mjs +0 -12
  156. package/dist/chunk-7SFUJWTB.mjs +0 -211
  157. package/dist/chunk-FFBNU6IJ.mjs +0 -386
  158. package/dist/chunk-FMTOYQLO.mjs +0 -37
  159. package/dist/chunk-TKLQWU7H.mjs +0 -1920
  160. package/dist/chunk-Z7JHYNAS.mjs +0 -57
  161. package/dist/client/index.css +0 -2847
  162. package/dist/client/ssr.css +0 -2847
  163. package/dist/types-Dj-bfnC3.d.mts +0 -74
  164. package/dist/types-Dj-bfnC3.d.ts +0 -74
  165. package/src/client/theme/components/CodeBlock/CodeBlock.tsx +0 -61
  166. package/src/client/theme/components/CodeBlock/index.ts +0 -1
  167. package/src/client/theme/components/PackageManagerTabs/PackageManagerTabs.tsx +0 -131
  168. package/src/client/theme/components/PackageManagerTabs/index.ts +0 -1
  169. package/src/client/theme/components/PackageManagerTabs/pkg-tabs.css +0 -64
  170. package/src/client/theme/components/Playground/Playground.tsx +0 -180
  171. package/src/client/theme/components/Playground/index.ts +0 -1
  172. package/src/client/theme/components/Playground/playground.css +0 -238
  173. package/src/client/theme/components/Video/Video.tsx +0 -84
  174. package/src/client/theme/components/Video/index.ts +0 -1
  175. package/src/client/theme/components/Video/video.css +0 -41
  176. package/src/client/theme/components/mdx/Admonition.tsx +0 -80
  177. package/src/client/theme/components/mdx/Badge.tsx +0 -31
  178. package/src/client/theme/components/mdx/Button.tsx +0 -50
  179. package/src/client/theme/components/mdx/Card.tsx +0 -80
  180. package/src/client/theme/components/mdx/Field.tsx +0 -60
  181. package/src/client/theme/components/mdx/FileTree.tsx +0 -229
  182. package/src/client/theme/components/mdx/List.tsx +0 -57
  183. package/src/client/theme/components/mdx/Table.tsx +0 -151
  184. package/src/client/theme/components/mdx/Tabs.tsx +0 -123
  185. package/src/client/theme/components/mdx/index.ts +0 -27
  186. package/src/client/theme/components/mdx/mdx-components.css +0 -764
  187. package/src/client/theme/icons/bun.tsx +0 -62
  188. package/src/client/theme/icons/deno.tsx +0 -20
  189. package/src/client/theme/icons/discord.tsx +0 -12
  190. package/src/client/theme/icons/github.tsx +0 -15
  191. package/src/client/theme/icons/npm.tsx +0 -13
  192. package/src/client/theme/icons/pnpm.tsx +0 -72
  193. package/src/client/theme/icons/twitter.tsx +0 -12
  194. package/src/client/theme/styles/markdown.css +0 -394
  195. package/src/client/theme/styles/variables.css +0 -175
  196. package/src/client/theme/styles.css +0 -39
  197. package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +0 -68
  198. package/src/client/theme/ui/Breadcrumbs/index.ts +0 -1
  199. package/src/client/theme/ui/CopyMarkdown/CopyMarkdown.tsx +0 -82
  200. package/src/client/theme/ui/CopyMarkdown/copy-markdown.css +0 -112
  201. package/src/client/theme/ui/CopyMarkdown/index.ts +0 -1
  202. package/src/client/theme/ui/ErrorBoundary/ErrorBoundary.tsx +0 -50
  203. package/src/client/theme/ui/ErrorBoundary/error-boundary.css +0 -55
  204. package/src/client/theme/ui/ErrorBoundary/index.ts +0 -1
  205. package/src/client/theme/ui/Footer/footer.css +0 -32
  206. package/src/client/theme/ui/Head/Head.tsx +0 -69
  207. package/src/client/theme/ui/Head/index.ts +0 -1
  208. package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +0 -125
  209. package/src/client/theme/ui/LanguageSwitcher/index.ts +0 -1
  210. package/src/client/theme/ui/LanguageSwitcher/language-switcher.css +0 -98
  211. package/src/client/theme/ui/Layout/Layout.tsx +0 -203
  212. package/src/client/theme/ui/Layout/base.css +0 -106
  213. package/src/client/theme/ui/Layout/index.ts +0 -2
  214. package/src/client/theme/ui/Layout/pagination.css +0 -72
  215. package/src/client/theme/ui/Layout/responsive.css +0 -47
  216. package/src/client/theme/ui/Link/Link.tsx +0 -392
  217. package/src/client/theme/ui/Link/LinkPreview.tsx +0 -59
  218. package/src/client/theme/ui/Link/index.ts +0 -2
  219. package/src/client/theme/ui/Link/link-preview.css +0 -48
  220. package/src/client/theme/ui/Loading/Loading.tsx +0 -10
  221. package/src/client/theme/ui/Loading/index.ts +0 -1
  222. package/src/client/theme/ui/Loading/loading.css +0 -30
  223. package/src/client/theme/ui/Navbar/GithubStars.tsx +0 -27
  224. package/src/client/theme/ui/Navbar/Navbar.tsx +0 -193
  225. package/src/client/theme/ui/Navbar/Tabs.tsx +0 -99
  226. package/src/client/theme/ui/Navbar/index.ts +0 -2
  227. package/src/client/theme/ui/Navbar/navbar.css +0 -347
  228. package/src/client/theme/ui/NotFound/NotFound.tsx +0 -19
  229. package/src/client/theme/ui/NotFound/index.ts +0 -1
  230. package/src/client/theme/ui/NotFound/not-found.css +0 -64
  231. package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +0 -244
  232. package/src/client/theme/ui/OnThisPage/index.ts +0 -1
  233. package/src/client/theme/ui/OnThisPage/toc.css +0 -152
  234. package/src/client/theme/ui/PoweredBy/PoweredBy.tsx +0 -18
  235. package/src/client/theme/ui/PoweredBy/index.ts +0 -1
  236. package/src/client/theme/ui/PoweredBy/powered-by.css +0 -76
  237. package/src/client/theme/ui/ProgressBar/ProgressBar.css +0 -17
  238. package/src/client/theme/ui/ProgressBar/ProgressBar.tsx +0 -51
  239. package/src/client/theme/ui/ProgressBar/index.ts +0 -1
  240. package/src/client/theme/ui/SearchDialog/SearchDialog.tsx +0 -209
  241. package/src/client/theme/ui/SearchDialog/index.ts +0 -1
  242. package/src/client/theme/ui/SearchDialog/search.css +0 -152
  243. package/src/client/theme/ui/Sidebar/Sidebar.tsx +0 -244
  244. package/src/client/theme/ui/Sidebar/index.ts +0 -1
  245. package/src/client/theme/ui/Sidebar/sidebar.css +0 -230
  246. package/src/client/theme/ui/ThemeToggle/ThemeToggle.tsx +0 -69
  247. package/src/client/theme/ui/ThemeToggle/index.ts +0 -1
  248. package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +0 -136
  249. package/src/client/theme/ui/VersionSwitcher/index.ts +0 -1
  250. package/src/client/utils.ts +0 -49
@@ -0,0 +1,40 @@
1
+ import { useLayoutEffect } from 'react'
2
+ import { useLocation } from 'react-router-dom'
3
+
4
+ /**
5
+ * Handles scroll restoration and hash scrolling on navigation.
6
+ * It ensures the page scrolls to top on pathname changes,
7
+ * or specifically to an anchor element if a hash is present.
8
+ */
9
+ export function ScrollHandler() {
10
+ const { pathname, hash } = useLocation()
11
+
12
+ // biome-ignore lint/correctness/useExhaustiveDependencies: pathname is used as a trigger for scroll-to-top on navigation
13
+ useLayoutEffect(() => {
14
+ const container = document.querySelector('.boltdocs-content')
15
+ if (!container) return
16
+
17
+ if (hash) {
18
+ const id = hash.replace('#', '')
19
+ const element = document.getElementById(id)
20
+ if (element) {
21
+ const offset = 80
22
+ const containerRect = container.getBoundingClientRect().top
23
+ const elementRect = element.getBoundingClientRect().top
24
+ const elementPosition = elementRect - containerRect
25
+ const offsetPosition = elementPosition - offset + container.scrollTop
26
+
27
+ container.scrollTo({
28
+ top: offsetPosition,
29
+ behavior: 'smooth',
30
+ })
31
+ return
32
+ }
33
+ }
34
+
35
+ // Scroll to top on navigation when no hash is specified
36
+ container.scrollTo(0, 0)
37
+ }, [pathname, hash])
38
+
39
+ return null
40
+ }
@@ -0,0 +1,75 @@
1
+ import { createContext, use, useEffect, useState } from 'react'
2
+
3
+ type Theme = 'light' | 'dark'
4
+
5
+ interface ThemeContextType {
6
+ theme: Theme
7
+ toggleTheme: () => void
8
+ setTheme: (theme: Theme) => void
9
+ }
10
+
11
+ const ThemeContext = createContext<ThemeContextType | undefined>(undefined)
12
+
13
+ export function ThemeProvider({ children }: { children: React.ReactNode }) {
14
+ const [theme, setThemeState] = useState<Theme>('dark')
15
+ const [mounted, setMounted] = useState(false)
16
+
17
+ useEffect(() => {
18
+ setMounted(true)
19
+ const stored = localStorage.getItem('boltdocs-theme')
20
+ if (stored === 'light' || stored === 'dark') {
21
+ setThemeState(stored as Theme)
22
+ } else {
23
+ const prefersDark = window.matchMedia(
24
+ '(prefers-color-scheme: dark)',
25
+ ).matches
26
+ setThemeState(prefersDark ? 'dark' : 'light')
27
+ }
28
+
29
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
30
+ const handleChange = (e: MediaQueryListEvent) => {
31
+ if (!localStorage.getItem('boltdocs-theme')) {
32
+ setThemeState(e.matches ? 'dark' : 'light')
33
+ }
34
+ }
35
+ mediaQuery.addEventListener('change', handleChange)
36
+ return () => mediaQuery.removeEventListener('change', handleChange)
37
+ }, [])
38
+
39
+ useEffect(() => {
40
+ if (!mounted) return
41
+ const root = document.documentElement
42
+ if (theme === 'light') {
43
+ root.classList.add('theme-light')
44
+ root.dataset.theme = 'light'
45
+ } else {
46
+ root.classList.remove('theme-light')
47
+ root.dataset.theme = 'dark'
48
+ }
49
+ }, [theme, mounted])
50
+
51
+ const toggleTheme = () => {
52
+ const newTheme = theme === 'dark' ? 'light' : 'dark'
53
+ setThemeState(newTheme)
54
+ localStorage.setItem('boltdocs-theme', newTheme)
55
+ }
56
+
57
+ const setTheme = (newTheme: Theme) => {
58
+ setThemeState(newTheme)
59
+ localStorage.setItem('boltdocs-theme', newTheme)
60
+ }
61
+
62
+ return (
63
+ <ThemeContext.Provider value={{ theme, toggleTheme, setTheme }}>
64
+ {children}
65
+ </ThemeContext.Provider>
66
+ )
67
+ }
68
+
69
+ export function useTheme() {
70
+ const context = use(ThemeContext)
71
+ if (context === undefined) {
72
+ throw new Error('useTheme must be used within a ThemeProvider')
73
+ }
74
+ return context
75
+ }
@@ -0,0 +1,80 @@
1
+ import { DocsLayout } from '@components/docs-layout'
2
+ import { Navbar } from '@components/ui-base/navbar'
3
+ import { Sidebar } from '@components/ui-base/sidebar'
4
+ import { OnThisPage } from '@components/ui-base/on-this-page'
5
+ import { Head } from '@components/ui-base/head'
6
+ import { Breadcrumbs } from '@components/ui-base/breadcrumbs'
7
+ import { PageNav } from '@components/ui-base/page-nav'
8
+ import { ProgressBar } from '@components/ui-base/progress-bar'
9
+ import { ErrorBoundary } from '@components/ui-base/error-boundary'
10
+ import { CopyMarkdown } from '@components/ui-base/copy-markdown'
11
+ import { useRoutes } from '@client/hooks/use-routes'
12
+ import { useConfig } from '@client/app/config-context'
13
+ import { useMdxComponents } from '@client/app/mdx-components-context'
14
+
15
+ import { useLocation } from 'react-router-dom'
16
+
17
+ export interface LayoutProps {
18
+ children: React.ReactNode
19
+ }
20
+
21
+ /**
22
+ * The built-in default layout for Boltdocs.
23
+ * Users who create their own `layout.tsx` can import the same building blocks
24
+ * and rearrange, wrap, or replace any section.
25
+ */
26
+ export function DefaultLayout({ children }: LayoutProps) {
27
+ const { routes: filteredRoutes, allRoutes, currentRoute } = useRoutes()
28
+ const { pathname } = useLocation()
29
+ const config = useConfig()
30
+ const mdxComponents = useMdxComponents()
31
+ const CopyMarkdownComp = (mdxComponents.CopyMarkdown as any) || CopyMarkdown
32
+
33
+ const isHome = pathname === '/' || pathname === ''
34
+
35
+ return (
36
+ <DocsLayout>
37
+ <ProgressBar />
38
+ <Head
39
+ siteTitle={config.themeConfig?.title || 'Boltdocs'}
40
+ siteDescription={config.themeConfig?.description || ''}
41
+ routes={allRoutes}
42
+ />
43
+ <Navbar />
44
+
45
+ <DocsLayout.Body>
46
+ {!isHome && <Sidebar routes={filteredRoutes} config={config} />}
47
+
48
+ <DocsLayout.Content>
49
+ {!isHome && (
50
+ <DocsLayout.ContentHeader>
51
+ <Breadcrumbs />
52
+ <CopyMarkdownComp
53
+ mdxRaw={currentRoute?._rawContent}
54
+ route={currentRoute}
55
+ config={config.themeConfig?.copyMarkdown}
56
+ />
57
+ </DocsLayout.ContentHeader>
58
+ )}
59
+
60
+ <ErrorBoundary>{children}</ErrorBoundary>
61
+
62
+ {!isHome && (
63
+ <DocsLayout.ContentFooter>
64
+ <PageNav />
65
+ </DocsLayout.ContentFooter>
66
+ )}
67
+ </DocsLayout.Content>
68
+
69
+ {!isHome && (
70
+ <OnThisPage
71
+ headings={currentRoute?.headings}
72
+ editLink={config.themeConfig?.editLink}
73
+ communityHelp={config.themeConfig?.communityHelp}
74
+ filePath={currentRoute?.filePath}
75
+ />
76
+ )}
77
+ </DocsLayout.Body>
78
+ </DocsLayout>
79
+ )
80
+ }
@@ -0,0 +1,105 @@
1
+ import type React from 'react'
2
+ import { cn } from '@client/utils/cn'
3
+
4
+ /**
5
+ * Props shared by all layout slot components.
6
+ */
7
+ interface SlotProps {
8
+ children?: React.ReactNode
9
+ className?: string
10
+ style?: React.CSSProperties
11
+ }
12
+
13
+ /**
14
+ * Root layout shell. Renders a full-height flex column.
15
+ *
16
+ * Usage:
17
+ * ```tsx
18
+ * <DocsLayout>
19
+ * <Navbar />
20
+ * <DocsLayout.Body>...</DocsLayout.Body>
21
+ * </DocsLayout>
22
+ * ```
23
+ */
24
+ function DocsLayoutRoot({ children, className, style }: SlotProps) {
25
+ return (
26
+ <div
27
+ className={cn(
28
+ 'h-screen flex flex-col overflow-hidden bg-bg-main text-text-main',
29
+ className,
30
+ )}
31
+ style={style}
32
+ >
33
+ {children}
34
+ </div>
35
+ )
36
+ }
37
+
38
+ /**
39
+ * Horizontal flex container for sidebar + content + toc.
40
+ */
41
+ function Body({ children, className, style }: SlotProps) {
42
+ return (
43
+ <div
44
+ className={cn(
45
+ 'mx-auto flex flex-1 w-full max-w-(--breakpoint-3xl) bg-bg-main overflow-hidden',
46
+ className,
47
+ )}
48
+ style={style}
49
+ >
50
+ {children}
51
+ </div>
52
+ )
53
+ }
54
+
55
+ /**
56
+ * Main scrollable content area.
57
+ */
58
+ function Content({ children, className, style }: SlotProps) {
59
+ return (
60
+ <main
61
+ className={cn(
62
+ 'boltdocs-content flex-1 min-w-0 overflow-y-auto',
63
+ className,
64
+ )}
65
+ style={style}
66
+ >
67
+ <div className="boltdocs-page mx-auto max-w-content-max pt-4 pb-20 px-4 sm:px-8">
68
+ {children}
69
+ </div>
70
+ </main>
71
+ )
72
+ }
73
+
74
+ /**
75
+ * Content header row (breadcrumbs + copy markdown).
76
+ */
77
+ function ContentHeader({ children, className, style }: SlotProps) {
78
+ return (
79
+ <div
80
+ className={cn('flex items-center justify-between mb-10', className)}
81
+ style={style}
82
+ >
83
+ {children}
84
+ </div>
85
+ )
86
+ }
87
+
88
+ /**
89
+ * Footer area inside the content section (page nav).
90
+ */
91
+ function ContentFooter({ children, className, style }: SlotProps) {
92
+ return (
93
+ <div className={cn('mt-20', className)} style={style}>
94
+ {children}
95
+ </div>
96
+ )
97
+ }
98
+
99
+ // Attach sub-components to the root
100
+ export const DocsLayout = Object.assign(DocsLayoutRoot, {
101
+ Body,
102
+ Content,
103
+ ContentHeader,
104
+ ContentFooter,
105
+ })
@@ -0,0 +1,74 @@
1
+ import type { SVGProps } from 'react'
2
+
3
+ type WrapperProps = SVGProps<SVGSVGElement> & {
4
+ size?: number
5
+ }
6
+
7
+ function wrapperProps(props: WrapperProps) {
8
+ const { size = 20, ...rest } = props
9
+ return {
10
+ ...rest,
11
+ width: size,
12
+ height: size,
13
+ }
14
+ }
15
+
16
+ export const Github = (props: WrapperProps) => (
17
+ <svg
18
+ xmlns="http://www.w3.org/2000/svg"
19
+ viewBox="0 0 24 24"
20
+ fill="currentColor"
21
+ {...wrapperProps(props)}
22
+ >
23
+ <title>{'GitHub'}</title>
24
+ <path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
25
+ </svg>
26
+ )
27
+
28
+ export const Discord = (props: WrapperProps) => (
29
+ <svg
30
+ xmlns="http://www.w3.org/2000/svg"
31
+ viewBox="0 0 24 24"
32
+ fill="currentColor"
33
+ {...wrapperProps(props)}
34
+ >
35
+ <title>{'Discord'}</title>
36
+ <path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418Z" />
37
+ </svg>
38
+ )
39
+
40
+ export const XSocial = (props: WrapperProps) => (
41
+ <svg
42
+ xmlns="http://www.w3.org/2000/svg"
43
+ viewBox="0 0 24 24"
44
+ fill="currentColor"
45
+ {...wrapperProps(props)}
46
+ >
47
+ <title>{'X'}</title>
48
+ <path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z" />
49
+ </svg>
50
+ )
51
+
52
+ export const CodeSandbox = (props: WrapperProps) => (
53
+ <svg
54
+ xmlns="http://www.w3.org/2000/svg"
55
+ viewBox="0 0 24 24"
56
+ fill="currentColor"
57
+ {...wrapperProps(props)}
58
+ >
59
+ <title>{'CodeSandbox'}</title>
60
+ <path d="M0 24h24V0H0v2.455h21.546v19.09H2.454V0H0Z" />
61
+ </svg>
62
+ )
63
+
64
+ export const Bluesky = (props: WrapperProps) => (
65
+ <svg
66
+ xmlns="http://www.w3.org/2000/svg"
67
+ viewBox="0 0 24 24"
68
+ fill="currentColor"
69
+ {...wrapperProps(props)}
70
+ >
71
+ <title>{'Bluesky'}</title>
72
+ <path d="M5.202 2.857C7.954 4.922 10.913 9.11 12 11.358c1.087-2.247 4.046-6.436 6.798-8.501C20.783 1.366 24 .213 24 3.883c0 .732-.42 6.156-.667 7.037-.856 3.061-3.978 3.842-6.755 3.37 4.854.826 6.089 3.562 3.422 6.299-5.065 5.196-7.28-1.304-7.847-2.97-.104-.305-.152-.448-.153-.327 0-.121-.05.022-.153.327-.568 1.666-2.782 8.166-7.847 2.97-2.667-2.737-1.432-5.473 3.422-6.3-2.777.473-5.899-.308-6.755-3.369C.42 10.04 0 4.615 0 3.883c0-3.67 3.217-2.517 5.202-1.026" />
73
+ </svg>
74
+ )
@@ -0,0 +1,107 @@
1
+ import {
2
+ Info,
3
+ Lightbulb,
4
+ AlertTriangle,
5
+ ShieldAlert,
6
+ Bookmark,
7
+ Zap,
8
+ Flame,
9
+ } from 'lucide-react'
10
+ import { cn } from '@client/utils/cn'
11
+ import { cva } from 'class-variance-authority'
12
+ import type { VariantProps } from 'class-variance-authority'
13
+
14
+ const ICON_MAP: Record<string, React.ReactNode> = {
15
+ note: <Bookmark size={18} />,
16
+ tip: <Lightbulb size={18} />,
17
+ info: <Info size={18} />,
18
+ warning: <AlertTriangle size={18} />,
19
+ danger: <ShieldAlert size={18} />,
20
+ important: <Flame size={18} />,
21
+ caution: <Zap size={18} />,
22
+ }
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
+
34
+ const admonitionVariants = cva('py-4 px-4 rounded-lg', {
35
+ variants: {
36
+ type: {
37
+ note: 'border-primary-400 bg-primary-500/5 text-primary-400',
38
+ tip: 'border-emerald-500 bg-emerald-500/5 text-emerald-500',
39
+ info: 'border-sky-500 bg-sky-500/5 text-sky-500',
40
+ warning: 'border-amber-500 bg-amber-500/5 text-amber-500',
41
+ danger: 'border-red-500 bg-red-500/5 text-red-500',
42
+ important: 'border-orange-500 bg-orange-500/5 text-orange-500',
43
+ caution: 'border-yellow-500 bg-yellow-500/5 text-yellow-500',
44
+ },
45
+ },
46
+ defaultVariants: {
47
+ type: 'note',
48
+ },
49
+ })
50
+ type AdmonitionVariants = VariantProps<typeof admonitionVariants>
51
+
52
+ export interface AdmonitionProps
53
+ extends React.HTMLAttributes<HTMLDivElement>,
54
+ AdmonitionVariants {
55
+ title?: string
56
+ children: React.ReactNode
57
+ }
58
+
59
+ export function Admonition({
60
+ type = 'note',
61
+ title,
62
+ children,
63
+ className = '',
64
+ ...rest
65
+ }: AdmonitionProps) {
66
+ return (
67
+ <div
68
+ className={cn(admonitionVariants({ type }), className)}
69
+ role={type === 'warning' || type === 'danger' ? 'alert' : 'note'}
70
+ {...rest}
71
+ >
72
+ <div className="flex items-center flex-row gap-2 mb-2">
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>
80
+ <div className="text-sm text-text-muted leading-relaxed [&>p]:m-0 [&>p]:mb-2 [&>p:last-child]:mb-0">
81
+ {children}
82
+ </div>
83
+ </div>
84
+ )
85
+ }
86
+
87
+ export const Note = (props: Omit<AdmonitionProps, 'type'>) => (
88
+ <Admonition type="note" {...props} />
89
+ )
90
+ export const Tip = (props: Omit<AdmonitionProps, 'type'>) => (
91
+ <Admonition type="tip" {...props} />
92
+ )
93
+ export const Warning = (props: Omit<AdmonitionProps, 'type'>) => (
94
+ <Admonition type="warning" {...props} />
95
+ )
96
+ export const Danger = (props: Omit<AdmonitionProps, 'type'>) => (
97
+ <Admonition type="danger" {...props} />
98
+ )
99
+ export const InfoBox = (props: Omit<AdmonitionProps, 'type'>) => (
100
+ <Admonition type="info" {...props} />
101
+ )
102
+ export const Important = (props: Omit<AdmonitionProps, 'type'>) => (
103
+ <Admonition type="important" {...props} />
104
+ )
105
+ export const Caution = (props: Omit<AdmonitionProps, 'type'>) => (
106
+ <Admonition type="caution" {...props} />
107
+ )
@@ -0,0 +1,41 @@
1
+ import { cn } from '@client/utils/cn'
2
+ import { cva } from 'class-variance-authority'
3
+ import type { VariantProps } from 'class-variance-authority'
4
+
5
+ const badgeVariants = cva(
6
+ 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold tracking-tight',
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: 'bg-bg-surface text-text-muted border-border-subtle',
11
+ primary: 'bg-primary-500/15 text-primary-400 border-primary-500/20',
12
+ success: 'bg-emerald-500/15 text-emerald-400 border-emerald-500/20',
13
+ warning: 'bg-amber-500/15 text-amber-400 border-amber-500/20',
14
+ danger: 'bg-red-500/15 text-red-400 border-red-500/20',
15
+ info: 'bg-sky-500/15 text-sky-400 border-sky-500/20',
16
+ },
17
+ },
18
+ defaultVariants: {
19
+ variant: 'default',
20
+ },
21
+ },
22
+ )
23
+
24
+ export interface BadgeProps
25
+ extends React.HTMLAttributes<HTMLSpanElement>,
26
+ VariantProps<typeof badgeVariants> {
27
+ children: React.ReactNode
28
+ }
29
+
30
+ export function Badge({
31
+ variant = 'default',
32
+ children,
33
+ className = '',
34
+ ...rest
35
+ }: BadgeProps) {
36
+ return (
37
+ <span className={cn(badgeVariants({ variant }), className)} {...rest}>
38
+ {children}
39
+ </span>
40
+ )
41
+ }
@@ -0,0 +1,35 @@
1
+ import {
2
+ Button as ButtonPrimitive,
3
+ buttonVariants,
4
+ type ButtonProps,
5
+ } from '@components/primitives/button'
6
+ import { cn } from '@client/utils/cn'
7
+
8
+ export type { ButtonProps } from '@components/primitives/button'
9
+
10
+ export const Button = ({
11
+ className,
12
+ variant,
13
+ size,
14
+ rounded,
15
+ iconSize,
16
+ disabled,
17
+ ...props
18
+ }: ButtonProps) => {
19
+ return (
20
+ <ButtonPrimitive
21
+ className={cn(
22
+ 'group',
23
+ buttonVariants({
24
+ variant,
25
+ size,
26
+ rounded,
27
+ iconSize,
28
+ disabled,
29
+ className,
30
+ }),
31
+ )}
32
+ {...props}
33
+ />
34
+ )
35
+ }
@@ -0,0 +1,124 @@
1
+ import type { MouseEvent as ReactMouseEvent } from 'react'
2
+ import { useCallback, useRef } from 'react'
3
+ import * as RAC from 'react-aria-components'
4
+ import { cn } from '@client/utils/cn'
5
+ import { cva } from 'class-variance-authority'
6
+ import type { VariantProps } from 'class-variance-authority'
7
+
8
+ const cardsVariants = cva('grid gap-4 my-6', {
9
+ variants: {
10
+ cols: {
11
+ 1: 'grid-cols-1',
12
+ 2: 'grid-cols-1 sm:grid-cols-2',
13
+ 3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
14
+ 4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4',
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ cols: 3,
19
+ },
20
+ })
21
+ type CardsVariants = VariantProps<typeof cardsVariants>
22
+
23
+ export interface CardsProps
24
+ extends React.HTMLAttributes<HTMLDivElement>,
25
+ CardsVariants {}
26
+
27
+ export function Cards({
28
+ cols = 3,
29
+ children,
30
+ className = '',
31
+ ...rest
32
+ }: CardsProps) {
33
+ return (
34
+ <div className={cn(cardsVariants({ cols }), className)} {...rest}>
35
+ {children}
36
+ </div>
37
+ )
38
+ }
39
+
40
+ export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
41
+ title?: string
42
+ icon?: React.ReactNode
43
+ href?: string
44
+ children?: React.ReactNode
45
+ }
46
+
47
+ export function Card({
48
+ title,
49
+ icon,
50
+ href,
51
+ children,
52
+ className = '',
53
+ ...rest
54
+ }: CardProps) {
55
+ const cardRef = useRef<HTMLDivElement>(null)
56
+ const linkRef = useRef<HTMLAnchorElement>(null)
57
+
58
+ const handleMouseMove = useCallback((e: ReactMouseEvent<HTMLDivElement>) => {
59
+ const el = cardRef.current || linkRef.current
60
+ if (!el) return
61
+ const { left, top } = el.getBoundingClientRect()
62
+ el.style.setProperty('--x', `${e.clientX - left}px`)
63
+ el.style.setProperty('--y', `${e.clientY - top}px`)
64
+ }, [])
65
+
66
+ const inner = (
67
+ <>
68
+ <div
69
+ className="pointer-events-none absolute -inset-px rounded-xl opacity-0 transition-opacity duration-300 group-hover:opacity-100"
70
+ style={{
71
+ background:
72
+ 'radial-gradient(400px circle at var(--x) var(--y), color-mix(in oklch, var(--color-primary-500), transparent 90%), transparent 80%)',
73
+ }}
74
+ />
75
+ {icon && (
76
+ <div className="mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-primary-500/10 text-primary-400 text-lg transition-transform duration-300 group-hover:scale-105 group-hover:-rotate-3">
77
+ {icon}
78
+ </div>
79
+ )}
80
+ <div className="space-y-1.5">
81
+ {title && <h3 className="text-sm font-bold text-text-main">{title}</h3>}
82
+ {children && (
83
+ <div className="text-sm text-text-muted leading-relaxed">
84
+ {children}
85
+ </div>
86
+ )}
87
+ </div>
88
+ </>
89
+ )
90
+
91
+ const cardClasses = cn(
92
+ 'group relative block rounded-xl border border-border-subtle bg-bg-surface p-5 outline-none overflow-hidden',
93
+ 'transition-all duration-200 hover:border-primary-500/40 hover:shadow-lg hover:shadow-primary-500/5',
94
+ 'focus-visible:ring-2 focus-visible:ring-primary-500/30',
95
+ className,
96
+ )
97
+
98
+ if (href) {
99
+ return (
100
+ <RAC.Link
101
+ ref={linkRef}
102
+ href={href}
103
+ className={cn(cardClasses, 'no-underline cursor-pointer')}
104
+ onMouseMove={handleMouseMove}
105
+ {...(rest as any)}
106
+ >
107
+ {inner}
108
+ </RAC.Link>
109
+ )
110
+ }
111
+
112
+ return (
113
+ // biome-ignore lint/a11y/noStaticElementInteractions: spotlight effect is decorative
114
+ <div
115
+ ref={cardRef}
116
+ role="presentation"
117
+ className={cardClasses}
118
+ onMouseMove={handleMouseMove}
119
+ {...rest}
120
+ >
121
+ {inner}
122
+ </div>
123
+ )
124
+ }