boltdocs 1.10.2 → 2.0.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 +7 -0
- package/LICENSE +21 -0
- package/dist/cache-7G6D532T.mjs +1 -0
- package/dist/chunk-A4HQPEPU.mjs +1 -0
- package/dist/chunk-BA5NH5HU.mjs +1 -0
- package/dist/chunk-BQCD3DWG.mjs +1 -0
- package/dist/chunk-H63UMKYF.mjs +1 -0
- package/dist/chunk-IWHRQHS7.mjs +1 -0
- package/dist/chunk-JZXLCA2E.mjs +1 -0
- package/dist/chunk-MFU7Q6WF.mjs +1 -0
- package/dist/chunk-QYPNX5UN.mjs +1 -0
- package/dist/chunk-XEAPSFMB.mjs +1 -0
- package/dist/client/components/mdx/index.d.mts +209 -0
- package/dist/client/components/mdx/index.d.ts +209 -0
- package/dist/client/components/mdx/index.js +1 -0
- package/dist/client/components/mdx/index.mjs +1 -0
- package/dist/client/hooks/index.d.mts +133 -0
- package/dist/client/hooks/index.d.ts +133 -0
- package/dist/client/hooks/index.js +1 -0
- package/dist/client/hooks/index.mjs +1 -0
- package/dist/client/index.d.mts +138 -298
- package/dist/client/index.d.ts +138 -298
- package/dist/client/index.js +1 -3630
- package/dist/client/index.mjs +1 -697
- package/dist/client/ssr.d.mts +7 -3
- package/dist/client/ssr.d.ts +7 -3
- package/dist/client/ssr.js +1 -2928
- package/dist/client/ssr.mjs +1 -33
- package/dist/{config-BsFQ-ErD.d.ts → config-CX4l-ZNp.d.mts} +42 -35
- package/dist/{config-BsFQ-ErD.d.mts → config-CX4l-ZNp.d.ts} +42 -35
- package/dist/node/index.d.mts +2 -4
- package/dist/node/index.d.ts +2 -4
- package/dist/node/index.js +31 -1161
- package/dist/node/index.mjs +31 -736
- package/dist/search-dialog-EB3N4TYM.mjs +1 -0
- package/dist/types-BuZWFT7r.d.ts +159 -0
- package/dist/types-CvT-SGbK.d.mts +159 -0
- package/dist/use-routes-5bAtAAYX.d.mts +30 -0
- package/dist/use-routes-BefRXY3v.d.ts +30 -0
- package/package.json +34 -12
- package/src/client/app/config-context.tsx +18 -0
- package/src/client/app/docs-layout.tsx +14 -0
- package/src/client/app/index.tsx +137 -262
- package/src/client/app/mdx-component.tsx +52 -0
- package/src/client/app/mdx-components-context.tsx +23 -0
- package/src/client/app/mdx-page.tsx +20 -0
- package/src/client/app/preload.tsx +38 -30
- package/src/client/app/router.tsx +30 -0
- package/src/client/app/scroll-handler.tsx +40 -0
- package/src/client/app/theme-context.tsx +75 -0
- package/src/client/components/default-layout.tsx +80 -0
- package/src/client/components/docs-layout.tsx +105 -0
- package/src/client/components/icons-dev.tsx +74 -0
- package/src/client/components/mdx/admonition.tsx +107 -0
- package/src/client/components/mdx/badge.tsx +41 -0
- package/src/client/components/mdx/button.tsx +35 -0
- package/src/client/components/mdx/card.tsx +124 -0
- package/src/client/components/mdx/code-block.tsx +119 -0
- package/src/client/components/mdx/component-preview.tsx +47 -0
- package/src/client/components/mdx/component-props.tsx +83 -0
- package/src/client/components/mdx/field.tsx +66 -0
- package/src/client/components/mdx/file-tree.tsx +287 -0
- package/src/client/components/mdx/hooks/use-code-block.ts +56 -0
- package/src/client/components/mdx/hooks/use-component-preview.ts +16 -0
- package/src/client/components/mdx/hooks/useTable.ts +74 -0
- package/src/client/components/mdx/hooks/useTabs.ts +68 -0
- package/src/client/components/mdx/image.tsx +23 -0
- package/src/client/components/mdx/index.ts +53 -0
- package/src/client/components/mdx/link.tsx +38 -0
- package/src/client/components/mdx/list.tsx +192 -0
- package/src/client/components/mdx/table.tsx +156 -0
- package/src/client/components/mdx/tabs.tsx +135 -0
- package/src/client/components/mdx/video.tsx +68 -0
- package/src/client/components/primitives/breadcrumbs.tsx +79 -0
- package/src/client/components/primitives/button-group.tsx +54 -0
- package/src/client/components/primitives/button.tsx +145 -0
- package/src/client/components/primitives/helpers/observer.ts +120 -0
- package/src/client/components/primitives/index.ts +17 -0
- package/src/client/components/primitives/link.tsx +122 -0
- package/src/client/components/primitives/menu.tsx +159 -0
- package/src/client/components/primitives/navbar.tsx +359 -0
- package/src/client/components/primitives/navigation-menu.tsx +116 -0
- package/src/client/components/primitives/on-this-page.tsx +461 -0
- package/src/client/components/primitives/page-nav.tsx +87 -0
- package/src/client/components/primitives/popover.tsx +47 -0
- package/src/client/components/primitives/search-dialog.tsx +183 -0
- package/src/client/components/primitives/sidebar.tsx +154 -0
- package/src/client/components/primitives/tabs.tsx +90 -0
- package/src/client/components/primitives/tooltip.tsx +83 -0
- package/src/client/components/primitives/types.ts +11 -0
- package/src/client/components/ui-base/breadcrumbs.tsx +42 -0
- package/src/client/components/ui-base/copy-markdown.tsx +112 -0
- package/src/client/components/ui-base/error-boundary.tsx +52 -0
- package/src/client/components/ui-base/github-stars.tsx +27 -0
- package/src/client/components/ui-base/head.tsx +69 -0
- package/src/client/components/ui-base/loading.tsx +87 -0
- package/src/client/components/ui-base/navbar.tsx +138 -0
- package/src/client/components/ui-base/not-found.tsx +24 -0
- package/src/client/components/ui-base/on-this-page.tsx +152 -0
- package/src/client/components/ui-base/page-nav.tsx +39 -0
- package/src/client/components/ui-base/powered-by.tsx +19 -0
- package/src/client/components/ui-base/progress-bar.tsx +67 -0
- package/src/client/components/ui-base/search-dialog.tsx +82 -0
- package/src/client/components/ui-base/sidebar.tsx +104 -0
- package/src/client/components/ui-base/tabs.tsx +65 -0
- package/src/client/components/ui-base/theme-toggle.tsx +32 -0
- package/src/client/hooks/index.ts +12 -0
- package/src/client/hooks/use-breadcrumbs.ts +22 -0
- package/src/client/hooks/use-i18n.ts +84 -0
- package/src/client/hooks/use-localized-to.ts +95 -0
- package/src/client/hooks/use-location.ts +5 -0
- package/src/client/hooks/use-navbar.ts +60 -0
- package/src/client/hooks/use-onthispage.ts +23 -0
- package/src/client/hooks/use-page-nav.ts +22 -0
- package/src/client/hooks/use-routes.ts +72 -0
- package/src/client/hooks/use-search.ts +71 -0
- package/src/client/hooks/use-sidebar.ts +49 -0
- package/src/client/hooks/use-tabs.ts +43 -0
- package/src/client/hooks/use-version.ts +78 -0
- package/src/client/index.ts +55 -17
- package/src/client/integrations/codesandbox.ts +179 -0
- package/src/client/ssr.tsx +27 -16
- package/src/client/theme/neutral.css +360 -0
- package/src/client/types.ts +131 -27
- package/src/client/utils/cn.ts +6 -0
- package/src/client/utils/copy-clipboard.ts +22 -0
- package/src/client/utils/get-base-file-path.ts +21 -0
- package/src/client/utils/github.ts +121 -0
- package/src/client/utils/use-on-change.ts +15 -0
- package/src/client/virtual.d.ts +24 -0
- package/src/node/cache.ts +156 -156
- package/src/node/config.ts +159 -103
- package/src/node/index.ts +13 -13
- package/src/node/mdx.ts +213 -61
- package/src/node/plugin/entry.ts +29 -18
- package/src/node/plugin/html.ts +11 -11
- package/src/node/plugin/index.ts +161 -84
- package/src/node/plugin/types.ts +2 -4
- package/src/node/routes/cache.ts +6 -6
- package/src/node/routes/index.ts +206 -113
- package/src/node/routes/parser.ts +102 -82
- package/src/node/routes/sorter.ts +15 -15
- package/src/node/routes/types.ts +24 -24
- package/src/node/ssg/index.ts +73 -47
- package/src/node/ssg/meta.ts +4 -4
- package/src/node/ssg/options.ts +5 -5
- package/src/node/ssg/sitemap.ts +14 -14
- package/src/node/utils.ts +54 -31
- package/tsconfig.json +25 -20
- package/tsup.config.ts +23 -14
- package/dist/PackageManagerTabs-NVT7G625.mjs +0 -99
- package/dist/SearchDialog-AGVF6JBO.mjs +0 -194
- package/dist/SearchDialog-YPDOM7Q6.css +0 -2847
- package/dist/Video-KNTY5BNO.mjs +0 -6
- package/dist/cache-KNL5B4EE.mjs +0 -12
- package/dist/chunk-7SFUJWTB.mjs +0 -211
- package/dist/chunk-FFBNU6IJ.mjs +0 -386
- package/dist/chunk-FMTOYQLO.mjs +0 -37
- package/dist/chunk-TKLQWU7H.mjs +0 -1920
- package/dist/chunk-Z7JHYNAS.mjs +0 -57
- package/dist/client/index.css +0 -2847
- package/dist/client/ssr.css +0 -2847
- package/dist/types-Dj-bfnC3.d.mts +0 -74
- package/dist/types-Dj-bfnC3.d.ts +0 -74
- package/src/client/theme/components/CodeBlock/CodeBlock.tsx +0 -61
- package/src/client/theme/components/CodeBlock/index.ts +0 -1
- package/src/client/theme/components/PackageManagerTabs/PackageManagerTabs.tsx +0 -131
- package/src/client/theme/components/PackageManagerTabs/index.ts +0 -1
- package/src/client/theme/components/PackageManagerTabs/pkg-tabs.css +0 -64
- package/src/client/theme/components/Playground/Playground.tsx +0 -180
- package/src/client/theme/components/Playground/index.ts +0 -1
- package/src/client/theme/components/Playground/playground.css +0 -238
- package/src/client/theme/components/Video/Video.tsx +0 -84
- package/src/client/theme/components/Video/index.ts +0 -1
- package/src/client/theme/components/Video/video.css +0 -41
- package/src/client/theme/components/mdx/Admonition.tsx +0 -80
- package/src/client/theme/components/mdx/Badge.tsx +0 -31
- package/src/client/theme/components/mdx/Button.tsx +0 -50
- package/src/client/theme/components/mdx/Card.tsx +0 -80
- package/src/client/theme/components/mdx/Field.tsx +0 -60
- package/src/client/theme/components/mdx/FileTree.tsx +0 -229
- package/src/client/theme/components/mdx/List.tsx +0 -57
- package/src/client/theme/components/mdx/Table.tsx +0 -151
- package/src/client/theme/components/mdx/Tabs.tsx +0 -123
- package/src/client/theme/components/mdx/index.ts +0 -27
- package/src/client/theme/components/mdx/mdx-components.css +0 -764
- package/src/client/theme/icons/bun.tsx +0 -62
- package/src/client/theme/icons/deno.tsx +0 -20
- package/src/client/theme/icons/discord.tsx +0 -12
- package/src/client/theme/icons/github.tsx +0 -15
- package/src/client/theme/icons/npm.tsx +0 -13
- package/src/client/theme/icons/pnpm.tsx +0 -72
- package/src/client/theme/icons/twitter.tsx +0 -12
- package/src/client/theme/styles/markdown.css +0 -394
- package/src/client/theme/styles/variables.css +0 -175
- package/src/client/theme/styles.css +0 -39
- package/src/client/theme/ui/Breadcrumbs/Breadcrumbs.tsx +0 -68
- package/src/client/theme/ui/Breadcrumbs/index.ts +0 -1
- package/src/client/theme/ui/CopyMarkdown/CopyMarkdown.tsx +0 -82
- package/src/client/theme/ui/CopyMarkdown/copy-markdown.css +0 -112
- package/src/client/theme/ui/CopyMarkdown/index.ts +0 -1
- package/src/client/theme/ui/ErrorBoundary/ErrorBoundary.tsx +0 -50
- package/src/client/theme/ui/ErrorBoundary/error-boundary.css +0 -55
- package/src/client/theme/ui/ErrorBoundary/index.ts +0 -1
- package/src/client/theme/ui/Footer/footer.css +0 -32
- package/src/client/theme/ui/Head/Head.tsx +0 -69
- package/src/client/theme/ui/Head/index.ts +0 -1
- package/src/client/theme/ui/LanguageSwitcher/LanguageSwitcher.tsx +0 -125
- package/src/client/theme/ui/LanguageSwitcher/index.ts +0 -1
- package/src/client/theme/ui/LanguageSwitcher/language-switcher.css +0 -98
- package/src/client/theme/ui/Layout/Layout.tsx +0 -203
- package/src/client/theme/ui/Layout/base.css +0 -106
- package/src/client/theme/ui/Layout/index.ts +0 -2
- package/src/client/theme/ui/Layout/pagination.css +0 -72
- package/src/client/theme/ui/Layout/responsive.css +0 -47
- package/src/client/theme/ui/Link/Link.tsx +0 -392
- package/src/client/theme/ui/Link/LinkPreview.tsx +0 -59
- package/src/client/theme/ui/Link/index.ts +0 -2
- package/src/client/theme/ui/Link/link-preview.css +0 -48
- package/src/client/theme/ui/Loading/Loading.tsx +0 -10
- package/src/client/theme/ui/Loading/index.ts +0 -1
- package/src/client/theme/ui/Loading/loading.css +0 -30
- package/src/client/theme/ui/Navbar/GithubStars.tsx +0 -27
- package/src/client/theme/ui/Navbar/Navbar.tsx +0 -193
- package/src/client/theme/ui/Navbar/Tabs.tsx +0 -99
- package/src/client/theme/ui/Navbar/index.ts +0 -2
- package/src/client/theme/ui/Navbar/navbar.css +0 -347
- package/src/client/theme/ui/NotFound/NotFound.tsx +0 -19
- package/src/client/theme/ui/NotFound/index.ts +0 -1
- package/src/client/theme/ui/NotFound/not-found.css +0 -64
- package/src/client/theme/ui/OnThisPage/OnThisPage.tsx +0 -244
- package/src/client/theme/ui/OnThisPage/index.ts +0 -1
- package/src/client/theme/ui/OnThisPage/toc.css +0 -152
- package/src/client/theme/ui/PoweredBy/PoweredBy.tsx +0 -18
- package/src/client/theme/ui/PoweredBy/index.ts +0 -1
- package/src/client/theme/ui/PoweredBy/powered-by.css +0 -76
- package/src/client/theme/ui/ProgressBar/ProgressBar.css +0 -17
- package/src/client/theme/ui/ProgressBar/ProgressBar.tsx +0 -51
- package/src/client/theme/ui/ProgressBar/index.ts +0 -1
- package/src/client/theme/ui/SearchDialog/SearchDialog.tsx +0 -209
- package/src/client/theme/ui/SearchDialog/index.ts +0 -1
- package/src/client/theme/ui/SearchDialog/search.css +0 -152
- package/src/client/theme/ui/Sidebar/Sidebar.tsx +0 -244
- package/src/client/theme/ui/Sidebar/index.ts +0 -1
- package/src/client/theme/ui/Sidebar/sidebar.css +0 -230
- package/src/client/theme/ui/ThemeToggle/ThemeToggle.tsx +0 -69
- package/src/client/theme/ui/ThemeToggle/index.ts +0 -1
- package/src/client/theme/ui/VersionSwitcher/VersionSwitcher.tsx +0 -136
- package/src/client/theme/ui/VersionSwitcher/index.ts +0 -1
- package/src/client/utils.ts +0 -49
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useState, useMemo } from 'react'
|
|
2
|
+
|
|
3
|
+
interface SortConfig {
|
|
4
|
+
key: number
|
|
5
|
+
direction: 'asc' | 'desc'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface UseTableProps {
|
|
9
|
+
data?: (string | React.ReactNode)[][]
|
|
10
|
+
sortable?: boolean
|
|
11
|
+
paginated?: boolean
|
|
12
|
+
pageSize?: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function useTable({
|
|
16
|
+
data,
|
|
17
|
+
sortable = false,
|
|
18
|
+
paginated = false,
|
|
19
|
+
pageSize = 10,
|
|
20
|
+
}: UseTableProps) {
|
|
21
|
+
const [sortConfig, setSortConfig] = useState<SortConfig | null>(null)
|
|
22
|
+
const [currentPage, setCurrentPage] = useState(1)
|
|
23
|
+
|
|
24
|
+
const processedData = useMemo(() => {
|
|
25
|
+
if (!data) return []
|
|
26
|
+
const items = [...data]
|
|
27
|
+
|
|
28
|
+
if (sortable && sortConfig !== null) {
|
|
29
|
+
items.sort((a, b) => {
|
|
30
|
+
const aVal = a[sortConfig.key]
|
|
31
|
+
const bVal = b[sortConfig.key]
|
|
32
|
+
|
|
33
|
+
const aStr = typeof aVal === 'string' ? aVal : ''
|
|
34
|
+
const bStr = typeof bVal === 'string' ? bVal : ''
|
|
35
|
+
|
|
36
|
+
if (aStr < bStr) return sortConfig.direction === 'asc' ? -1 : 1
|
|
37
|
+
if (aStr > bStr) return sortConfig.direction === 'asc' ? 1 : -1
|
|
38
|
+
return 0
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return items
|
|
43
|
+
}, [data, sortConfig, sortable])
|
|
44
|
+
|
|
45
|
+
const totalPages = Math.ceil(processedData.length / pageSize)
|
|
46
|
+
|
|
47
|
+
const paginatedData = useMemo(() => {
|
|
48
|
+
if (!paginated) return processedData
|
|
49
|
+
const start = (currentPage - 1) * pageSize
|
|
50
|
+
return processedData.slice(start, start + pageSize)
|
|
51
|
+
}, [processedData, paginated, currentPage, pageSize])
|
|
52
|
+
|
|
53
|
+
const requestSort = (index: number) => {
|
|
54
|
+
if (!sortable) return
|
|
55
|
+
let direction: 'asc' | 'desc' = 'asc'
|
|
56
|
+
if (
|
|
57
|
+
sortConfig &&
|
|
58
|
+
sortConfig.key === index &&
|
|
59
|
+
sortConfig.direction === 'asc'
|
|
60
|
+
) {
|
|
61
|
+
direction = 'desc'
|
|
62
|
+
}
|
|
63
|
+
setSortConfig({ key: index, direction })
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
sortConfig,
|
|
68
|
+
currentPage,
|
|
69
|
+
setCurrentPage,
|
|
70
|
+
totalPages,
|
|
71
|
+
paginatedData,
|
|
72
|
+
requestSort,
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useState,
|
|
3
|
+
useRef,
|
|
4
|
+
useEffect,
|
|
5
|
+
useCallback,
|
|
6
|
+
type ReactElement,
|
|
7
|
+
type KeyboardEvent,
|
|
8
|
+
} from 'react'
|
|
9
|
+
|
|
10
|
+
interface UseTabsProps {
|
|
11
|
+
initialIndex?: number
|
|
12
|
+
tabs: ReactElement<any>[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function useTabs({ initialIndex = 0, tabs }: UseTabsProps) {
|
|
16
|
+
const defaultActive = tabs[initialIndex]?.props.disabled
|
|
17
|
+
? tabs.findIndex((t) => !t.props.disabled)
|
|
18
|
+
: initialIndex
|
|
19
|
+
|
|
20
|
+
const [active, setActive] = useState(defaultActive === -1 ? 0 : defaultActive)
|
|
21
|
+
const tabRefs = useRef<(HTMLButtonElement | null)[]>([])
|
|
22
|
+
const [indicatorStyle, setIndicatorStyle] = useState<React.CSSProperties>({
|
|
23
|
+
opacity: 0,
|
|
24
|
+
transform: 'translateX(0)',
|
|
25
|
+
width: 0,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: updates when content changes
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const activeTab = tabRefs.current[active]
|
|
31
|
+
if (activeTab) {
|
|
32
|
+
setIndicatorStyle({
|
|
33
|
+
opacity: 1,
|
|
34
|
+
width: activeTab.offsetWidth,
|
|
35
|
+
transform: `translateX(${activeTab.offsetLeft}px)`,
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
}, [active, tabs])
|
|
39
|
+
|
|
40
|
+
const handleKeyDown = useCallback(
|
|
41
|
+
(e: KeyboardEvent<HTMLDivElement>) => {
|
|
42
|
+
let direction = 0
|
|
43
|
+
if (e.key === 'ArrowRight') direction = 1
|
|
44
|
+
else if (e.key === 'ArrowLeft') direction = -1
|
|
45
|
+
|
|
46
|
+
if (direction !== 0) {
|
|
47
|
+
let nextIndex = (active + direction + tabs.length) % tabs.length
|
|
48
|
+
while (tabs[nextIndex].props.disabled && nextIndex !== active) {
|
|
49
|
+
nextIndex = (nextIndex + direction + tabs.length) % tabs.length
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (nextIndex !== active && !tabs[nextIndex].props.disabled) {
|
|
53
|
+
setActive(nextIndex)
|
|
54
|
+
tabRefs.current[nextIndex]?.focus()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
[active, tabs],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
active,
|
|
63
|
+
setActive,
|
|
64
|
+
tabRefs,
|
|
65
|
+
indicatorStyle,
|
|
66
|
+
handleKeyDown,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ImgHTMLAttributes } from 'react'
|
|
2
|
+
import { useTheme } from '@client/app/theme-context'
|
|
3
|
+
|
|
4
|
+
export interface ImageProps extends ImgHTMLAttributes<HTMLImageElement> {
|
|
5
|
+
src: string
|
|
6
|
+
darkSrc?: string
|
|
7
|
+
theme?: 'light' | 'dark'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A themed Image component for Boltdocs.
|
|
12
|
+
* It supports rendering based on the current active theme.
|
|
13
|
+
*/
|
|
14
|
+
export function Image({ src, alt, theme: imageTheme, ...props }: ImageProps) {
|
|
15
|
+
const { theme: currentTheme } = useTheme()
|
|
16
|
+
|
|
17
|
+
// If a specific theme is required for this image, only render if it matches
|
|
18
|
+
if (imageTheme && imageTheme !== currentTheme) {
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return <img src={src} alt={alt || ''} {...props} />
|
|
23
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export { Button } from './button'
|
|
2
|
+
export type { ButtonProps } from './button'
|
|
3
|
+
|
|
4
|
+
export { CodeBlock } from './code-block'
|
|
5
|
+
|
|
6
|
+
export { Tabs, Tab } from './tabs'
|
|
7
|
+
export type { TabsProps, TabProps } from './tabs'
|
|
8
|
+
|
|
9
|
+
export { Video } from './video'
|
|
10
|
+
|
|
11
|
+
export { Badge } from './badge'
|
|
12
|
+
export type { BadgeProps } from './badge'
|
|
13
|
+
|
|
14
|
+
export { Card, Cards } from './card'
|
|
15
|
+
export type { CardProps, CardsProps } from './card'
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
Admonition,
|
|
19
|
+
Note,
|
|
20
|
+
Tip,
|
|
21
|
+
Warning,
|
|
22
|
+
Danger,
|
|
23
|
+
InfoBox,
|
|
24
|
+
Important,
|
|
25
|
+
Caution,
|
|
26
|
+
} from './admonition'
|
|
27
|
+
export type { AdmonitionProps } from './admonition'
|
|
28
|
+
|
|
29
|
+
export { List } from './list'
|
|
30
|
+
export type { ListProps } from './list'
|
|
31
|
+
|
|
32
|
+
export { FileTree } from './file-tree'
|
|
33
|
+
export type { FileTreeProps } from './file-tree'
|
|
34
|
+
|
|
35
|
+
export { Table } from './table'
|
|
36
|
+
export type { TableProps } from './table'
|
|
37
|
+
|
|
38
|
+
export { Field } from './field'
|
|
39
|
+
export type { FieldProps } from './field'
|
|
40
|
+
|
|
41
|
+
export { Link } from './link'
|
|
42
|
+
export type { LinkProps } from './link'
|
|
43
|
+
|
|
44
|
+
export { Image } from './image'
|
|
45
|
+
export type { ImageProps } from './image'
|
|
46
|
+
|
|
47
|
+
export { ComponentProps } from './component-props'
|
|
48
|
+
export type { ComponentPropsProps } from './component-props'
|
|
49
|
+
|
|
50
|
+
export { ComponentPreview } from './component-preview'
|
|
51
|
+
export type { ComponentPreviewProps } from './component-preview'
|
|
52
|
+
export { CopyMarkdown } from '../ui-base/copy-markdown'
|
|
53
|
+
export type { CopyMarkdownProps } from '../ui-base/copy-markdown'
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Link as LinkPrimitive,
|
|
3
|
+
type LinkProps as LinkPrimitiveProps,
|
|
4
|
+
} from '@components/primitives/link'
|
|
5
|
+
import { cn } from '@client/utils/cn'
|
|
6
|
+
|
|
7
|
+
export type LinkProps = LinkPrimitiveProps & {
|
|
8
|
+
to: string
|
|
9
|
+
children?: React.ReactNode
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A premium Link component for Boltdocs that handles internal and external routing.
|
|
14
|
+
*/
|
|
15
|
+
export function Link({ to, children, className = '', ...props }: LinkProps) {
|
|
16
|
+
const isExternal =
|
|
17
|
+
to &&
|
|
18
|
+
(to.startsWith('http://') ||
|
|
19
|
+
to.startsWith('https://') ||
|
|
20
|
+
to.startsWith('//'))
|
|
21
|
+
|
|
22
|
+
const combinedClassName = cn(
|
|
23
|
+
'text-blue-600 hover:text-blue-800 hover:underline cursor-pointer',
|
|
24
|
+
className,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<LinkPrimitive
|
|
29
|
+
href={to}
|
|
30
|
+
className={combinedClassName}
|
|
31
|
+
target={isExternal ? '_blank' : undefined}
|
|
32
|
+
rel={isExternal ? 'noopener noreferrer' : undefined}
|
|
33
|
+
{...props}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</LinkPrimitive>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
isValidElement,
|
|
4
|
+
type ReactNode,
|
|
5
|
+
type ReactElement,
|
|
6
|
+
type ComponentPropsWithoutRef,
|
|
7
|
+
} from 'react'
|
|
8
|
+
import { Check, ChevronRight, Circle } from 'lucide-react'
|
|
9
|
+
import { cn } from '@client/utils/cn'
|
|
10
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
11
|
+
|
|
12
|
+
const listVariants = cva('my-6 transition-all duration-200', {
|
|
13
|
+
variants: {
|
|
14
|
+
variant: {
|
|
15
|
+
default: 'list-disc pl-5 text-text-muted marker:text-primary-500/50',
|
|
16
|
+
number:
|
|
17
|
+
'list-decimal pl-5 text-text-muted marker:text-primary-500/50 marker:font-bold',
|
|
18
|
+
checked: 'list-none p-0',
|
|
19
|
+
arrow: 'list-none p-0',
|
|
20
|
+
bubble: 'list-none p-0',
|
|
21
|
+
},
|
|
22
|
+
cols: {
|
|
23
|
+
1: 'grid-cols-1',
|
|
24
|
+
2: 'grid-cols-1 sm:grid-cols-2',
|
|
25
|
+
3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
|
|
26
|
+
4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4',
|
|
27
|
+
},
|
|
28
|
+
isGrid: {
|
|
29
|
+
true: 'grid gap-x-8 gap-y-3',
|
|
30
|
+
false: 'space-y-2',
|
|
31
|
+
},
|
|
32
|
+
dense: {
|
|
33
|
+
true: 'space-y-1',
|
|
34
|
+
false: 'space-y-2',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
compoundVariants: [
|
|
38
|
+
{
|
|
39
|
+
variant: 'default',
|
|
40
|
+
dense: true,
|
|
41
|
+
className: 'space-y-0.5',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
defaultVariants: {
|
|
45
|
+
variant: 'default',
|
|
46
|
+
cols: 1,
|
|
47
|
+
isGrid: false,
|
|
48
|
+
dense: false,
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const itemVariants = cva(
|
|
53
|
+
'group flex items-start gap-3 text-sm leading-relaxed transition-all duration-200',
|
|
54
|
+
{
|
|
55
|
+
variants: {
|
|
56
|
+
variant: {
|
|
57
|
+
default: '',
|
|
58
|
+
number: '',
|
|
59
|
+
checked: 'hover:translate-x-0.5',
|
|
60
|
+
arrow: 'hover:translate-x-0.5',
|
|
61
|
+
bubble: 'hover:translate-x-0.5',
|
|
62
|
+
},
|
|
63
|
+
dense: {
|
|
64
|
+
true: 'py-0',
|
|
65
|
+
false: 'py-0.5',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
defaultVariants: {
|
|
69
|
+
variant: 'default',
|
|
70
|
+
dense: false,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
const iconContainerVariants = cva(
|
|
76
|
+
'mt-1 shrink-0 flex items-center justify-center transition-transform group-hover:scale-110',
|
|
77
|
+
{
|
|
78
|
+
variants: {
|
|
79
|
+
variant: {
|
|
80
|
+
bubble:
|
|
81
|
+
'h-5 w-5 rounded-full bg-primary-500/10 text-primary-500 text-[10px] font-bold',
|
|
82
|
+
default: '',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
defaultVariants: {
|
|
86
|
+
variant: 'default',
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
type ListVariantProps = VariantProps<typeof listVariants>
|
|
92
|
+
|
|
93
|
+
export interface ListProps
|
|
94
|
+
extends ComponentPropsWithoutRef<'ul'>,
|
|
95
|
+
Omit<ListVariantProps, 'variant'> {
|
|
96
|
+
variant?: 'checked' | 'arrow' | 'default' | 'bubble' | 'number'
|
|
97
|
+
children: ReactNode
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface ListItemProps extends VariantProps<typeof itemVariants> {
|
|
101
|
+
icon?: ReactNode
|
|
102
|
+
children: ReactNode
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function ListItem({ icon, children, variant, dense }: ListItemProps) {
|
|
106
|
+
return (
|
|
107
|
+
<li className={cn(itemVariants({ variant, dense }))}>
|
|
108
|
+
{icon && (
|
|
109
|
+
<span
|
|
110
|
+
className={cn(
|
|
111
|
+
iconContainerVariants({
|
|
112
|
+
variant: variant === 'bubble' ? 'bubble' : 'default',
|
|
113
|
+
}),
|
|
114
|
+
)}
|
|
115
|
+
>
|
|
116
|
+
{icon}
|
|
117
|
+
</span>
|
|
118
|
+
)}
|
|
119
|
+
<div className="flex-1 text-text-muted group-hover:text-text-main transition-colors">
|
|
120
|
+
{children}
|
|
121
|
+
</div>
|
|
122
|
+
</li>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const ICON_MAP: Record<string, (cls?: string) => ReactNode> = {
|
|
127
|
+
checked: (cls) => (
|
|
128
|
+
<Check size={14} className={cn('text-emerald-500 shrink-0', cls)} />
|
|
129
|
+
),
|
|
130
|
+
arrow: (cls) => (
|
|
131
|
+
<ChevronRight size={14} className={cn('text-primary-400 shrink-0', cls)} />
|
|
132
|
+
),
|
|
133
|
+
bubble: (cls) => (
|
|
134
|
+
<Circle
|
|
135
|
+
size={6}
|
|
136
|
+
fill="currentColor"
|
|
137
|
+
className={cn('text-primary-500 shrink-0', cls)}
|
|
138
|
+
/>
|
|
139
|
+
),
|
|
140
|
+
default: () => null,
|
|
141
|
+
number: () => null,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function List({
|
|
145
|
+
variant = 'default',
|
|
146
|
+
cols = 1,
|
|
147
|
+
dense = false,
|
|
148
|
+
children,
|
|
149
|
+
className,
|
|
150
|
+
...props
|
|
151
|
+
}: ListProps) {
|
|
152
|
+
const isGrid = cols !== undefined && Number(cols) > 1
|
|
153
|
+
const renderIcon = ICON_MAP[variant]
|
|
154
|
+
const containerClasses = listVariants({
|
|
155
|
+
variant,
|
|
156
|
+
cols,
|
|
157
|
+
dense,
|
|
158
|
+
isGrid,
|
|
159
|
+
className,
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
const Component = variant === 'number' ? 'ol' : 'ul'
|
|
163
|
+
|
|
164
|
+
// Handling raw MDX siblings (nested logic)
|
|
165
|
+
if (variant === 'default' || variant === 'number') {
|
|
166
|
+
return (
|
|
167
|
+
<Component className={containerClasses} {...props}>
|
|
168
|
+
{children}
|
|
169
|
+
</Component>
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<ul className={containerClasses} {...props}>
|
|
175
|
+
{Children.map(children, (child) => {
|
|
176
|
+
if (!isValidElement(child)) return child
|
|
177
|
+
|
|
178
|
+
const element = child as ReactElement<{ children?: ReactNode }>
|
|
179
|
+
const content =
|
|
180
|
+
element.type === 'li'
|
|
181
|
+
? element.props.children
|
|
182
|
+
: element.props.children || child
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<ListItem icon={renderIcon()} variant={variant} dense={dense}>
|
|
186
|
+
{content}
|
|
187
|
+
</ListItem>
|
|
188
|
+
)
|
|
189
|
+
})}
|
|
190
|
+
</ul>
|
|
191
|
+
)
|
|
192
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import * as RAC from 'react-aria-components'
|
|
2
|
+
import { useTable } from './hooks/useTable'
|
|
3
|
+
import {
|
|
4
|
+
ChevronUp,
|
|
5
|
+
ChevronDown,
|
|
6
|
+
ChevronLeft,
|
|
7
|
+
ChevronRight,
|
|
8
|
+
ChevronsLeft,
|
|
9
|
+
ChevronsRight,
|
|
10
|
+
} from 'lucide-react'
|
|
11
|
+
import { cn } from '@client/utils/cn'
|
|
12
|
+
|
|
13
|
+
export interface TableProps {
|
|
14
|
+
headers?: string[]
|
|
15
|
+
data?: (string | React.ReactNode)[][]
|
|
16
|
+
children?: React.ReactNode
|
|
17
|
+
className?: string
|
|
18
|
+
sortable?: boolean
|
|
19
|
+
paginated?: boolean
|
|
20
|
+
pageSize?: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function Table({
|
|
24
|
+
headers,
|
|
25
|
+
data,
|
|
26
|
+
children,
|
|
27
|
+
className = '',
|
|
28
|
+
sortable = false,
|
|
29
|
+
paginated = false,
|
|
30
|
+
pageSize = 10,
|
|
31
|
+
}: TableProps) {
|
|
32
|
+
const {
|
|
33
|
+
sortConfig,
|
|
34
|
+
currentPage,
|
|
35
|
+
setCurrentPage,
|
|
36
|
+
totalPages,
|
|
37
|
+
paginatedData,
|
|
38
|
+
requestSort,
|
|
39
|
+
} = useTable({
|
|
40
|
+
data,
|
|
41
|
+
sortable,
|
|
42
|
+
paginated,
|
|
43
|
+
pageSize,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const renderSortIcon = (index: number) => {
|
|
47
|
+
if (!sortable) return null
|
|
48
|
+
if (sortConfig?.key !== index)
|
|
49
|
+
return <ChevronDown size={14} className="ml-1 opacity-30" />
|
|
50
|
+
return sortConfig.direction === 'asc' ? (
|
|
51
|
+
<ChevronUp size={14} className="ml-1 text-primary-400" />
|
|
52
|
+
) : (
|
|
53
|
+
<ChevronDown size={14} className="ml-1 text-primary-400" />
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const tableContent = children ? (
|
|
58
|
+
children
|
|
59
|
+
) : (
|
|
60
|
+
<>
|
|
61
|
+
{headers && (
|
|
62
|
+
<thead>
|
|
63
|
+
<tr>
|
|
64
|
+
{headers.map((header, i) => (
|
|
65
|
+
<th
|
|
66
|
+
key={i}
|
|
67
|
+
onClick={() => requestSort(i)}
|
|
68
|
+
className={cn(
|
|
69
|
+
'text-left px-3 py-2.5 border-b-2 border-border-subtle text-text-main font-semibold text-sm',
|
|
70
|
+
sortable &&
|
|
71
|
+
'cursor-pointer select-none hover:text-primary-400 transition-colors',
|
|
72
|
+
)}
|
|
73
|
+
>
|
|
74
|
+
<div className="flex items-center">
|
|
75
|
+
{header}
|
|
76
|
+
{renderSortIcon(i)}
|
|
77
|
+
</div>
|
|
78
|
+
</th>
|
|
79
|
+
))}
|
|
80
|
+
</tr>
|
|
81
|
+
</thead>
|
|
82
|
+
)}
|
|
83
|
+
{paginatedData && (
|
|
84
|
+
<tbody>
|
|
85
|
+
{paginatedData.map((row, i) => (
|
|
86
|
+
<tr key={i} className="transition-colors hover:bg-bg-surface">
|
|
87
|
+
{row.map((cell, j) => (
|
|
88
|
+
<td
|
|
89
|
+
key={j}
|
|
90
|
+
className="px-3 py-2 border-b border-border-subtle text-sm text-text-muted"
|
|
91
|
+
>
|
|
92
|
+
{cell}
|
|
93
|
+
</td>
|
|
94
|
+
))}
|
|
95
|
+
</tr>
|
|
96
|
+
))}
|
|
97
|
+
</tbody>
|
|
98
|
+
)}
|
|
99
|
+
</>
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<div
|
|
104
|
+
className={cn(
|
|
105
|
+
'my-6 rounded-lg border border-border-subtle overflow-hidden',
|
|
106
|
+
className,
|
|
107
|
+
)}
|
|
108
|
+
>
|
|
109
|
+
<div className="overflow-x-auto">
|
|
110
|
+
<table className="w-full border-collapse text-sm">{tableContent}</table>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
{paginated && totalPages > 1 && (
|
|
114
|
+
<div className="flex items-center justify-between border-t border-border-subtle px-4 py-3">
|
|
115
|
+
<span className="text-xs text-text-muted">
|
|
116
|
+
Page {currentPage} of {totalPages}
|
|
117
|
+
</span>
|
|
118
|
+
<div className="flex items-center gap-1">
|
|
119
|
+
<RAC.Button
|
|
120
|
+
onPress={() => setCurrentPage(1)}
|
|
121
|
+
isDisabled={currentPage === 1}
|
|
122
|
+
className="grid place-items-center h-7 w-7 rounded-md text-text-muted outline-none transition-colors hover:bg-bg-surface disabled:opacity-30 disabled:pointer-events-none cursor-pointer"
|
|
123
|
+
>
|
|
124
|
+
<ChevronsLeft size={16} />
|
|
125
|
+
</RAC.Button>
|
|
126
|
+
<RAC.Button
|
|
127
|
+
onPress={() =>
|
|
128
|
+
setCurrentPage((prev: number) => Math.max(prev - 1, 1))
|
|
129
|
+
}
|
|
130
|
+
isDisabled={currentPage === 1}
|
|
131
|
+
className="grid place-items-center h-7 w-7 rounded-md text-text-muted outline-none transition-colors hover:bg-bg-surface disabled:opacity-30 disabled:pointer-events-none cursor-pointer"
|
|
132
|
+
>
|
|
133
|
+
<ChevronLeft size={16} />
|
|
134
|
+
</RAC.Button>
|
|
135
|
+
<RAC.Button
|
|
136
|
+
onPress={() =>
|
|
137
|
+
setCurrentPage((prev: number) => Math.min(prev + 1, totalPages))
|
|
138
|
+
}
|
|
139
|
+
isDisabled={currentPage === totalPages}
|
|
140
|
+
className="grid place-items-center h-7 w-7 rounded-md text-text-muted outline-none transition-colors hover:bg-bg-surface disabled:opacity-30 disabled:pointer-events-none cursor-pointer"
|
|
141
|
+
>
|
|
142
|
+
<ChevronRight size={16} />
|
|
143
|
+
</RAC.Button>
|
|
144
|
+
<RAC.Button
|
|
145
|
+
onPress={() => setCurrentPage(totalPages)}
|
|
146
|
+
isDisabled={currentPage === totalPages}
|
|
147
|
+
className="grid place-items-center h-7 w-7 rounded-md text-text-muted outline-none transition-colors hover:bg-bg-surface disabled:opacity-30 disabled:pointer-events-none cursor-pointer"
|
|
148
|
+
>
|
|
149
|
+
<ChevronsRight size={16} />
|
|
150
|
+
</RAC.Button>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
)}
|
|
154
|
+
</div>
|
|
155
|
+
)
|
|
156
|
+
}
|