boltdocs 2.1.1 → 2.3.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/CHANGELOG.md +19 -0
- package/bin/boltdocs.js +2 -2
- package/dist/base-ui/index.d.mts +25 -0
- package/dist/base-ui/index.d.ts +25 -0
- package/dist/base-ui/index.js +1 -0
- package/dist/base-ui/index.mjs +1 -0
- package/dist/{cache-Q4T6VAUL.mjs → cache-P6WK424C.mjs} +1 -1
- package/dist/chunk-22NXDNP4.mjs +74 -0
- package/dist/chunk-2HUVMMJU.mjs +1 -0
- package/dist/chunk-2Z5T6EAU.mjs +1 -0
- package/dist/chunk-CRZGOE32.mjs +1 -0
- package/dist/chunk-HA6543SL.mjs +1 -0
- package/dist/chunk-JD3RSDE4.mjs +1 -0
- package/dist/chunk-JZXLCA2E.mjs +1 -0
- package/dist/chunk-NBCYHLAA.mjs +1 -0
- package/dist/chunk-RPUERTVC.mjs +1 -0
- package/dist/chunk-T3W44KWY.mjs +1 -0
- package/dist/chunk-URTD6E6S.mjs +1 -0
- package/dist/chunk-W2NB4T6V.mjs +1 -0
- package/dist/chunk-Y4RRHPXC.mjs +1 -0
- package/dist/client/index.d.mts +13 -115
- package/dist/client/index.d.ts +13 -115
- package/dist/client/index.js +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/client/ssr.js +1 -1
- package/dist/client/ssr.mjs +1 -1
- package/dist/client/types.d.mts +3 -0
- package/dist/client/types.d.ts +3 -0
- package/dist/client/types.js +1 -0
- package/dist/client/types.mjs +0 -0
- package/dist/copy-markdown-C-90ixSe.d.ts +15 -0
- package/dist/copy-markdown-CbS8X-qe.d.mts +15 -0
- package/dist/{client/hooks → hooks}/index.d.mts +16 -11
- package/dist/{client/hooks → hooks}/index.d.ts +16 -11
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/index.mjs +1 -0
- package/dist/integrations/index.d.mts +48 -0
- package/dist/integrations/index.d.ts +48 -0
- package/dist/integrations/index.js +1 -0
- package/dist/integrations/index.mjs +1 -0
- package/dist/link-DfBwCeZc.d.mts +68 -0
- package/dist/link-DfBwCeZc.d.ts +68 -0
- package/dist/loading-B7X5Wchs.d.ts +66 -0
- package/dist/loading-WuaQbsKb.d.mts +66 -0
- package/dist/{client/components/mdx → mdx}/index.d.mts +6 -38
- package/dist/{client/components/mdx → mdx}/index.d.ts +6 -38
- package/dist/mdx/index.js +1 -0
- package/dist/mdx/index.mjs +1 -0
- package/dist/node/cli-entry.js +31 -27
- package/dist/node/cli-entry.mjs +5 -1
- package/dist/node/index.d.mts +44 -14
- package/dist/node/index.d.ts +44 -14
- package/dist/node/index.js +24 -24
- package/dist/node/index.mjs +1 -1
- package/dist/primitives/index.d.mts +301 -0
- package/dist/primitives/index.d.ts +301 -0
- package/dist/primitives/index.js +1 -0
- package/dist/primitives/index.mjs +1 -0
- package/dist/search-dialog-ZRXBAQJ5.mjs +1 -0
- package/dist/{types-Cp21DHI6.d.mts → types-j7jvWsJj.d.mts} +63 -17
- package/dist/{types-Cp21DHI6.d.ts → types-j7jvWsJj.d.ts} +63 -17
- package/dist/{use-routes-xLhumjbV.d.ts → use-routes-Cd806kGw.d.ts} +1 -1
- package/dist/{use-routes-8Iei6jTp.d.mts → use-routes-DDL0_jkQ.d.mts} +1 -1
- package/package.json +35 -8
- package/src/client/app/index.tsx +155 -35
- package/src/client/app/mdx-component.tsx +7 -3
- package/src/client/app/theme-context.tsx +47 -23
- package/src/client/components/default-layout.tsx +16 -6
- package/src/client/components/primitives/breadcrumbs.tsx +1 -1
- package/src/client/components/primitives/navbar.tsx +8 -5
- package/src/client/components/primitives/search-dialog.tsx +15 -6
- package/src/client/components/primitives/sidebar.tsx +3 -2
- package/src/client/components/primitives/skeleton.tsx +26 -0
- package/src/client/components/ui-base/breadcrumbs.tsx +1 -1
- package/src/client/components/ui-base/index.ts +17 -0
- package/src/client/components/ui-base/loading.tsx +43 -73
- package/src/client/components/ui-base/navbar.tsx +74 -39
- package/src/client/components/ui-base/page-nav.tsx +2 -1
- package/src/client/components/ui-base/powered-by.tsx +11 -5
- package/src/client/components/ui-base/search-dialog.tsx +16 -5
- package/src/client/components/ui-base/sidebar.tsx +33 -22
- package/src/client/components/ui-base/tabs.tsx +4 -1
- package/src/client/components/ui-base/theme-toggle.tsx +35 -15
- package/src/client/hooks/use-i18n.ts +38 -7
- package/src/client/hooks/use-localized-to.ts +51 -73
- package/src/client/hooks/use-navbar.ts +10 -3
- package/src/client/hooks/use-page-nav.ts +27 -6
- package/src/client/hooks/use-routes.ts +62 -17
- package/src/client/hooks/use-search.ts +84 -46
- package/src/client/hooks/use-sidebar.ts +6 -2
- package/src/client/hooks/use-version.ts +5 -0
- package/src/client/integrations/index.ts +1 -0
- package/src/client/store/use-boltdocs-store.ts +44 -0
- package/src/client/theme/neutral.css +29 -0
- package/src/client/types.ts +4 -2
- package/src/client/utils/i18n.ts +23 -0
- package/src/node/{cli.ts → cli/build.ts} +17 -23
- package/src/node/cli/dev.ts +22 -0
- package/src/node/cli/doctor.ts +243 -0
- package/src/node/cli/index.ts +9 -0
- package/src/node/cli/ui.ts +54 -0
- package/src/node/cli-entry.ts +16 -16
- package/src/node/config.ts +54 -17
- package/src/node/index.ts +1 -1
- package/src/node/mdx/cache.ts +12 -0
- package/src/node/mdx/highlighter.ts +47 -0
- package/src/node/mdx/index.ts +114 -0
- package/src/node/mdx/rehype-shiki.ts +53 -0
- package/src/node/mdx/remark-shiki.ts +61 -0
- package/src/node/plugin/entry.ts +1 -1
- package/src/node/plugin/html.ts +8 -4
- package/src/node/plugin/index.ts +135 -72
- package/src/node/routes/index.ts +34 -13
- package/src/node/routes/parser.ts +13 -5
- package/src/node/search/index.ts +55 -0
- package/src/node/ssg/index.ts +15 -7
- package/src/node/ssg/robots.ts +7 -4
- package/src/node/utils.ts +32 -2
- package/tsup.config.ts +7 -2
- package/dist/chunk-52MVMZWS.mjs +0 -1
- package/dist/chunk-BVWWKXJH.mjs +0 -1
- package/dist/chunk-DVY3RDXD.mjs +0 -1
- package/dist/chunk-FUVYCYWC.mjs +0 -1
- package/dist/chunk-GBLMDJ2B.mjs +0 -1
- package/dist/chunk-ISPX45DF.mjs +0 -1
- package/dist/chunk-PNXZMUCO.mjs +0 -1
- package/dist/chunk-V2ZHKQSP.mjs +0 -74
- package/dist/client/components/mdx/index.js +0 -1
- package/dist/client/components/mdx/index.mjs +0 -1
- package/dist/client/hooks/index.js +0 -1
- package/dist/client/hooks/index.mjs +0 -1
- package/dist/search-dialog-TWGYKF2D.mjs +0 -1
- package/src/node/mdx.ts +0 -279
|
@@ -13,6 +13,7 @@ import { useConfig } from '@client/app/config-context'
|
|
|
13
13
|
import { useMdxComponents } from '@client/app/mdx-components-context'
|
|
14
14
|
|
|
15
15
|
import { useLocation } from 'react-router-dom'
|
|
16
|
+
import { getTranslated } from '@client/utils/i18n'
|
|
16
17
|
|
|
17
18
|
export interface LayoutProps {
|
|
18
19
|
children: React.ReactNode
|
|
@@ -24,7 +25,12 @@ export interface LayoutProps {
|
|
|
24
25
|
* and rearrange, wrap, or replace any section.
|
|
25
26
|
*/
|
|
26
27
|
export function DefaultLayout({ children }: LayoutProps) {
|
|
27
|
-
const {
|
|
28
|
+
const {
|
|
29
|
+
routes: filteredRoutes,
|
|
30
|
+
allRoutes,
|
|
31
|
+
currentRoute,
|
|
32
|
+
currentLocale,
|
|
33
|
+
} = useRoutes()
|
|
28
34
|
const { pathname } = useLocation()
|
|
29
35
|
const config = useConfig()
|
|
30
36
|
const mdxComponents = useMdxComponents()
|
|
@@ -36,8 +42,12 @@ export function DefaultLayout({ children }: LayoutProps) {
|
|
|
36
42
|
<DocsLayout>
|
|
37
43
|
<ProgressBar />
|
|
38
44
|
<Head
|
|
39
|
-
siteTitle={
|
|
40
|
-
|
|
45
|
+
siteTitle={
|
|
46
|
+
getTranslated(config.theme?.title, currentLocale) || 'Boltdocs'
|
|
47
|
+
}
|
|
48
|
+
siteDescription={
|
|
49
|
+
getTranslated(config.theme?.description, currentLocale) || ''
|
|
50
|
+
}
|
|
41
51
|
routes={allRoutes}
|
|
42
52
|
/>
|
|
43
53
|
<Navbar />
|
|
@@ -52,7 +62,7 @@ export function DefaultLayout({ children }: LayoutProps) {
|
|
|
52
62
|
<CopyMarkdownComp
|
|
53
63
|
mdxRaw={currentRoute?._rawContent}
|
|
54
64
|
route={currentRoute}
|
|
55
|
-
config={config.
|
|
65
|
+
config={config.theme?.copyMarkdown}
|
|
56
66
|
/>
|
|
57
67
|
</DocsLayout.ContentHeader>
|
|
58
68
|
)}
|
|
@@ -69,8 +79,8 @@ export function DefaultLayout({ children }: LayoutProps) {
|
|
|
69
79
|
{!isHome && (
|
|
70
80
|
<OnThisPage
|
|
71
81
|
headings={currentRoute?.headings}
|
|
72
|
-
editLink={config.
|
|
73
|
-
communityHelp={config.
|
|
82
|
+
editLink={config.theme?.editLink}
|
|
83
|
+
communityHelp={config.theme?.communityHelp}
|
|
74
84
|
filePath={currentRoute?.filePath}
|
|
75
85
|
/>
|
|
76
86
|
)}
|
|
@@ -180,8 +180,11 @@ export const NavbarLink = ({
|
|
|
180
180
|
href={href}
|
|
181
181
|
target={to === 'external' ? '_blank' : undefined}
|
|
182
182
|
className={cn(
|
|
183
|
-
'transition-colors outline-none
|
|
184
|
-
|
|
183
|
+
'transition-colors outline-none focus-visible:ring-2 focus-visible:ring-primary-500/30 rounded-sm',
|
|
184
|
+
{
|
|
185
|
+
'text-primary-500 font-bold': active,
|
|
186
|
+
'text-text-muted hover:text-text-main font-medium': !active,
|
|
187
|
+
},
|
|
185
188
|
className,
|
|
186
189
|
)}
|
|
187
190
|
>
|
|
@@ -211,7 +214,7 @@ export const NavbarSearchTrigger = ({
|
|
|
211
214
|
onPress={onPress}
|
|
212
215
|
className={cn(
|
|
213
216
|
'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-
|
|
217
|
+
'transition-all duration-200 hover:border-border-strong hover:text-text-main hover:bg-bg-muted hover:shadow-sm active:scale-[0.98]',
|
|
215
218
|
'focus-visible:ring-2 focus-visible:ring-primary-500/30',
|
|
216
219
|
'w-full max-w-[320px] justify-between',
|
|
217
220
|
className,
|
|
@@ -243,8 +246,8 @@ export const NavbarTheme = ({
|
|
|
243
246
|
isSelected={theme === 'dark'}
|
|
244
247
|
onChange={onThemeChange}
|
|
245
248
|
className={cn(
|
|
246
|
-
'rounded-md p-2 text-text-muted outline-none cursor-pointer
|
|
247
|
-
'hover:bg-bg-surface hover:text-text-main',
|
|
249
|
+
'rounded-md p-2 text-text-muted outline-none cursor-pointer',
|
|
250
|
+
'transition-all duration-300 hover:bg-bg-surface hover:text-text-main hover:rotate-12 active:scale-90',
|
|
248
251
|
'focus-visible:ring-2 focus-visible:ring-primary-500/30',
|
|
249
252
|
className,
|
|
250
253
|
)}
|
|
@@ -50,16 +50,25 @@ export const SearchDialogRoot = ({
|
|
|
50
50
|
)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export const SearchDialogAutocomplete = ({
|
|
53
|
+
export const SearchDialogAutocomplete = <T extends object>({
|
|
54
54
|
children,
|
|
55
55
|
className,
|
|
56
|
+
onSelectionChange,
|
|
56
57
|
...props
|
|
57
|
-
}: RAC.AutocompleteProps<
|
|
58
|
+
}: RAC.AutocompleteProps<T> & {
|
|
59
|
+
className?: string
|
|
60
|
+
onSelectionChange?: (key: RAC.Key) => void
|
|
61
|
+
}) => {
|
|
62
|
+
const Autocomplete = RAC.Autocomplete as any
|
|
58
63
|
return (
|
|
59
64
|
<div className={className}>
|
|
60
|
-
<
|
|
65
|
+
<Autocomplete
|
|
66
|
+
{...props}
|
|
67
|
+
onSelectionChange={onSelectionChange}
|
|
68
|
+
className="flex flex-col min-h-0"
|
|
69
|
+
>
|
|
61
70
|
{children}
|
|
62
|
-
</
|
|
71
|
+
</Autocomplete>
|
|
63
72
|
</div>
|
|
64
73
|
)
|
|
65
74
|
}
|
|
@@ -89,11 +98,11 @@ export const SearchDialogInput = ({
|
|
|
89
98
|
)
|
|
90
99
|
}
|
|
91
100
|
|
|
92
|
-
export const SearchDialogList = ({
|
|
101
|
+
export const SearchDialogList = <T extends object>({
|
|
93
102
|
children,
|
|
94
103
|
className,
|
|
95
104
|
...props
|
|
96
|
-
}: RAC.ListBoxProps<
|
|
105
|
+
}: RAC.ListBoxProps<T> & { className?: string }) => {
|
|
97
106
|
return (
|
|
98
107
|
<RAC.ListBox
|
|
99
108
|
{...props}
|
|
@@ -122,11 +122,12 @@ export const SidebarLink = ({
|
|
|
122
122
|
<Link
|
|
123
123
|
href={href}
|
|
124
124
|
className={cn(
|
|
125
|
-
'group flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm outline-none
|
|
125
|
+
'group flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm outline-none',
|
|
126
|
+
'transition-all duration-200 ease-in-out',
|
|
126
127
|
'focus-visible:ring-2 focus-visible:ring-primary-500/30',
|
|
127
128
|
active
|
|
128
129
|
? 'bg-primary-500/10 text-primary-500 font-medium'
|
|
129
|
-
: 'text-text-muted hover:bg-bg-surface hover:text-text-main',
|
|
130
|
+
: 'text-text-muted hover:bg-bg-surface hover:text-text-main hover:translate-x-1',
|
|
130
131
|
className,
|
|
131
132
|
)}
|
|
132
133
|
>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { cn } from '@client/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-bg-muted',
|
|
20
|
+
variant === 'circle' ? 'rounded-full' : 'rounded-md',
|
|
21
|
+
className,
|
|
22
|
+
)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -12,7 +12,7 @@ import { useConfig } from '@client/app/config-context'
|
|
|
12
12
|
export function Breadcrumbs() {
|
|
13
13
|
const { crumbs, activeRoute } = useBreadcrumbs()
|
|
14
14
|
const config = useConfig()
|
|
15
|
-
const themeConfig = config.theme ||
|
|
15
|
+
const themeConfig = config.theme || {}
|
|
16
16
|
|
|
17
17
|
if (crumbs.length === 0) return null
|
|
18
18
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { Breadcrumbs } from './breadcrumbs'
|
|
2
|
+
export { CopyMarkdown } from './copy-markdown'
|
|
3
|
+
export type { CopyMarkdownProps } from './copy-markdown'
|
|
4
|
+
export { ErrorBoundary } from './error-boundary'
|
|
5
|
+
export { GithubStars } from './github-stars'
|
|
6
|
+
export { Head } from './head'
|
|
7
|
+
export { Loading } from './loading'
|
|
8
|
+
export { Navbar } from './navbar'
|
|
9
|
+
export { NotFound } from './not-found'
|
|
10
|
+
export { OnThisPage } from './on-this-page'
|
|
11
|
+
export { PageNav } from './page-nav'
|
|
12
|
+
export { PoweredBy } from './powered-by'
|
|
13
|
+
export { ProgressBar } from './progress-bar'
|
|
14
|
+
export { SearchDialog } from './search-dialog'
|
|
15
|
+
export { Sidebar } from './sidebar'
|
|
16
|
+
export { Tabs } from './tabs'
|
|
17
|
+
export { ThemeToggle } from './theme-toggle'
|
|
@@ -1,85 +1,55 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cn } from '@client/utils/cn'
|
|
2
|
+
import { Skeleton } from '@primitives/skeleton'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
* A premium loading component that
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* It features a glassmorphism container and a Bolt-style SVG logo
|
|
8
|
-
* with a dynamic fill effect.
|
|
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.
|
|
9
7
|
*/
|
|
10
8
|
export function Loading() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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>
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
currentProgress += 1
|
|
20
|
-
if (currentProgress >= 100) {
|
|
21
|
-
currentProgress = 100
|
|
22
|
-
up = false
|
|
23
|
-
}
|
|
24
|
-
} else {
|
|
25
|
-
currentProgress -= 1
|
|
26
|
-
if (currentProgress <= 0) {
|
|
27
|
-
currentProgress = 0
|
|
28
|
-
up = true
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
setProgress(currentProgress)
|
|
32
|
-
}, 20)
|
|
22
|
+
{/* Page Title */}
|
|
23
|
+
<Skeleton className="h-10 w-[60%] sm:h-12" />
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
|
|
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>
|
|
36
31
|
|
|
37
|
-
|
|
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>
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<div className="relative group">
|
|
42
|
-
<div className="relative inline-block">
|
|
43
|
-
{/* SVG Background (Dimmed Base) */}
|
|
44
|
-
<svg
|
|
45
|
-
className="w-24 h-auto opacity-10 filter grayscale brightness-50"
|
|
46
|
-
viewBox="0 0 60 51"
|
|
47
|
-
fill="none"
|
|
48
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
49
|
-
role="img"
|
|
50
|
-
aria-hidden="true"
|
|
51
|
-
>
|
|
52
|
-
<title>Loading indicator background</title>
|
|
53
|
-
<path
|
|
54
|
-
d="M29.4449 0H19.4449V16.5L29.4449 6.5V0Z"
|
|
55
|
-
fill="currentColor"
|
|
56
|
-
/>
|
|
57
|
-
<path
|
|
58
|
-
d="M26.9449 22.7265C26.9449 22.5077 21.2201 27.0658 16.9449 28.5C13.7491 29.5721 12.3156 29.5038 8.94486 29.5C5.59532 29.4963 0 28.5 0 28.5C0 28.5 5.57953 28.5146 8.94486 27.5C12.5409 26.4158 14.8203 25.5843 17.9449 23.5C23.3445 19.898 29.4449 11.5 29.4449 11.5L29.9449 18C29.9449 18 33.5825 15.8308 36.4449 15C39.4452 14.1291 44.4449 14 44.4449 14C44.4449 14 36.9449 19 34.4449 21.5C31.5322 24.4126 29.8582 26.9017 29.4449 31C29.1217 34.2041 29.4771 36.4508 31.4449 39C33.5792 41.765 35.952 43.0183 39.4449 43C42.677 42.9831 45.3003 42.4182 47.4449 40C49.7406 37.4113 50.2495 34.4466 49.9449 31C49.6603 27.7804 48.4876 25.4953 45.9449 23.5C43.2931 21.4191 36.4449 24 36.4449 24L47.9449 15C47.9449 15 51.5761 16.771 53.4449 18.5C55.711 20.5967 56.7467 22.1546 57.9449 25C59.1784 27.9295 59.4832 29.8216 59.4449 33C59.4089 35.9867 59.179 37.78 57.9449 40.5C56.8475 42.9185 55.8511 44.6507 53.9449 46.5C51.9236 48.4609 50.5803 49.0076 47.9449 50C45.5414 50.9051 44.0131 51 41.4449 51C38.8766 51 37.3235 50.9685 34.9449 50C32.4851 48.9985 29.4449 46 29.4449 46V51H19.4449V37.9904L22.9449 31.4226L26.9449 22.7265Z"
|
|
59
|
-
fill="currentColor"
|
|
60
|
-
/>
|
|
61
|
-
</svg>
|
|
43
|
+
{/* Code Block Placeholder */}
|
|
44
|
+
<Skeleton className="h-32 w-full rounded-lg bg-bg-muted/50" />
|
|
62
45
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
role="img"
|
|
71
|
-
aria-hidden="true"
|
|
72
|
-
>
|
|
73
|
-
<title>Loading indicator animated fill</title>
|
|
74
|
-
<path
|
|
75
|
-
d="M29.4449 0H19.4449V16.5L29.4449 6.5V0Z"
|
|
76
|
-
fill="currentColor"
|
|
77
|
-
/>
|
|
78
|
-
<path
|
|
79
|
-
d="M26.9449 22.7265C26.9449 22.5077 21.2201 27.0658 16.9449 28.5C13.7491 29.5721 12.3156 29.5038 8.94486 29.5C5.59532 29.4963 0 28.5 0 28.5C0 28.5 5.57953 28.5146 8.94486 27.5C12.5409 26.4158 14.8203 25.5843 17.9449 23.5C23.3445 19.898 29.4449 11.5 29.4449 11.5L29.9449 18C29.9449 18 33.5825 15.8308 36.4449 15C39.4452 14.1291 44.4449 14 44.4449 14C44.4449 14 36.9449 19 34.4449 21.5C31.5322 24.4126 29.8582 26.9017 29.4449 31C29.1217 34.2041 29.4771 36.4508 31.4449 39C33.5792 41.765 35.952 43.0183 39.4449 43C42.677 42.9831 45.3003 42.4182 47.4449 40C49.7406 37.4113 50.2495 34.4466 49.9449 31C49.6603 27.7804 48.4876 25.4953 45.9449 23.5C43.2931 21.4191 36.4449 24 36.4449 24L47.9449 15C47.9449 15 51.5761 16.771 53.4449 18.5C55.711 20.5967 56.7467 22.1546 57.9449 25C59.1784 27.9295 59.4832 29.8216 59.4449 33C59.4089 35.9867 59.179 37.78 57.9449 40.5C56.8475 42.9185 55.8511 44.6507 53.9449 46.5C51.9236 48.4609 50.5803 49.0076 47.9449 50C45.5414 50.9051 44.0131 51 41.4449 51C38.8766 51 37.3235 50.9685 34.9449 50C32.4851 48.9985 29.4449 46 29.4449 46V51H19.4449V37.9904L22.9449 31.4226L26.9449 22.7265Z"
|
|
80
|
-
fill="currentColor"
|
|
81
|
-
/>
|
|
82
|
-
</svg>
|
|
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>
|
|
83
53
|
</div>
|
|
84
54
|
</div>
|
|
85
55
|
</div>
|
|
@@ -11,8 +11,9 @@ import { useLocation } from 'react-router-dom'
|
|
|
11
11
|
import type { BoltdocsSocialLink } from '@node/config'
|
|
12
12
|
import Menu from '@components/primitives/menu'
|
|
13
13
|
import { Button } from '@components/primitives/button'
|
|
14
|
-
import { ChevronDown } from 'lucide-react'
|
|
15
|
-
import {
|
|
14
|
+
import { ChevronDown, Languages } from 'lucide-react'
|
|
15
|
+
import { useLocalizedTo } from '@hooks/use-localized-to'
|
|
16
|
+
import type { NavbarLink as NavbarLinkType } from '@client/types'
|
|
16
17
|
|
|
17
18
|
const SearchDialog = lazy(() =>
|
|
18
19
|
import('./search-dialog').then((m) => ({
|
|
@@ -24,7 +25,7 @@ export function Navbar() {
|
|
|
24
25
|
const { links, title, logo, logoProps, github, social, config } = useNavbar()
|
|
25
26
|
const { routes, allRoutes, currentVersion, currentLocale } = useRoutes()
|
|
26
27
|
const { pathname } = useLocation()
|
|
27
|
-
const themeConfig = config.theme ||
|
|
28
|
+
const themeConfig = config.theme || {}
|
|
28
29
|
|
|
29
30
|
const hasTabs = themeConfig?.tabs && themeConfig.tabs.length > 0
|
|
30
31
|
|
|
@@ -32,19 +33,21 @@ export function Navbar() {
|
|
|
32
33
|
<NavbarPrimitive.NavbarRoot className={hasTabs ? 'border-b-0' : ''}>
|
|
33
34
|
<NavbarPrimitive.Content>
|
|
34
35
|
<NavbarPrimitive.NavbarLeft>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
{logo && (
|
|
37
|
+
<NavbarPrimitive.NavbarLogo
|
|
38
|
+
src={logo}
|
|
39
|
+
alt={logoProps?.alt || title}
|
|
40
|
+
width={logoProps?.width ?? 24}
|
|
41
|
+
height={logoProps?.height ?? 24}
|
|
42
|
+
/>
|
|
43
|
+
)}
|
|
41
44
|
<NavbarPrimitive.Title>{title}</NavbarPrimitive.Title>
|
|
42
45
|
|
|
43
46
|
{config.versions && currentVersion && <NavbarVersion />}
|
|
44
47
|
|
|
45
48
|
<NavbarPrimitive.Links>
|
|
46
49
|
{links.map((link) => (
|
|
47
|
-
<
|
|
50
|
+
<NavbarLinkItem key={link.href} link={link} />
|
|
48
51
|
))}
|
|
49
52
|
</NavbarPrimitive.Links>
|
|
50
53
|
</NavbarPrimitive.NavbarLeft>
|
|
@@ -78,16 +81,18 @@ export function Navbar() {
|
|
|
78
81
|
|
|
79
82
|
{pathname !== '/' && hasTabs && themeConfig?.tabs && (
|
|
80
83
|
<div className="w-full border-b border-border-subtle bg-bg-main">
|
|
81
|
-
<Tabs
|
|
82
|
-
tabs={themeConfig.tabs}
|
|
83
|
-
routes={allRoutes || routes || []}
|
|
84
|
-
/>
|
|
84
|
+
<Tabs tabs={themeConfig.tabs} routes={allRoutes || routes || []} />
|
|
85
85
|
</div>
|
|
86
86
|
)}
|
|
87
87
|
</NavbarPrimitive.NavbarRoot>
|
|
88
88
|
)
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
function NavbarLinkItem({ link }: { link: NavbarLinkType }) {
|
|
92
|
+
const localizedHref = useLocalizedTo(link.href)
|
|
93
|
+
return <NavbarPrimitive.Link {...(link as any)} href={localizedHref} />
|
|
94
|
+
}
|
|
95
|
+
|
|
91
96
|
function NavbarVersion() {
|
|
92
97
|
const { currentVersionLabel, availableVersions, handleVersionChange } =
|
|
93
98
|
useVersion()
|
|
@@ -96,43 +101,73 @@ function NavbarVersion() {
|
|
|
96
101
|
|
|
97
102
|
return (
|
|
98
103
|
<Menu.Trigger>
|
|
99
|
-
<Button
|
|
100
|
-
{
|
|
104
|
+
<Button
|
|
105
|
+
variant={'outline'}
|
|
106
|
+
size="sm"
|
|
107
|
+
rounded="lg"
|
|
108
|
+
iconPosition="right"
|
|
109
|
+
icon={<ChevronDown className="w-3.5 h-3.5 text-text-muted/60" />}
|
|
110
|
+
className="h-8 border-border-subtle/60 bg-bg-surface/30 backdrop-blur-sm transition-all duration-200 hover:border-primary-500/50 hover:bg-primary-500/5"
|
|
111
|
+
>
|
|
112
|
+
<span className="font-semibold text-[0.8125rem]">
|
|
113
|
+
{currentVersionLabel}
|
|
114
|
+
</span>
|
|
101
115
|
</Button>
|
|
102
|
-
<Menu.
|
|
103
|
-
{
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
116
|
+
<Menu.Root>
|
|
117
|
+
<Menu.Section items={availableVersions}>
|
|
118
|
+
{(version) => (
|
|
119
|
+
<Menu.Item
|
|
120
|
+
key={`${version.value ?? ''}`}
|
|
121
|
+
onPress={() => handleVersionChange(version.value)}
|
|
122
|
+
>
|
|
123
|
+
{version.label as string}
|
|
124
|
+
</Menu.Item>
|
|
125
|
+
)}
|
|
126
|
+
</Menu.Section>
|
|
127
|
+
</Menu.Root>
|
|
112
128
|
</Menu.Trigger>
|
|
113
129
|
)
|
|
114
130
|
}
|
|
115
131
|
|
|
116
132
|
function NavbarI18n() {
|
|
117
|
-
const {
|
|
133
|
+
const { currentLocale, availableLocales, handleLocaleChange } = useI18n()
|
|
118
134
|
|
|
119
135
|
if (availableLocales.length === 0) return null
|
|
120
136
|
|
|
121
137
|
return (
|
|
122
138
|
<Menu.Trigger>
|
|
123
|
-
<Button
|
|
124
|
-
{
|
|
139
|
+
<Button
|
|
140
|
+
variant={'outline'}
|
|
141
|
+
size="sm"
|
|
142
|
+
rounded="lg"
|
|
143
|
+
iconPosition="right"
|
|
144
|
+
icon={<ChevronDown className="w-3.5 h-3.5 text-text-muted/60" />}
|
|
145
|
+
className="h-8 border-border-subtle/60 bg-bg-surface/30 backdrop-blur-sm transition-all duration-200 hover:border-primary-500/50 hover:bg-primary-500/5 px-2.5"
|
|
146
|
+
>
|
|
147
|
+
<div className="flex items-center gap-1.5">
|
|
148
|
+
<Languages className="w-3.5 h-3.5 text-primary-500" />
|
|
149
|
+
<span className="font-bold text-[0.75rem] tracking-wider uppercase opacity-90">
|
|
150
|
+
{currentLocale || 'en'}
|
|
151
|
+
</span>
|
|
152
|
+
</div>
|
|
125
153
|
</Button>
|
|
126
|
-
<Menu.
|
|
127
|
-
{
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
154
|
+
<Menu.Root>
|
|
155
|
+
<Menu.Section items={availableLocales}>
|
|
156
|
+
{(locale) => (
|
|
157
|
+
<Menu.Item
|
|
158
|
+
key={`${locale.value ?? ''}`}
|
|
159
|
+
onPress={() => handleLocaleChange(locale.value)}
|
|
160
|
+
>
|
|
161
|
+
<div className="flex items-center justify-between w-full gap-4">
|
|
162
|
+
<span>{locale.label as string}</span>
|
|
163
|
+
<span className="text-[10px] font-bold opacity-40 uppercase tracking-tighter">
|
|
164
|
+
{locale.value}
|
|
165
|
+
</span>
|
|
166
|
+
</div>
|
|
167
|
+
</Menu.Item>
|
|
168
|
+
)}
|
|
169
|
+
</Menu.Section>
|
|
170
|
+
</Menu.Root>
|
|
136
171
|
</Menu.Trigger>
|
|
137
172
|
)
|
|
138
173
|
}
|
|
@@ -3,6 +3,7 @@ import PageNavPrimitive from '@components/primitives/page-nav'
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Component to display the previous and next page navigation buttons.
|
|
6
|
+
* Enhanced with subtle entrance animations and a modern card layout.
|
|
6
7
|
*/
|
|
7
8
|
export function PageNav() {
|
|
8
9
|
const { prevPage, nextPage } = usePageNav()
|
|
@@ -10,7 +11,7 @@ export function PageNav() {
|
|
|
10
11
|
if (!prevPage && !nextPage) return null
|
|
11
12
|
|
|
12
13
|
return (
|
|
13
|
-
<PageNavPrimitive.PageNavRoot>
|
|
14
|
+
<PageNavPrimitive.PageNavRoot className="animate-in fade-in slide-in-from-bottom-4 duration-700">
|
|
14
15
|
{prevPage ? (
|
|
15
16
|
<PageNavPrimitive.PageNavLink to={prevPage.path} direction="prev">
|
|
16
17
|
<PageNavPrimitive.PageNavLink.Title>
|
|
@@ -2,16 +2,22 @@ import { Zap } from 'lucide-react'
|
|
|
2
2
|
|
|
3
3
|
export function PoweredBy() {
|
|
4
4
|
return (
|
|
5
|
-
<div className="
|
|
5
|
+
<div className="flex items-center justify-center mt-10 mb-4 px-4 w-full">
|
|
6
6
|
<a
|
|
7
7
|
href="https://github.com/jesusalcaladev/boltdocs"
|
|
8
8
|
target="_blank"
|
|
9
9
|
rel="noopener noreferrer"
|
|
10
|
-
className="flex items-center gap-
|
|
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
11
|
>
|
|
12
|
-
<Zap
|
|
13
|
-
|
|
14
|
-
|
|
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>
|
|
15
21
|
</span>
|
|
16
22
|
</a>
|
|
17
23
|
</div>
|
|
@@ -12,8 +12,17 @@ import {
|
|
|
12
12
|
} from '@components/primitives/search-dialog'
|
|
13
13
|
import Navbar from '@components/primitives/navbar'
|
|
14
14
|
import { useNavigate } from 'react-router-dom'
|
|
15
|
+
import type { ComponentRoute } from '@client/types'
|
|
16
|
+
interface SearchResult {
|
|
17
|
+
id: string
|
|
18
|
+
title: string
|
|
19
|
+
path: string
|
|
20
|
+
bio: string
|
|
21
|
+
groupTitle?: string
|
|
22
|
+
isHeading?: boolean
|
|
23
|
+
}
|
|
15
24
|
|
|
16
|
-
export function SearchDialog({ routes }: { routes:
|
|
25
|
+
export function SearchDialog({ routes }: { routes: ComponentRoute[] }) {
|
|
17
26
|
const { isOpen, setIsOpen, query, setQuery, list } = useSearch(routes)
|
|
18
27
|
const navigate = useNavigate()
|
|
19
28
|
|
|
@@ -58,10 +67,12 @@ export function SearchDialog({ routes }: { routes: any[] }) {
|
|
|
58
67
|
<SearchDialogAutocomplete onSelectionChange={handleSelect}>
|
|
59
68
|
<SearchDialogInput
|
|
60
69
|
value={query}
|
|
61
|
-
onChange={(e:
|
|
70
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
71
|
+
setQuery(e.target.value)
|
|
72
|
+
}
|
|
62
73
|
/>
|
|
63
|
-
<SearchDialogList items={list}>
|
|
64
|
-
{(item:
|
|
74
|
+
<SearchDialogList items={list as SearchResult[]}>
|
|
75
|
+
{(item: SearchResult) => (
|
|
65
76
|
<SearchDialogItemRoot
|
|
66
77
|
key={item.id}
|
|
67
78
|
onPress={() => handleSelect(item.id)}
|
|
@@ -70,7 +81,7 @@ export function SearchDialog({ routes }: { routes: any[] }) {
|
|
|
70
81
|
<SearchDialogItemIcon isHeading={item.isHeading} />
|
|
71
82
|
<div className="flex flex-col justify-center gap-0.5">
|
|
72
83
|
<SearchDialogItemTitle>{item.title}</SearchDialogItemTitle>
|
|
73
|
-
<SearchDialogItemBio>{item.
|
|
84
|
+
<SearchDialogItemBio>{item.bio}</SearchDialogItemBio>
|
|
74
85
|
</div>
|
|
75
86
|
</SearchDialogItemRoot>
|
|
76
87
|
)}
|