boltdocs 2.6.1 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/boltdocs.js +0 -1
- package/dist/cache-CQKlT4fI.mjs +6 -0
- package/dist/cache-DorPMFgW.cjs +6 -0
- package/dist/cards-BLoSiRuL.d.ts +30 -0
- package/dist/cards-CQn9mXZS.d.cts +30 -0
- package/dist/chunk-Ds5LZdWN.cjs +6 -0
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.d.cts +173 -1328
- package/dist/client/index.d.ts +172 -1327
- package/dist/client/index.js +1 -1
- package/dist/{package-c99Cs7mD.cjs → client/mdx.cjs} +1 -1
- package/dist/client/mdx.d.cts +128 -0
- package/dist/client/mdx.d.ts +129 -0
- package/dist/client/mdx.js +6 -0
- package/dist/client/primitives.cjs +6 -0
- package/dist/client/primitives.d.cts +818 -0
- package/dist/client/primitives.d.ts +818 -0
- package/dist/client/primitives.js +6 -0
- package/dist/client/theme/neutral.css +74 -361
- package/dist/client/theme/reset.css +189 -0
- package/dist/docs-layout-BlDhcQRv.cjs +6 -0
- package/dist/docs-layout-BvAOWEJw.js +6 -0
- package/dist/doctor-BQiQhCTl.cjs +6 -0
- package/dist/doctor-COpf35L2.cjs +20 -0
- package/dist/doctor-Dh1XP7Pz.mjs +20 -0
- package/dist/generator-DGW6pkCC.cjs +22 -0
- package/dist/generator-Dv3wEmhZ.mjs +22 -0
- package/dist/icons-dev-CrQLjoQp.js +6 -0
- package/dist/icons-dev-rzdz6Lf3.cjs +6 -0
- package/dist/image-BkIfa9oo.js +6 -0
- package/dist/image-DIGjCPe6.cjs +6 -0
- package/dist/mdx-K0WYBAJ3.js +7 -0
- package/dist/mdx-hpErbRUe.cjs +7 -0
- package/dist/meta-loader-0gJ4PtBC.cjs +6 -0
- package/dist/meta-loader-9IpAHWDS.mjs +6 -0
- package/dist/node/cli-entry.cjs +1 -2
- package/dist/node/cli-entry.mjs +1 -2
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +66 -13
- package/dist/node/index.d.mts +66 -14
- package/dist/node/index.mjs +1 -1
- package/dist/node/routes/worker.cjs +6 -0
- package/dist/node/routes/worker.d.cts +2 -0
- package/dist/node/routes/worker.d.mts +2 -0
- package/dist/node/routes/worker.mjs +6 -0
- package/dist/node-C2nWXElP.mjs +112 -0
- package/dist/node-CinkUtxV.cjs +112 -0
- package/dist/package-BMYLDBBP.cjs +6 -0
- package/dist/{package-DukYeKmD.mjs → package-HegMOTL_.mjs} +1 -1
- package/dist/parser-Bh11BsdA.cjs +6 -0
- package/dist/parser-D8eQvE7N.mjs +6 -0
- package/dist/parser-DYRzXWmA.cjs +6 -0
- package/dist/routes-CHf76Ye4.cjs +6 -0
- package/dist/routes-CMUZGI6T.mjs +6 -0
- package/dist/routes-Co1mRM58.cjs +6 -0
- package/dist/search-dialog-BACuzoVX.cjs +6 -0
- package/dist/search-dialog-BKagVT17.js +6 -0
- package/dist/search-dialog-C8w12eUx.js +6 -0
- package/dist/search-dialog-CGyrozZE.cjs +6 -0
- package/dist/search-dialog-D26rUnJ_.cjs +6 -0
- package/dist/sidebar-DKvg6KOc.d.cts +491 -0
- package/dist/sidebar-Dr1TiRIy.d.ts +491 -0
- package/dist/utils-BxNAXhZZ.mjs +7 -0
- package/dist/utils-Clzu7jvb.cjs +7 -0
- package/dist/worker-pool-Bd8Y9KDv.mjs +6 -0
- package/dist/worker-pool-BwU8ckrg.cjs +6 -0
- package/package.json +27 -8
- package/src/client/app/doc-page.tsx +9 -5
- package/src/client/app/docs-layout.tsx +17 -3
- package/src/client/app/head.tsx +122 -0
- package/src/client/app/helmet-compat.tsx +36 -0
- package/src/client/app/mdx-component.tsx +5 -52
- package/src/client/app/mdx-components-context.tsx +32 -8
- package/src/client/app/routes-context.tsx +2 -2
- package/src/client/app/scroll-handler.tsx +1 -1
- package/src/client/app/theme-context.tsx +5 -5
- package/src/client/app/ui-context.tsx +42 -0
- package/src/client/components/docs-layout-default.tsx +85 -0
- package/src/client/components/icons-dev.tsx +38 -15
- package/src/client/components/mdx/callout.tsx +97 -0
- package/src/client/components/mdx/card.tsx +73 -98
- package/src/client/components/mdx/cards.tsx +27 -0
- package/src/client/components/mdx/code-block.tsx +37 -17
- package/src/client/components/mdx/field.tsx +24 -56
- package/src/client/components/mdx/image.tsx +36 -15
- package/src/client/components/mdx/index.ts +19 -53
- package/src/client/components/mdx/table.tsx +46 -148
- package/src/client/components/mdx/typographics.tsx +120 -0
- package/src/client/components/mdx/{hooks/use-code-block.ts → use-code-block.ts} +5 -7
- package/src/client/components/primitives/breadcrumbs.tsx +5 -24
- package/src/client/components/primitives/button.tsx +3 -142
- package/src/client/components/primitives/code-block.tsx +104 -97
- package/src/client/components/{docs-layout.tsx → primitives/docs-layout.tsx} +15 -24
- package/src/client/components/primitives/error-boundary.tsx +107 -0
- package/src/client/components/primitives/heading.tsx +128 -0
- package/src/client/components/primitives/helpers/observer.ts +62 -32
- package/src/client/components/primitives/image.tsx +26 -0
- package/src/client/components/primitives/link.tsx +50 -52
- package/src/client/components/primitives/menu.tsx +25 -49
- package/src/client/components/primitives/navbar.tsx +234 -59
- package/src/client/components/primitives/on-this-page.tsx +169 -40
- package/src/client/components/primitives/page-nav.tsx +11 -39
- package/src/client/components/primitives/popover.tsx +12 -30
- package/src/client/components/primitives/search-dialog.tsx +77 -71
- package/src/client/components/primitives/sidebar.tsx +312 -119
- package/src/client/components/primitives/skeleton.tsx +1 -1
- package/src/client/components/primitives/tabs.tsx +5 -16
- package/src/client/components/primitives/tooltip.tsx +1 -1
- package/src/client/components/ui-base/banner.tsx +66 -0
- package/src/client/components/ui-base/breadcrumbs.tsx +26 -20
- package/src/client/components/ui-base/copy-markdown.tsx +43 -35
- package/src/client/components/ui-base/error-boundary.tsx +9 -46
- package/src/client/components/ui-base/github-stars.tsx +5 -3
- package/src/client/components/ui-base/index.ts +3 -3
- package/src/client/components/ui-base/last-updated.tsx +27 -0
- package/src/client/components/ui-base/navbar.tsx +183 -89
- package/src/client/components/ui-base/not-found.tsx +11 -9
- package/src/client/components/ui-base/on-this-page.tsx +8 -104
- package/src/client/components/ui-base/page-nav.tsx +23 -9
- package/src/client/components/ui-base/search-dialog.tsx +111 -36
- package/src/client/components/ui-base/search-highlight.tsx +10 -0
- package/src/client/components/ui-base/sidebar.tsx +77 -154
- package/src/client/components/ui-base/tabs.tsx +20 -7
- package/src/client/components/ui-base/theme-toggle.tsx +88 -10
- package/src/client/components/ui-base/version-i18n.tsx +80 -0
- package/src/client/hooks/index.ts +2 -1
- package/src/client/hooks/use-analytics.ts +272 -0
- package/src/client/hooks/use-i18n.ts +120 -53
- package/src/client/hooks/use-localized-to.ts +70 -30
- package/src/client/hooks/use-navbar.ts +69 -39
- package/src/client/hooks/use-page-nav.ts +28 -25
- package/src/client/hooks/use-routes.ts +64 -81
- package/src/client/hooks/use-search-highlight.ts +185 -0
- package/src/client/hooks/use-search.ts +12 -3
- package/src/client/hooks/use-sidebar.ts +183 -77
- package/src/client/hooks/use-tabs.ts +3 -4
- package/src/client/hooks/use-version.ts +46 -18
- package/src/client/index.ts +13 -86
- package/src/client/mdx.ts +2 -0
- package/src/client/primitives.ts +19 -0
- package/src/client/ssg/boltdocs-shell.tsx +78 -57
- package/src/client/ssg/create-routes.tsx +290 -50
- package/src/client/ssg/mdx-page.tsx +2 -1
- package/src/client/store/boltdocs-context.tsx +83 -12
- package/src/client/theme/neutral.css +74 -361
- package/src/client/theme/reset.css +189 -0
- package/src/client/types.ts +10 -2
- package/src/client/utils/path.ts +9 -0
- package/src/client/utils/react-to-text.ts +24 -24
- package/src/client/virtual.d.ts +1 -1
- package/src/shared/types.ts +97 -21
- package/dist/node-CWN8U_p8.mjs +0 -88
- package/dist/node-D5iosYXv.cjs +0 -88
- package/dist/search-dialog-3lvKsbVG.js +0 -6
- package/dist/search-dialog-DMK5OpgH.cjs +0 -6
- package/dist/use-search-C9bxCqfF.js +0 -6
- package/dist/use-search-DcfZSunO.cjs +0 -6
- package/src/client/components/mdx/admonition.tsx +0 -91
- package/src/client/components/mdx/badge.tsx +0 -41
- package/src/client/components/mdx/button.tsx +0 -35
- package/src/client/components/mdx/component-preview.tsx +0 -37
- package/src/client/components/mdx/component-props.tsx +0 -83
- package/src/client/components/mdx/file-tree.tsx +0 -325
- package/src/client/components/mdx/hooks/use-component-preview.ts +0 -16
- package/src/client/components/mdx/hooks/useTable.ts +0 -74
- package/src/client/components/mdx/hooks/useTabs.ts +0 -68
- package/src/client/components/mdx/link.tsx +0 -38
- package/src/client/components/mdx/list.tsx +0 -192
- package/src/client/components/mdx/tabs.tsx +0 -135
- package/src/client/components/mdx/video.tsx +0 -68
- package/src/client/components/primitives/index.ts +0 -19
- package/src/client/components/primitives/navigation-menu.tsx +0 -114
- package/src/client/components/ui-base/head.tsx +0 -76
- package/src/client/components/ui-base/loading.tsx +0 -57
- package/src/client/components/ui-base/powered-by.tsx +0 -25
- package/src/client/hooks/use-onthispage.ts +0 -23
- package/src/client/utils/use-on-change.ts +0 -15
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Children,
|
|
3
|
-
isValidElement,
|
|
4
|
-
type ReactNode,
|
|
5
|
-
type ReactElement,
|
|
6
|
-
type ComponentPropsWithoutRef,
|
|
7
|
-
} from 'react'
|
|
8
|
-
import { Check, ChevronRight, Circle } from 'lucide-react'
|
|
9
|
-
import { cn } from '../../utils/cn'
|
|
10
|
-
import { cva, type VariantProps } from 'class-variance-authority'
|
|
11
|
-
|
|
12
|
-
const listVariants = cva('my-6 transition-all duration-200', {
|
|
13
|
-
variants: {
|
|
14
|
-
variant: {
|
|
15
|
-
default: 'list-disc pl-5 text-text-muted marker:text-primary-500/50',
|
|
16
|
-
number:
|
|
17
|
-
'list-decimal pl-5 text-text-muted marker:text-primary-500/50 marker:font-bold',
|
|
18
|
-
checked: 'list-none p-0',
|
|
19
|
-
arrow: 'list-none p-0',
|
|
20
|
-
bubble: 'list-none p-0',
|
|
21
|
-
},
|
|
22
|
-
cols: {
|
|
23
|
-
1: 'grid-cols-1',
|
|
24
|
-
2: 'grid-cols-1 sm:grid-cols-2',
|
|
25
|
-
3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
|
|
26
|
-
4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4',
|
|
27
|
-
},
|
|
28
|
-
isGrid: {
|
|
29
|
-
true: 'grid gap-x-8 gap-y-3',
|
|
30
|
-
false: 'space-y-2',
|
|
31
|
-
},
|
|
32
|
-
dense: {
|
|
33
|
-
true: 'space-y-1',
|
|
34
|
-
false: 'space-y-2',
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
compoundVariants: [
|
|
38
|
-
{
|
|
39
|
-
variant: 'default',
|
|
40
|
-
dense: true,
|
|
41
|
-
className: 'space-y-0.5',
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
defaultVariants: {
|
|
45
|
-
variant: 'default',
|
|
46
|
-
cols: 1,
|
|
47
|
-
isGrid: false,
|
|
48
|
-
dense: false,
|
|
49
|
-
},
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
const itemVariants = cva(
|
|
53
|
-
'group flex items-start gap-3 text-sm leading-relaxed transition-all duration-200',
|
|
54
|
-
{
|
|
55
|
-
variants: {
|
|
56
|
-
variant: {
|
|
57
|
-
default: '',
|
|
58
|
-
number: '',
|
|
59
|
-
checked: 'hover:translate-x-0.5',
|
|
60
|
-
arrow: 'hover:translate-x-0.5',
|
|
61
|
-
bubble: 'hover:translate-x-0.5',
|
|
62
|
-
},
|
|
63
|
-
dense: {
|
|
64
|
-
true: 'py-0',
|
|
65
|
-
false: 'py-0.5',
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
defaultVariants: {
|
|
69
|
-
variant: 'default',
|
|
70
|
-
dense: false,
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
const iconContainerVariants = cva(
|
|
76
|
-
'mt-1 shrink-0 flex items-center justify-center transition-transform group-hover:scale-110',
|
|
77
|
-
{
|
|
78
|
-
variants: {
|
|
79
|
-
variant: {
|
|
80
|
-
bubble:
|
|
81
|
-
'h-5 w-5 rounded-full bg-primary-500/10 text-primary-500 text-[10px] font-bold',
|
|
82
|
-
default: '',
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
defaultVariants: {
|
|
86
|
-
variant: 'default',
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
type ListVariantProps = VariantProps<typeof listVariants>
|
|
92
|
-
|
|
93
|
-
export interface ListProps
|
|
94
|
-
extends ComponentPropsWithoutRef<'ul'>,
|
|
95
|
-
Omit<ListVariantProps, 'variant'> {
|
|
96
|
-
variant?: 'checked' | 'arrow' | 'default' | 'bubble' | 'number'
|
|
97
|
-
children: ReactNode
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
interface ListItemProps extends VariantProps<typeof itemVariants> {
|
|
101
|
-
icon?: ReactNode
|
|
102
|
-
children: ReactNode
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function ListItem({ icon, children, variant, dense }: ListItemProps) {
|
|
106
|
-
return (
|
|
107
|
-
<li className={cn(itemVariants({ variant, dense }))}>
|
|
108
|
-
{icon && (
|
|
109
|
-
<span
|
|
110
|
-
className={cn(
|
|
111
|
-
iconContainerVariants({
|
|
112
|
-
variant: variant === 'bubble' ? 'bubble' : 'default',
|
|
113
|
-
}),
|
|
114
|
-
)}
|
|
115
|
-
>
|
|
116
|
-
{icon}
|
|
117
|
-
</span>
|
|
118
|
-
)}
|
|
119
|
-
<div className="flex-1 text-text-muted group-hover:text-text-main transition-colors">
|
|
120
|
-
{children}
|
|
121
|
-
</div>
|
|
122
|
-
</li>
|
|
123
|
-
)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const ICON_MAP: Record<string, (cls?: string) => ReactNode> = {
|
|
127
|
-
checked: (cls) => (
|
|
128
|
-
<Check size={14} className={cn('text-emerald-500 shrink-0', cls)} />
|
|
129
|
-
),
|
|
130
|
-
arrow: (cls) => (
|
|
131
|
-
<ChevronRight size={14} className={cn('text-primary-400 shrink-0', cls)} />
|
|
132
|
-
),
|
|
133
|
-
bubble: (cls) => (
|
|
134
|
-
<Circle
|
|
135
|
-
size={6}
|
|
136
|
-
fill="currentColor"
|
|
137
|
-
className={cn('text-primary-500 shrink-0', cls)}
|
|
138
|
-
/>
|
|
139
|
-
),
|
|
140
|
-
default: () => null,
|
|
141
|
-
number: () => null,
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export function List({
|
|
145
|
-
variant = 'default',
|
|
146
|
-
cols = 1,
|
|
147
|
-
dense = false,
|
|
148
|
-
children,
|
|
149
|
-
className,
|
|
150
|
-
...props
|
|
151
|
-
}: ListProps) {
|
|
152
|
-
const isGrid = cols !== undefined && Number(cols) > 1
|
|
153
|
-
const renderIcon = ICON_MAP[variant]
|
|
154
|
-
const containerClasses = listVariants({
|
|
155
|
-
variant,
|
|
156
|
-
cols,
|
|
157
|
-
dense,
|
|
158
|
-
isGrid,
|
|
159
|
-
className,
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
const Component = variant === 'number' ? 'ol' : 'ul'
|
|
163
|
-
|
|
164
|
-
// Handling raw MDX siblings (nested logic)
|
|
165
|
-
if (variant === 'default' || variant === 'number') {
|
|
166
|
-
return (
|
|
167
|
-
<Component className={containerClasses} {...props}>
|
|
168
|
-
{children}
|
|
169
|
-
</Component>
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return (
|
|
174
|
-
<ul className={containerClasses} {...props}>
|
|
175
|
-
{Children.map(children, (child) => {
|
|
176
|
-
if (!isValidElement(child)) return child
|
|
177
|
-
|
|
178
|
-
const element = child as ReactElement<{ children?: ReactNode }>
|
|
179
|
-
const content =
|
|
180
|
-
element.type === 'li'
|
|
181
|
-
? element.props.children
|
|
182
|
-
: element.props.children || child
|
|
183
|
-
|
|
184
|
-
return (
|
|
185
|
-
<ListItem icon={renderIcon()} variant={variant} dense={dense}>
|
|
186
|
-
{content}
|
|
187
|
-
</ListItem>
|
|
188
|
-
)
|
|
189
|
-
})}
|
|
190
|
-
</ul>
|
|
191
|
-
)
|
|
192
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { Children, isValidElement, useMemo } from 'react'
|
|
2
|
-
import * as RAC from 'react-aria-components'
|
|
3
|
-
import { useTabs } from './hooks/useTabs'
|
|
4
|
-
import { cn } from '../../utils/cn'
|
|
5
|
-
import { CodeBlock } from './code-block'
|
|
6
|
-
import { cva } from 'class-variance-authority'
|
|
7
|
-
|
|
8
|
-
const tabListVariants = cva(
|
|
9
|
-
'relative flex items-center border-b border-border-subtle gap-1 overflow-x-auto no-scrollbar',
|
|
10
|
-
{
|
|
11
|
-
variants: {
|
|
12
|
-
size: {
|
|
13
|
-
default: 'px-0',
|
|
14
|
-
compact: 'px-2',
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
defaultVariants: {
|
|
18
|
-
size: 'default',
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
const tabItemVariants = cva(
|
|
24
|
-
'flex items-center gap-2 px-4 py-2.5 text-sm font-medium outline-none transition-all duration-200 cursor-pointer bg-transparent border-none select-none whitespace-nowrap',
|
|
25
|
-
{
|
|
26
|
-
variants: {
|
|
27
|
-
isActive: {
|
|
28
|
-
true: 'text-primary-500',
|
|
29
|
-
false: 'text-text-muted hover:text-text-main',
|
|
30
|
-
},
|
|
31
|
-
isDisabled: {
|
|
32
|
-
true: 'opacity-40 pointer-events-none',
|
|
33
|
-
false: '',
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
defaultVariants: {
|
|
37
|
-
isActive: false,
|
|
38
|
-
isDisabled: false,
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
export interface TabProps {
|
|
44
|
-
label: string
|
|
45
|
-
icon?: React.ReactNode
|
|
46
|
-
disabled?: boolean
|
|
47
|
-
children: React.ReactNode
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function Tab({ children }: TabProps) {
|
|
51
|
-
const content =
|
|
52
|
-
typeof children === 'string' ? (
|
|
53
|
-
<CodeBlock className="language-bash">
|
|
54
|
-
<code>{children.trim()}</code>
|
|
55
|
-
</CodeBlock>
|
|
56
|
-
) : (
|
|
57
|
-
children
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
return <div className="py-4">{content}</div>
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface TabsProps {
|
|
64
|
-
defaultIndex?: number
|
|
65
|
-
children: React.ReactNode
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function Tabs({ defaultIndex = 0, children }: TabsProps) {
|
|
69
|
-
const tabs = useMemo(() => {
|
|
70
|
-
return Children.toArray(children).filter(
|
|
71
|
-
(child) =>
|
|
72
|
-
isValidElement(child) &&
|
|
73
|
-
(child as React.ReactElement<TabProps>).props?.label,
|
|
74
|
-
) as React.ReactElement<TabProps>[]
|
|
75
|
-
}, [children])
|
|
76
|
-
|
|
77
|
-
const { active, setActive, tabRefs, indicatorStyle } = useTabs({
|
|
78
|
-
initialIndex: defaultIndex,
|
|
79
|
-
tabs,
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<div className="my-8 w-full group/tabs">
|
|
84
|
-
<RAC.Tabs
|
|
85
|
-
selectedKey={active.toString()}
|
|
86
|
-
onSelectionChange={(key) => setActive(Number(key))}
|
|
87
|
-
className="w-full"
|
|
88
|
-
>
|
|
89
|
-
<RAC.TabList
|
|
90
|
-
aria-label="Content Tabs"
|
|
91
|
-
className={cn(tabListVariants())}
|
|
92
|
-
>
|
|
93
|
-
{tabs.map((child, i) => {
|
|
94
|
-
const { label, icon, disabled } = child.props
|
|
95
|
-
const key = i.toString()
|
|
96
|
-
|
|
97
|
-
return (
|
|
98
|
-
<RAC.Tab
|
|
99
|
-
key={key}
|
|
100
|
-
id={key}
|
|
101
|
-
isDisabled={disabled}
|
|
102
|
-
ref={(el: any) => {
|
|
103
|
-
tabRefs.current[i] = el
|
|
104
|
-
}}
|
|
105
|
-
className={({ isSelected, isDisabled }) =>
|
|
106
|
-
cn(tabItemVariants({ isActive: isSelected, isDisabled }))
|
|
107
|
-
}
|
|
108
|
-
>
|
|
109
|
-
{!!icon && (
|
|
110
|
-
<span className="shrink-0 [&>svg]:w-4 [&>svg]:h-4">
|
|
111
|
-
{icon}
|
|
112
|
-
</span>
|
|
113
|
-
)}
|
|
114
|
-
<span>{label}</span>
|
|
115
|
-
</RAC.Tab>
|
|
116
|
-
)
|
|
117
|
-
})}
|
|
118
|
-
|
|
119
|
-
<div
|
|
120
|
-
className="absolute bottom-0 h-0.5 bg-primary-500 transition-all duration-300 ease-in-out pointer-events-none"
|
|
121
|
-
style={indicatorStyle}
|
|
122
|
-
aria-hidden="true"
|
|
123
|
-
/>
|
|
124
|
-
</RAC.TabList>
|
|
125
|
-
|
|
126
|
-
{tabs.map((_tab, i) => (
|
|
127
|
-
<RAC.TabPanel key={i} id={i.toString()}>
|
|
128
|
-
{/* biome-ignore lint/suspicious/noExplicitAny: bypass version-specific ReactNode mismatch */}
|
|
129
|
-
{tabs[i] as any}
|
|
130
|
-
</RAC.TabPanel>
|
|
131
|
-
))}
|
|
132
|
-
</RAC.Tabs>
|
|
133
|
-
</div>
|
|
134
|
-
)
|
|
135
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { useRef, useState, useEffect } from 'react'
|
|
2
|
-
|
|
3
|
-
interface VideoProps {
|
|
4
|
-
src?: string
|
|
5
|
-
poster?: string
|
|
6
|
-
alt?: string
|
|
7
|
-
controls?: boolean
|
|
8
|
-
preload?: string
|
|
9
|
-
children?: React.ReactNode
|
|
10
|
-
[key: string]: any
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function Video({
|
|
14
|
-
src,
|
|
15
|
-
poster,
|
|
16
|
-
alt,
|
|
17
|
-
children,
|
|
18
|
-
controls,
|
|
19
|
-
preload = 'metadata',
|
|
20
|
-
...rest
|
|
21
|
-
}: VideoProps) {
|
|
22
|
-
const containerRef = useRef<HTMLDivElement>(null)
|
|
23
|
-
const [isVisible, setIsVisible] = useState(false)
|
|
24
|
-
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
const el = containerRef.current
|
|
27
|
-
if (!el) return
|
|
28
|
-
const observer = new IntersectionObserver(
|
|
29
|
-
([entry]) => {
|
|
30
|
-
if (entry.isIntersecting) {
|
|
31
|
-
setIsVisible(true)
|
|
32
|
-
observer.disconnect()
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
{ rootMargin: '200px' },
|
|
36
|
-
)
|
|
37
|
-
observer.observe(el)
|
|
38
|
-
return () => observer.disconnect()
|
|
39
|
-
}, [])
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<div
|
|
43
|
-
ref={containerRef}
|
|
44
|
-
className="my-6 overflow-hidden rounded-lg border border-border-subtle"
|
|
45
|
-
>
|
|
46
|
-
{isVisible ? (
|
|
47
|
-
<video
|
|
48
|
-
className="block w-full h-auto"
|
|
49
|
-
src={src}
|
|
50
|
-
poster={poster}
|
|
51
|
-
controls={true}
|
|
52
|
-
preload={preload}
|
|
53
|
-
playsInline
|
|
54
|
-
{...rest}
|
|
55
|
-
>
|
|
56
|
-
{children}
|
|
57
|
-
Your browser does not support the video tag.
|
|
58
|
-
</video>
|
|
59
|
-
) : (
|
|
60
|
-
<div
|
|
61
|
-
className="aspect-video bg-bg-surface animate-pulse"
|
|
62
|
-
role="img"
|
|
63
|
-
aria-label={alt || 'Video'}
|
|
64
|
-
/>
|
|
65
|
-
)}
|
|
66
|
-
</div>
|
|
67
|
-
)
|
|
68
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export * as Navbar from './navbar'
|
|
2
|
-
export * as NavigationMenu from './navigation-menu'
|
|
3
|
-
export * as SearchDialog from './search-dialog'
|
|
4
|
-
export * as OnThisPage from './on-this-page'
|
|
5
|
-
export * as PageNav from './page-nav'
|
|
6
|
-
export * as Tabs from './tabs'
|
|
7
|
-
export * as Sidebar from './sidebar'
|
|
8
|
-
export * as Breadcrumbs from './breadcrumbs'
|
|
9
|
-
export { Button } from './button'
|
|
10
|
-
export { ButtonGroup } from './button-group'
|
|
11
|
-
export { Menu } from './menu'
|
|
12
|
-
export { Popover } from './popover'
|
|
13
|
-
export { Tooltip } from './tooltip'
|
|
14
|
-
export { Link } from './link'
|
|
15
|
-
export { Skeleton } from './skeleton'
|
|
16
|
-
export { Separator } from 'react-aria-components'
|
|
17
|
-
export { ToggleButton } from 'react-aria-components'
|
|
18
|
-
|
|
19
|
-
export { cn } from '../../utils/cn'
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import * as RAC from 'react-aria-components'
|
|
2
|
-
import { ChevronDown } from 'lucide-react'
|
|
3
|
-
import { cn } from '../../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
|
-
export const NavigationMenu = ({
|
|
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
|
-
NavigationMenu.Root = NavigationMenu
|
|
112
|
-
NavigationMenu.List = NavigationMenuList
|
|
113
|
-
NavigationMenu.Item = NavigationMenuItem
|
|
114
|
-
NavigationMenu.Link = NavigationMenuLink
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { useLocation } from 'react-router-dom'
|
|
2
|
-
import { Helmet } from 'react-helmet-async'
|
|
3
|
-
import { useConfig } from '../../app/config-context'
|
|
4
|
-
|
|
5
|
-
interface HeadProps {
|
|
6
|
-
siteTitle: string
|
|
7
|
-
siteDescription?: string
|
|
8
|
-
routes: Array<{ path: string; title: string; description?: string; seo?: Record<string, any> }>
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function Head({ siteTitle, siteDescription, routes }: HeadProps) {
|
|
12
|
-
const location = useLocation()
|
|
13
|
-
const config = useConfig()
|
|
14
|
-
|
|
15
|
-
// Find the current route's metadata
|
|
16
|
-
const currentRoute = routes?.find?.((r) => r.path === location.pathname)
|
|
17
|
-
const pageTitle = currentRoute?.title
|
|
18
|
-
const pageDescription = currentRoute?.description || siteDescription || ''
|
|
19
|
-
|
|
20
|
-
const finalTitle = pageTitle ? `${pageTitle} | ${siteTitle}` : siteTitle
|
|
21
|
-
|
|
22
|
-
const seo = currentRoute?.seo || {}
|
|
23
|
-
|
|
24
|
-
// Merge custom global metatags
|
|
25
|
-
const globalMetatags = config?.seo?.metatags || {}
|
|
26
|
-
|
|
27
|
-
// Calculate specific ones
|
|
28
|
-
const defaultOgImage = config?.seo?.thumbnails?.background
|
|
29
|
-
const ogImage = seo['og:image'] || defaultOgImage
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
// @ts-ignore
|
|
33
|
-
<Helmet>
|
|
34
|
-
<title>{finalTitle}</title>
|
|
35
|
-
<meta name="description" content={pageDescription} />
|
|
36
|
-
|
|
37
|
-
{/* Default OG Tags */}
|
|
38
|
-
<meta property="og:title" content={finalTitle} />
|
|
39
|
-
<meta property="og:description" content={pageDescription} />
|
|
40
|
-
<meta property="og:type" content="article" />
|
|
41
|
-
{/* Canonical URL for both <link> and og:url */}
|
|
42
|
-
{typeof window !== 'undefined' && <meta property="og:url" content={window.location.href} />}
|
|
43
|
-
{typeof window !== 'undefined' && <link rel="canonical" href={window.location.origin + location.pathname} />}
|
|
44
|
-
|
|
45
|
-
{/* Default Twitter Card */}
|
|
46
|
-
<meta name="twitter:card" content="summary" />
|
|
47
|
-
<meta name="twitter:title" content={finalTitle} />
|
|
48
|
-
<meta name="twitter:description" content={pageDescription} />
|
|
49
|
-
{ogImage && <meta name="twitter:image" content={ogImage} />}
|
|
50
|
-
{ogImage && <meta property="og:image" content={ogImage} />}
|
|
51
|
-
|
|
52
|
-
{/* Generator */}
|
|
53
|
-
<meta name="generator" content="Boltdocs" />
|
|
54
|
-
|
|
55
|
-
{/* User-defined global metatags */}
|
|
56
|
-
{Object.entries(globalMetatags).map(([key, value]) => {
|
|
57
|
-
const isProperty = key.startsWith('og:') || key.startsWith('music:') || key.startsWith('video:') || key.startsWith('article:') || key.startsWith('book:') || key.startsWith('profile:')
|
|
58
|
-
return isProperty
|
|
59
|
-
? <meta key={key} property={key} content={value as string} />
|
|
60
|
-
: <meta key={key} name={key} content={value as string} />
|
|
61
|
-
})}
|
|
62
|
-
|
|
63
|
-
{/* Page granular SEO tags (override global) */}
|
|
64
|
-
{Object.entries(seo).map(([key, value]) => {
|
|
65
|
-
if (key === 'noindex' && value === true) return <meta key="noindex" name="robots" content="noindex" />
|
|
66
|
-
if (key === 'robots') return <meta key="robots" name="robots" content={value as string} />
|
|
67
|
-
if (key === 'canonical') return <link key="canonical" rel="canonical" href={value as string} />
|
|
68
|
-
|
|
69
|
-
const isProperty = key.startsWith('og:') || key.startsWith('music:') || key.startsWith('video:') || key.startsWith('article:') || key.startsWith('book:') || key.startsWith('profile:')
|
|
70
|
-
return isProperty
|
|
71
|
-
? <meta key={key} property={key} content={value as string} />
|
|
72
|
-
: <meta key={key} name={key} content={value as string} />
|
|
73
|
-
})}
|
|
74
|
-
</Helmet>
|
|
75
|
-
)
|
|
76
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { cn } from '../../utils/cn'
|
|
2
|
-
import { Skeleton } from '../primitives/skeleton'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* A premium loading component that only skeletons the markdown content area.
|
|
6
|
-
* Designed to be used as a Suspense fallback within a persistent layout.
|
|
7
|
-
*/
|
|
8
|
-
export function Loading() {
|
|
9
|
-
return (
|
|
10
|
-
<div
|
|
11
|
-
className={cn(
|
|
12
|
-
'w-full h-full relative overflow-y-auto transition-opacity duration-300 animate-fade-in',
|
|
13
|
-
)}
|
|
14
|
-
>
|
|
15
|
-
<div className="mx-auto max-w-(--spacing-content-max) px-4 py-8 space-y-10">
|
|
16
|
-
{/* Breadcrumbs */}
|
|
17
|
-
<div className="flex gap-2">
|
|
18
|
-
<Skeleton className="h-3 w-16" />
|
|
19
|
-
<Skeleton className="h-3 w-24" />
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
{/* Page Title */}
|
|
23
|
-
<Skeleton className="h-10 w-[60%] sm:h-12" />
|
|
24
|
-
|
|
25
|
-
{/* Intro Paragraph */}
|
|
26
|
-
<div className="space-y-3">
|
|
27
|
-
<Skeleton className="h-4 w-full" />
|
|
28
|
-
<Skeleton className="h-4 w-[95%]" />
|
|
29
|
-
<Skeleton className="h-4 w-[40%]" />
|
|
30
|
-
</div>
|
|
31
|
-
|
|
32
|
-
{/* Section 1 */}
|
|
33
|
-
<div className="space-y-6 pt-4">
|
|
34
|
-
<Skeleton className="h-7 w-32" />
|
|
35
|
-
<div className="space-y-3">
|
|
36
|
-
<Skeleton className="h-4 w-full" />
|
|
37
|
-
<Skeleton className="h-4 w-[98%]" />
|
|
38
|
-
<Skeleton className="h-4 w-[92%]" />
|
|
39
|
-
<Skeleton className="h-4 w-[60%]" />
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
|
|
43
|
-
{/* Code Block Placeholder */}
|
|
44
|
-
<Skeleton className="h-32 w-full rounded-lg bg-bg-muted/50" />
|
|
45
|
-
|
|
46
|
-
{/* Section 2 */}
|
|
47
|
-
<div className="space-y-6 pt-4">
|
|
48
|
-
<Skeleton className="h-7 w-48" />
|
|
49
|
-
<div className="space-y-3">
|
|
50
|
-
<Skeleton className="h-4 w-full" />
|
|
51
|
-
<Skeleton className="h-4 w-[85%]" />
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
)
|
|
57
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Zap } from 'lucide-react'
|
|
2
|
-
|
|
3
|
-
export function PoweredBy() {
|
|
4
|
-
return (
|
|
5
|
-
<div className="flex items-center justify-center mt-10 mb-4 px-4 w-full">
|
|
6
|
-
<a
|
|
7
|
-
href="https://github.com/jesusalcaladev/boltdocs"
|
|
8
|
-
target="_blank"
|
|
9
|
-
rel="noopener noreferrer"
|
|
10
|
-
className="group relative flex items-center gap-2 px-4 py-2 rounded-full border border-border-subtle bg-bg-surface/50 backdrop-blur-md transition-all duration-300 hover:border-primary-500/50 hover:bg-bg-surface hover:shadow-xl hover:shadow-primary-500/5 select-none"
|
|
11
|
-
>
|
|
12
|
-
<Zap
|
|
13
|
-
className="w-3.5 h-3.5 text-text-muted group-hover:text-primary-500 transition-colors duration-300"
|
|
14
|
-
fill="currentColor"
|
|
15
|
-
/>
|
|
16
|
-
<span className="text-[11px] font-medium text-text-muted group-hover:text-text-main transition-colors duration-300 tracking-wide">
|
|
17
|
-
Powered by{' '}
|
|
18
|
-
<strong className="font-bold text-text-main/80 group-hover:text-text-main">
|
|
19
|
-
Boltdocs
|
|
20
|
-
</strong>
|
|
21
|
-
</span>
|
|
22
|
-
</a>
|
|
23
|
-
</div>
|
|
24
|
-
)
|
|
25
|
-
}
|