@xyd-js/plugin-docs 0.1.0-build.160
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/LICENSE +21 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +4605 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
- package/src/const.ts +7 -0
- package/src/declarations.d.ts +29 -0
- package/src/index.ts +386 -0
- package/src/pages/context.tsx +9 -0
- package/src/pages/layout.tsx +340 -0
- package/src/pages/metatags.ts +96 -0
- package/src/pages/page.tsx +463 -0
- package/src/presets/docs/index.ts +317 -0
- package/src/presets/docs/settings.ts +262 -0
- package/src/presets/graphql/index.ts +69 -0
- package/src/presets/openapi/index.ts +66 -0
- package/src/presets/sources/index.ts +74 -0
- package/src/presets/uniform/index.ts +832 -0
- package/src/types.ts +40 -0
- package/src/utils.ts +19 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import { useEffect, useMemo } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Outlet,
|
|
4
|
+
useLoaderData,
|
|
5
|
+
useLocation,
|
|
6
|
+
useNavigate,
|
|
7
|
+
useNavigation,
|
|
8
|
+
useMatches
|
|
9
|
+
} from "react-router";
|
|
10
|
+
|
|
11
|
+
import { UXNode } from "openux-js";
|
|
12
|
+
|
|
13
|
+
import { mapSettingsToProps } from "@xyd-js/framework/hydration";
|
|
14
|
+
|
|
15
|
+
import type { Metadata, MetadataMap, Settings, Theme as ThemeSettings } from "@xyd-js/core";
|
|
16
|
+
import type { INavLinks, IBreadcrumb } from "@xyd-js/ui";
|
|
17
|
+
import { Framework, FwLink, FwLogo, useSettings, type FwSidebarItemProps } from "@xyd-js/framework/react";
|
|
18
|
+
import { ReactContent } from "@xyd-js/components/content";
|
|
19
|
+
import { Atlas, AtlasContext, type VariantToggleConfig } from "@xyd-js/atlas";
|
|
20
|
+
import AtlasXydPlugin from "@xyd-js/atlas/xydPlugin";
|
|
21
|
+
|
|
22
|
+
import { Surfaces, pageMetaLayout } from "@xyd-js/framework";
|
|
23
|
+
import { Composer } from "@xyd-js/composer";
|
|
24
|
+
import { Analytics, useAnalytics } from "@xyd-js/analytics";
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
import { iconSet } from 'virtual:xyd-icon-set';
|
|
27
|
+
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
import virtualSettings from "virtual:xyd-settings";
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
const { settings: getSettings, settingsClone, userPreferences } = virtualSettings
|
|
32
|
+
|
|
33
|
+
// const settings = globalThis.__xydSettings
|
|
34
|
+
import Theme from "virtual:xyd-theme";
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
import { loadProvider } from 'virtual:xyd-analytics-providers'
|
|
37
|
+
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
import "virtual:xyd-theme/index.css"
|
|
40
|
+
import "virtual:xyd-theme-override/index.css"
|
|
41
|
+
import 'katex/dist/katex.min.css'
|
|
42
|
+
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
import { components as userComponents } from 'virtual:xyd-user-components';
|
|
45
|
+
|
|
46
|
+
import { PageContext } from "./context";
|
|
47
|
+
import React from "react";
|
|
48
|
+
|
|
49
|
+
import { markdownPlugins } from "@xyd-js/content/md";
|
|
50
|
+
import { ContentFS } from "@xyd-js/content";
|
|
51
|
+
import { Icon, IconProvider } from "@xyd-js/components/writer";
|
|
52
|
+
import { CoderProvider } from "@xyd-js/components/coder";
|
|
53
|
+
import { SearchButton } from "@xyd-js/components/system"
|
|
54
|
+
|
|
55
|
+
globalThis.__xydSettings = getSettings
|
|
56
|
+
globalThis.__xydSettingsClone = settingsClone
|
|
57
|
+
globalThis.__xydUserComponents = userComponents // Add user components to global scope TODO: problematic
|
|
58
|
+
globalThis.__xydUserPreferences = userPreferences
|
|
59
|
+
|
|
60
|
+
const settings = globalThis.__xydSettings as Settings
|
|
61
|
+
|
|
62
|
+
// console.log(JSON.stringify(settings?.navigation?.sidebar, null, 2), "settings?.navigation?.sidebar")
|
|
63
|
+
|
|
64
|
+
const surfaces = new Surfaces()
|
|
65
|
+
const atlasXyd = AtlasXydPlugin()(settings) // TODO: in the future via standard plugin API
|
|
66
|
+
const SidebarItemRight = atlasXyd?.customComponents?.["AtlasSidebarItemRight"]
|
|
67
|
+
|
|
68
|
+
if (SidebarItemRight) {
|
|
69
|
+
surfaces.define(
|
|
70
|
+
SidebarItemRight.surface,
|
|
71
|
+
SidebarItemRight.component,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const reactContent = new ReactContent(settings, {
|
|
76
|
+
Link: FwLink,
|
|
77
|
+
components: {
|
|
78
|
+
Atlas,
|
|
79
|
+
},
|
|
80
|
+
useLocation, // // TODO: !!!! BETTER API !!!!!
|
|
81
|
+
useNavigate,
|
|
82
|
+
useNavigation
|
|
83
|
+
})
|
|
84
|
+
globalThis.__xydThemeSettings = settings?.theme
|
|
85
|
+
globalThis.__xydNavigation = settings?.navigation
|
|
86
|
+
globalThis.__xydWebeditor = settings?.webeditor
|
|
87
|
+
globalThis.__xydReactContent = reactContent
|
|
88
|
+
globalThis.__xydSurfaces = surfaces
|
|
89
|
+
|
|
90
|
+
const theme = new Theme()
|
|
91
|
+
//@ts-ignore TODO: in the future better api like PageLoad interface or something like that
|
|
92
|
+
if (theme.mergeUserAppearance) {
|
|
93
|
+
// its needed after user declaration
|
|
94
|
+
//@ts-ignore
|
|
95
|
+
theme.mergeUserAppearance()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (
|
|
99
|
+
settings?.theme?.appearance?.sidebar?.scrollbar === "secondary"
|
|
100
|
+
) {
|
|
101
|
+
import("@xyd-js/themes/decorators/sidebar-scroll.css").catch(() => {
|
|
102
|
+
// Ignore CSS import errors during development
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const { Layout: BaseThemeLayout } = theme
|
|
107
|
+
|
|
108
|
+
interface LoaderData {
|
|
109
|
+
sidebarGroups: FwSidebarItemProps[]
|
|
110
|
+
breadcrumbs: IBreadcrumb[],
|
|
111
|
+
toc: MetadataMap,
|
|
112
|
+
slug: string
|
|
113
|
+
metadata: Metadata | null
|
|
114
|
+
navlinks?: INavLinks,
|
|
115
|
+
bannerContentCode?: string
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function loader({ request }: { request: any }) {
|
|
119
|
+
globalThis.__xydFrontmatterNotExists = {}
|
|
120
|
+
|
|
121
|
+
new Composer() // TODO: better API
|
|
122
|
+
|
|
123
|
+
const slug = getPathname(request.url || "index") || "index"
|
|
124
|
+
|
|
125
|
+
const {
|
|
126
|
+
groups: sidebarGroups,
|
|
127
|
+
breadcrumbs,
|
|
128
|
+
navlinks,
|
|
129
|
+
metadata
|
|
130
|
+
} = await mapSettingsToProps(
|
|
131
|
+
settings,
|
|
132
|
+
globalThis.__xydPagePathMapping,
|
|
133
|
+
slug,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
let bannerContentCode = ""
|
|
137
|
+
|
|
138
|
+
const mdPlugins = await markdownPlugins({
|
|
139
|
+
maxDepth: metadata?.maxTocDepth || settings?.theme?.writer?.maxTocDepth || 2,
|
|
140
|
+
}, settings)
|
|
141
|
+
const contentFs = new ContentFS(settings, mdPlugins.remarkPlugins, mdPlugins.rehypePlugins, mdPlugins.recmaPlugins)
|
|
142
|
+
|
|
143
|
+
if (settings?.components?.banner?.content && typeof settings?.components?.banner?.content === "string") {
|
|
144
|
+
bannerContentCode = await contentFs.compileContent(
|
|
145
|
+
settings?.components?.banner?.content,
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// TODO: IN THE FUTURE BETTER API
|
|
150
|
+
const layout = pageMetaLayout(metadata)
|
|
151
|
+
if (metadata && layout) {
|
|
152
|
+
metadata.layout = layout
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
sidebarGroups,
|
|
157
|
+
breadcrumbs,
|
|
158
|
+
navlinks,
|
|
159
|
+
slug,
|
|
160
|
+
metadata,
|
|
161
|
+
bannerContentCode
|
|
162
|
+
} as LoaderData
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export default function Layout() {
|
|
166
|
+
const loaderData = useLoaderData<LoaderData>()
|
|
167
|
+
const matches = useMatches()
|
|
168
|
+
|
|
169
|
+
const lastMatchId = matches[matches.length - 1]?.id || null
|
|
170
|
+
|
|
171
|
+
let atlasVariantToggles: VariantToggleConfig[] = [];
|
|
172
|
+
|
|
173
|
+
// TODO: BETTER HANDLE THAT
|
|
174
|
+
if (loaderData.metadata?.openapi) {
|
|
175
|
+
atlasVariantToggles = [
|
|
176
|
+
{ key: "status", defaultValue: "200" },
|
|
177
|
+
{ key: "contentType", defaultValue: "application/json" }
|
|
178
|
+
];
|
|
179
|
+
} else {
|
|
180
|
+
atlasVariantToggles = [
|
|
181
|
+
{ key: "symbolName", defaultValue: "" }
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let bannerContent: any = null
|
|
186
|
+
// TODO: !!!! BETTER API !!!!
|
|
187
|
+
if (loaderData.bannerContentCode) {
|
|
188
|
+
const content = mdxContent(loaderData.bannerContentCode)
|
|
189
|
+
const BannerContent = MemoMDXComponent(content.component)
|
|
190
|
+
|
|
191
|
+
bannerContent = function () {
|
|
192
|
+
return <BannerContent components={theme.reactContentComponents()} />
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const userComponents = (globalThis.__xydUserComponents || []).reduce((acc, component) => {
|
|
197
|
+
acc[component.name] = component.component;
|
|
198
|
+
return acc;
|
|
199
|
+
}, {});
|
|
200
|
+
|
|
201
|
+
return <>
|
|
202
|
+
<Analytics settings={settings} loader={loadProvider}>
|
|
203
|
+
<IconProvider value={{
|
|
204
|
+
iconSet: iconSet
|
|
205
|
+
}}>
|
|
206
|
+
{/* TOOD: better solution for roto ux node cuz for example in user components then its not defined but neede to use analyitcs hooks (but should be optional?) */}
|
|
207
|
+
<UXNode
|
|
208
|
+
name="Framework"
|
|
209
|
+
props={{
|
|
210
|
+
location: "",
|
|
211
|
+
}}
|
|
212
|
+
>
|
|
213
|
+
<Framework
|
|
214
|
+
settings={settings || globalThis.__xydSettings}
|
|
215
|
+
sidebarGroups={loaderData.sidebarGroups || []}
|
|
216
|
+
metadata={loaderData.metadata || {}}
|
|
217
|
+
surfaces={surfaces}
|
|
218
|
+
BannerContent={bannerContent}
|
|
219
|
+
components={{
|
|
220
|
+
Search: SearchButton,
|
|
221
|
+
Logo: FwLogo,
|
|
222
|
+
...userComponents
|
|
223
|
+
}}
|
|
224
|
+
>
|
|
225
|
+
<AtlasContext
|
|
226
|
+
value={{
|
|
227
|
+
Link: FwLink,
|
|
228
|
+
syntaxHighlight: settings?.theme?.coder?.syntaxHighlight || null,
|
|
229
|
+
baseMatch: lastMatchId || "",
|
|
230
|
+
variantToggles: atlasVariantToggles
|
|
231
|
+
}}
|
|
232
|
+
>
|
|
233
|
+
<CoderProvider lines={settings?.theme?.coder?.lines} scroll={settings?.theme?.coder?.scroll}>
|
|
234
|
+
<BaseThemeLayout>
|
|
235
|
+
<PageContext value={{ theme }}>
|
|
236
|
+
<PostLayout>
|
|
237
|
+
<Outlet />
|
|
238
|
+
</PostLayout>
|
|
239
|
+
</PageContext>
|
|
240
|
+
</BaseThemeLayout>
|
|
241
|
+
</CoderProvider>
|
|
242
|
+
</AtlasContext>
|
|
243
|
+
</Framework>
|
|
244
|
+
</UXNode>
|
|
245
|
+
|
|
246
|
+
</IconProvider>
|
|
247
|
+
</Analytics>
|
|
248
|
+
</>
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function PostLayout({ children }: { children: React.ReactNode }) {
|
|
252
|
+
const analytics = useAnalytics()
|
|
253
|
+
|
|
254
|
+
useEffect(() => {
|
|
255
|
+
// @ts-ignore
|
|
256
|
+
window.analytics = analytics
|
|
257
|
+
}, [])
|
|
258
|
+
|
|
259
|
+
return children
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function getPathname(url: string) {
|
|
263
|
+
const parsedUrl = new URL(url);
|
|
264
|
+
return parsedUrl.pathname.replace(/^\//, '');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
// TODO: move to content?
|
|
269
|
+
function mdxExport(code: string) {
|
|
270
|
+
// Create a wrapper around React.createElement that adds keys to elements in lists
|
|
271
|
+
const scope = {
|
|
272
|
+
Fragment: React.Fragment,
|
|
273
|
+
jsxs: createElementWithKeys,
|
|
274
|
+
jsx: createElementWithKeys,
|
|
275
|
+
jsxDEV: createElementWithKeys,
|
|
276
|
+
}
|
|
277
|
+
const fn = new Function(...Object.keys(scope), code)
|
|
278
|
+
|
|
279
|
+
return fn(scope)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
// // TODO: move to content?
|
|
284
|
+
function mdxContent(code: string) {
|
|
285
|
+
const content = mdxExport(code) // TODO: fix any
|
|
286
|
+
if (!mdxExport) {
|
|
287
|
+
return {}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
component: content?.default,
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const createElementWithKeys = (type: any, props: any) => {
|
|
296
|
+
// Process children to add keys to all elements
|
|
297
|
+
const processChildren = (childrenArray: any[]): any[] => {
|
|
298
|
+
return childrenArray.map((child, index) => {
|
|
299
|
+
// If the child is a React element and doesn't have a key, add one
|
|
300
|
+
if (React.isValidElement(child) && !child.key) {
|
|
301
|
+
return React.cloneElement(child, { key: `mdx-${index}` });
|
|
302
|
+
}
|
|
303
|
+
// If the child is an array, process it recursively
|
|
304
|
+
if (Array.isArray(child)) {
|
|
305
|
+
return processChildren(child);
|
|
306
|
+
}
|
|
307
|
+
return child;
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// Handle both cases: children as separate args or as props.children
|
|
312
|
+
let processedChildren;
|
|
313
|
+
|
|
314
|
+
if (props && props.children) {
|
|
315
|
+
if (Array.isArray(props.children)) {
|
|
316
|
+
processedChildren = processChildren(props.children);
|
|
317
|
+
} else if (React.isValidElement(props.children) && !props.children.key) {
|
|
318
|
+
// Single child without key
|
|
319
|
+
processedChildren = React.cloneElement(props.children, { key: 'mdx-child' });
|
|
320
|
+
} else {
|
|
321
|
+
// Single child with key or non-React element
|
|
322
|
+
processedChildren = props.children;
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
processedChildren = [];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Create the element with processed children
|
|
329
|
+
return React.createElement(type, {
|
|
330
|
+
...props,
|
|
331
|
+
children: processedChildren
|
|
332
|
+
});
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
function MemoMDXComponent(codeComponent: any) {
|
|
336
|
+
return useMemo(
|
|
337
|
+
() => codeComponent ? codeComponent : null,
|
|
338
|
+
[codeComponent]
|
|
339
|
+
)
|
|
340
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { MetaTags } from "@xyd-js/core";
|
|
2
|
+
|
|
3
|
+
export const SUPPORTED_META_TAGS: MetaTags = {
|
|
4
|
+
"robots": "name",
|
|
5
|
+
"charset": "name",
|
|
6
|
+
"viewport": "name",
|
|
7
|
+
"description": "name",
|
|
8
|
+
"keywords": "name",
|
|
9
|
+
"author": "name",
|
|
10
|
+
"googlebot": "name",
|
|
11
|
+
"google": "name",
|
|
12
|
+
"google-site-verification": "name",
|
|
13
|
+
"generator": "name",
|
|
14
|
+
"theme-color": "name",
|
|
15
|
+
"color-scheme": "name",
|
|
16
|
+
"format-detection": "name",
|
|
17
|
+
"referrer": "name",
|
|
18
|
+
"refresh": "name",
|
|
19
|
+
"rating": "name",
|
|
20
|
+
"revisit-after": "name",
|
|
21
|
+
"language": "name",
|
|
22
|
+
"copyright": "name",
|
|
23
|
+
"reply-to": "name",
|
|
24
|
+
"distribution": "name",
|
|
25
|
+
"coverage": "name",
|
|
26
|
+
"category": "name",
|
|
27
|
+
"target": "name",
|
|
28
|
+
"HandheldFriendly": "name",
|
|
29
|
+
"MobileOptimized": "name",
|
|
30
|
+
"apple-mobile-web-app-capable": "name",
|
|
31
|
+
"apple-mobile-web-app-status-bar-style": "name",
|
|
32
|
+
"apple-mobile-web-app-title": "name",
|
|
33
|
+
"application-name": "name",
|
|
34
|
+
"msapplication-TileColor": "name",
|
|
35
|
+
"msapplication-TileImage": "name",
|
|
36
|
+
"msapplication-config": "name",
|
|
37
|
+
|
|
38
|
+
"og:title": "property",
|
|
39
|
+
"og:type": "property",
|
|
40
|
+
"og:url": "property",
|
|
41
|
+
"og:image": "property",
|
|
42
|
+
"og:description": "property",
|
|
43
|
+
"og:site_name": "property",
|
|
44
|
+
"og:locale": "property",
|
|
45
|
+
"og:video": "property",
|
|
46
|
+
"og:audio": "property",
|
|
47
|
+
|
|
48
|
+
"twitter:card": "property",
|
|
49
|
+
"twitter:site": "property",
|
|
50
|
+
"twitter:creator": "property",
|
|
51
|
+
"twitter:title": "property",
|
|
52
|
+
"twitter:description": "property",
|
|
53
|
+
"twitter:image": "property",
|
|
54
|
+
"twitter:image:alt": "property",
|
|
55
|
+
"twitter:player": "property",
|
|
56
|
+
"twitter:player:width": "property",
|
|
57
|
+
"twitter:player:height": "property",
|
|
58
|
+
"twitter:app:name:iphone": "property",
|
|
59
|
+
"twitter:app:id:iphone": "property",
|
|
60
|
+
"twitter:app:url:iphone": "property",
|
|
61
|
+
|
|
62
|
+
"article:published_time": "property",
|
|
63
|
+
"article:modified_time": "property",
|
|
64
|
+
"article:expiration_time": "property",
|
|
65
|
+
"article:author": "property",
|
|
66
|
+
"article:section": "property",
|
|
67
|
+
"article:tag": "property",
|
|
68
|
+
|
|
69
|
+
"book:author": "property",
|
|
70
|
+
"book:isbn": "property",
|
|
71
|
+
"book:release_date": "property",
|
|
72
|
+
"book:tag": "property",
|
|
73
|
+
|
|
74
|
+
"profile:first_name": "property",
|
|
75
|
+
"profile:last_name": "property",
|
|
76
|
+
"profile:username": "property",
|
|
77
|
+
"profile:gender": "property",
|
|
78
|
+
|
|
79
|
+
"music:duration": "property",
|
|
80
|
+
"music:album": "property",
|
|
81
|
+
"music:album:disc": "property",
|
|
82
|
+
"music:album:track": "property",
|
|
83
|
+
"music:musician": "property",
|
|
84
|
+
"music:song": "property",
|
|
85
|
+
"music:song:disc": "property",
|
|
86
|
+
"music:song:track": "property",
|
|
87
|
+
|
|
88
|
+
"video:actor": "property",
|
|
89
|
+
"video:actor:role": "property",
|
|
90
|
+
"video:director": "property",
|
|
91
|
+
"video:writer": "property",
|
|
92
|
+
"video:duration": "property",
|
|
93
|
+
"video:release_date": "property",
|
|
94
|
+
"video:tag": "property",
|
|
95
|
+
"video:series": "property"
|
|
96
|
+
}
|