@acmekit/docs-app 2.13.43
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/dist/entry-server.d.mts +5 -0
- package/dist/entry-server.d.ts +5 -0
- package/dist/entry-server.js +52 -0
- package/dist/entry-server.mjs +26 -0
- package/dist/index.d.mts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +507 -0
- package/dist/index.mjs +490 -0
- package/package.json +50 -0
- package/src/__tests__/build-routes.spec.ts +134 -0
- package/src/__tests__/search-scoring.spec.ts +144 -0
- package/src/components/DocPage.tsx +31 -0
- package/src/components/HomePage.tsx +139 -0
- package/src/components/Layout.tsx +103 -0
- package/src/components/MDXContent.tsx +11 -0
- package/src/components/RouteErrorBoundary.tsx +22 -0
- package/src/components/SearchModal.tsx +167 -0
- package/src/docs-app.tsx +99 -0
- package/src/entry-server.tsx +29 -0
- package/src/index.ts +2 -0
- package/src/module.d.ts +21 -0
- package/src/providers/DocsProviders.tsx +66 -0
- package/src/routes/build-routes.ts +13 -0
- package/src/types.ts +7 -0
package/src/docs-app.tsx
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React, { Suspense, useEffect, useRef } from "react"
|
|
2
|
+
import { BrowserRouter, Routes, Route } from "react-router-dom"
|
|
3
|
+
import { routes, components, importers } from "virtual:acmekit/docs-routes"
|
|
4
|
+
import { config } from "virtual:acmekit/docs-config"
|
|
5
|
+
import { Loading } from "@acmekit/docs-ui"
|
|
6
|
+
import { DocsProviders } from "./providers/DocsProviders"
|
|
7
|
+
import { Layout } from "./components/Layout"
|
|
8
|
+
import { DocPage } from "./components/DocPage"
|
|
9
|
+
import { HomePage } from "./components/HomePage"
|
|
10
|
+
import { RouteErrorBoundary } from "./components/RouteErrorBoundary"
|
|
11
|
+
import { SearchModal } from "./components/SearchModal"
|
|
12
|
+
import type { DocsPlugin } from "./types"
|
|
13
|
+
|
|
14
|
+
type DocsAppProps = {
|
|
15
|
+
plugins?: DocsPlugin[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function DocsApp({ plugins = [] }: DocsAppProps) {
|
|
19
|
+
const allRoutes = [...routes]
|
|
20
|
+
const prefetched = useRef(new Set<string>())
|
|
21
|
+
|
|
22
|
+
// Merge plugin contributions
|
|
23
|
+
for (const plugin of plugins) {
|
|
24
|
+
if (plugin.routes) {
|
|
25
|
+
allRoutes.push(...plugin.routes)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Prefetch chunks on link hover
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
function onMouseOver(e: MouseEvent) {
|
|
32
|
+
const anchor = (e.target as HTMLElement).closest?.("a")
|
|
33
|
+
if (!anchor) return
|
|
34
|
+
|
|
35
|
+
const href = anchor.getAttribute("href")
|
|
36
|
+
if (!href || prefetched.current.has(href)) return
|
|
37
|
+
|
|
38
|
+
const importer = importers[href]
|
|
39
|
+
if (importer) {
|
|
40
|
+
prefetched.current.add(href)
|
|
41
|
+
importer()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
document.addEventListener("mouseover", onMouseOver)
|
|
46
|
+
return () => document.removeEventListener("mouseover", onMouseOver)
|
|
47
|
+
}, [])
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<BrowserRouter basename={config.basePath}>
|
|
51
|
+
<DocsProviders config={config}>
|
|
52
|
+
<div className="h-screen w-full overflow-hidden">
|
|
53
|
+
<RouteErrorBoundary>
|
|
54
|
+
<Suspense fallback={<Loading count={8} />}>
|
|
55
|
+
<Routes>
|
|
56
|
+
<Route element={<Layout />}>
|
|
57
|
+
<Route index element={<HomePage />} />
|
|
58
|
+
{allRoutes.map((route) => {
|
|
59
|
+
const Component = components[route.path]
|
|
60
|
+
if (!Component) return null
|
|
61
|
+
|
|
62
|
+
if (route.type === "mdx") {
|
|
63
|
+
return (
|
|
64
|
+
<Route
|
|
65
|
+
key={route.path}
|
|
66
|
+
path={route.path}
|
|
67
|
+
element={
|
|
68
|
+
<DocPage frontmatter={route.frontmatter}>
|
|
69
|
+
<Suspense fallback={<Loading count={8} />}>
|
|
70
|
+
<Component />
|
|
71
|
+
</Suspense>
|
|
72
|
+
</DocPage>
|
|
73
|
+
}
|
|
74
|
+
/>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Route
|
|
80
|
+
key={route.path}
|
|
81
|
+
path={route.path}
|
|
82
|
+
element={
|
|
83
|
+
<Suspense fallback={<Loading count={8} />}>
|
|
84
|
+
<Component />
|
|
85
|
+
</Suspense>
|
|
86
|
+
}
|
|
87
|
+
/>
|
|
88
|
+
)
|
|
89
|
+
})}
|
|
90
|
+
</Route>
|
|
91
|
+
</Routes>
|
|
92
|
+
</Suspense>
|
|
93
|
+
</RouteErrorBoundary>
|
|
94
|
+
<SearchModal />
|
|
95
|
+
</div>
|
|
96
|
+
</DocsProviders>
|
|
97
|
+
</BrowserRouter>
|
|
98
|
+
)
|
|
99
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { renderToString } from "react-dom/server"
|
|
3
|
+
import { StaticRouter } from "react-router-dom/server"
|
|
4
|
+
import { Routes, Route } from "react-router-dom"
|
|
5
|
+
import { routes, components } from "virtual:acmekit/docs-routes"
|
|
6
|
+
|
|
7
|
+
export { routes }
|
|
8
|
+
|
|
9
|
+
export function render(url: string, basePath: string): string {
|
|
10
|
+
return renderToString(
|
|
11
|
+
<StaticRouter basename={basePath} location={url}>
|
|
12
|
+
<div className="h-screen w-full overflow-hidden">
|
|
13
|
+
<Routes>
|
|
14
|
+
{routes.map((route) => {
|
|
15
|
+
const Component = components[route.path]
|
|
16
|
+
if (!Component) return null
|
|
17
|
+
return (
|
|
18
|
+
<Route
|
|
19
|
+
key={route.path}
|
|
20
|
+
path={route.path}
|
|
21
|
+
element={<Component />}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
})}
|
|
25
|
+
</Routes>
|
|
26
|
+
</div>
|
|
27
|
+
</StaticRouter>
|
|
28
|
+
)
|
|
29
|
+
}
|
package/src/index.ts
ADDED
package/src/module.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
declare module "virtual:acmekit/docs-routes" {
|
|
2
|
+
import type { DocsRouteEntry } from "@acmekit/docs-shared"
|
|
3
|
+
export const routes: DocsRouteEntry[]
|
|
4
|
+
export const components: Record<string, React.ComponentType<any>>
|
|
5
|
+
export const importers: Record<string, () => Promise<any>>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
declare module "virtual:acmekit/docs-search" {
|
|
9
|
+
import type { DocsSearchEntry } from "@acmekit/docs-shared"
|
|
10
|
+
export const searchIndex: DocsSearchEntry[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
declare module "virtual:acmekit/docs-sidebar" {
|
|
14
|
+
import type { DocsSidebarItem } from "@acmekit/docs-shared"
|
|
15
|
+
export const sidebar: DocsSidebarItem[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare module "virtual:acmekit/docs-config" {
|
|
19
|
+
import type { DocsConfig } from "@acmekit/docs-shared"
|
|
20
|
+
export const config: DocsConfig
|
|
21
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { useMemo } from "react"
|
|
2
|
+
import {
|
|
3
|
+
RootProviders,
|
|
4
|
+
SiteConfigProvider,
|
|
5
|
+
ScrollControllerProvider,
|
|
6
|
+
SidebarProvider,
|
|
7
|
+
NotificationProvider,
|
|
8
|
+
PaginationProvider,
|
|
9
|
+
MainNavProvider,
|
|
10
|
+
SearchProvider,
|
|
11
|
+
AiAssistantProvider,
|
|
12
|
+
} from "@acmekit/docs-ui"
|
|
13
|
+
type DocsProvidersProps = {
|
|
14
|
+
children: React.ReactNode
|
|
15
|
+
config: Record<string, any>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function DocsProviders({ children, config }: DocsProvidersProps) {
|
|
19
|
+
const navItems = useMemo(() => {
|
|
20
|
+
if (!config.areas?.length) {
|
|
21
|
+
return []
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return config.areas.map((area: any) => ({
|
|
25
|
+
type: "link" as const,
|
|
26
|
+
link: `/${area.id}`,
|
|
27
|
+
title: area.title,
|
|
28
|
+
}))
|
|
29
|
+
}, [config.areas])
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<RootProviders>
|
|
33
|
+
<SiteConfigProvider
|
|
34
|
+
config={{
|
|
35
|
+
baseUrl: "",
|
|
36
|
+
basePath: config.basePath,
|
|
37
|
+
sidebars: config.sidebars || [],
|
|
38
|
+
project: {
|
|
39
|
+
title: config.title || "Documentation",
|
|
40
|
+
key: "docs",
|
|
41
|
+
},
|
|
42
|
+
logo: config.logo || "",
|
|
43
|
+
version: config.version,
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
<ScrollControllerProvider scrollableSelector="#main">
|
|
47
|
+
<SidebarProvider
|
|
48
|
+
sidebars={config.sidebars || []}
|
|
49
|
+
isSidebarStatic={true}
|
|
50
|
+
shouldHandlePathChange={true}
|
|
51
|
+
>
|
|
52
|
+
<NotificationProvider>
|
|
53
|
+
<PaginationProvider>
|
|
54
|
+
<MainNavProvider navItems={navItems}>
|
|
55
|
+
<SearchProvider>
|
|
56
|
+
<AiAssistantProvider>{children}</AiAssistantProvider>
|
|
57
|
+
</SearchProvider>
|
|
58
|
+
</MainNavProvider>
|
|
59
|
+
</PaginationProvider>
|
|
60
|
+
</NotificationProvider>
|
|
61
|
+
</SidebarProvider>
|
|
62
|
+
</ScrollControllerProvider>
|
|
63
|
+
</SiteConfigProvider>
|
|
64
|
+
</RootProviders>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DocsRouteEntry } from "@acmekit/docs-shared"
|
|
2
|
+
|
|
3
|
+
export function buildRoutes(
|
|
4
|
+
routes: DocsRouteEntry[],
|
|
5
|
+
components: Record<string, React.ComponentType<any>>
|
|
6
|
+
) {
|
|
7
|
+
return routes
|
|
8
|
+
.filter((route) => components[route.path])
|
|
9
|
+
.map((route) => ({
|
|
10
|
+
...route,
|
|
11
|
+
component: components[route.path],
|
|
12
|
+
}))
|
|
13
|
+
}
|