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,48 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Link as RACLink,
|
|
3
|
-
type LinkProps as RACLinkProps,
|
|
4
|
-
} from 'react-aria-components'
|
|
5
|
-
import { useLocation } from 'react-router-dom'
|
|
1
|
+
import { useNavigate, useLocation } from 'react-router-dom'
|
|
6
2
|
import { useLocalizedTo } from '../../hooks/use-localized-to'
|
|
7
3
|
import { cn } from '../../utils/cn'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export interface LinkProps extends RACLinkProps {
|
|
4
|
+
export interface LinkProps
|
|
5
|
+
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
11
6
|
/** Should prefetch the page on hover? Default 'hover' */
|
|
12
7
|
prefetch?: 'hover' | 'none'
|
|
13
8
|
}
|
|
14
9
|
|
|
15
10
|
/**
|
|
16
|
-
* A primitive Link component that wraps
|
|
11
|
+
* A primitive Link component that wraps a standard anchor tag
|
|
17
12
|
* and adds framework-specific logic for path localization and preloading.
|
|
18
|
-
*
|
|
19
|
-
* It uses the global navigation configuration from BoltdocsRouterProvider
|
|
20
|
-
* to handle seamless client-side transitions.
|
|
21
13
|
*/
|
|
22
|
-
export const Link =
|
|
23
|
-
const { href,
|
|
14
|
+
export const Link = (props: LinkProps) => {
|
|
15
|
+
const { href, onMouseEnter, onFocus, onClick, ...rest } = props
|
|
24
16
|
|
|
17
|
+
const navigate = useNavigate()
|
|
25
18
|
const localizedHref = useLocalizedTo(href ?? '')
|
|
26
19
|
|
|
20
|
+
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
21
|
+
onClick?.(e)
|
|
22
|
+
if (e.defaultPrevented) return
|
|
23
|
+
|
|
24
|
+
const isExternal =
|
|
25
|
+
localizedHref &&
|
|
26
|
+
(localizedHref.startsWith('http://') ||
|
|
27
|
+
localizedHref.startsWith('https://') ||
|
|
28
|
+
localizedHref.startsWith('//'))
|
|
29
|
+
|
|
30
|
+
if (!isExternal) {
|
|
31
|
+
e.preventDefault()
|
|
32
|
+
navigate(localizedHref)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
27
36
|
const handleMouseEnter = (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
28
37
|
onMouseEnter?.(e)
|
|
29
38
|
}
|
|
30
39
|
|
|
31
|
-
const handleFocus = (e: React.FocusEvent) => {
|
|
32
|
-
onFocus?.(e
|
|
40
|
+
const handleFocus = (e: React.FocusEvent<HTMLAnchorElement>) => {
|
|
41
|
+
onFocus?.(e)
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
return (
|
|
36
|
-
<
|
|
45
|
+
<a
|
|
37
46
|
{...rest}
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
href={localizedHref}
|
|
48
|
+
onClick={handleClick}
|
|
40
49
|
onMouseEnter={handleMouseEnter}
|
|
41
|
-
onFocus={handleFocus
|
|
50
|
+
onFocus={handleFocus}
|
|
42
51
|
/>
|
|
43
52
|
)
|
|
44
|
-
}
|
|
45
|
-
Link.displayName = 'Link'
|
|
53
|
+
}
|
|
46
54
|
|
|
47
55
|
/**
|
|
48
56
|
* Props for the NavLink component, extending standard Link props.
|
|
@@ -68,37 +76,27 @@ export interface NavLinkProps
|
|
|
68
76
|
|
|
69
77
|
/**
|
|
70
78
|
* A primitive NavLink component that provides active state detection.
|
|
71
|
-
*
|
|
72
|
-
* It combines the Link primitive with path matching logic to determine
|
|
73
|
-
* if the link is currently active based on the browser's location.
|
|
74
79
|
*/
|
|
75
|
-
export const NavLink =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const location = useLocation()
|
|
79
|
-
const localizedHref = useLocalizedTo(href ?? '')
|
|
80
|
+
export const NavLink = (props: NavLinkProps) => {
|
|
81
|
+
const { href, end = false, className, children, ...rest } = props
|
|
82
|
+
const location = useLocation()
|
|
80
83
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
const localizedHref = useLocalizedTo(href ?? '')
|
|
85
|
+
|
|
86
|
+
const isActive = end
|
|
87
|
+
? location.pathname === localizedHref
|
|
88
|
+
: location.pathname.startsWith(localizedHref)
|
|
84
89
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
const resolvedClassName =
|
|
91
|
+
typeof className === 'function'
|
|
92
|
+
? className({ isActive })
|
|
93
|
+
: cn(className, isActive && 'active')
|
|
94
|
+
const resolvedChildren =
|
|
95
|
+
typeof children === 'function' ? children({ isActive }) : children
|
|
91
96
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
>
|
|
99
|
-
{resolvedChildren as any}
|
|
100
|
-
</Link>
|
|
101
|
-
)
|
|
102
|
-
},
|
|
103
|
-
)
|
|
104
|
-
NavLink.displayName = 'NavLink'
|
|
97
|
+
return (
|
|
98
|
+
<Link {...rest} href={href} className={resolvedClassName}>
|
|
99
|
+
{resolvedChildren}
|
|
100
|
+
</Link>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { Check, ChevronRight, Dot } from 'lucide-react'
|
|
1
|
+
import { Check, ChevronRight } from 'lucide-react'
|
|
4
2
|
import * as RAC from 'react-aria-components'
|
|
5
3
|
import { Children } from 'react'
|
|
6
4
|
import { Popover, type PopoverProps } from './popover'
|
|
7
5
|
import { cn } from '../../utils/cn'
|
|
6
|
+
|
|
8
7
|
/**
|
|
9
8
|
* MenuTrigger wraps a trigger (usually a Button) and a Menu.
|
|
10
9
|
*/
|
|
11
10
|
export interface MenuTriggerProps extends RAC.MenuTriggerProps {
|
|
12
11
|
placement?: PopoverProps['placement']
|
|
12
|
+
className?: string
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
function MenuTrigger(props: MenuTriggerProps) {
|
|
15
|
+
function MenuTrigger({ placement, className, ...props }: MenuTriggerProps) {
|
|
16
16
|
const [trigger, menu] = (
|
|
17
17
|
Children.toArray(props.children) as React.ReactElement[]
|
|
18
18
|
).slice(0, 2)
|
|
19
19
|
return (
|
|
20
20
|
<RAC.MenuTrigger {...props}>
|
|
21
21
|
{trigger as any}
|
|
22
|
-
<Popover placement={
|
|
22
|
+
<Popover placement={placement} className={className}>
|
|
23
23
|
{menu as any}
|
|
24
24
|
</Popover>
|
|
25
25
|
</RAC.MenuTrigger>
|
|
@@ -29,14 +29,18 @@ function MenuTrigger(props: MenuTriggerProps) {
|
|
|
29
29
|
/**
|
|
30
30
|
* SubmenuTrigger for nested menus.
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
export interface SubmenuTriggerProps extends RAC.SubmenuTriggerProps {
|
|
33
|
+
className?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function SubmenuTrigger({ className, ...props }: SubmenuTriggerProps) {
|
|
33
37
|
const [trigger, menu] = (
|
|
34
38
|
Children.toArray(props.children) as React.ReactElement[]
|
|
35
39
|
).slice(0, 2)
|
|
36
40
|
return (
|
|
37
41
|
<RAC.SubmenuTrigger {...props}>
|
|
38
42
|
{trigger as any}
|
|
39
|
-
<Popover offset={-4} crossOffset={-4}>
|
|
43
|
+
<Popover offset={-4} crossOffset={-4} className={className}>
|
|
40
44
|
{menu as any}
|
|
41
45
|
</Popover>
|
|
42
46
|
</RAC.SubmenuTrigger>
|
|
@@ -51,10 +55,7 @@ export function Menu<T extends object>(props: RAC.MenuProps<T>) {
|
|
|
51
55
|
<RAC.Menu
|
|
52
56
|
{...props}
|
|
53
57
|
className={RAC.composeRenderProps(props.className, (className) =>
|
|
54
|
-
cn(
|
|
55
|
-
'p-1.5 outline-none max-h-[inherit] overflow-auto max-w-75',
|
|
56
|
-
className,
|
|
57
|
-
),
|
|
58
|
+
cn('outline-none overflow-auto', className),
|
|
58
59
|
)}
|
|
59
60
|
/>
|
|
60
61
|
)
|
|
@@ -72,42 +73,24 @@ function MenuItem(props: RAC.MenuItemProps) {
|
|
|
72
73
|
<RAC.MenuItem
|
|
73
74
|
{...props}
|
|
74
75
|
textValue={textValue}
|
|
75
|
-
className={RAC.composeRenderProps(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
'text-text-main text-[12px]',
|
|
81
|
-
{
|
|
82
|
-
'bg-bg-surface-elevated text-primary-600 ring-1 ring-border-strong/5':
|
|
83
|
-
isFocused,
|
|
84
|
-
'bg-bg-surface-elevanted': isPressed,
|
|
85
|
-
'opacity-40 grayscale pointer-events-none': isDisabled,
|
|
86
|
-
},
|
|
87
|
-
className,
|
|
88
|
-
),
|
|
76
|
+
className={RAC.composeRenderProps(props.className, (className) =>
|
|
77
|
+
cn(
|
|
78
|
+
'group relative flex flex-row items-center cursor-default outline-none',
|
|
79
|
+
className,
|
|
80
|
+
),
|
|
89
81
|
)}
|
|
90
82
|
>
|
|
91
83
|
{RAC.composeRenderProps(
|
|
92
84
|
props.children,
|
|
93
85
|
(children, { selectionMode, isSelected, hasSubmenu }) => (
|
|
94
86
|
<>
|
|
95
|
-
{selectionMode
|
|
96
|
-
<span className="flex items-center
|
|
97
|
-
{isSelected &&
|
|
98
|
-
<Check className="size-3.5 stroke-[2.5px] text-primary-500 animate-in zoom-in-50 duration-200" />
|
|
99
|
-
)}
|
|
100
|
-
{isSelected && selectionMode === 'single' && (
|
|
101
|
-
<Dot className="size-5 text-primary-500 animate-in zoom-in-50 duration-200" />
|
|
102
|
-
)}
|
|
87
|
+
{selectionMode === 'multiple' && (
|
|
88
|
+
<span className="flex items-center shrink-0 justify-center">
|
|
89
|
+
{isSelected && <Check className="size-3.5" />}
|
|
103
90
|
</span>
|
|
104
91
|
)}
|
|
105
|
-
<div className="flex flex-row w-full
|
|
106
|
-
|
|
107
|
-
</div>
|
|
108
|
-
{hasSubmenu && (
|
|
109
|
-
<ChevronRight className="size-4 ml-auto text-text-muted group-focused:text-primary-500/70 transition-colors" />
|
|
110
|
-
)}
|
|
92
|
+
<div className="flex flex-row w-full items-center">{children}</div>
|
|
93
|
+
{hasSubmenu && <ChevronRight className="size-4 ml-auto" />}
|
|
111
94
|
</>
|
|
112
95
|
),
|
|
113
96
|
)}
|
|
@@ -129,13 +112,9 @@ function MenuSection<T extends object>({
|
|
|
129
112
|
return (
|
|
130
113
|
<RAC.MenuSection
|
|
131
114
|
{...props}
|
|
132
|
-
className={cn('flex flex-col
|
|
115
|
+
className={cn('flex flex-col', props.className)}
|
|
133
116
|
>
|
|
134
|
-
{title &&
|
|
135
|
-
<RAC.Header className="px-3 py-2 text-[10px] font-bold uppercase tracking-[0.075em] text-text-muted/50 select-none">
|
|
136
|
-
{title}
|
|
137
|
-
</RAC.Header>
|
|
138
|
-
)}
|
|
117
|
+
{title && <RAC.Header className="select-none">{title}</RAC.Header>}
|
|
139
118
|
<RAC.Collection items={props.items}>{props.children}</RAC.Collection>
|
|
140
119
|
</RAC.MenuSection>
|
|
141
120
|
)
|
|
@@ -146,10 +125,7 @@ function MenuSection<T extends object>({
|
|
|
146
125
|
*/
|
|
147
126
|
function MenuSeparator(props: RAC.SeparatorProps) {
|
|
148
127
|
return (
|
|
149
|
-
<RAC.Separator
|
|
150
|
-
{...props}
|
|
151
|
-
className="mx-2 my-1.5 border-t border-border-subtle/50"
|
|
152
|
-
/>
|
|
128
|
+
<RAC.Separator {...props} className={cn('border-t', props.className)} />
|
|
153
129
|
)
|
|
154
130
|
}
|
|
155
131
|
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { type ReactNode, useState, useEffect } from 'react'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import {
|
|
3
|
+
Button as ButtonRAC,
|
|
4
|
+
ModalOverlay,
|
|
5
|
+
Modal,
|
|
6
|
+
Dialog,
|
|
7
|
+
Separator,
|
|
8
|
+
ToggleButton,
|
|
9
|
+
} from 'react-aria-components'
|
|
10
|
+
import { Link } from './link'
|
|
11
|
+
import { Menu } from './menu'
|
|
12
|
+
import { Popover } from './popover'
|
|
13
|
+
import { cn } from '../../utils/cn'
|
|
14
|
+
import { Sun, Moon, ExternalLink, MoreVertical, X } from 'lucide-react'
|
|
5
15
|
import * as IconsSocials from '../icons-dev'
|
|
6
16
|
import type { ComponentBase } from './types'
|
|
7
17
|
import type { BoltdocsSocialLink } from '../../../shared/types'
|
|
@@ -9,7 +19,6 @@ import type { BoltdocsSocialLink } from '../../../shared/types'
|
|
|
9
19
|
export interface NavbarLinkProps extends Omit<ComponentBase, 'children'> {
|
|
10
20
|
label: ReactNode
|
|
11
21
|
href: string
|
|
12
|
-
active?: boolean
|
|
13
22
|
to?: 'internal' | 'external'
|
|
14
23
|
}
|
|
15
24
|
|
|
@@ -18,6 +27,7 @@ export interface NavbarLogoProps extends Omit<ComponentBase, 'children'> {
|
|
|
18
27
|
alt: string
|
|
19
28
|
width?: number
|
|
20
29
|
height?: number
|
|
30
|
+
href?: string
|
|
21
31
|
}
|
|
22
32
|
|
|
23
33
|
export interface NavbarSearchTriggerProps extends ComponentBase {
|
|
@@ -38,10 +48,7 @@ export interface NavbarSocialsProps extends ComponentBase {
|
|
|
38
48
|
export const Navbar = ({ children, className, ...props }: ComponentBase) => {
|
|
39
49
|
return (
|
|
40
50
|
<header
|
|
41
|
-
className={cn(
|
|
42
|
-
'boltdocs-navbar sticky top-0 z-50 w-full border-b border-border-subtle bg-bg-main/80 backdrop-blur-md',
|
|
43
|
-
className,
|
|
44
|
-
)}
|
|
51
|
+
className={cn('boltdocs-navbar sticky top-0 z-50 w-full', className)}
|
|
45
52
|
{...props}
|
|
46
53
|
>
|
|
47
54
|
{children}
|
|
@@ -107,10 +114,11 @@ const NavbarLogo = ({
|
|
|
107
114
|
width = 24,
|
|
108
115
|
height = 24,
|
|
109
116
|
className,
|
|
117
|
+
href = '/',
|
|
110
118
|
}: NavbarLogoProps) => {
|
|
111
119
|
return (
|
|
112
120
|
<Link
|
|
113
|
-
href=
|
|
121
|
+
href={href}
|
|
114
122
|
className={cn('flex items-center gap-2 shrink-0 outline-none', className)}
|
|
115
123
|
>
|
|
116
124
|
{src ? (
|
|
@@ -126,9 +134,13 @@ const NavbarLogo = ({
|
|
|
126
134
|
)
|
|
127
135
|
}
|
|
128
136
|
|
|
129
|
-
const NavbarTitle = ({
|
|
137
|
+
const NavbarTitle = ({
|
|
138
|
+
children,
|
|
139
|
+
className,
|
|
140
|
+
href = '/',
|
|
141
|
+
}: { href?: string } & ComponentBase) => {
|
|
130
142
|
return (
|
|
131
|
-
<Link href=
|
|
143
|
+
<Link href={href}>
|
|
132
144
|
<span
|
|
133
145
|
className={cn(
|
|
134
146
|
'text-lg font-bold tracking-tight hidden sm:inline-block',
|
|
@@ -154,25 +166,12 @@ const NavbarLinks = ({ children, className }: ComponentBase) => {
|
|
|
154
166
|
)
|
|
155
167
|
}
|
|
156
168
|
|
|
157
|
-
const NavbarLink = ({
|
|
158
|
-
label,
|
|
159
|
-
href,
|
|
160
|
-
active,
|
|
161
|
-
to,
|
|
162
|
-
className,
|
|
163
|
-
}: NavbarLinkProps) => {
|
|
169
|
+
const NavbarLink = ({ label, href, to, className }: NavbarLinkProps) => {
|
|
164
170
|
return (
|
|
165
171
|
<Link
|
|
166
172
|
href={href}
|
|
167
173
|
target={to === 'external' ? '_blank' : undefined}
|
|
168
|
-
className={cn(
|
|
169
|
-
'transition-colors outline-none font-medium focus-visible:ring-2 focus-visible:ring-primary-500/30 rounded-sm',
|
|
170
|
-
{
|
|
171
|
-
'text-primary-500': active,
|
|
172
|
-
'text-text-muted hover:text-text-main': !active,
|
|
173
|
-
},
|
|
174
|
-
className,
|
|
175
|
-
)}
|
|
174
|
+
className={cn('transition-all outline-none', className)}
|
|
176
175
|
>
|
|
177
176
|
{label as any}
|
|
178
177
|
{to === 'external' && (
|
|
@@ -184,10 +183,115 @@ const NavbarLink = ({
|
|
|
184
183
|
)
|
|
185
184
|
}
|
|
186
185
|
|
|
187
|
-
const
|
|
186
|
+
const NavbarDropdown = ({
|
|
187
|
+
label,
|
|
188
|
+
className,
|
|
189
|
+
children,
|
|
190
|
+
}: {
|
|
191
|
+
label: React.ReactNode
|
|
192
|
+
className?: string
|
|
193
|
+
children: React.ReactNode
|
|
194
|
+
}) => {
|
|
195
|
+
const [isOpen, setIsOpen] = useState(false)
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<div
|
|
199
|
+
className={cn('relative', className)}
|
|
200
|
+
onMouseEnter={() => {
|
|
201
|
+
setIsOpen(true)
|
|
202
|
+
}}
|
|
203
|
+
onMouseLeave={() => {
|
|
204
|
+
setIsOpen(false)
|
|
205
|
+
}}
|
|
206
|
+
>
|
|
207
|
+
<div
|
|
208
|
+
className={cn(
|
|
209
|
+
'flex items-center gap-1 outline-none cursor-pointer select-none font-medium text-muted hover:text-body transition-colors',
|
|
210
|
+
)}
|
|
211
|
+
>
|
|
212
|
+
{label}
|
|
213
|
+
<svg
|
|
214
|
+
className={cn('w-4 h-4 transition-transform', isOpen && 'rotate-180')}
|
|
215
|
+
fill="none"
|
|
216
|
+
viewBox="0 0 24 24"
|
|
217
|
+
stroke="currentColor"
|
|
218
|
+
>
|
|
219
|
+
<path
|
|
220
|
+
strokeLinecap="round"
|
|
221
|
+
strokeLinejoin="round"
|
|
222
|
+
strokeWidth={2}
|
|
223
|
+
d="M19 9l-7 7-7-7"
|
|
224
|
+
/>
|
|
225
|
+
</svg>
|
|
226
|
+
</div>
|
|
227
|
+
{isOpen && (
|
|
228
|
+
<div className="absolute top-full left-0 pt-1 z-[9999]">
|
|
229
|
+
<div className="min-w-[180px] p-1 bg-surface border border-subtle rounded-md shadow-lg">
|
|
230
|
+
{children}
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
)}
|
|
234
|
+
</div>
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const NavbarDropdownItem = ({
|
|
239
|
+
href,
|
|
240
|
+
label,
|
|
241
|
+
className,
|
|
242
|
+
}: {
|
|
243
|
+
href: string
|
|
244
|
+
label: string
|
|
245
|
+
className?: string
|
|
246
|
+
}) => {
|
|
247
|
+
return (
|
|
248
|
+
<Link
|
|
249
|
+
href={href}
|
|
250
|
+
className={cn('block px-2 py-1.5 rounded hover:bg-surface', className)}
|
|
251
|
+
>
|
|
252
|
+
{label}
|
|
253
|
+
</Link>
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const NavbarSearchTriggerDesktop = ({
|
|
258
|
+
className,
|
|
259
|
+
onPress,
|
|
260
|
+
children,
|
|
261
|
+
}: NavbarSearchTriggerProps) => {
|
|
262
|
+
return (
|
|
263
|
+
<ButtonRAC
|
|
264
|
+
onPress={onPress}
|
|
265
|
+
className={cn(
|
|
266
|
+
'hidden lg:flex items-center justify-between gap-2 px-3 py-2 text-sm outline-none cursor-pointer w-full max-w-[720px]',
|
|
267
|
+
className,
|
|
268
|
+
)}
|
|
269
|
+
>
|
|
270
|
+
{children}
|
|
271
|
+
</ButtonRAC>
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const NavbarSearchTriggerMobile = ({
|
|
188
276
|
className,
|
|
189
277
|
onPress,
|
|
278
|
+
children,
|
|
190
279
|
}: NavbarSearchTriggerProps) => {
|
|
280
|
+
return (
|
|
281
|
+
<ButtonRAC
|
|
282
|
+
onPress={onPress}
|
|
283
|
+
className={cn(
|
|
284
|
+
'lg:hidden flex h-10 w-10 items-center justify-center outline-none cursor-pointer',
|
|
285
|
+
className,
|
|
286
|
+
)}
|
|
287
|
+
aria-label="Search"
|
|
288
|
+
>
|
|
289
|
+
{children}
|
|
290
|
+
</ButtonRAC>
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const NavbarSearchTriggerKbd = ({ className }: ComponentBase) => {
|
|
191
295
|
const [mounted, setMounted] = useState(false)
|
|
192
296
|
const isMac = mounted && /Mac|iPod|iPhone|iPad/.test(navigator.platform)
|
|
193
297
|
|
|
@@ -196,43 +300,34 @@ const NavbarSearchTrigger = ({
|
|
|
196
300
|
}, [])
|
|
197
301
|
|
|
198
302
|
return (
|
|
199
|
-
<
|
|
200
|
-
onPress={onPress}
|
|
303
|
+
<div
|
|
201
304
|
className={cn(
|
|
202
|
-
'flex items-center gap-
|
|
203
|
-
'transition-all duration-200 hover:border-border-strong hover:text-text-main hover:bg-bg-muted hover:shadow-sm active:scale-[0.98]',
|
|
204
|
-
'focus-visible:ring-2 focus-visible:ring-primary-500/30',
|
|
205
|
-
'w-full max-w-[720px] justify-between',
|
|
305
|
+
'hidden sm:flex items-center gap-1 pointer-events-none select-none',
|
|
206
306
|
className,
|
|
207
307
|
)}
|
|
208
308
|
>
|
|
209
|
-
<
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
</kbd>
|
|
217
|
-
<kbd className="flex h-5 w-5 items-center justify-center rounded border border-border-subtle bg-bg-main font-mono text-[10px] font-medium">
|
|
218
|
-
K
|
|
219
|
-
</kbd>
|
|
220
|
-
</div>
|
|
221
|
-
</ButtonRAC>
|
|
309
|
+
<kbd className="flex items-center justify-center font-mono text-[10px]">
|
|
310
|
+
{isMac ? '⌘' : 'Ctrl'}
|
|
311
|
+
</kbd>
|
|
312
|
+
<kbd className="flex items-center justify-center font-mono text-[10px]">
|
|
313
|
+
K
|
|
314
|
+
</kbd>
|
|
315
|
+
</div>
|
|
222
316
|
)
|
|
223
317
|
}
|
|
224
318
|
|
|
319
|
+
const NavbarSearchTrigger = {
|
|
320
|
+
Desktop: NavbarSearchTriggerDesktop,
|
|
321
|
+
Mobile: NavbarSearchTriggerMobile,
|
|
322
|
+
Kbd: NavbarSearchTriggerKbd,
|
|
323
|
+
}
|
|
324
|
+
|
|
225
325
|
const NavbarTheme = ({ className, theme, onThemeChange }: NavbarThemeProps) => {
|
|
226
326
|
return (
|
|
227
327
|
<ToggleButton
|
|
228
328
|
isSelected={theme === 'dark'}
|
|
229
329
|
onChange={onThemeChange}
|
|
230
|
-
className={cn(
|
|
231
|
-
'rounded-md p-2 text-text-muted outline-none cursor-pointer',
|
|
232
|
-
'transition-all duration-300 hover:bg-bg-surface hover:text-text-main hover:rotate-12 active:scale-90',
|
|
233
|
-
'focus-visible:ring-2 focus-visible:ring-primary-500/30',
|
|
234
|
-
className,
|
|
235
|
-
)}
|
|
330
|
+
className={cn('outline-none cursor-pointer', className)}
|
|
236
331
|
aria-label="Toggle theme"
|
|
237
332
|
>
|
|
238
333
|
{theme === 'dark' ? <Sun size={20} /> : <Moon size={20} />}
|
|
@@ -253,12 +348,7 @@ const NavbarSocials = ({ icon, link, className }: NavbarSocialsProps) => {
|
|
|
253
348
|
href={link}
|
|
254
349
|
target="_blank"
|
|
255
350
|
rel="noopener noreferrer"
|
|
256
|
-
className={cn(
|
|
257
|
-
'rounded-md p-2 text-text-muted outline-none transition-colors',
|
|
258
|
-
'hover:bg-bg-surface hover:text-text-main',
|
|
259
|
-
'focus-visible:ring-2 focus-visible:ring-primary-500/30',
|
|
260
|
-
className,
|
|
261
|
-
)}
|
|
351
|
+
className={cn('outline-none', className)}
|
|
262
352
|
>
|
|
263
353
|
<Icon name={icon} />
|
|
264
354
|
</Link>
|
|
@@ -269,11 +359,91 @@ const NavbarSplit = ({ className }: ComponentBase) => {
|
|
|
269
359
|
return (
|
|
270
360
|
<Separator
|
|
271
361
|
orientation="vertical"
|
|
272
|
-
className={cn('h-
|
|
362
|
+
className={cn('h-full w-px', className)}
|
|
273
363
|
/>
|
|
274
364
|
)
|
|
275
365
|
}
|
|
276
366
|
|
|
367
|
+
export interface NavbarMoreProps extends ComponentBase {
|
|
368
|
+
onPress?: () => void
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const NavbarMore = ({ onPress, className }: NavbarMoreProps) => {
|
|
372
|
+
return (
|
|
373
|
+
<ButtonRAC
|
|
374
|
+
onPress={onPress}
|
|
375
|
+
className={cn(
|
|
376
|
+
'md:hidden flex items-center justify-center outline-none cursor-pointer',
|
|
377
|
+
className,
|
|
378
|
+
)}
|
|
379
|
+
aria-label="More navigation"
|
|
380
|
+
>
|
|
381
|
+
<MoreVertical size={20} />
|
|
382
|
+
</ButtonRAC>
|
|
383
|
+
)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export interface NavbarMobileMenuProps extends ComponentBase {
|
|
387
|
+
isOpen: boolean
|
|
388
|
+
onClose: () => void
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const NavbarMobileMenu = ({
|
|
392
|
+
isOpen,
|
|
393
|
+
onClose,
|
|
394
|
+
children,
|
|
395
|
+
className,
|
|
396
|
+
}: NavbarMobileMenuProps) => {
|
|
397
|
+
return (
|
|
398
|
+
<ModalOverlay
|
|
399
|
+
isOpen={isOpen}
|
|
400
|
+
onOpenChange={(open) => !open && onClose()}
|
|
401
|
+
isDismissable={true}
|
|
402
|
+
className={cn(
|
|
403
|
+
'fixed inset-0 z-60 md:hidden transition-all duration-100',
|
|
404
|
+
className,
|
|
405
|
+
)}
|
|
406
|
+
>
|
|
407
|
+
<Modal className="fixed inset-0 outline-none">
|
|
408
|
+
<Dialog className="relative h-full outline-none flex flex-col p-6 pt-[calc(1.5rem+env(safe-area-inset-top,0px))] pb-[calc(1.5rem+env(safe-area-inset-bottom,0px))] px-[calc(1.5rem+env(safe-area-inset-left,0px))]">
|
|
409
|
+
<div className="flex items-center justify-between mb-6">
|
|
410
|
+
<span></span>
|
|
411
|
+
<ButtonRAC
|
|
412
|
+
onPress={onClose}
|
|
413
|
+
className="flex items-center justify-center outline-none cursor-pointer text-muted hover:text-body transition-colors"
|
|
414
|
+
aria-label="Close menu"
|
|
415
|
+
>
|
|
416
|
+
<X size={24} />
|
|
417
|
+
</ButtonRAC>
|
|
418
|
+
</div>
|
|
419
|
+
<nav className="flex-1 overflow-y-auto flex flex-col gap-4">
|
|
420
|
+
{children}
|
|
421
|
+
</nav>
|
|
422
|
+
</Dialog>
|
|
423
|
+
</Modal>
|
|
424
|
+
</ModalOverlay>
|
|
425
|
+
)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const NavbarMobileLink = ({
|
|
429
|
+
label,
|
|
430
|
+
href,
|
|
431
|
+
to,
|
|
432
|
+
onPress,
|
|
433
|
+
className,
|
|
434
|
+
}: NavbarLinkProps & { onPress?: () => void }) => {
|
|
435
|
+
return (
|
|
436
|
+
<Link
|
|
437
|
+
href={href}
|
|
438
|
+
target={to === 'external' ? '_blank' : undefined}
|
|
439
|
+
onClick={onPress}
|
|
440
|
+
className={cn('group flex items-center outline-none', className)}
|
|
441
|
+
>
|
|
442
|
+
{label as any}
|
|
443
|
+
</Link>
|
|
444
|
+
)
|
|
445
|
+
}
|
|
446
|
+
|
|
277
447
|
Navbar.Root = Navbar
|
|
278
448
|
Navbar.Left = NavbarLeft
|
|
279
449
|
Navbar.Right = NavbarRight
|
|
@@ -282,10 +452,15 @@ Navbar.Logo = NavbarLogo
|
|
|
282
452
|
Navbar.Title = NavbarTitle
|
|
283
453
|
Navbar.Links = NavbarLinks
|
|
284
454
|
Navbar.Link = NavbarLink
|
|
455
|
+
Navbar.Dropdown = NavbarDropdown
|
|
456
|
+
Navbar.DropdownItem = NavbarDropdownItem
|
|
285
457
|
Navbar.SearchTrigger = NavbarSearchTrigger
|
|
286
458
|
Navbar.Theme = NavbarTheme
|
|
287
459
|
Navbar.Socials = NavbarSocials
|
|
288
460
|
Navbar.Split = NavbarSplit
|
|
289
461
|
Navbar.Content = NavbarContent
|
|
462
|
+
Navbar.More = NavbarMore
|
|
463
|
+
Navbar.MobileMenu = NavbarMobileMenu
|
|
464
|
+
Navbar.MobileLink = NavbarMobileLink
|
|
290
465
|
|
|
291
466
|
export default Navbar
|