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,71 @@
|
|
|
1
|
+
import { useState, useMemo } from 'react'
|
|
2
|
+
import type { ComponentRoute } from '@client/types'
|
|
3
|
+
|
|
4
|
+
export function useSearch(routes: ComponentRoute[]) {
|
|
5
|
+
const [isOpen, setIsOpen] = useState(false)
|
|
6
|
+
const [query, setQuery] = useState('')
|
|
7
|
+
|
|
8
|
+
const list = useMemo(() => {
|
|
9
|
+
if (!query) {
|
|
10
|
+
return routes.slice(0, 10).map((r) => ({
|
|
11
|
+
id: r.path,
|
|
12
|
+
title: r.title,
|
|
13
|
+
path: r.path,
|
|
14
|
+
bio: r.description || '',
|
|
15
|
+
groupTitle: r.groupTitle,
|
|
16
|
+
}))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const results: any[] = []
|
|
20
|
+
const lowerQuery = query.toLowerCase()
|
|
21
|
+
|
|
22
|
+
for (const route of routes) {
|
|
23
|
+
if (route.title?.toLowerCase().includes(lowerQuery)) {
|
|
24
|
+
results.push({
|
|
25
|
+
id: route.path,
|
|
26
|
+
title: route.title,
|
|
27
|
+
path: route.path,
|
|
28
|
+
bio: route.description || '',
|
|
29
|
+
groupTitle: route.groupTitle,
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (route.headings) {
|
|
34
|
+
for (const heading of route.headings) {
|
|
35
|
+
if (heading.text.toLowerCase().includes(lowerQuery)) {
|
|
36
|
+
results.push({
|
|
37
|
+
id: `${route.path}#${heading.id}`,
|
|
38
|
+
title: heading.text,
|
|
39
|
+
path: `${route.path}#${heading.id}`,
|
|
40
|
+
bio: `Heading in ${route.title}`,
|
|
41
|
+
groupTitle: route.title,
|
|
42
|
+
isHeading: true,
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Deduplicate by path
|
|
50
|
+
const seen = new Set()
|
|
51
|
+
return results
|
|
52
|
+
.filter((r) => {
|
|
53
|
+
if (seen.has(r.path)) return false
|
|
54
|
+
seen.add(r.path)
|
|
55
|
+
return true
|
|
56
|
+
})
|
|
57
|
+
.slice(0, 10)
|
|
58
|
+
}, [routes, query])
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
isOpen,
|
|
62
|
+
setIsOpen,
|
|
63
|
+
query,
|
|
64
|
+
setQuery,
|
|
65
|
+
list,
|
|
66
|
+
input: {
|
|
67
|
+
value: query,
|
|
68
|
+
onChange: (e: any) => setQuery(e.target.value),
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useLocation } from 'react-router-dom'
|
|
2
|
+
import { useConfig } from '@client/app/config-context'
|
|
3
|
+
import type { ComponentRoute } from '../types'
|
|
4
|
+
|
|
5
|
+
export function useSidebar(routes: ComponentRoute[]) {
|
|
6
|
+
const config = useConfig()
|
|
7
|
+
const location = useLocation()
|
|
8
|
+
|
|
9
|
+
// Find active route and tab
|
|
10
|
+
const activeRoute = routes.find((r) => r.path === location.pathname)
|
|
11
|
+
const activeTabId = activeRoute?.tab?.toLowerCase()
|
|
12
|
+
|
|
13
|
+
// Filter routes by active tab if any
|
|
14
|
+
const filteredRoutes = activeTabId
|
|
15
|
+
? routes.filter((r) => !r.tab || r.tab.toLowerCase() === activeTabId)
|
|
16
|
+
: routes
|
|
17
|
+
|
|
18
|
+
const ungrouped: ComponentRoute[] = []
|
|
19
|
+
const groupsMap = new Map<
|
|
20
|
+
string,
|
|
21
|
+
{ slug: string; title: string; routes: ComponentRoute[]; icon?: string }
|
|
22
|
+
>()
|
|
23
|
+
|
|
24
|
+
for (const route of filteredRoutes) {
|
|
25
|
+
if (!route.group) {
|
|
26
|
+
ungrouped.push(route)
|
|
27
|
+
} else {
|
|
28
|
+
if (!groupsMap.has(route.group)) {
|
|
29
|
+
groupsMap.set(route.group, {
|
|
30
|
+
slug: route.group,
|
|
31
|
+
title: route.groupTitle || route.group,
|
|
32
|
+
routes: [],
|
|
33
|
+
icon: route.groupIcon,
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
groupsMap.get(route.group)!.routes.push(route)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const groups = Array.from(groupsMap.values())
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
groups,
|
|
44
|
+
ungrouped,
|
|
45
|
+
activeRoute,
|
|
46
|
+
activePath: location.pathname,
|
|
47
|
+
config,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useLocation } from 'react-router-dom'
|
|
2
|
+
import { useEffect, useState, useRef } from 'react'
|
|
3
|
+
import type { ComponentRoute, BoltdocsTab } from '@client/types'
|
|
4
|
+
|
|
5
|
+
export function useTabs(
|
|
6
|
+
tabs: BoltdocsTab[] = [],
|
|
7
|
+
routes: ComponentRoute[] = [],
|
|
8
|
+
) {
|
|
9
|
+
const location = useLocation()
|
|
10
|
+
const tabRefs = useRef<(HTMLAnchorElement | null)[]>([])
|
|
11
|
+
const [indicatorStyle, setIndicatorStyle] = useState<React.CSSProperties>({
|
|
12
|
+
opacity: 0,
|
|
13
|
+
transform: 'translateX(0) scaleX(0)',
|
|
14
|
+
width: 0,
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const activeRoute = routes.find((r) => r.path === location.pathname)
|
|
18
|
+
const activeTabId = activeRoute?.tab?.toLowerCase()
|
|
19
|
+
const activeIndex = tabs.findIndex(
|
|
20
|
+
(tab) => tab.id.toLowerCase() === activeTabId,
|
|
21
|
+
)
|
|
22
|
+
const finalActiveIndex = activeIndex === -1 ? 0 : activeIndex
|
|
23
|
+
|
|
24
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: Updated pointer to the tab
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const activeTab = tabRefs.current[finalActiveIndex]
|
|
27
|
+
if (activeTab) {
|
|
28
|
+
setIndicatorStyle({
|
|
29
|
+
opacity: 1,
|
|
30
|
+
width: activeTab.offsetWidth,
|
|
31
|
+
transform: `translateX(${activeTab.offsetLeft}px)`,
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}, [finalActiveIndex, tabs.length, location.pathname])
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
tabs,
|
|
38
|
+
activeIndex: finalActiveIndex,
|
|
39
|
+
indicatorStyle,
|
|
40
|
+
tabRefs,
|
|
41
|
+
activeTabId,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useNavigate } from 'react-router-dom'
|
|
2
|
+
import { getBaseFilePath } from '@client/utils/get-base-file-path'
|
|
3
|
+
import { useRoutes } from './use-routes'
|
|
4
|
+
|
|
5
|
+
export interface VersionOption {
|
|
6
|
+
key: string
|
|
7
|
+
label: string
|
|
8
|
+
value: string
|
|
9
|
+
isCurrent: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UseVersionReturn {
|
|
13
|
+
currentVersion: string | undefined
|
|
14
|
+
currentVersionLabel: string | undefined
|
|
15
|
+
availableVersions: VersionOption[]
|
|
16
|
+
handleVersionChange: (version: string) => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Hook to manage and switch between different versions of the documentation.
|
|
21
|
+
*/
|
|
22
|
+
export function useVersion(): UseVersionReturn {
|
|
23
|
+
const navigate = useNavigate()
|
|
24
|
+
const routeContext = useRoutes()
|
|
25
|
+
const { allRoutes, currentRoute, currentVersion, currentLocale, config } =
|
|
26
|
+
routeContext
|
|
27
|
+
const versions = config.versions
|
|
28
|
+
|
|
29
|
+
const handleVersionChange = (version: string) => {
|
|
30
|
+
if (!versions || version === currentVersion) return
|
|
31
|
+
|
|
32
|
+
let targetPath = `/docs/${version}`
|
|
33
|
+
|
|
34
|
+
if (currentRoute) {
|
|
35
|
+
const baseFile = getBaseFilePath(
|
|
36
|
+
currentRoute.filePath,
|
|
37
|
+
currentRoute.version,
|
|
38
|
+
currentRoute.locale,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
const targetRoute = allRoutes.find(
|
|
42
|
+
(r) =>
|
|
43
|
+
getBaseFilePath(r.filePath, r.version, r.locale) === baseFile &&
|
|
44
|
+
(r.version || versions.defaultVersion) === version &&
|
|
45
|
+
(currentLocale ? r.locale === currentLocale : !r.locale),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if (targetRoute) {
|
|
49
|
+
targetPath = targetRoute.path
|
|
50
|
+
} else {
|
|
51
|
+
const versionIndexRoute = allRoutes.find(
|
|
52
|
+
(r) =>
|
|
53
|
+
getBaseFilePath(r.filePath, r.version, r.locale) === 'index.md' &&
|
|
54
|
+
(r.version || versions.defaultVersion) === version &&
|
|
55
|
+
(currentLocale ? r.locale === currentLocale : !r.locale),
|
|
56
|
+
)
|
|
57
|
+
targetPath = versionIndexRoute
|
|
58
|
+
? versionIndexRoute.path
|
|
59
|
+
: `/docs/${version}${currentLocale ? `/${currentLocale}` : ''}`
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
navigate(targetPath)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const availableVersions = routeContext.availableVersions.map((v) => ({
|
|
67
|
+
...v,
|
|
68
|
+
label: v.label as string,
|
|
69
|
+
value: v.key,
|
|
70
|
+
}))
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
currentVersion,
|
|
74
|
+
currentVersionLabel: routeContext.currentVersionLabel,
|
|
75
|
+
availableVersions,
|
|
76
|
+
handleVersionChange,
|
|
77
|
+
}
|
|
78
|
+
}
|
package/src/client/index.ts
CHANGED
|
@@ -1,18 +1,46 @@
|
|
|
1
|
-
export type { BoltdocsConfig, BoltdocsThemeConfig } from
|
|
2
|
-
export type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
11
|
-
export {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
1
|
+
export type { BoltdocsConfig, BoltdocsThemeConfig } from '../node/config'
|
|
2
|
+
export type {
|
|
3
|
+
ComponentRoute,
|
|
4
|
+
CreateBoltdocsAppOptions,
|
|
5
|
+
LayoutProps,
|
|
6
|
+
} from './types'
|
|
7
|
+
export { createBoltdocsApp } from './app'
|
|
8
|
+
export { useConfig } from '@client/app/config-context'
|
|
9
|
+
export { useTheme } from '@client/app/theme-context'
|
|
10
|
+
export { useRoutes } from '@client/hooks/use-routes'
|
|
11
|
+
export { useMdxComponents } from '@client/app/mdx-components-context'
|
|
12
|
+
|
|
13
|
+
// Composable layout building blocks
|
|
14
|
+
export { DocsLayout } from '@components/docs-layout'
|
|
15
|
+
export { DefaultLayout } from '@components/default-layout'
|
|
16
|
+
|
|
17
|
+
// Default UI components (for use in custom layout.tsx)
|
|
18
|
+
export { Navbar } from '@components/ui-base/navbar'
|
|
19
|
+
export { Sidebar } from '@components/ui-base/sidebar'
|
|
20
|
+
export { OnThisPage } from '@components/ui-base/on-this-page'
|
|
21
|
+
export { Head } from '@components/ui-base/head'
|
|
22
|
+
export { Breadcrumbs } from '@components/ui-base/breadcrumbs'
|
|
23
|
+
export { PageNav } from '@components/ui-base/page-nav'
|
|
24
|
+
export { ProgressBar } from '@components/ui-base/progress-bar'
|
|
25
|
+
export { ErrorBoundary } from '@components/ui-base/error-boundary'
|
|
26
|
+
export { CopyMarkdown } from '@components/ui-base/copy-markdown'
|
|
27
|
+
|
|
28
|
+
export { NotFound } from '@components/ui-base/not-found'
|
|
29
|
+
export { Loading } from '@components/ui-base/loading'
|
|
30
|
+
export { CodeBlock } from '@components/mdx/code-block'
|
|
31
|
+
export { Video } from '@components/mdx/video'
|
|
32
|
+
export {
|
|
33
|
+
defineSandbox,
|
|
34
|
+
openSandbox,
|
|
35
|
+
embedSandbox,
|
|
36
|
+
} from '@integrations/codesandbox'
|
|
37
|
+
|
|
38
|
+
export type {
|
|
39
|
+
SandboxOptions,
|
|
40
|
+
SandboxFile,
|
|
41
|
+
SandboxFiles,
|
|
42
|
+
SandboxEmbedOptions,
|
|
43
|
+
} from './types'
|
|
16
44
|
export {
|
|
17
45
|
Button,
|
|
18
46
|
Badge,
|
|
@@ -26,11 +54,17 @@ export {
|
|
|
26
54
|
Warning,
|
|
27
55
|
Danger,
|
|
28
56
|
InfoBox,
|
|
57
|
+
ComponentProps,
|
|
58
|
+
ComponentPreview,
|
|
59
|
+
Important,
|
|
60
|
+
Caution,
|
|
29
61
|
List,
|
|
30
62
|
FileTree,
|
|
31
63
|
Table,
|
|
32
64
|
Field,
|
|
33
|
-
|
|
65
|
+
Link,
|
|
66
|
+
Image,
|
|
67
|
+
} from './components/mdx'
|
|
34
68
|
export type {
|
|
35
69
|
ButtonProps,
|
|
36
70
|
BadgeProps,
|
|
@@ -39,8 +73,12 @@ export type {
|
|
|
39
73
|
TabsProps,
|
|
40
74
|
TabProps,
|
|
41
75
|
AdmonitionProps,
|
|
76
|
+
ComponentPropsProps,
|
|
77
|
+
ComponentPreviewProps,
|
|
42
78
|
ListProps,
|
|
43
79
|
FileTreeProps,
|
|
44
80
|
TableProps,
|
|
45
81
|
FieldProps,
|
|
46
|
-
|
|
82
|
+
LinkProps,
|
|
83
|
+
ImageProps,
|
|
84
|
+
} from './components/mdx'
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { getParameters } from 'codesandbox/lib/api/define.js'
|
|
2
|
+
import { SandboxOptions } from '../types'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build the files payload for the CodeSandbox Define API.
|
|
6
|
+
* Ensures every file conforms to the `{ content, isBinary }` shape
|
|
7
|
+
* required by the SDK, and auto-generates a `package.json` when one
|
|
8
|
+
* isn't explicitly provided.
|
|
9
|
+
*/
|
|
10
|
+
function buildSandboxFiles(options: SandboxOptions) {
|
|
11
|
+
const files = options.files || {}
|
|
12
|
+
const dependencies = options.dependencies || {}
|
|
13
|
+
const devDependencies = options.devDependencies || {}
|
|
14
|
+
const title = options.title || 'codesandbox-project'
|
|
15
|
+
const description = options.description || 'Generic Sandbox'
|
|
16
|
+
|
|
17
|
+
const finalFiles: Record<string, { content: string; isBinary: boolean }> = {}
|
|
18
|
+
|
|
19
|
+
for (const [path, file] of Object.entries(files)) {
|
|
20
|
+
const content =
|
|
21
|
+
typeof file.content === 'object'
|
|
22
|
+
? JSON.stringify(file.content, null, 2)
|
|
23
|
+
: file.content
|
|
24
|
+
finalFiles[path] = { content, isBinary: file.isBinary ?? false }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!finalFiles['package.json']) {
|
|
28
|
+
const isVite =
|
|
29
|
+
options.template === 'vite' ||
|
|
30
|
+
!!devDependencies.vite ||
|
|
31
|
+
!!devDependencies['@vitejs/plugin-react']
|
|
32
|
+
|
|
33
|
+
const defaultScripts = isVite
|
|
34
|
+
? {
|
|
35
|
+
dev: 'vite',
|
|
36
|
+
build: 'vite build',
|
|
37
|
+
preview: 'vite preview',
|
|
38
|
+
}
|
|
39
|
+
: {
|
|
40
|
+
start: 'node index.js',
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
finalFiles['package.json'] = {
|
|
44
|
+
content: JSON.stringify(
|
|
45
|
+
{
|
|
46
|
+
private: true,
|
|
47
|
+
name: title,
|
|
48
|
+
description,
|
|
49
|
+
type: 'module',
|
|
50
|
+
version: '1.0.0',
|
|
51
|
+
scripts: options.scripts || defaultScripts,
|
|
52
|
+
dependencies,
|
|
53
|
+
devDependencies,
|
|
54
|
+
},
|
|
55
|
+
null,
|
|
56
|
+
2,
|
|
57
|
+
),
|
|
58
|
+
isBinary: false,
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return finalFiles
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Helper to define a sandbox and get a URL for the CodeSandbox Define API.
|
|
67
|
+
* Uses the official SDK `getParameters` for proper LZ-string compression.
|
|
68
|
+
*/
|
|
69
|
+
export function defineSandbox(options: SandboxOptions) {
|
|
70
|
+
const finalFiles = buildSandboxFiles(options)
|
|
71
|
+
const parameters = getParameters({ files: finalFiles })
|
|
72
|
+
|
|
73
|
+
// FIX: Agregar query params que forzan comportamiento correcto
|
|
74
|
+
const query = new URLSearchParams({
|
|
75
|
+
parameters,
|
|
76
|
+
// FIX: Forzar instalación de dependencias
|
|
77
|
+
installDependencies: 'true',
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// FIX: Agregar file query para que abra el entry correcto
|
|
81
|
+
if (options.entry) {
|
|
82
|
+
query.set('file', `/${options.entry}`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
parameters,
|
|
87
|
+
url: `https://codesandbox.io/api/v1/sandboxes/define?${query.toString()}`,
|
|
88
|
+
options,
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* CORE API: Open a CodeSandbox using a form POST to the Define API.
|
|
94
|
+
*
|
|
95
|
+
* Uses a hidden form + POST which avoids URL length limits and is the
|
|
96
|
+
* recommended approach from CodeSandbox documentation. The SDK's
|
|
97
|
+
* `getParameters` handles LZ-string compression internally.
|
|
98
|
+
*/
|
|
99
|
+
export function openSandbox(options: SandboxOptions) {
|
|
100
|
+
if (typeof window === 'undefined') return defineSandbox(options)
|
|
101
|
+
|
|
102
|
+
const finalFiles = buildSandboxFiles(options)
|
|
103
|
+
const parameters = getParameters({ files: finalFiles })
|
|
104
|
+
const entry = options.entry || 'src/App.tsx'
|
|
105
|
+
|
|
106
|
+
// Use form POST – the most reliable method for the Define API
|
|
107
|
+
const form = document.createElement('form')
|
|
108
|
+
form.method = 'POST'
|
|
109
|
+
form.target = '_blank'
|
|
110
|
+
form.action = 'https://codesandbox.io/api/v1/sandboxes/define'
|
|
111
|
+
form.style.display = 'none'
|
|
112
|
+
|
|
113
|
+
const addField = (name: string, value: string) => {
|
|
114
|
+
const input = document.createElement('input')
|
|
115
|
+
input.type = 'hidden'
|
|
116
|
+
input.name = name
|
|
117
|
+
input.value = value
|
|
118
|
+
form.appendChild(input)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const queryParams = new URLSearchParams({
|
|
122
|
+
file: `/${entry}`,
|
|
123
|
+
// FIX: Forzar vista de preview (no solo editor)
|
|
124
|
+
// FIX: Deshabilitar eslint que a veces bloquea
|
|
125
|
+
eslint: '0',
|
|
126
|
+
// FIX: Habilitar codemirror
|
|
127
|
+
codemirror: '1',
|
|
128
|
+
// FIX: Forzar instalación de deps
|
|
129
|
+
installDependencies: 'true',
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
addField('query', queryParams.toString())
|
|
133
|
+
addField('parameters', parameters)
|
|
134
|
+
|
|
135
|
+
document.body.appendChild(form)
|
|
136
|
+
form.submit()
|
|
137
|
+
document.body.removeChild(form)
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
parameters,
|
|
141
|
+
url: `https://codesandbox.io/api/v1/sandboxes/define?parameters=${parameters}`,
|
|
142
|
+
options,
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Generate an embeddable iframe URL for a CodeSandbox.
|
|
148
|
+
*
|
|
149
|
+
* This gives you more control than `openSandbox` — you can embed the sandbox
|
|
150
|
+
* inline on the page rather than opening a new tab. The returned URL can be
|
|
151
|
+
* used as the `src` of an `<iframe>`.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```tsx
|
|
155
|
+
* const url = embedSandbox({
|
|
156
|
+
* files: { "index.js": { content: "console.log('hello')" } },
|
|
157
|
+
* embed: { view: "editor", theme: "dark" },
|
|
158
|
+
* }).url;
|
|
159
|
+
* // url → "https://codesandbox.io/api/v1/sandboxes/define?parameters=…&embed=1&view=editor&theme=dark"
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export function embedSandbox(options: SandboxOptions) {
|
|
163
|
+
const finalFiles = buildSandboxFiles(options)
|
|
164
|
+
const parameters = getParameters({ files: finalFiles })
|
|
165
|
+
const embedOptions = options.embed || {}
|
|
166
|
+
|
|
167
|
+
const query = new URLSearchParams({ parameters, embed: '1' })
|
|
168
|
+
|
|
169
|
+
if (embedOptions.view) query.set('view', embedOptions.view)
|
|
170
|
+
if (embedOptions.theme) query.set('theme', embedOptions.theme)
|
|
171
|
+
if (embedOptions.hideNavigation) query.set('hidenavigation', '1')
|
|
172
|
+
if (options.entry) query.set('file', `/${options.entry}`)
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
parameters,
|
|
176
|
+
url: `https://codesandbox.io/api/v1/sandboxes/define?${query.toString()}`,
|
|
177
|
+
options,
|
|
178
|
+
}
|
|
179
|
+
}
|
package/src/client/ssr.tsx
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import ReactDOMServer from
|
|
3
|
-
import { StaticRouter } from
|
|
4
|
-
import { AppShell } from
|
|
5
|
-
import { ComponentRoute } from
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import ReactDOMServer from 'react-dom/server'
|
|
3
|
+
import { StaticRouter } from 'react-router-dom/server'
|
|
4
|
+
import { AppShell } from './app'
|
|
5
|
+
import type { ComponentRoute } from './types'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Options for rendering the Boltdocs application on the server (SSG).
|
|
9
9
|
*/
|
|
10
10
|
export interface RenderOptions {
|
|
11
11
|
/** The URL path currently being rendered */
|
|
12
|
-
path: string
|
|
12
|
+
path: string
|
|
13
13
|
/** Initial routes generated by the Vite plugin (`virtual:boltdocs-routes`) */
|
|
14
|
-
routes: ComponentRoute[]
|
|
14
|
+
routes: ComponentRoute[]
|
|
15
15
|
/** Site configuration (`virtual:boltdocs-config`) */
|
|
16
|
-
config: any
|
|
16
|
+
config: any
|
|
17
17
|
/** The name of the documentation directory (e.g. 'docs') */
|
|
18
|
-
docsDirName: string
|
|
18
|
+
docsDirName: string
|
|
19
19
|
/** Optional custom React component to render when visiting the root path ('/') */
|
|
20
|
-
homePage?: React.ComponentType
|
|
20
|
+
homePage?: React.ComponentType
|
|
21
|
+
/** Custom external pages mapped by their route path */
|
|
22
|
+
externalPages?: Record<string, React.ComponentType<any>>
|
|
21
23
|
/** Preloaded modules (since SSR cannot use dynamic imports easily) */
|
|
22
|
-
modules: Record<string, any
|
|
24
|
+
modules: Record<string, any>
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
/**
|
|
@@ -27,13 +29,21 @@ export interface RenderOptions {
|
|
|
27
29
|
* This is called by the Node SSG script during the Vite build process.
|
|
28
30
|
*/
|
|
29
31
|
export async function render(options: RenderOptions): Promise<string> {
|
|
30
|
-
const {
|
|
32
|
+
const {
|
|
33
|
+
path,
|
|
34
|
+
routes,
|
|
35
|
+
config,
|
|
36
|
+
modules,
|
|
37
|
+
homePage,
|
|
38
|
+
externalPages,
|
|
39
|
+
docsDirName,
|
|
40
|
+
} = options
|
|
31
41
|
|
|
32
42
|
// For SSR, we must resolve modules synchronously. We create a mock 'loader'
|
|
33
43
|
// that instantly returns the module since the SSG script already loaded it.
|
|
34
|
-
const resolvedModules: Record<string, () => Promise<any>> = {}
|
|
44
|
+
const resolvedModules: Record<string, () => Promise<any>> = {}
|
|
35
45
|
for (const [key, mod] of Object.entries(modules)) {
|
|
36
|
-
resolvedModules[key] = () => Promise.resolve(mod)
|
|
46
|
+
resolvedModules[key] = () => Promise.resolve(mod)
|
|
37
47
|
}
|
|
38
48
|
|
|
39
49
|
const html = ReactDOMServer.renderToString(
|
|
@@ -45,10 +55,11 @@ export async function render(options: RenderOptions): Promise<string> {
|
|
|
45
55
|
docsDirName={docsDirName}
|
|
46
56
|
modules={resolvedModules}
|
|
47
57
|
homePage={homePage}
|
|
58
|
+
externalPages={externalPages}
|
|
48
59
|
/>
|
|
49
60
|
</StaticRouter>
|
|
50
61
|
</React.StrictMode>,
|
|
51
|
-
)
|
|
62
|
+
)
|
|
52
63
|
|
|
53
|
-
return html
|
|
64
|
+
return html
|
|
54
65
|
}
|