boltdocs 2.5.6 → 2.6.1
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 +2 -2
- package/dist/client/index.cjs +6 -0
- package/dist/client/{index.d.mts → index.d.cts} +135 -265
- package/dist/client/index.d.ts +136 -266
- package/dist/client/index.js +1 -1
- package/dist/client/theme/neutral.css +90 -50
- package/dist/node/cli-entry.cjs +2 -2
- package/dist/node/cli-entry.mjs +2 -2
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +168 -205
- package/dist/node/index.d.mts +168 -205
- package/dist/node/index.mjs +1 -1
- package/dist/node-CWN8U_p8.mjs +88 -0
- package/dist/node-D5iosYXv.cjs +88 -0
- package/dist/{package-OFZf0s2j.mjs → package-DukYeKmD.mjs} +1 -1
- package/dist/{package-BY8Jd2j4.cjs → package-c99Cs7mD.cjs} +1 -1
- package/dist/search-dialog-3lvKsbVG.js +6 -0
- package/dist/search-dialog-DMK5OpgH.cjs +6 -0
- package/dist/use-search-C9bxCqfF.js +6 -0
- package/dist/use-search-DcfZSunO.cjs +6 -0
- package/package.json +21 -23
- package/src/client/app/config-context.tsx +38 -5
- package/src/client/app/doc-page.tsx +34 -0
- package/src/client/app/mdx-component.tsx +2 -3
- package/src/client/app/mdx-components-context.tsx +27 -2
- package/src/client/app/routes-context.tsx +34 -0
- package/src/client/app/scroll-handler.tsx +7 -4
- package/src/client/app/theme-context.tsx +71 -67
- package/src/client/components/docs-layout.tsx +1 -2
- package/src/client/components/icons-dev.tsx +36 -5
- package/src/client/components/mdx/admonition.tsx +11 -27
- package/src/client/components/mdx/badge.tsx +1 -1
- package/src/client/components/mdx/button.tsx +3 -3
- package/src/client/components/mdx/card.tsx +1 -1
- package/src/client/components/mdx/code-block.tsx +90 -80
- package/src/client/components/mdx/component-preview.tsx +1 -5
- package/src/client/components/mdx/component-props.tsx +1 -1
- package/src/client/components/mdx/field.tsx +4 -5
- package/src/client/components/mdx/file-tree.tsx +6 -3
- package/src/client/components/mdx/hooks/use-code-block.ts +2 -2
- package/src/client/components/mdx/image.tsx +1 -1
- package/src/client/components/mdx/link.tsx +2 -2
- package/src/client/components/mdx/list.tsx +1 -1
- package/src/client/components/mdx/table.tsx +1 -1
- package/src/client/components/mdx/tabs.tsx +1 -1
- package/src/client/components/primitives/breadcrumbs.tsx +1 -7
- package/src/client/components/primitives/button-group.tsx +1 -1
- package/src/client/components/primitives/button.tsx +1 -1
- package/src/client/components/primitives/code-block.tsx +113 -0
- package/src/client/components/primitives/link.tsx +23 -41
- package/src/client/components/primitives/menu.tsx +5 -6
- package/src/client/components/primitives/navbar.tsx +6 -18
- package/src/client/components/primitives/navigation-menu.tsx +4 -4
- package/src/client/components/primitives/on-this-page.tsx +6 -10
- package/src/client/components/primitives/page-nav.tsx +4 -9
- package/src/client/components/primitives/popover.tsx +1 -1
- package/src/client/components/primitives/search-dialog.tsx +3 -6
- package/src/client/components/primitives/sidebar.tsx +80 -22
- package/src/client/components/primitives/skeleton.tsx +1 -1
- package/src/client/components/primitives/tabs.tsx +4 -11
- package/src/client/components/primitives/tooltip.tsx +3 -3
- package/src/client/components/ui-base/breadcrumbs.tsx +4 -6
- package/src/client/components/ui-base/copy-markdown.tsx +2 -7
- package/src/client/components/ui-base/github-stars.tsx +2 -2
- package/src/client/components/ui-base/head.tsx +58 -51
- package/src/client/components/ui-base/loading.tsx +2 -2
- package/src/client/components/ui-base/navbar.tsx +12 -14
- package/src/client/components/ui-base/not-found.tsx +1 -1
- package/src/client/components/ui-base/on-this-page.tsx +6 -6
- package/src/client/components/ui-base/page-nav.tsx +4 -8
- package/src/client/components/ui-base/search-dialog.tsx +10 -8
- package/src/client/components/ui-base/sidebar.tsx +76 -23
- package/src/client/components/ui-base/tabs.tsx +9 -8
- package/src/client/components/ui-base/theme-toggle.tsx +2 -2
- package/src/client/hooks/use-i18n.ts +3 -3
- package/src/client/hooks/use-localized-to.ts +1 -1
- package/src/client/hooks/use-navbar.ts +8 -6
- package/src/client/hooks/use-routes.ts +19 -11
- package/src/client/hooks/use-search.ts +1 -1
- package/src/client/hooks/use-sidebar.ts +48 -2
- package/src/client/hooks/use-tabs.ts +6 -2
- package/src/client/hooks/use-version.ts +3 -3
- package/src/client/index.ts +20 -22
- package/src/client/ssg/boltdocs-shell.tsx +127 -0
- package/src/client/ssg/create-routes.tsx +179 -0
- package/src/client/ssg/index.ts +3 -0
- package/src/client/ssg/mdx-page.tsx +37 -0
- package/src/client/store/boltdocs-context.tsx +46 -99
- package/src/client/theme/neutral.css +90 -50
- package/src/client/types.ts +5 -33
- package/src/client/utils/react-to-text.ts +34 -0
- package/src/shared/config-utils.ts +12 -0
- package/src/shared/types.ts +171 -0
- package/dist/cache-Cr8W2zgZ.cjs +0 -6
- package/dist/cache-DFdakSmR.mjs +0 -6
- package/dist/client/index.mjs +0 -6
- package/dist/client/ssr.cjs +0 -6
- package/dist/client/ssr.d.cts +0 -80
- package/dist/client/ssr.d.mts +0 -80
- package/dist/client/ssr.mjs +0 -6
- package/dist/node-CWXme96p.mjs +0 -73
- package/dist/node-VYfhzGrh.cjs +0 -73
- package/dist/search-dialog-BeNyI_KQ.mjs +0 -6
- package/dist/search-dialog-dYsCAk5S.js +0 -6
- package/dist/use-search-D25n0PrV.mjs +0 -6
- package/dist/use-search-WuzdH1cJ.js +0 -6
- package/src/client/app/index.tsx +0 -348
- package/src/client/app/mdx-page.tsx +0 -15
- package/src/client/app/preload.tsx +0 -66
- package/src/client/app/router.tsx +0 -30
- package/src/client/components/default-layout.tsx +0 -90
- package/src/client/integrations/codesandbox.ts +0 -179
- package/src/client/integrations/index.ts +0 -1
- package/src/client/ssr.tsx +0 -65
|
@@ -2,9 +2,9 @@ import { type ReactNode, useState, useEffect } from 'react'
|
|
|
2
2
|
import { Separator, ToggleButton, Link, cn } from './index'
|
|
3
3
|
import { Button as ButtonRAC } from 'react-aria-components'
|
|
4
4
|
import { Search, Sun, Moon, ExternalLink } from 'lucide-react'
|
|
5
|
-
import * as IconsSocials from '
|
|
5
|
+
import * as IconsSocials from '../icons-dev'
|
|
6
6
|
import type { ComponentBase } from './types'
|
|
7
|
-
import type { BoltdocsSocialLink } from '
|
|
7
|
+
import type { BoltdocsSocialLink } from '../../../shared/types'
|
|
8
8
|
|
|
9
9
|
export interface NavbarLinkProps extends Omit<ComponentBase, 'children'> {
|
|
10
10
|
label: ReactNode
|
|
@@ -35,11 +35,7 @@ export interface NavbarSocialsProps extends ComponentBase {
|
|
|
35
35
|
link: string
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export const Navbar = ({
|
|
39
|
-
children,
|
|
40
|
-
className,
|
|
41
|
-
...props
|
|
42
|
-
}: ComponentBase) => {
|
|
38
|
+
export const Navbar = ({ children, className, ...props }: ComponentBase) => {
|
|
43
39
|
return (
|
|
44
40
|
<header
|
|
45
41
|
className={cn(
|
|
@@ -226,11 +222,7 @@ const NavbarSearchTrigger = ({
|
|
|
226
222
|
)
|
|
227
223
|
}
|
|
228
224
|
|
|
229
|
-
const NavbarTheme = ({
|
|
230
|
-
className,
|
|
231
|
-
theme,
|
|
232
|
-
onThemeChange,
|
|
233
|
-
}: NavbarThemeProps) => {
|
|
225
|
+
const NavbarTheme = ({ className, theme, onThemeChange }: NavbarThemeProps) => {
|
|
234
226
|
return (
|
|
235
227
|
<ToggleButton
|
|
236
228
|
isSelected={theme === 'dark'}
|
|
@@ -255,11 +247,7 @@ const Icon = ({ name }: { name: BoltdocsSocialLink['icon'] }) => {
|
|
|
255
247
|
if (name === 'bluesky') return <IconsSocials.Bluesky />
|
|
256
248
|
}
|
|
257
249
|
|
|
258
|
-
const NavbarSocials = ({
|
|
259
|
-
icon,
|
|
260
|
-
link,
|
|
261
|
-
className,
|
|
262
|
-
}: NavbarSocialsProps) => {
|
|
250
|
+
const NavbarSocials = ({ icon, link, className }: NavbarSocialsProps) => {
|
|
263
251
|
return (
|
|
264
252
|
<Link
|
|
265
253
|
href={link}
|
|
@@ -300,4 +288,4 @@ Navbar.Socials = NavbarSocials
|
|
|
300
288
|
Navbar.Split = NavbarSplit
|
|
301
289
|
Navbar.Content = NavbarContent
|
|
302
290
|
|
|
303
|
-
export default Navbar
|
|
291
|
+
export default Navbar
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as RAC from 'react-aria-components'
|
|
2
2
|
import { ChevronDown } from 'lucide-react'
|
|
3
|
-
import { cn } from '
|
|
3
|
+
import { cn } from '../../utils/cn'
|
|
4
4
|
import type { ComponentBase, CompoundComponent } from './types'
|
|
5
5
|
|
|
6
6
|
export interface NavigationMenuItemProps extends ComponentBase {
|
|
@@ -13,8 +13,8 @@ export interface NavigationMenuLinkProps
|
|
|
13
13
|
label: string
|
|
14
14
|
description?: string
|
|
15
15
|
children?:
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
| React.ReactNode
|
|
17
|
+
| ((opts: RAC.MenuItemRenderProps) => React.ReactNode)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export type NavigationMenuComponent = CompoundComponent<
|
|
@@ -111,4 +111,4 @@ const NavigationMenuLink = ({
|
|
|
111
111
|
NavigationMenu.Root = NavigationMenu
|
|
112
112
|
NavigationMenu.List = NavigationMenuList
|
|
113
113
|
NavigationMenu.Item = NavigationMenuItem
|
|
114
|
-
NavigationMenu.Link = NavigationMenuLink
|
|
114
|
+
NavigationMenu.Link = NavigationMenuLink
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
2
|
createContext,
|
|
3
3
|
use,
|
|
4
4
|
useEffect,
|
|
@@ -10,8 +10,8 @@ import React, {
|
|
|
10
10
|
type RefObject,
|
|
11
11
|
} from 'react'
|
|
12
12
|
import scrollIntoView from 'scroll-into-view-if-needed'
|
|
13
|
-
import { cn } from '
|
|
14
|
-
import { useOnChange } from '
|
|
13
|
+
import { cn } from '../../utils/cn'
|
|
14
|
+
import { useOnChange } from '../../utils/use-on-change'
|
|
15
15
|
import type { ComponentBase } from './types'
|
|
16
16
|
import { getItemId, Observer } from './helpers/observer'
|
|
17
17
|
|
|
@@ -165,15 +165,11 @@ export const OnThisPage = ({ children, className }: ComponentBase) => {
|
|
|
165
165
|
)
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
const OnThisPageHeader = ({
|
|
169
|
-
children,
|
|
170
|
-
className,
|
|
171
|
-
...props
|
|
172
|
-
}: ComponentBase) => {
|
|
168
|
+
const OnThisPageHeader = ({ children, className, ...props }: ComponentBase) => {
|
|
173
169
|
return (
|
|
174
170
|
<div
|
|
175
171
|
className={cn(
|
|
176
|
-
'mb-4 text-xs font-bold
|
|
172
|
+
'mb-4 text-xs font-bold text-text-main',
|
|
177
173
|
className,
|
|
178
174
|
)}
|
|
179
175
|
{...props}
|
|
@@ -302,4 +298,4 @@ OnThisPage.Content = OnThisPageContent
|
|
|
302
298
|
OnThisPage.List = OnThisPageList
|
|
303
299
|
OnThisPage.Item = OnThisPageItem
|
|
304
300
|
OnThisPage.Link = OnThisPageLink
|
|
305
|
-
OnThisPage.Indicator = OnThisPageIndicator
|
|
301
|
+
OnThisPage.Indicator = OnThisPageIndicator
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as RAC from 'react-aria-components'
|
|
2
2
|
import { ChevronLeft, ChevronRight } from 'lucide-react'
|
|
3
|
-
import { cn } from '
|
|
3
|
+
import { cn } from '../../utils/cn'
|
|
4
4
|
import type { ComponentBase } from './types'
|
|
5
5
|
|
|
6
6
|
export interface PageNavProps extends ComponentBase {
|
|
@@ -21,12 +21,7 @@ export const PageNav = ({ children, className }: ComponentBase) => {
|
|
|
21
21
|
)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const PageNavLink = ({
|
|
25
|
-
children,
|
|
26
|
-
to,
|
|
27
|
-
direction,
|
|
28
|
-
className,
|
|
29
|
-
}: PageNavProps) => {
|
|
24
|
+
const PageNavLink = ({ children, to, direction, className }: PageNavProps) => {
|
|
30
25
|
const isNext = direction === 'next'
|
|
31
26
|
return (
|
|
32
27
|
<RAC.Link
|
|
@@ -54,7 +49,7 @@ const PageNavTitle = ({ children, className }: ComponentBase) => {
|
|
|
54
49
|
return (
|
|
55
50
|
<span
|
|
56
51
|
className={cn(
|
|
57
|
-
'text-xs font-medium uppercase
|
|
52
|
+
'text-xs font-medium uppercase text-text-muted',
|
|
58
53
|
className,
|
|
59
54
|
)}
|
|
60
55
|
>
|
|
@@ -81,4 +76,4 @@ PageNav.Root = PageNav
|
|
|
81
76
|
PageNav.Link = PageNavLink
|
|
82
77
|
PageNav.Title = PageNavTitle
|
|
83
78
|
PageNav.Description = PageNavDescription
|
|
84
|
-
PageNav.Icon = PageNavIcon
|
|
79
|
+
PageNav.Icon = PageNavIcon
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as RAC from 'react-aria-components'
|
|
2
2
|
import { Search, Hash, FileText, CornerDownLeft } from 'lucide-react'
|
|
3
|
-
import { cn } from '
|
|
3
|
+
import { cn } from '../../utils/cn'
|
|
4
4
|
import type { ComponentBase } from './types'
|
|
5
5
|
|
|
6
6
|
export interface SearchDialogProps extends ComponentBase {
|
|
@@ -153,10 +153,7 @@ const SearchDialogItemIcon = ({
|
|
|
153
153
|
)
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
const SearchDialogItemTitle = ({
|
|
157
|
-
children,
|
|
158
|
-
className,
|
|
159
|
-
}: ComponentBase) => {
|
|
156
|
+
const SearchDialogItemTitle = ({ children, className }: ComponentBase) => {
|
|
160
157
|
return (
|
|
161
158
|
<span
|
|
162
159
|
className={cn('block font-medium truncate flex-1 text-sm', className)}
|
|
@@ -187,4 +184,4 @@ SearchDialog.Item = Object.assign(SearchDialogItemRoot, {
|
|
|
187
184
|
Icon: SearchDialogItemIcon,
|
|
188
185
|
Title: SearchDialogItemTitle,
|
|
189
186
|
Bio: SearchDialogItemBio,
|
|
190
|
-
})
|
|
187
|
+
})
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { Link } from './link'
|
|
2
2
|
import * as RAC from 'react-aria-components'
|
|
3
3
|
import { ChevronRight } from 'lucide-react'
|
|
4
|
-
import { cn } from '
|
|
4
|
+
import { cn } from '../../utils/cn'
|
|
5
5
|
import type { ComponentBase } from './types'
|
|
6
|
-
import type { ComponentRoute } from '
|
|
6
|
+
import type { ComponentRoute } from '../../types'
|
|
7
7
|
|
|
8
8
|
export interface SidebarGroupProps extends ComponentBase {
|
|
9
9
|
title?: string
|
|
10
10
|
icon?: React.ElementType
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface SidebarSubGroupProps extends SidebarLinkProps {
|
|
11
14
|
isOpen?: boolean
|
|
12
15
|
onToggle?: () => void
|
|
16
|
+
children?: React.ReactNode
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
export interface SidebarLinkProps extends ComponentBase {
|
|
@@ -73,35 +77,24 @@ const SidebarGroup = ({
|
|
|
73
77
|
children,
|
|
74
78
|
title,
|
|
75
79
|
icon: Icon,
|
|
76
|
-
isOpen = true,
|
|
77
|
-
onToggle,
|
|
78
80
|
className,
|
|
79
81
|
}: SidebarGroupProps) => {
|
|
80
82
|
return (
|
|
81
83
|
<div className={cn('space-y-1', className)}>
|
|
82
84
|
{title && (
|
|
83
|
-
<
|
|
84
|
-
onPress={onToggle}
|
|
85
|
+
<div
|
|
85
86
|
className={cn(
|
|
86
|
-
'flex w-full items-center justify-between px-2 py-1.5 text-
|
|
87
|
-
'text-text-
|
|
88
|
-
'focus-visible:ring-2 focus-visible:ring-primary-500/30 rounded-md',
|
|
87
|
+
'flex w-full items-center justify-between px-2 py-1.5 text-sm font-semibold',
|
|
88
|
+
'text-text-main',
|
|
89
89
|
)}
|
|
90
90
|
>
|
|
91
91
|
<div className="flex items-center gap-2">
|
|
92
92
|
{Icon && <Icon size={14} />}
|
|
93
93
|
{title}
|
|
94
94
|
</div>
|
|
95
|
-
|
|
96
|
-
size={14}
|
|
97
|
-
className={cn(
|
|
98
|
-
'transition-transform duration-200',
|
|
99
|
-
isOpen && 'rotate-90',
|
|
100
|
-
)}
|
|
101
|
-
/>
|
|
102
|
-
</RAC.Button>
|
|
95
|
+
</div>
|
|
103
96
|
)}
|
|
104
|
-
{
|
|
97
|
+
{children && <div className="space-y-0.5">{children}</div>}
|
|
105
98
|
</div>
|
|
106
99
|
)
|
|
107
100
|
}
|
|
@@ -125,9 +118,10 @@ const SidebarLink = ({
|
|
|
125
118
|
'group flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm outline-none',
|
|
126
119
|
'transition-all duration-200 ease-in-out',
|
|
127
120
|
'focus-visible:ring-2 focus-visible:ring-primary-500/30',
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
121
|
+
{
|
|
122
|
+
'bg-primary-500/10 text-primary-500 font-medium': active,
|
|
123
|
+
'text-text-muted hover:bg-bg-muted hover:text-text-main': !active,
|
|
124
|
+
},
|
|
131
125
|
className,
|
|
132
126
|
)}
|
|
133
127
|
>
|
|
@@ -147,7 +141,71 @@ const SidebarLink = ({
|
|
|
147
141
|
)
|
|
148
142
|
}
|
|
149
143
|
|
|
144
|
+
const SidebarSubGroup = ({
|
|
145
|
+
label,
|
|
146
|
+
href,
|
|
147
|
+
active,
|
|
148
|
+
icon: Icon,
|
|
149
|
+
badge,
|
|
150
|
+
className,
|
|
151
|
+
isOpen = false,
|
|
152
|
+
onToggle,
|
|
153
|
+
children,
|
|
154
|
+
}: SidebarSubGroupProps) => {
|
|
155
|
+
return (
|
|
156
|
+
<div className="space-y-0.5">
|
|
157
|
+
<div className="flex items-center w-full">
|
|
158
|
+
<Link
|
|
159
|
+
href={href}
|
|
160
|
+
className={cn(
|
|
161
|
+
'group flex flex-1 items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm outline-none',
|
|
162
|
+
'transition-all duration-200 ease-in-out',
|
|
163
|
+
'focus-visible:ring-2 focus-visible:ring-primary-500/30',
|
|
164
|
+
active
|
|
165
|
+
? 'bg-primary-500/10 text-primary-500 font-medium'
|
|
166
|
+
: 'text-text-muted hover:bg-bg-surface hover:text-text-main hover:translate-x-1',
|
|
167
|
+
className,
|
|
168
|
+
)}
|
|
169
|
+
>
|
|
170
|
+
{Icon && (
|
|
171
|
+
<Icon
|
|
172
|
+
size={16}
|
|
173
|
+
className={cn(
|
|
174
|
+
active
|
|
175
|
+
? 'text-primary-500'
|
|
176
|
+
: 'text-text-muted group-hover:text-text-main',
|
|
177
|
+
)}
|
|
178
|
+
/>
|
|
179
|
+
)}
|
|
180
|
+
<span className="truncate">{label}</span>
|
|
181
|
+
{badge && <Badge badge={badge} />}
|
|
182
|
+
</Link>
|
|
183
|
+
{children && (
|
|
184
|
+
<RAC.Button
|
|
185
|
+
onPress={onToggle}
|
|
186
|
+
className="flex items-center justify-center p-1.5 ml-1 rounded-md text-text-muted hover:bg-bg-surface hover:text-text-main transition-colors outline-none focus-visible:ring-2 focus-visible:ring-primary-500/30 cursor-pointer"
|
|
187
|
+
>
|
|
188
|
+
<ChevronRight
|
|
189
|
+
size={16}
|
|
190
|
+
className={cn(
|
|
191
|
+
'transition-transform duration-200',
|
|
192
|
+
isOpen && 'rotate-90',
|
|
193
|
+
)}
|
|
194
|
+
/>
|
|
195
|
+
</RAC.Button>
|
|
196
|
+
)}
|
|
197
|
+
</div>
|
|
198
|
+
{isOpen && children && (
|
|
199
|
+
<div className="pl-4 ml-[7px] border-l border-border-subtle/50 space-y-0.5 mt-0.5">
|
|
200
|
+
{children}
|
|
201
|
+
</div>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
|
|
150
207
|
Sidebar.Root = Sidebar
|
|
151
208
|
Sidebar.Group = SidebarGroup
|
|
209
|
+
Sidebar.SubGroup = SidebarSubGroup
|
|
152
210
|
Sidebar.GroupItem = SidebarGroupItem
|
|
153
|
-
Sidebar.Link = SidebarLink
|
|
211
|
+
Sidebar.Link = SidebarLink
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cn } from '
|
|
1
|
+
import { cn } from '../../utils/cn'
|
|
2
2
|
import type { ComponentBase } from './types'
|
|
3
3
|
|
|
4
4
|
export interface TabsItemProps extends ComponentBase {
|
|
@@ -13,11 +13,7 @@ export interface TabsIndicatorProps extends ComponentBase {
|
|
|
13
13
|
style?: React.CSSProperties
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const Tabs = ({
|
|
17
|
-
children,
|
|
18
|
-
className = '',
|
|
19
|
-
...props
|
|
20
|
-
}: ComponentBase) => {
|
|
16
|
+
export const Tabs = ({ children, className = '', ...props }: ComponentBase) => {
|
|
21
17
|
return (
|
|
22
18
|
<div className={cn('w-full', className)} {...props}>
|
|
23
19
|
{children}
|
|
@@ -66,10 +62,7 @@ const TabsContent = ({ children, className = '' }: ComponentBase) => {
|
|
|
66
62
|
return <div className={cn('p-4 outline-none', className)}>{children}</div>
|
|
67
63
|
}
|
|
68
64
|
|
|
69
|
-
const TabsIndicator = ({
|
|
70
|
-
className = '',
|
|
71
|
-
style,
|
|
72
|
-
}: TabsIndicatorProps) => {
|
|
65
|
+
const TabsIndicator = ({ className = '', style }: TabsIndicatorProps) => {
|
|
73
66
|
return (
|
|
74
67
|
<div
|
|
75
68
|
className={cn(
|
|
@@ -85,4 +78,4 @@ Tabs.Root = Tabs
|
|
|
85
78
|
Tabs.List = TabsList
|
|
86
79
|
Tabs.Item = TabsItem
|
|
87
80
|
Tabs.Content = TabsContent
|
|
88
|
-
Tabs.Indicator = TabsIndicator
|
|
81
|
+
Tabs.Indicator = TabsIndicator
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react'
|
|
2
2
|
import * as RAC from 'react-aria-components'
|
|
3
|
-
import { cn } from '
|
|
3
|
+
import { cn } from '../../utils/cn'
|
|
4
4
|
|
|
5
5
|
export interface TooltipProps extends Omit<RAC.TooltipProps, 'children'> {
|
|
6
6
|
/** The content to show inside the tooltip */
|
|
@@ -14,7 +14,7 @@ export interface TooltipProps extends Omit<RAC.TooltipProps, 'children'> {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// Fixed type for TooltipContentProps to match RAC's internal expectations
|
|
17
|
-
export interface TooltipContentProps extends RAC.TooltipProps {
|
|
17
|
+
export interface TooltipContentProps extends RAC.TooltipProps {}
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Modern, accessible Tooltip component built with React Aria Components.
|
|
@@ -78,4 +78,4 @@ export const Tooltip = ({
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
Tooltip.Root = Tooltip
|
|
81
|
-
Tooltip.Content = TooltipContent
|
|
81
|
+
Tooltip.Content = TooltipContent
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { useBreadcrumbs } from '
|
|
1
|
+
import { useBreadcrumbs } from '../../hooks/use-breadcrumbs'
|
|
2
2
|
import { Home } from 'lucide-react'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
} from '
|
|
6
|
-
import { cn } from '@client/utils/cn'
|
|
7
|
-
import { useConfig } from '@client/app/config-context'
|
|
3
|
+
import { Breadcrumbs as BreadcrumbsRoot } from '../primitives/breadcrumbs'
|
|
4
|
+
import { cn } from '../../utils/cn'
|
|
5
|
+
import { useConfig } from '../../app/config-context'
|
|
8
6
|
|
|
9
7
|
export function Breadcrumbs() {
|
|
10
8
|
const { crumbs, activeRoute } = useBreadcrumbs()
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import { useState } from 'react'
|
|
2
2
|
import { Copy, Check, ExternalLink, ChevronDown } from 'lucide-react'
|
|
3
|
-
import {
|
|
4
|
-
Button,
|
|
5
|
-
ButtonGroup,
|
|
6
|
-
Menu,
|
|
7
|
-
cn,
|
|
8
|
-
} from '@client/components/primitives'
|
|
3
|
+
import { Button, ButtonGroup, Menu, cn } from '../../components/primitives'
|
|
9
4
|
|
|
10
|
-
import type { ComponentRoute } from '
|
|
5
|
+
import type { ComponentRoute } from '../../types'
|
|
11
6
|
|
|
12
7
|
export interface CopyMarkdownProps {
|
|
13
8
|
content?: string
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react'
|
|
2
|
-
import { getStarsRepo } from '
|
|
3
|
-
import { Github } from '
|
|
2
|
+
import { getStarsRepo } from '../../utils/github'
|
|
3
|
+
import { Github } from '../icons-dev'
|
|
4
4
|
|
|
5
5
|
export function GithubStars({ repo }: { repo: string }) {
|
|
6
6
|
const [stars, setStars] = useState<string | null>(null)
|
|
@@ -1,69 +1,76 @@
|
|
|
1
|
-
import { useEffect } from 'react'
|
|
2
1
|
import { useLocation } from 'react-router-dom'
|
|
2
|
+
import { Helmet } from 'react-helmet-async'
|
|
3
|
+
import { useConfig } from '../../app/config-context'
|
|
3
4
|
|
|
4
5
|
interface HeadProps {
|
|
5
6
|
siteTitle: string
|
|
6
7
|
siteDescription?: string
|
|
7
|
-
routes: Array<{ path: string; title: string; description?: string }>
|
|
8
|
+
routes: Array<{ path: string; title: string; description?: string; seo?: Record<string, any> }>
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export function Head({ siteTitle, siteDescription, routes }: HeadProps) {
|
|
11
12
|
const location = useLocation()
|
|
13
|
+
const config = useConfig()
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const pageDescription = currentRoute?.description || siteDescription || ''
|
|
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 || ''
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
document.title = pageTitle ? `${pageTitle} | ${siteTitle}` : siteTitle
|
|
20
|
+
const finalTitle = pageTitle ? `${pageTitle} | ${siteTitle}` : siteTitle
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
let metaDesc = document.querySelector(
|
|
24
|
-
'meta[name="description"]',
|
|
25
|
-
) as HTMLMetaElement | null
|
|
26
|
-
if (!metaDesc) {
|
|
27
|
-
metaDesc = document.createElement('meta')
|
|
28
|
-
metaDesc.name = 'description'
|
|
29
|
-
document.head.appendChild(metaDesc)
|
|
30
|
-
}
|
|
31
|
-
metaDesc.content = pageDescription
|
|
22
|
+
const seo = currentRoute?.seo || {}
|
|
32
23
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
setMetaTag('property', 'og:description', pageDescription)
|
|
36
|
-
setMetaTag('property', 'og:type', 'article')
|
|
37
|
-
setMetaTag('property', 'og:url', window.location.href)
|
|
24
|
+
// Merge custom global metatags
|
|
25
|
+
const globalMetatags = config?.seo?.metatags || {}
|
|
38
26
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
setMetaTag('name', 'twitter:description', pageDescription)
|
|
27
|
+
// Calculate specific ones
|
|
28
|
+
const defaultOgImage = config?.seo?.thumbnails?.background
|
|
29
|
+
const ogImage = seo['og:image'] || defaultOgImage
|
|
43
30
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
canonical = document.createElement('link')
|
|
50
|
-
canonical.rel = 'canonical'
|
|
51
|
-
document.head.appendChild(canonical)
|
|
52
|
-
}
|
|
53
|
-
canonical.href = window.location.origin + location.pathname
|
|
54
|
-
}, [location.pathname, siteTitle, siteDescription, routes])
|
|
31
|
+
return (
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
<Helmet>
|
|
34
|
+
<title>{finalTitle}</title>
|
|
35
|
+
<meta name="description" content={pageDescription} />
|
|
55
36
|
|
|
56
|
-
|
|
57
|
-
}
|
|
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} />
|
|
58
68
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
document.head.appendChild(tag)
|
|
67
|
-
}
|
|
68
|
-
tag.content = content
|
|
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
|
+
)
|
|
69
76
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { Suspense, lazy } from 'react'
|
|
2
|
-
import { useNavbar } from '
|
|
3
|
-
import { useVersion } from '
|
|
4
|
-
import { useI18n } from '
|
|
5
|
-
import { useRoutes } from '
|
|
6
|
-
import NavbarPrimitive from '
|
|
2
|
+
import { useNavbar } from '../../hooks/use-navbar'
|
|
3
|
+
import { useVersion } from '../../hooks/use-version'
|
|
4
|
+
import { useI18n } from '../../hooks/use-i18n'
|
|
5
|
+
import { useRoutes } from '../../hooks/use-routes'
|
|
6
|
+
import NavbarPrimitive from '../primitives/navbar'
|
|
7
7
|
import { ThemeToggle } from './theme-toggle'
|
|
8
8
|
import { GithubStars } from './github-stars'
|
|
9
9
|
import { Tabs } from './tabs'
|
|
10
10
|
import { useLocation } from 'react-router-dom'
|
|
11
|
-
import type { BoltdocsSocialLink } from '
|
|
12
|
-
import { Menu } from '
|
|
13
|
-
import { Button } from '
|
|
11
|
+
import type { BoltdocsSocialLink } from '../../../shared/types'
|
|
12
|
+
import { Menu } from '../primitives/menu'
|
|
13
|
+
import { Button } from '../primitives/button'
|
|
14
14
|
import { ChevronDown, Languages } from 'lucide-react'
|
|
15
|
-
import { useLocalizedTo } from '
|
|
16
|
-
import type { NavbarLink as NavbarLinkType } from '
|
|
15
|
+
import { useLocalizedTo } from '../../hooks/use-localized-to'
|
|
16
|
+
import type { NavbarLink as NavbarLinkType } from '../../types'
|
|
17
17
|
|
|
18
18
|
const SearchDialog = lazy(() =>
|
|
19
19
|
import('./search-dialog').then((m) => ({
|
|
@@ -57,9 +57,7 @@ export function Navbar() {
|
|
|
57
57
|
<NavbarPrimitive.Right>
|
|
58
58
|
<NavbarPrimitive.Links>
|
|
59
59
|
{links.map((link) => (
|
|
60
|
-
|
|
61
|
-
<NavbarLinkItem key={link.href} link={link} />
|
|
62
|
-
</>
|
|
60
|
+
<NavbarLinkItem key={link.href} link={link} />
|
|
63
61
|
))}
|
|
64
62
|
</NavbarPrimitive.Links>
|
|
65
63
|
{config.i18n && currentLocale && <NavbarI18n />}
|
|
@@ -147,7 +145,7 @@ function NavbarI18n() {
|
|
|
147
145
|
>
|
|
148
146
|
<div className="flex items-center gap-1.5">
|
|
149
147
|
<Languages className="w-3.5 h-3.5 text-primary-500" />
|
|
150
|
-
<span className="font-bold text-[0.75rem]
|
|
148
|
+
<span className="font-bold text-[0.75rem] uppercase opacity-90">
|
|
151
149
|
{currentLocale || 'en'}
|
|
152
150
|
</span>
|
|
153
151
|
</div>
|