boltdocs 2.7.10 → 2.7.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.cjs +1929 -1
- package/dist/client/index.js +1880 -1
- package/dist/client/mdx.cjs +7 -1
- package/dist/client/mdx.js +7 -1
- package/dist/client/primitives.cjs +60 -1
- package/dist/client/primitives.js +20 -1
- package/dist/docs-layout-BXHV0xw_.cjs +1431 -0
- package/dist/docs-layout-DwFndmj5.js +1231 -0
- package/dist/icons-dev-3cZMyt8r.cjs +1204 -0
- package/dist/icons-dev-Df8OQ481.js +839 -0
- package/dist/image-DtrI2cw3.cjs +268 -0
- package/dist/image-jxPb-2iV.js +214 -0
- package/dist/mdx-BdWkJTeB.cjs +523 -0
- package/dist/mdx-UTTLFWJq.js +494 -0
- package/dist/node/cli-entry.cjs +1 -1
- package/dist/node/cli-entry.mjs +1 -1
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.mjs +1 -1
- package/dist/{node-DtEDyN1u.cjs → node-BSM4qcDK.cjs} +1 -1
- package/dist/{node-_1jhMGYx.mjs → node-BspZN3R2.mjs} +1 -1
- package/dist/{package-DrwtlXfk.cjs → package-DIIrjuWI.cjs} +1 -1
- package/dist/{package--0Yf0t1N.mjs → package-K0zsjGIz.mjs} +1 -1
- package/dist/{search-dialog-ByvGScjt.js → search-dialog-BHuIiUC6.js} +3 -1
- package/dist/search-dialog-BNF10tDl.js +375 -0
- package/dist/search-dialog-BwkDuI9R.cjs +220 -0
- package/dist/search-dialog-C7xuvyNk.cjs +386 -0
- package/dist/search-dialog-CIQg6k8c.cjs +8 -0
- package/dist/search-dialog-D-DDN7zJ.js +208 -0
- package/package.json +3 -4
- package/dist/docs-layout-KoWNZc8_.js +0 -6
- package/dist/docs-layout-x2yKt2cL.cjs +0 -6
- package/dist/icons-dev-B_RZIyxu.js +0 -6
- package/dist/icons-dev-BlV3wWFT.cjs +0 -6
- package/dist/image-BHhTvQzr.cjs +0 -6
- package/dist/image-CqKzYD8f.js +0 -6
- package/dist/mdx-DudBEac0.js +0 -7
- package/dist/mdx-r4cDQxWu.cjs +0 -7
- package/dist/search-dialog-B584t9ZF.js +0 -6
- package/dist/search-dialog-BvBopRsZ.cjs +0 -6
- package/dist/search-dialog-Cyko6TJm.cjs +0 -6
- package/dist/search-dialog-D6BNohIJ.js +0 -6
- package/dist/search-dialog-DuYTIefy.cjs +0 -6
- package/src/client/app/config-context.tsx +0 -51
- package/src/client/app/doc-page.tsx +0 -38
- package/src/client/app/docs-layout.tsx +0 -28
- package/src/client/app/head.tsx +0 -122
- package/src/client/app/helmet-compat.tsx +0 -36
- package/src/client/app/mdx-component.tsx +0 -8
- package/src/client/app/mdx-components-context.tsx +0 -72
- package/src/client/app/routes-context.tsx +0 -34
- package/src/client/app/scroll-handler.tsx +0 -74
- package/src/client/app/theme-context.tsx +0 -103
- package/src/client/app/ui-context.tsx +0 -42
- package/src/client/components/docs-layout-default.tsx +0 -85
- package/src/client/components/icons-dev.tsx +0 -282
- package/src/client/components/mdx/callout.tsx +0 -97
- package/src/client/components/mdx/card.tsx +0 -99
- package/src/client/components/mdx/cards.tsx +0 -27
- package/src/client/components/mdx/code-block.tsx +0 -184
- package/src/client/components/mdx/field.tsx +0 -33
- package/src/client/components/mdx/image.tsx +0 -44
- package/src/client/components/mdx/index.ts +0 -19
- package/src/client/components/mdx/table.tsx +0 -54
- package/src/client/components/mdx/typographics.tsx +0 -120
- package/src/client/components/mdx/use-code-block.ts +0 -34
- package/src/client/components/primitives/breadcrumbs.tsx +0 -54
- package/src/client/components/primitives/button-group.tsx +0 -54
- package/src/client/components/primitives/button.tsx +0 -6
- package/src/client/components/primitives/code-block.tsx +0 -120
- package/src/client/components/primitives/docs-layout.tsx +0 -125
- package/src/client/components/primitives/error-boundary.tsx +0 -107
- package/src/client/components/primitives/heading.tsx +0 -128
- package/src/client/components/primitives/helpers/observer.ts +0 -141
- package/src/client/components/primitives/image.tsx +0 -26
- package/src/client/components/primitives/link.tsx +0 -102
- package/src/client/components/primitives/menu.tsx +0 -137
- package/src/client/components/primitives/navbar.tsx +0 -466
- package/src/client/components/primitives/on-this-page.tsx +0 -430
- package/src/client/components/primitives/page-nav.tsx +0 -51
- package/src/client/components/primitives/popover.tsx +0 -28
- package/src/client/components/primitives/search-dialog.tsx +0 -193
- package/src/client/components/primitives/sidebar.tsx +0 -423
- package/src/client/components/primitives/skeleton.tsx +0 -26
- package/src/client/components/primitives/tabs.tsx +0 -70
- package/src/client/components/primitives/tooltip.tsx +0 -81
- package/src/client/components/primitives/types.ts +0 -11
- package/src/client/components/ui-base/banner.tsx +0 -66
- package/src/client/components/ui-base/breadcrumbs.tsx +0 -44
- package/src/client/components/ui-base/copy-markdown.tsx +0 -107
- package/src/client/components/ui-base/error-boundary.tsx +0 -15
- package/src/client/components/ui-base/github-stars.tsx +0 -29
- package/src/client/components/ui-base/icons.tsx +0 -240
- package/src/client/components/ui-base/index.ts +0 -16
- package/src/client/components/ui-base/last-updated.tsx +0 -27
- package/src/client/components/ui-base/navbar.tsx +0 -266
- package/src/client/components/ui-base/not-found.tsx +0 -26
- package/src/client/components/ui-base/on-this-page.tsx +0 -57
- package/src/client/components/ui-base/page-nav.tsx +0 -50
- package/src/client/components/ui-base/search-dialog.tsx +0 -163
- package/src/client/components/ui-base/search-highlight.tsx +0 -10
- package/src/client/components/ui-base/sidebar.tsx +0 -92
- package/src/client/components/ui-base/tabs.tsx +0 -83
- package/src/client/components/ui-base/theme-toggle.tsx +0 -130
- package/src/client/components/ui-base/version-i18n.tsx +0 -80
- package/src/client/hooks/index.ts +0 -13
- package/src/client/hooks/use-analytics.ts +0 -272
- package/src/client/hooks/use-breadcrumbs.ts +0 -22
- package/src/client/hooks/use-i18n.ts +0 -182
- package/src/client/hooks/use-localized-to.ts +0 -113
- package/src/client/hooks/use-location.ts +0 -5
- package/src/client/hooks/use-navbar.ts +0 -130
- package/src/client/hooks/use-page-nav.ts +0 -46
- package/src/client/hooks/use-routes.ts +0 -108
- package/src/client/hooks/use-search-highlight.ts +0 -185
- package/src/client/hooks/use-search.ts +0 -118
- package/src/client/hooks/use-sidebar.ts +0 -205
- package/src/client/hooks/use-tabs.ts +0 -46
- package/src/client/hooks/use-version.ts +0 -111
- package/src/client/index.ts +0 -31
- package/src/client/mdx.ts +0 -2
- package/src/client/primitives.ts +0 -19
- package/src/client/ssg/boltdocs-shell.tsx +0 -148
- package/src/client/ssg/create-routes.tsx +0 -473
- package/src/client/ssg/index.ts +0 -4
- package/src/client/ssg/mdx-page.tsx +0 -38
- package/src/client/store/boltdocs-context.tsx +0 -137
- package/src/client/theme/neutral.css +0 -141
- package/src/client/theme/reset.css +0 -189
- package/src/client/types.ts +0 -116
- package/src/client/utils/cn.ts +0 -6
- package/src/client/utils/copy-clipboard.ts +0 -22
- package/src/client/utils/get-base-file-path.ts +0 -21
- package/src/client/utils/github.ts +0 -121
- package/src/client/utils/i18n.ts +0 -23
- package/src/client/utils/path.ts +0 -9
- package/src/client/utils/react-to-text.ts +0 -34
- package/src/client/virtual.d.ts +0 -24
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ReactNode,
|
|
3
|
-
useRef,
|
|
4
|
-
useLayoutEffect,
|
|
5
|
-
useEffect,
|
|
6
|
-
useState,
|
|
7
|
-
} from 'react'
|
|
8
|
-
import * as RAC from 'react-aria-components'
|
|
9
|
-
import { cn } from '../../utils/cn'
|
|
10
|
-
import { useUI } from '../../app/ui-context'
|
|
11
|
-
import { Link } from './link'
|
|
12
|
-
import { ChevronRight } from '../ui-base/icons'
|
|
13
|
-
import type { ComponentBase } from './types'
|
|
14
|
-
import type { ComponentRoute } from '../../types'
|
|
15
|
-
import { useSidebar } from '../../hooks/use-sidebar'
|
|
16
|
-
import { useLocalizedTo } from '../../hooks/use-localized-to'
|
|
17
|
-
import * as DefaultIcons from '../ui-base/icons'
|
|
18
|
-
import virtualIcons from 'virtual:boltdocs-icons'
|
|
19
|
-
|
|
20
|
-
// Persistent scroll position across navigation (SPA)
|
|
21
|
-
let sidebarScrollPos = 0
|
|
22
|
-
|
|
23
|
-
function getIcon(iconName?: string): React.ElementType | undefined {
|
|
24
|
-
if (!iconName) return undefined
|
|
25
|
-
const icons = { ...DefaultIcons, ...virtualIcons } as unknown as Record<
|
|
26
|
-
string,
|
|
27
|
-
React.ElementType
|
|
28
|
-
>
|
|
29
|
-
const IconComponent = icons[iconName] || icons[iconName + 'Icon']
|
|
30
|
-
return IconComponent || undefined
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Internal Badge component for links
|
|
35
|
-
*/
|
|
36
|
-
const Badge = ({ badge }: { badge: ComponentRoute['badge'] }) => {
|
|
37
|
-
const colors = {
|
|
38
|
-
new: 'bg-primary-500/10 text-primary-500 border border-primary-500/20',
|
|
39
|
-
updated: 'bg-emerald-500/10 text-emerald-500 border border-emerald-500/20',
|
|
40
|
-
deprecated: 'bg-danger-500/10 text-danger-500 border border-danger-500/20',
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const text = typeof badge === 'string' ? badge : badge?.text
|
|
44
|
-
if (!text) return null
|
|
45
|
-
|
|
46
|
-
return (
|
|
47
|
-
<span
|
|
48
|
-
className={cn(
|
|
49
|
-
'ml-auto flex h-5 items-center rounded-md text-[10px] font-bold px-1.5 py-0.5 uppercase tracking-wider',
|
|
50
|
-
colors[text as keyof typeof colors] || colors.new,
|
|
51
|
-
)}
|
|
52
|
-
>
|
|
53
|
-
{text}
|
|
54
|
-
</span>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Desktop Sidebar Container
|
|
60
|
-
*/
|
|
61
|
-
export function SidebarRoot({ children, className }: ComponentBase) {
|
|
62
|
-
return (
|
|
63
|
-
<aside
|
|
64
|
-
className={cn(
|
|
65
|
-
'hidden lg:flex flex-col w-sidebar sticky top-navbar h-[calc(100vh-var(--spacing-navbar))] border-r border-subtle bg-main',
|
|
66
|
-
className,
|
|
67
|
-
)}
|
|
68
|
-
>
|
|
69
|
-
{children}
|
|
70
|
-
</aside>
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Mobile Sidebar Modal
|
|
76
|
-
*/
|
|
77
|
-
export function SidebarMobile({ children, className }: ComponentBase) {
|
|
78
|
-
const { isSidebarOpen, closeSidebar } = useUI()
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<RAC.ModalOverlay
|
|
82
|
-
isOpen={isSidebarOpen}
|
|
83
|
-
onOpenChange={(open) => !open && closeSidebar()}
|
|
84
|
-
isDismissable={true}
|
|
85
|
-
className={cn(
|
|
86
|
-
'fixed inset-0 z-50 bg-black/20 backdrop-blur-sm lg:hidden',
|
|
87
|
-
'entering:animate-in entering:fade-in exiting:animate-out exiting:fade-out duration-300',
|
|
88
|
-
)}
|
|
89
|
-
>
|
|
90
|
-
<RAC.Modal
|
|
91
|
-
className={cn(
|
|
92
|
-
'fixed top-0 left-0 bottom-0 w-80 bg-main border-r border-subtle shadow-2xl outline-none',
|
|
93
|
-
'entering:animate-in entering:slide-in-from-left exiting:animate-out exiting:slide-out-to-left duration-300',
|
|
94
|
-
className,
|
|
95
|
-
)}
|
|
96
|
-
>
|
|
97
|
-
<RAC.Dialog className="h-full focus:outline-none outline-none flex flex-col">
|
|
98
|
-
{children}
|
|
99
|
-
</RAC.Dialog>
|
|
100
|
-
</RAC.Modal>
|
|
101
|
-
</RAC.ModalOverlay>
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Shared Header for Sidebar
|
|
107
|
-
*/
|
|
108
|
-
export function SidebarHeader({ children, className }: ComponentBase) {
|
|
109
|
-
return (
|
|
110
|
-
<div
|
|
111
|
-
className={cn(
|
|
112
|
-
'flex items-center justify-between p-4 border-b border-subtle',
|
|
113
|
-
className,
|
|
114
|
-
)}
|
|
115
|
-
>
|
|
116
|
-
{children}
|
|
117
|
-
</div>
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Scrollable Content Wrapper
|
|
123
|
-
*/
|
|
124
|
-
export function SidebarContent({ children, className }: ComponentBase) {
|
|
125
|
-
const scrollRef = useRef<HTMLDivElement>(null)
|
|
126
|
-
|
|
127
|
-
// Restore scroll position
|
|
128
|
-
useLayoutEffect(() => {
|
|
129
|
-
if (scrollRef.current) {
|
|
130
|
-
scrollRef.current.scrollTop = sidebarScrollPos
|
|
131
|
-
}
|
|
132
|
-
}, [])
|
|
133
|
-
|
|
134
|
-
// Save scroll position
|
|
135
|
-
useEffect(() => {
|
|
136
|
-
const el = scrollRef.current
|
|
137
|
-
if (!el) return
|
|
138
|
-
const handleScroll = () => {
|
|
139
|
-
sidebarScrollPos = el.scrollTop
|
|
140
|
-
}
|
|
141
|
-
el.addEventListener('scroll', handleScroll, { passive: true })
|
|
142
|
-
return () => el.removeEventListener('scroll', handleScroll)
|
|
143
|
-
}, [])
|
|
144
|
-
|
|
145
|
-
return (
|
|
146
|
-
<div
|
|
147
|
-
ref={scrollRef}
|
|
148
|
-
className={cn(
|
|
149
|
-
'flex-1 overflow-y-auto p-4 pb-16 custom-scrollbar',
|
|
150
|
-
className,
|
|
151
|
-
)}
|
|
152
|
-
>
|
|
153
|
-
<nav className="flex flex-col gap-6">{children}</nav>
|
|
154
|
-
</div>
|
|
155
|
-
)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Navigation Group
|
|
160
|
-
*/
|
|
161
|
-
export const SidebarGroup = ({
|
|
162
|
-
title,
|
|
163
|
-
icon: Icon,
|
|
164
|
-
children,
|
|
165
|
-
className,
|
|
166
|
-
}: { title?: string; icon?: React.ElementType } & ComponentBase) => {
|
|
167
|
-
return (
|
|
168
|
-
<div className={className}>
|
|
169
|
-
{title && (
|
|
170
|
-
<h4 className="px-2 mb-2 flex items-center gap-2 text-[11px] font-bold uppercase tracking-widest text-muted/50">
|
|
171
|
-
{Icon && <Icon size={12} />}
|
|
172
|
-
{title}
|
|
173
|
-
</h4>
|
|
174
|
-
)}
|
|
175
|
-
<div className="flex flex-col gap-0.5">{children}</div>
|
|
176
|
-
</div>
|
|
177
|
-
)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Sidebar Link
|
|
182
|
-
*/
|
|
183
|
-
export interface SidebarLinkProps extends ComponentBase {
|
|
184
|
-
label: string
|
|
185
|
-
href: string
|
|
186
|
-
active?: boolean
|
|
187
|
-
icon?: React.ElementType
|
|
188
|
-
badge?: ComponentRoute['badge']
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export const SidebarLink = ({
|
|
192
|
-
label,
|
|
193
|
-
href,
|
|
194
|
-
active,
|
|
195
|
-
icon: Icon,
|
|
196
|
-
badge,
|
|
197
|
-
className,
|
|
198
|
-
}: SidebarLinkProps) => {
|
|
199
|
-
return (
|
|
200
|
-
<Link
|
|
201
|
-
href={href}
|
|
202
|
-
className={cn(
|
|
203
|
-
'group flex items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-sm transition-all outline-none',
|
|
204
|
-
active
|
|
205
|
-
? 'bg-primary-500/10 text-primary-500 font-medium shadow-sm'
|
|
206
|
-
: 'text-muted hover:bg-surface hover:text-body',
|
|
207
|
-
className,
|
|
208
|
-
)}
|
|
209
|
-
>
|
|
210
|
-
{Icon && (
|
|
211
|
-
<Icon
|
|
212
|
-
size={16}
|
|
213
|
-
className={cn(
|
|
214
|
-
active ? 'text-primary-500' : 'text-muted group-hover:text-body',
|
|
215
|
-
)}
|
|
216
|
-
/>
|
|
217
|
-
)}
|
|
218
|
-
<span className="truncate">{label}</span>
|
|
219
|
-
{badge && <Badge badge={badge} />}
|
|
220
|
-
</Link>
|
|
221
|
-
)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Nested SubGroup
|
|
226
|
-
*/
|
|
227
|
-
export const SidebarSubGroup = ({
|
|
228
|
-
label,
|
|
229
|
-
href,
|
|
230
|
-
active,
|
|
231
|
-
icon: Icon,
|
|
232
|
-
badge,
|
|
233
|
-
isOpen,
|
|
234
|
-
onToggle,
|
|
235
|
-
children,
|
|
236
|
-
className,
|
|
237
|
-
}: SidebarLinkProps & {
|
|
238
|
-
isOpen: boolean
|
|
239
|
-
onToggle: () => void
|
|
240
|
-
children: ReactNode
|
|
241
|
-
}) => {
|
|
242
|
-
return (
|
|
243
|
-
<div className="flex flex-col gap-0.5">
|
|
244
|
-
<div className="group relative flex items-center">
|
|
245
|
-
<SidebarLink
|
|
246
|
-
label={label}
|
|
247
|
-
href={href}
|
|
248
|
-
active={active}
|
|
249
|
-
icon={Icon}
|
|
250
|
-
badge={badge}
|
|
251
|
-
className={cn('flex-1 pr-8', className)}
|
|
252
|
-
/>
|
|
253
|
-
<button
|
|
254
|
-
onClick={(e) => {
|
|
255
|
-
e.preventDefault()
|
|
256
|
-
e.stopPropagation()
|
|
257
|
-
onToggle()
|
|
258
|
-
}}
|
|
259
|
-
className="absolute right-1 p-1.5 text-muted hover:text-body transition-colors outline-none cursor-pointer"
|
|
260
|
-
>
|
|
261
|
-
<ChevronRight
|
|
262
|
-
size={14}
|
|
263
|
-
className={cn(
|
|
264
|
-
'transition-transform duration-200',
|
|
265
|
-
isOpen && 'rotate-90',
|
|
266
|
-
)}
|
|
267
|
-
/>
|
|
268
|
-
</button>
|
|
269
|
-
</div>
|
|
270
|
-
{isOpen && (
|
|
271
|
-
<div className="ml-4 pl-3 border-l border-subtle/50 mt-0.5 flex flex-col gap-0.5">
|
|
272
|
-
{children}
|
|
273
|
-
</div>
|
|
274
|
-
)}
|
|
275
|
-
</div>
|
|
276
|
-
)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Automated single-route rendering primitive
|
|
281
|
-
*/
|
|
282
|
-
export interface SidebarItemProps extends ComponentBase {
|
|
283
|
-
route: ComponentRoute
|
|
284
|
-
activePath: string
|
|
285
|
-
activeRoute?: ComponentRoute
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
export function SidebarItem({
|
|
289
|
-
route,
|
|
290
|
-
activePath,
|
|
291
|
-
activeRoute,
|
|
292
|
-
className,
|
|
293
|
-
}: SidebarItemProps) {
|
|
294
|
-
const localizedHref = useLocalizedTo(route.path)
|
|
295
|
-
const isCurrent =
|
|
296
|
-
activePath ===
|
|
297
|
-
(localizedHref.endsWith('/')
|
|
298
|
-
? localizedHref.slice(0, -1)
|
|
299
|
-
: localizedHref) ||
|
|
300
|
-
(!!activeRoute?.filePath &&
|
|
301
|
-
!!route.filePath &&
|
|
302
|
-
activeRoute.filePath === route.filePath)
|
|
303
|
-
const hasChildren = !!route.routes?.length || !!route.subRoutes?.length
|
|
304
|
-
const children = route.routes || route.subRoutes
|
|
305
|
-
|
|
306
|
-
const [isOpen, setIsOpen] = useState(
|
|
307
|
-
() =>
|
|
308
|
-
activePath.startsWith(localizedHref) ||
|
|
309
|
-
(!!activeRoute?.filePath &&
|
|
310
|
-
!!route.filePath &&
|
|
311
|
-
activeRoute.filePath === route.filePath),
|
|
312
|
-
)
|
|
313
|
-
const [prevActivePath, setPrevActivePath] = useState(activePath)
|
|
314
|
-
|
|
315
|
-
if (activePath !== prevActivePath) {
|
|
316
|
-
setPrevActivePath(activePath)
|
|
317
|
-
if (
|
|
318
|
-
activePath.startsWith(localizedHref) ||
|
|
319
|
-
(!!activeRoute?.filePath &&
|
|
320
|
-
!!route.filePath &&
|
|
321
|
-
activeRoute.filePath === route.filePath)
|
|
322
|
-
) {
|
|
323
|
-
setIsOpen(true)
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if (hasChildren) {
|
|
328
|
-
return (
|
|
329
|
-
<SidebarSubGroup
|
|
330
|
-
label={route.title}
|
|
331
|
-
href={route.path}
|
|
332
|
-
active={isCurrent}
|
|
333
|
-
icon={getIcon(route.icon)}
|
|
334
|
-
badge={route.badge}
|
|
335
|
-
isOpen={isOpen}
|
|
336
|
-
onToggle={() => setIsOpen(!isOpen)}
|
|
337
|
-
className={className}
|
|
338
|
-
>
|
|
339
|
-
{children?.map((subRoute) => (
|
|
340
|
-
<SidebarItem
|
|
341
|
-
key={subRoute.path}
|
|
342
|
-
route={subRoute}
|
|
343
|
-
activePath={activePath}
|
|
344
|
-
activeRoute={activeRoute}
|
|
345
|
-
/>
|
|
346
|
-
))}
|
|
347
|
-
</SidebarSubGroup>
|
|
348
|
-
)
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
return (
|
|
352
|
-
<SidebarLink
|
|
353
|
-
label={route.title}
|
|
354
|
-
href={route.path}
|
|
355
|
-
active={isCurrent}
|
|
356
|
-
icon={getIcon(route.icon)}
|
|
357
|
-
badge={route.badge}
|
|
358
|
-
className={className}
|
|
359
|
-
/>
|
|
360
|
-
)
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* High-level automated routes data rendering primitive
|
|
365
|
-
*/
|
|
366
|
-
export interface SidebarItemsProps extends ComponentBase {
|
|
367
|
-
routes: ComponentRoute[]
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
export function SidebarItems({ routes, className }: SidebarItemsProps) {
|
|
371
|
-
const { groups, ungrouped, activePath, activeRoute } = useSidebar(routes)
|
|
372
|
-
|
|
373
|
-
return (
|
|
374
|
-
<div className={cn('flex flex-col gap-6', className)}>
|
|
375
|
-
{ungrouped.length > 0 && (
|
|
376
|
-
<SidebarGroup>
|
|
377
|
-
{ungrouped.map((route) => (
|
|
378
|
-
<SidebarItem
|
|
379
|
-
key={route.path}
|
|
380
|
-
route={route}
|
|
381
|
-
activePath={activePath}
|
|
382
|
-
activeRoute={activeRoute}
|
|
383
|
-
/>
|
|
384
|
-
))}
|
|
385
|
-
</SidebarGroup>
|
|
386
|
-
)}
|
|
387
|
-
|
|
388
|
-
{groups.map((group) => (
|
|
389
|
-
<SidebarGroup
|
|
390
|
-
key={group.title}
|
|
391
|
-
title={group.title}
|
|
392
|
-
icon={getIcon(group.icon)}
|
|
393
|
-
>
|
|
394
|
-
{group.routes.map((route) => (
|
|
395
|
-
<SidebarItem
|
|
396
|
-
key={route.path}
|
|
397
|
-
route={route}
|
|
398
|
-
activePath={activePath}
|
|
399
|
-
activeRoute={activeRoute}
|
|
400
|
-
/>
|
|
401
|
-
))}
|
|
402
|
-
</SidebarGroup>
|
|
403
|
-
))}
|
|
404
|
-
</div>
|
|
405
|
-
)
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* Main Sidebar Export
|
|
410
|
-
*/
|
|
411
|
-
export const Sidebar = Object.assign(SidebarRoot, {
|
|
412
|
-
Root: SidebarRoot,
|
|
413
|
-
Mobile: SidebarMobile,
|
|
414
|
-
Header: SidebarHeader,
|
|
415
|
-
Content: SidebarContent,
|
|
416
|
-
Group: SidebarGroup,
|
|
417
|
-
Link: SidebarLink,
|
|
418
|
-
SubGroup: SidebarSubGroup,
|
|
419
|
-
Item: SidebarItem,
|
|
420
|
-
Items: SidebarItems,
|
|
421
|
-
})
|
|
422
|
-
|
|
423
|
-
export default Sidebar
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { cn } from '../../utils/cn'
|
|
2
|
-
|
|
3
|
-
interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
4
|
-
variant?: 'rect' | 'circle'
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A flexible skeleton component that mimics the shape of content
|
|
9
|
-
* while it is loading. Features a smooth pulse animation.
|
|
10
|
-
*/
|
|
11
|
-
export function Skeleton({
|
|
12
|
-
className,
|
|
13
|
-
variant = 'rect',
|
|
14
|
-
...props
|
|
15
|
-
}: SkeletonProps) {
|
|
16
|
-
return (
|
|
17
|
-
<div
|
|
18
|
-
className={cn(
|
|
19
|
-
'animate-pulse bg-soft',
|
|
20
|
-
variant === 'circle' ? 'rounded-full' : 'rounded-md',
|
|
21
|
-
className,
|
|
22
|
-
)}
|
|
23
|
-
{...props}
|
|
24
|
-
/>
|
|
25
|
-
)
|
|
26
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { cn } from '../../utils/cn'
|
|
2
|
-
import type { ComponentBase } from './types'
|
|
3
|
-
|
|
4
|
-
export interface TabsItemProps extends ComponentBase {
|
|
5
|
-
id: string
|
|
6
|
-
selected?: boolean
|
|
7
|
-
onClick?: () => void
|
|
8
|
-
onKeyDown?: (event: React.KeyboardEvent) => void
|
|
9
|
-
disabled?: boolean
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface TabsIndicatorProps extends ComponentBase {
|
|
13
|
-
style?: React.CSSProperties
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const Tabs = ({ children, className = '', ...props }: ComponentBase) => {
|
|
17
|
-
return (
|
|
18
|
-
<div className={cn('w-full', className)} {...props}>
|
|
19
|
-
{children}
|
|
20
|
-
</div>
|
|
21
|
-
)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const TabsList = ({ children, className = '' }: ComponentBase) => {
|
|
25
|
-
return (
|
|
26
|
-
<div
|
|
27
|
-
role="tablist"
|
|
28
|
-
className={cn('relative flex flex-row items-center', className)}
|
|
29
|
-
>
|
|
30
|
-
{children}
|
|
31
|
-
</div>
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const TabsItem = ({
|
|
36
|
-
children,
|
|
37
|
-
id,
|
|
38
|
-
selected,
|
|
39
|
-
className = '',
|
|
40
|
-
...props
|
|
41
|
-
}: TabsItemProps) => {
|
|
42
|
-
return (
|
|
43
|
-
<button
|
|
44
|
-
role="tab"
|
|
45
|
-
aria-selected={selected}
|
|
46
|
-
data-selected={selected}
|
|
47
|
-
className={cn(
|
|
48
|
-
'outline-none cursor-pointer bg-transparent border-none',
|
|
49
|
-
className,
|
|
50
|
-
)}
|
|
51
|
-
{...props}
|
|
52
|
-
>
|
|
53
|
-
{children}
|
|
54
|
-
</button>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const TabsContent = ({ children, className = '' }: ComponentBase) => {
|
|
59
|
-
return <div className={cn('outline-none', className)}>{children}</div>
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const TabsIndicator = ({ className = '', style }: TabsIndicatorProps) => {
|
|
63
|
-
return <div className={cn('absolute bottom-0', className)} style={style} />
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
Tabs.Root = Tabs
|
|
67
|
-
Tabs.List = TabsList
|
|
68
|
-
Tabs.Item = TabsItem
|
|
69
|
-
Tabs.Content = TabsContent
|
|
70
|
-
Tabs.Indicator = TabsIndicator
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react'
|
|
2
|
-
import * as RAC from 'react-aria-components'
|
|
3
|
-
import { cn } from '../../utils/cn'
|
|
4
|
-
|
|
5
|
-
export interface TooltipProps extends Omit<RAC.TooltipProps, 'children'> {
|
|
6
|
-
/** The content to show inside the tooltip */
|
|
7
|
-
content: ReactNode
|
|
8
|
-
/** The trigger element (usually a button or link) */
|
|
9
|
-
children: React.ReactElement
|
|
10
|
-
/** Delay in milliseconds before showing the tooltip */
|
|
11
|
-
delay?: number
|
|
12
|
-
/** Delay in milliseconds before hiding the tooltip */
|
|
13
|
-
closeDelay?: number
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Fixed type for TooltipContentProps to match RAC's internal expectations
|
|
17
|
-
export interface TooltipContentProps extends RAC.TooltipProps {}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Modern, accessible Tooltip component built with React Aria Components.
|
|
21
|
-
* Featuring glassmorphism, animations, and smart positioning.
|
|
22
|
-
*/
|
|
23
|
-
const TooltipContent = ({
|
|
24
|
-
className,
|
|
25
|
-
children,
|
|
26
|
-
...props
|
|
27
|
-
}: TooltipContentProps) => {
|
|
28
|
-
return (
|
|
29
|
-
<RAC.Tooltip
|
|
30
|
-
{...props}
|
|
31
|
-
offset={8}
|
|
32
|
-
className={(values) =>
|
|
33
|
-
cn(
|
|
34
|
-
'group z-50 overflow-visible rounded-md bg-surface px-2.5 py-1.5 text-xs font-medium text-body ring-1 ring-subtle outline-hidden select-none',
|
|
35
|
-
'data-entering:animate-in data-entering:fade-in data-entering:zoom-in-95 data-entering:duration-100',
|
|
36
|
-
'data-exiting:animate-out data-exiting:fade-out data-exiting:zoom-out-95 data-exiting:duration-75',
|
|
37
|
-
'data-[placement=top]:slide-in-from-bottom-1',
|
|
38
|
-
'data-[placement=bottom]:slide-in-from-top-1',
|
|
39
|
-
'data-[placement=left]:slide-in-from-right-1',
|
|
40
|
-
'data-[placement=right]:slide-in-from-left-1',
|
|
41
|
-
typeof className === 'function' ? className(values) : className,
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
>
|
|
45
|
-
{(values) => (
|
|
46
|
-
<>
|
|
47
|
-
<RAC.OverlayArrow>
|
|
48
|
-
<svg
|
|
49
|
-
width={8}
|
|
50
|
-
height={8}
|
|
51
|
-
viewBox="0 0 8 8"
|
|
52
|
-
className="fill-bg-surface/90 stroke-border-subtle group-data-[placement=bottom]:rotate-180 group-data-[placement=left]:-rotate-90 group-data-[placement=right]:rotate-90"
|
|
53
|
-
>
|
|
54
|
-
<title>Arrow</title>
|
|
55
|
-
<path d="M0 0 L4 4 L8 0" />
|
|
56
|
-
</svg>
|
|
57
|
-
</RAC.OverlayArrow>
|
|
58
|
-
{typeof children === 'function' ? children(values) : children}
|
|
59
|
-
</>
|
|
60
|
-
)}
|
|
61
|
-
</RAC.Tooltip>
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export const Tooltip = ({
|
|
66
|
-
content,
|
|
67
|
-
children,
|
|
68
|
-
delay = 500,
|
|
69
|
-
closeDelay = 0,
|
|
70
|
-
...props
|
|
71
|
-
}: TooltipProps) => {
|
|
72
|
-
return (
|
|
73
|
-
<RAC.TooltipTrigger delay={delay} closeDelay={closeDelay}>
|
|
74
|
-
{children}
|
|
75
|
-
<TooltipContent {...props}>{content}</TooltipContent>
|
|
76
|
-
</RAC.TooltipTrigger>
|
|
77
|
-
)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
Tooltip.Root = Tooltip
|
|
81
|
-
Tooltip.Content = TooltipContent
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react'
|
|
2
|
-
|
|
3
|
-
export type ComponentBase = {
|
|
4
|
-
className?: string
|
|
5
|
-
children?: ReactNode
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Helper to type compound components (e.g. Navbar with Navbar.Link)
|
|
10
|
-
*/
|
|
11
|
-
export type CompoundComponent<P, S> = React.FC<P> & S
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react'
|
|
2
|
-
import { X } from './icons'
|
|
3
|
-
|
|
4
|
-
export interface BannerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
5
|
-
/**
|
|
6
|
-
* If true, shows a close button to dismiss the banner.
|
|
7
|
-
*/
|
|
8
|
-
dismissible?: boolean
|
|
9
|
-
/**
|
|
10
|
-
* Unique identifier for the banner. If provided and dismissible is true,
|
|
11
|
-
* the dismissed state will be saved in localStorage so it doesn't reappear
|
|
12
|
-
* on subsequent visits.
|
|
13
|
-
*/
|
|
14
|
-
id?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function Banner({
|
|
18
|
-
children,
|
|
19
|
-
className = '',
|
|
20
|
-
dismissible = false,
|
|
21
|
-
id = 'boltdocs-banner',
|
|
22
|
-
...props
|
|
23
|
-
}: BannerProps) {
|
|
24
|
-
const [isVisible, setIsVisible] = useState(true)
|
|
25
|
-
|
|
26
|
-
useEffect(() => {
|
|
27
|
-
if (dismissible && id) {
|
|
28
|
-
const isDismissed = localStorage.getItem(
|
|
29
|
-
`boltdocs-banner-dismissed-${id}`,
|
|
30
|
-
)
|
|
31
|
-
if (isDismissed === 'true') {
|
|
32
|
-
setIsVisible(false)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}, [dismissible, id])
|
|
36
|
-
|
|
37
|
-
const handleDismiss = () => {
|
|
38
|
-
setIsVisible(false)
|
|
39
|
-
if (dismissible && id) {
|
|
40
|
-
localStorage.setItem(`boltdocs-banner-dismissed-${id}`, 'true')
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!isVisible) return null
|
|
45
|
-
|
|
46
|
-
return (
|
|
47
|
-
<div
|
|
48
|
-
className={`relative flex items-center justify-center px-4 py-2.5 text-xs font-semibold tracking-wide bg-primary-500/10 dark:bg-primary-500/15 text-primary-700 dark:text-primary-300 border-b border-primary-500/20 select-none animate-in fade-in duration-300 ${className}`}
|
|
49
|
-
{...props}
|
|
50
|
-
>
|
|
51
|
-
<div className="flex-1 text-center flex items-center justify-center gap-2">
|
|
52
|
-
{children}
|
|
53
|
-
</div>
|
|
54
|
-
{dismissible && (
|
|
55
|
-
<button
|
|
56
|
-
onClick={handleDismiss}
|
|
57
|
-
className="absolute right-3 top-1/2 -translate-y-1/2 p-1.5 opacity-70 hover:opacity-100 transition-all duration-300 rounded-xl hover:bg-primary-500/10 cursor-pointer border-none bg-transparent flex items-center justify-center outline-none"
|
|
58
|
-
aria-label="Dismiss banner"
|
|
59
|
-
>
|
|
60
|
-
<X className="w-3.5 h-3.5" />
|
|
61
|
-
</button>
|
|
62
|
-
)}
|
|
63
|
-
</div>
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
export default Banner
|