boltdocs 1.10.2 → 1.11.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 (225) hide show
  1. package/package.json +29 -7
  2. package/src/client/app/config-context.tsx +18 -0
  3. package/src/client/app/docs-layout.tsx +14 -0
  4. package/src/client/app/index.tsx +132 -260
  5. package/src/client/app/mdx-component.tsx +52 -0
  6. package/src/client/app/mdx-components-context.tsx +23 -0
  7. package/src/client/app/mdx-page.tsx +20 -0
  8. package/src/client/app/preload.tsx +38 -30
  9. package/src/client/app/router.tsx +30 -0
  10. package/src/client/app/scroll-handler.tsx +40 -0
  11. package/src/client/app/theme-context.tsx +75 -0
  12. package/src/client/components/default-layout.tsx +80 -0
  13. package/src/client/components/docs-layout.tsx +105 -0
  14. package/src/client/components/icons-dev.tsx +74 -0
  15. package/src/client/components/mdx/admonition.tsx +107 -0
  16. package/src/client/components/mdx/badge.tsx +41 -0
  17. package/src/client/components/mdx/button.tsx +35 -0
  18. package/src/client/components/mdx/card.tsx +124 -0
  19. package/src/client/components/mdx/code-block.tsx +119 -0
  20. package/src/client/components/mdx/component-preview.tsx +47 -0
  21. package/src/client/components/mdx/component-props.tsx +83 -0
  22. package/src/client/components/mdx/field.tsx +66 -0
  23. package/src/client/components/mdx/file-tree.tsx +287 -0
  24. package/src/client/components/mdx/hooks/use-code-block.ts +56 -0
  25. package/src/client/components/mdx/hooks/use-component-preview.ts +16 -0
  26. package/src/client/components/mdx/hooks/useTable.ts +74 -0
  27. package/src/client/components/mdx/hooks/useTabs.ts +68 -0
  28. package/src/client/components/mdx/image.tsx +23 -0
  29. package/src/client/components/mdx/index.ts +53 -0
  30. package/src/client/components/mdx/link.tsx +38 -0
  31. package/src/client/components/mdx/list.tsx +192 -0
  32. package/src/client/components/mdx/table.tsx +156 -0
  33. package/src/client/components/mdx/tabs.tsx +135 -0
  34. package/src/client/components/mdx/video.tsx +68 -0
  35. package/src/client/components/primitives/breadcrumbs.tsx +79 -0
  36. package/src/client/components/primitives/button-group.tsx +54 -0
  37. package/src/client/components/primitives/button.tsx +145 -0
  38. package/src/client/components/primitives/helpers/observer.ts +120 -0
  39. package/src/client/components/primitives/index.ts +17 -0
  40. package/src/client/components/primitives/link.tsx +122 -0
  41. package/src/client/components/primitives/menu.tsx +159 -0
  42. package/src/client/components/primitives/navbar.tsx +359 -0
  43. package/src/client/components/primitives/navigation-menu.tsx +116 -0
  44. package/src/client/components/primitives/on-this-page.tsx +461 -0
  45. package/src/client/components/primitives/page-nav.tsx +87 -0
  46. package/src/client/components/primitives/popover.tsx +47 -0
  47. package/src/client/components/primitives/search-dialog.tsx +183 -0
  48. package/src/client/components/primitives/sidebar.tsx +154 -0
  49. package/src/client/components/primitives/tabs.tsx +90 -0
  50. package/src/client/components/primitives/tooltip.tsx +83 -0
  51. package/src/client/components/primitives/types.ts +11 -0
  52. package/src/client/components/ui-base/breadcrumbs.tsx +42 -0
  53. package/src/client/components/ui-base/copy-markdown.tsx +112 -0
  54. package/src/client/components/ui-base/error-boundary.tsx +52 -0
  55. package/src/client/components/ui-base/github-stars.tsx +27 -0
  56. package/src/client/components/ui-base/head.tsx +69 -0
  57. package/src/client/components/ui-base/loading.tsx +87 -0
  58. package/src/client/components/ui-base/navbar.tsx +138 -0
  59. package/src/client/components/ui-base/not-found.tsx +24 -0
  60. package/src/client/components/ui-base/on-this-page.tsx +152 -0
  61. package/src/client/components/ui-base/page-nav.tsx +39 -0
  62. package/src/client/components/ui-base/powered-by.tsx +19 -0
  63. package/src/client/components/ui-base/progress-bar.tsx +67 -0
  64. package/src/client/components/ui-base/search-dialog.tsx +82 -0
  65. package/src/client/components/ui-base/sidebar.tsx +104 -0
  66. package/src/client/components/ui-base/tabs.tsx +65 -0
  67. package/src/client/components/ui-base/theme-toggle.tsx +32 -0
  68. package/src/client/hooks/index.ts +12 -0
  69. package/src/client/hooks/use-breadcrumbs.ts +22 -0
  70. package/src/client/hooks/use-i18n.ts +84 -0
  71. package/src/client/hooks/use-localized-to.ts +95 -0
  72. package/src/client/hooks/use-location.ts +5 -0
  73. package/src/client/hooks/use-navbar.ts +60 -0
  74. package/src/client/hooks/use-onthispage.ts +23 -0
  75. package/src/client/hooks/use-page-nav.ts +22 -0
  76. package/src/client/hooks/use-routes.ts +72 -0
  77. package/src/client/hooks/use-search.ts +71 -0
  78. package/src/client/hooks/use-sidebar.ts +49 -0
  79. package/src/client/hooks/use-tabs.ts +43 -0
  80. package/src/client/hooks/use-version.ts +78 -0
  81. package/src/client/index.ts +55 -17
  82. package/src/client/integrations/codesandbox.ts +179 -0
  83. package/src/client/ssr.tsx +27 -16
  84. package/src/client/theme/neutral.css +360 -0
  85. package/src/client/types.ts +131 -27
  86. package/src/client/utils/cn.ts +6 -0
  87. package/src/client/utils/copy-clipboard.ts +22 -0
  88. package/src/client/utils/get-base-file-path.ts +21 -0
  89. package/src/client/utils/github.ts +121 -0
  90. package/src/client/utils/use-on-change.ts +15 -0
  91. package/src/client/virtual.d.ts +24 -0
  92. package/src/node/cache.ts +156 -156
  93. package/src/node/config.ts +159 -103
  94. package/src/node/index.ts +13 -13
  95. package/src/node/mdx.ts +213 -61
  96. package/src/node/plugin/entry.ts +29 -18
  97. package/src/node/plugin/html.ts +11 -11
  98. package/src/node/plugin/index.ts +161 -83
  99. package/src/node/plugin/types.ts +2 -4
  100. package/src/node/routes/cache.ts +6 -6
  101. package/src/node/routes/index.ts +206 -113
  102. package/src/node/routes/parser.ts +106 -81
  103. package/src/node/routes/sorter.ts +15 -15
  104. package/src/node/routes/types.ts +24 -24
  105. package/src/node/ssg/index.ts +46 -46
  106. package/src/node/ssg/meta.ts +4 -4
  107. package/src/node/ssg/options.ts +5 -5
  108. package/src/node/ssg/sitemap.ts +14 -14
  109. package/src/node/utils.ts +31 -31
  110. package/tsconfig.json +25 -20
  111. package/tsup.config.ts +23 -14
  112. package/dist/PackageManagerTabs-NVT7G625.mjs +0 -99
  113. package/dist/SearchDialog-AGVF6JBO.mjs +0 -194
  114. package/dist/SearchDialog-YPDOM7Q6.css +0 -2847
  115. package/dist/Video-KNTY5BNO.mjs +0 -6
  116. package/dist/cache-KNL5B4EE.mjs +0 -12
  117. package/dist/chunk-7SFUJWTB.mjs +0 -211
  118. package/dist/chunk-FFBNU6IJ.mjs +0 -386
  119. package/dist/chunk-FMTOYQLO.mjs +0 -37
  120. package/dist/chunk-TKLQWU7H.mjs +0 -1920
  121. package/dist/chunk-Z7JHYNAS.mjs +0 -57
  122. package/dist/client/index.css +0 -2847
  123. package/dist/client/index.d.mts +0 -372
  124. package/dist/client/index.d.ts +0 -372
  125. package/dist/client/index.js +0 -3630
  126. package/dist/client/index.mjs +0 -697
  127. package/dist/client/ssr.css +0 -2847
  128. package/dist/client/ssr.d.mts +0 -27
  129. package/dist/client/ssr.d.ts +0 -27
  130. package/dist/client/ssr.js +0 -2928
  131. package/dist/client/ssr.mjs +0 -33
  132. package/dist/config-BsFQ-ErD.d.mts +0 -159
  133. package/dist/config-BsFQ-ErD.d.ts +0 -159
  134. package/dist/node/index.d.mts +0 -91
  135. package/dist/node/index.d.ts +0 -91
  136. package/dist/node/index.js +0 -1187
  137. package/dist/node/index.mjs +0 -762
  138. package/dist/types-Dj-bfnC3.d.mts +0 -74
  139. package/dist/types-Dj-bfnC3.d.ts +0 -74
  140. package/src/client/theme/components/CodeBlock/CodeBlock.tsx +0 -61
  141. package/src/client/theme/components/CodeBlock/index.ts +0 -1
  142. package/src/client/theme/components/PackageManagerTabs/PackageManagerTabs.tsx +0 -131
  143. package/src/client/theme/components/PackageManagerTabs/index.ts +0 -1
  144. package/src/client/theme/components/PackageManagerTabs/pkg-tabs.css +0 -64
  145. package/src/client/theme/components/Playground/Playground.tsx +0 -180
  146. package/src/client/theme/components/Playground/index.ts +0 -1
  147. package/src/client/theme/components/Playground/playground.css +0 -238
  148. package/src/client/theme/components/Video/Video.tsx +0 -84
  149. package/src/client/theme/components/Video/index.ts +0 -1
  150. package/src/client/theme/components/Video/video.css +0 -41
  151. package/src/client/theme/components/mdx/Admonition.tsx +0 -80
  152. package/src/client/theme/components/mdx/Badge.tsx +0 -31
  153. package/src/client/theme/components/mdx/Button.tsx +0 -50
  154. package/src/client/theme/components/mdx/Card.tsx +0 -80
  155. package/src/client/theme/components/mdx/Field.tsx +0 -60
  156. package/src/client/theme/components/mdx/FileTree.tsx +0 -229
  157. package/src/client/theme/components/mdx/List.tsx +0 -57
  158. package/src/client/theme/components/mdx/Table.tsx +0 -151
  159. package/src/client/theme/components/mdx/Tabs.tsx +0 -123
  160. package/src/client/theme/components/mdx/index.ts +0 -27
  161. package/src/client/theme/components/mdx/mdx-components.css +0 -764
  162. package/src/client/theme/icons/bun.tsx +0 -62
  163. package/src/client/theme/icons/deno.tsx +0 -20
  164. package/src/client/theme/icons/discord.tsx +0 -12
  165. package/src/client/theme/icons/github.tsx +0 -15
  166. package/src/client/theme/icons/npm.tsx +0 -13
  167. package/src/client/theme/icons/pnpm.tsx +0 -72
  168. package/src/client/theme/icons/twitter.tsx +0 -12
  169. package/src/client/theme/styles/markdown.css +0 -394
  170. package/src/client/theme/styles/variables.css +0 -175
  171. package/src/client/theme/styles.css +0 -39
  172. package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +0 -68
  173. package/src/client/theme/ui/Breadcrumbs/index.ts +0 -1
  174. package/src/client/theme/ui/CopyMarkdown/CopyMarkdown.tsx +0 -82
  175. package/src/client/theme/ui/CopyMarkdown/copy-markdown.css +0 -112
  176. package/src/client/theme/ui/CopyMarkdown/index.ts +0 -1
  177. package/src/client/theme/ui/ErrorBoundary/ErrorBoundary.tsx +0 -50
  178. package/src/client/theme/ui/ErrorBoundary/error-boundary.css +0 -55
  179. package/src/client/theme/ui/ErrorBoundary/index.ts +0 -1
  180. package/src/client/theme/ui/Footer/footer.css +0 -32
  181. package/src/client/theme/ui/Head/Head.tsx +0 -69
  182. package/src/client/theme/ui/Head/index.ts +0 -1
  183. package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +0 -125
  184. package/src/client/theme/ui/LanguageSwitcher/index.ts +0 -1
  185. package/src/client/theme/ui/LanguageSwitcher/language-switcher.css +0 -98
  186. package/src/client/theme/ui/Layout/Layout.tsx +0 -203
  187. package/src/client/theme/ui/Layout/base.css +0 -106
  188. package/src/client/theme/ui/Layout/index.ts +0 -2
  189. package/src/client/theme/ui/Layout/pagination.css +0 -72
  190. package/src/client/theme/ui/Layout/responsive.css +0 -47
  191. package/src/client/theme/ui/Link/Link.tsx +0 -392
  192. package/src/client/theme/ui/Link/LinkPreview.tsx +0 -59
  193. package/src/client/theme/ui/Link/index.ts +0 -2
  194. package/src/client/theme/ui/Link/link-preview.css +0 -48
  195. package/src/client/theme/ui/Loading/Loading.tsx +0 -10
  196. package/src/client/theme/ui/Loading/index.ts +0 -1
  197. package/src/client/theme/ui/Loading/loading.css +0 -30
  198. package/src/client/theme/ui/Navbar/GithubStars.tsx +0 -27
  199. package/src/client/theme/ui/Navbar/Navbar.tsx +0 -193
  200. package/src/client/theme/ui/Navbar/Tabs.tsx +0 -99
  201. package/src/client/theme/ui/Navbar/index.ts +0 -2
  202. package/src/client/theme/ui/Navbar/navbar.css +0 -347
  203. package/src/client/theme/ui/NotFound/NotFound.tsx +0 -19
  204. package/src/client/theme/ui/NotFound/index.ts +0 -1
  205. package/src/client/theme/ui/NotFound/not-found.css +0 -64
  206. package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +0 -244
  207. package/src/client/theme/ui/OnThisPage/index.ts +0 -1
  208. package/src/client/theme/ui/OnThisPage/toc.css +0 -152
  209. package/src/client/theme/ui/PoweredBy/PoweredBy.tsx +0 -18
  210. package/src/client/theme/ui/PoweredBy/index.ts +0 -1
  211. package/src/client/theme/ui/PoweredBy/powered-by.css +0 -76
  212. package/src/client/theme/ui/ProgressBar/ProgressBar.css +0 -17
  213. package/src/client/theme/ui/ProgressBar/ProgressBar.tsx +0 -51
  214. package/src/client/theme/ui/ProgressBar/index.ts +0 -1
  215. package/src/client/theme/ui/SearchDialog/SearchDialog.tsx +0 -209
  216. package/src/client/theme/ui/SearchDialog/index.ts +0 -1
  217. package/src/client/theme/ui/SearchDialog/search.css +0 -152
  218. package/src/client/theme/ui/Sidebar/Sidebar.tsx +0 -244
  219. package/src/client/theme/ui/Sidebar/index.ts +0 -1
  220. package/src/client/theme/ui/Sidebar/sidebar.css +0 -230
  221. package/src/client/theme/ui/ThemeToggle/ThemeToggle.tsx +0 -69
  222. package/src/client/theme/ui/ThemeToggle/index.ts +0 -1
  223. package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +0 -136
  224. package/src/client/theme/ui/VersionSwitcher/index.ts +0 -1
  225. package/src/client/utils.ts +0 -49
@@ -0,0 +1,359 @@
1
+ import { type ReactNode, useState, useEffect } from 'react'
2
+ import {
3
+ Button,
4
+ Separator,
5
+ ToggleButton,
6
+ Link,
7
+ Menu,
8
+ MenuItem,
9
+ MenuTrigger,
10
+ cn,
11
+ } from './index'
12
+ import { Button as ButtonRAC } from 'react-aria-components'
13
+ import { Search, Sun, Moon, ExternalLink, ChevronDown } from 'lucide-react'
14
+ import * as IconsSocials from '@components/icons-dev'
15
+ import type { ComponentBase } from './types'
16
+ import type { BoltdocsSocialLink } from '@node/config'
17
+
18
+ export interface NavbarLinkProps extends Omit<ComponentBase, 'children'> {
19
+ label: ReactNode
20
+ href: string
21
+ active?: boolean
22
+ to?: 'internal' | 'external'
23
+ }
24
+
25
+ export interface NavbarLogoProps extends Omit<ComponentBase, 'children'> {
26
+ src: string
27
+ alt: string
28
+ width?: number
29
+ height?: number
30
+ }
31
+
32
+ export interface NavbarSearchTriggerProps extends ComponentBase {
33
+ onPress: () => void
34
+ }
35
+
36
+ export interface NavbarThemeProps {
37
+ className?: string
38
+ theme: 'dark' | 'light'
39
+ onThemeChange: (isSelected: boolean) => void
40
+ }
41
+
42
+ export interface NavbarMenuProps extends ComponentBase {
43
+ label: ReactNode
44
+ icon?: ReactNode
45
+ }
46
+
47
+ export interface NavbarVersionProps extends ComponentBase {
48
+ current: string
49
+ }
50
+
51
+ export interface NavbarItemProps extends Omit<ComponentBase, 'children'> {
52
+ label: string
53
+ onPress?: () => void
54
+ isCurrent?: boolean
55
+ }
56
+
57
+ export interface NavbarSocialsProps extends ComponentBase {
58
+ icon: string
59
+ link: string
60
+ }
61
+
62
+ export const NavbarRoot = ({
63
+ children,
64
+ className,
65
+ ...props
66
+ }: ComponentBase) => {
67
+ return (
68
+ <header
69
+ className={cn(
70
+ 'boltdocs-navbar sticky top-0 z-50 w-full border-b border-border-subtle bg-bg-main/80 backdrop-blur-md',
71
+ className,
72
+ )}
73
+ {...props}
74
+ >
75
+ {children}
76
+ </header>
77
+ )
78
+ }
79
+
80
+ export const NavbarContent = ({ children, className }: ComponentBase) => {
81
+ return (
82
+ <div
83
+ className={cn(
84
+ 'mx-auto flex lg:h-navbar max-w-(--breakpoint-3xl) items-center justify-between px-4 md:px-6',
85
+ className,
86
+ )}
87
+ >
88
+ {children}
89
+ </div>
90
+ )
91
+ }
92
+
93
+ export const NavbarLeft = ({ children, className }: ComponentBase) => {
94
+ return (
95
+ <div className={cn('flex items-center gap-4', className)}>{children}</div>
96
+ )
97
+ }
98
+
99
+ export const NavbarRight = ({ children, className }: ComponentBase) => {
100
+ return (
101
+ <div className={cn('flex items-center gap-2 md:gap-4', className)}>
102
+ {children}
103
+ </div>
104
+ )
105
+ }
106
+
107
+ export const NavbarCenter = ({ children, className }: ComponentBase) => {
108
+ return (
109
+ <div
110
+ className={cn(
111
+ 'hidden lg:flex flex-1 justify-center items-center gap-4 px-4',
112
+ className,
113
+ )}
114
+ >
115
+ {children}
116
+ </div>
117
+ )
118
+ }
119
+
120
+ export const NavbarLogo = ({
121
+ src,
122
+ alt,
123
+ width = 24,
124
+ height = 24,
125
+ className,
126
+ }: NavbarLogoProps) => {
127
+ return (
128
+ <Link
129
+ href="/"
130
+ className={cn('flex items-center gap-2 shrink-0 outline-none', className)}
131
+ >
132
+ {src ? (
133
+ <img
134
+ src={src}
135
+ alt={alt}
136
+ width={width}
137
+ height={height}
138
+ className="h-6 w-6 object-contain"
139
+ />
140
+ ) : null}
141
+ </Link>
142
+ )
143
+ }
144
+
145
+ export const NavbarTitle = ({ children, className }: ComponentBase) => {
146
+ return (
147
+ <span
148
+ className={cn(
149
+ 'text-lg font-bold tracking-tight hidden sm:inline-block',
150
+ className,
151
+ )}
152
+ >
153
+ {children}
154
+ </span>
155
+ )
156
+ }
157
+
158
+ export const NavbarLinks = ({ children, className }: ComponentBase) => {
159
+ return (
160
+ <nav
161
+ className={cn(
162
+ 'hidden md:flex items-center gap-6 text-sm font-medium',
163
+ className,
164
+ )}
165
+ >
166
+ {children}
167
+ </nav>
168
+ )
169
+ }
170
+
171
+ export const NavbarLink = ({
172
+ label,
173
+ href,
174
+ active,
175
+ to,
176
+ className,
177
+ }: NavbarLinkProps) => {
178
+ return (
179
+ <Link
180
+ href={href}
181
+ target={to === 'external' ? '_blank' : undefined}
182
+ className={cn(
183
+ 'transition-colors outline-none hover:text-text-main focus-visible:ring-2 focus-visible:ring-primary-500/30 rounded-sm',
184
+ active ? 'text-primary-500' : 'text-text-muted',
185
+ className,
186
+ )}
187
+ >
188
+ {label as any}
189
+ {to === 'external' && (
190
+ <span className="ml-1 inline-block">
191
+ <ExternalLink size={12} />
192
+ </span>
193
+ )}
194
+ </Link>
195
+ )
196
+ }
197
+
198
+ export const NavbarSearchTrigger = ({
199
+ className,
200
+ onPress,
201
+ }: NavbarSearchTriggerProps) => {
202
+ const [mounted, setMounted] = useState(false)
203
+ const isMac = mounted && /Mac|iPod|iPhone|iPad/.test(navigator.platform)
204
+
205
+ useEffect(() => {
206
+ setMounted(true)
207
+ }, [])
208
+
209
+ return (
210
+ <ButtonRAC
211
+ onPress={onPress}
212
+ className={cn(
213
+ 'flex items-center gap-2 rounded-full border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-muted outline-none cursor-pointer',
214
+ 'transition-colors hover:border-border-strong hover:text-text-main',
215
+ 'focus-visible:ring-2 focus-visible:ring-primary-500/30',
216
+ 'w-full max-w-[320px] justify-between',
217
+ className,
218
+ )}
219
+ >
220
+ <div className="flex items-center gap-2">
221
+ <Search size={16} />
222
+ <span className="hidden sm:inline-block">Search docs...</span>
223
+ </div>
224
+ <div className="hidden sm:flex items-center gap-1 pointer-events-none select-none">
225
+ <kbd className="flex h-5 items-center justify-center rounded border border-border-subtle bg-bg-main px-1.5 font-mono text-[10px] font-medium">
226
+ {isMac ? '⌘' : 'Ctrl'}
227
+ </kbd>
228
+ <kbd className="flex h-5 w-5 items-center justify-center rounded border border-border-subtle bg-bg-main font-mono text-[10px] font-medium">
229
+ K
230
+ </kbd>
231
+ </div>
232
+ </ButtonRAC>
233
+ )
234
+ }
235
+
236
+ export const NavbarTheme = ({
237
+ className,
238
+ theme,
239
+ onThemeChange,
240
+ }: NavbarThemeProps) => {
241
+ return (
242
+ <ToggleButton
243
+ isSelected={theme === 'dark'}
244
+ onChange={onThemeChange}
245
+ className={cn(
246
+ 'rounded-md p-2 text-text-muted outline-none cursor-pointer transition-colors',
247
+ 'hover:bg-bg-surface hover:text-text-main',
248
+ 'focus-visible:ring-2 focus-visible:ring-primary-500/30',
249
+ className,
250
+ )}
251
+ aria-label="Toggle theme"
252
+ >
253
+ {theme === 'dark' ? <Sun size={20} /> : <Moon size={20} />}
254
+ </ToggleButton>
255
+ )
256
+ }
257
+
258
+ export const NavbarMenu = ({
259
+ label,
260
+ children,
261
+ className,
262
+ icon,
263
+ }: NavbarMenuProps) => {
264
+ return (
265
+ <MenuTrigger placement="bottom end">
266
+ <Button
267
+ variant="ghost"
268
+ className={cn(
269
+ 'flex items-center gap-1.5 rounded-md px-3 py-1.5 text-text-muted outline-none cursor-pointer transition-colors',
270
+ 'hover:bg-bg-surface hover:text-text-main',
271
+ 'focus-visible:ring-2 focus-visible:ring-primary-500/30',
272
+ className,
273
+ )}
274
+ >
275
+ {icon && <span className="flex items-center shrink-0">{icon}</span>}
276
+ <span className="text-[13px] font-bold uppercase tracking-wide">
277
+ {label}
278
+ </span>
279
+ <ChevronDown size={14} className="ml-0.5 opacity-50" />
280
+ </Button>
281
+ <Menu className="min-w-[180px]">{children as any}</Menu>
282
+ </MenuTrigger>
283
+ )
284
+ }
285
+
286
+ export const NavbarItem = ({
287
+ label,
288
+ className,
289
+ onPress,
290
+ isCurrent,
291
+ }: NavbarItemProps) => {
292
+ return (
293
+ <MenuItem
294
+ onAction={onPress}
295
+ className={cn(
296
+ isCurrent &&
297
+ 'bg-primary-500 text-white font-medium hover:bg-primary-600 focus:bg-primary-600 focus:text-white',
298
+ className,
299
+ )}
300
+ >
301
+ {label}
302
+ </MenuItem>
303
+ )
304
+ }
305
+
306
+ export const Icon = ({ name }: { name: BoltdocsSocialLink['icon'] }) => {
307
+ if (name === 'github') return <IconsSocials.Github />
308
+ if (name === 'discord') return <IconsSocials.Discord />
309
+ if (name === 'x') return <IconsSocials.XSocial />
310
+ if (name === 'bluesky') return <IconsSocials.Bluesky />
311
+ }
312
+
313
+ export const NavbarSocials = ({
314
+ icon,
315
+ link,
316
+ className,
317
+ }: NavbarSocialsProps) => {
318
+ return (
319
+ <Link
320
+ href={link}
321
+ target="_blank"
322
+ rel="noopener noreferrer"
323
+ className={cn(
324
+ 'rounded-md p-2 text-text-muted outline-none transition-colors',
325
+ 'hover:bg-bg-surface hover:text-text-main',
326
+ 'focus-visible:ring-2 focus-visible:ring-primary-500/30',
327
+ className,
328
+ )}
329
+ >
330
+ <Icon name={icon} />
331
+ </Link>
332
+ )
333
+ }
334
+
335
+ export const NavbarSplit = ({ className }: ComponentBase) => {
336
+ return (
337
+ <Separator
338
+ orientation="vertical"
339
+ className={cn('h-6 w-px bg-border-subtle mx-1', className)}
340
+ />
341
+ )
342
+ }
343
+
344
+ export default {
345
+ NavbarRoot,
346
+ NavbarLeft,
347
+ NavbarRight,
348
+ NavbarCenter,
349
+ NavbarLogo,
350
+ Title: NavbarTitle,
351
+ Links: NavbarLinks,
352
+ Link: NavbarLink,
353
+ SearchTrigger: NavbarSearchTrigger,
354
+ Theme: NavbarTheme,
355
+ Item: NavbarItem,
356
+ Socials: NavbarSocials,
357
+ Split: NavbarSplit,
358
+ Content: NavbarContent,
359
+ }
@@ -0,0 +1,116 @@
1
+ import * as RAC from 'react-aria-components'
2
+ import { ChevronDown } from 'lucide-react'
3
+ import { cn } from '@client/utils/cn'
4
+ import type { ComponentBase, CompoundComponent } from './types'
5
+
6
+ export interface NavigationMenuItemProps extends ComponentBase {
7
+ label: string
8
+ }
9
+
10
+ export interface NavigationMenuLinkProps
11
+ extends Omit<ComponentBase, 'children'> {
12
+ href: string
13
+ label: string
14
+ description?: string
15
+ children?:
16
+ | React.ReactNode
17
+ | ((opts: RAC.MenuItemRenderProps) => React.ReactNode)
18
+ }
19
+
20
+ export type NavigationMenuComponent = CompoundComponent<
21
+ ComponentBase,
22
+ {
23
+ List: React.FC<ComponentBase>
24
+ Item: React.FC<NavigationMenuItemProps>
25
+ Link: React.FC<NavigationMenuLinkProps>
26
+ }
27
+ >
28
+
29
+ const NavigationMenuRoot = ({
30
+ children,
31
+ className,
32
+ ...props
33
+ }: ComponentBase) => {
34
+ return (
35
+ <nav className={cn('relative flex items-center', className)} {...props}>
36
+ {children}
37
+ </nav>
38
+ )
39
+ }
40
+
41
+ const NavigationMenuList = ({ children, className }: ComponentBase) => {
42
+ return (
43
+ <div className={cn('flex list-none items-center gap-1', className)}>
44
+ {children}
45
+ </div>
46
+ )
47
+ }
48
+
49
+ const NavigationMenuItem = ({
50
+ children,
51
+ label,
52
+ className,
53
+ }: NavigationMenuItemProps) => {
54
+ return (
55
+ <RAC.MenuTrigger>
56
+ <RAC.Button
57
+ className={cn(
58
+ 'flex items-center gap-1 rounded-md px-3 py-1.5 text-sm font-medium outline-none transition-colors cursor-pointer',
59
+ 'text-text-muted hover:bg-bg-surface hover:text-text-main',
60
+ 'focus-visible:ring-2 focus-visible:ring-primary-500/30',
61
+ className,
62
+ )}
63
+ >
64
+ {label}
65
+ <ChevronDown size={14} className="transition-transform" />
66
+ </RAC.Button>
67
+ <RAC.Popover
68
+ placement="bottom start"
69
+ className="entering:animate-in entering:fade-in entering:zoom-in-95 exiting:animate-out exiting:fade-out exiting:zoom-out-95 fill-mode-forwards"
70
+ >
71
+ <RAC.Menu className="w-56 outline-none rounded-xl border border-border-subtle bg-bg-surface p-2 shadow-xl ring-1 ring-border-strong/5">
72
+ {children as any}
73
+ </RAC.Menu>
74
+ </RAC.Popover>
75
+ </RAC.MenuTrigger>
76
+ )
77
+ }
78
+
79
+ const NavigationMenuLink = ({
80
+ label,
81
+ href,
82
+ description,
83
+ className,
84
+ children,
85
+ ...props
86
+ }: NavigationMenuLinkProps) => {
87
+ return (
88
+ <RAC.MenuItem
89
+ href={href}
90
+ className={cn(
91
+ 'block rounded-lg px-3 py-2 text-sm outline-none cursor-pointer transition-colors',
92
+ 'hover:bg-bg-muted focus:bg-bg-muted',
93
+ className,
94
+ )}
95
+ {...props}
96
+ >
97
+ {children || (
98
+ <>
99
+ <div className="font-semibold text-text-main">{label}</div>
100
+ {description && (
101
+ <div className="text-xs text-text-muted line-clamp-1 mt-0.5">
102
+ {description}
103
+ </div>
104
+ )}
105
+ </>
106
+ )}
107
+ </RAC.MenuItem>
108
+ )
109
+ }
110
+
111
+ export default {
112
+ NavigationMenuRoot,
113
+ NavigationMenuList,
114
+ NavigationMenuItem,
115
+ NavigationMenuLink,
116
+ }