zudoku 0.3.0-dev.10 → 0.3.0-dev.12
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/app/App.js +8 -6
- package/dist/app/App.js.map +1 -1
- package/dist/config/config.d.ts +5 -14
- package/dist/lib/authentication/authentication.d.ts +2 -2
- package/dist/lib/components/DevPortal.d.ts +2 -20
- package/dist/lib/components/DevPortal.js +13 -8
- package/dist/lib/components/DevPortal.js.map +1 -1
- package/dist/lib/components/Header.js +2 -2
- package/dist/lib/components/Header.js.map +1 -1
- package/dist/lib/components/Heading.d.ts +9 -4
- package/dist/lib/components/Heading.js +17 -2
- package/dist/lib/components/Heading.js.map +1 -1
- package/dist/lib/components/Layout.js +1 -1
- package/dist/lib/components/Layout.js.map +1 -1
- package/dist/lib/components/context/DevPortalProvider.d.ts +1 -1
- package/dist/lib/components/context/DevPortalProvider.js +2 -2
- package/dist/lib/components/context/DevPortalProvider.js.map +1 -1
- package/dist/lib/core/DevPortalContext.d.ts +33 -3
- package/dist/lib/core/DevPortalContext.js +4 -2
- package/dist/lib/core/DevPortalContext.js.map +1 -1
- package/dist/lib/core/plugins.d.ts +7 -4
- package/dist/lib/core/plugins.js +1 -0
- package/dist/lib/core/plugins.js.map +1 -1
- package/dist/lib/oas/graphql/index.js +1 -1
- package/dist/lib/oas/graphql/index.js.map +1 -1
- package/dist/lib/oas/parser/index.js +3 -1
- package/dist/lib/oas/parser/index.js.map +1 -1
- package/dist/lib/plugins/markdown/MdxPage.d.ts +3 -2
- package/dist/lib/plugins/markdown/MdxPage.js +5 -4
- package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
- package/dist/lib/plugins/markdown/generateRoutes.d.ts +2 -2
- package/dist/lib/plugins/markdown/generateRoutes.js +2 -2
- package/dist/lib/plugins/markdown/generateRoutes.js.map +1 -1
- package/dist/lib/plugins/markdown/index.d.ts +4 -1
- package/dist/lib/plugins/markdown/index.js +2 -2
- package/dist/lib/plugins/markdown/index.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +4 -3
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +8 -4
- package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/ParameterList.js +1 -1
- package/dist/lib/plugins/openapi/ParameterList.js.map +1 -1
- package/dist/lib/plugins/openapi/ParameterListItem.js +1 -1
- package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/{MakeRequest.d.ts → PlaygroundDialogWrapper.d.ts} +1 -1
- package/dist/lib/plugins/openapi/{MakeRequest.js → PlaygroundDialogWrapper.js} +4 -4
- package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js.map +1 -0
- package/dist/lib/plugins/openapi/RequestBodySidecarBox.js +1 -9
- package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
- package/dist/lib/plugins/openapi/ResponsesSidecarBox.js +1 -1
- package/dist/lib/plugins/openapi/ResponsesSidecarBox.js.map +1 -1
- package/dist/lib/plugins/openapi/SchemaListView.js +4 -26
- package/dist/lib/plugins/openapi/SchemaListView.js.map +1 -1
- package/dist/lib/plugins/openapi/SchemaListViewItem.d.ts +7 -0
- package/dist/lib/plugins/openapi/SchemaListViewItem.js +16 -0
- package/dist/lib/plugins/openapi/SchemaListViewItem.js.map +1 -0
- package/dist/lib/plugins/openapi/SchemaListViewItemGroup.d.ts +8 -0
- package/dist/lib/plugins/openapi/SchemaListViewItemGroup.js +17 -0
- package/dist/lib/plugins/openapi/SchemaListViewItemGroup.js.map +1 -0
- package/dist/lib/plugins/openapi/Sidecar.js +2 -2
- package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
- package/dist/lib/plugins/openapi/index.js +8 -0
- package/dist/lib/plugins/openapi/index.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.d.ts +4 -4
- package/dist/lib/plugins/openapi/playground/Playground.js +7 -11
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.d.ts +3 -0
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +10 -0
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -0
- package/dist/lib/plugins/openapi/util/prose.d.ts +1 -0
- package/dist/lib/plugins/openapi/util/prose.js +4 -0
- package/dist/lib/plugins/openapi/util/prose.js.map +1 -0
- package/dist/lib/plugins/openapi/worker/worker.js +25 -1
- package/dist/lib/plugins/openapi/worker/worker.js.map +1 -1
- package/dist/lib/ui/button-variants.d.ts +1 -1
- package/dist/lib/util/MdxComponents.js +1 -1
- package/dist/lib/util/MdxComponents.js.map +1 -1
- package/dist/lib/util/objectEntries.d.ts +4 -0
- package/dist/lib/util/objectEntries.js +2 -0
- package/dist/lib/util/objectEntries.js.map +1 -0
- package/dist/lib/util/renderIf.d.ts +1 -0
- package/dist/lib/util/renderIf.js +2 -0
- package/dist/lib/util/renderIf.js.map +1 -0
- package/dist/vite/plugin-docs.js +1 -1
- package/dist/vite/plugin-docs.js.map +1 -1
- package/lib/{Spinner-DCwVN24H.js → Spinner-CbtkR-Im.js} +3249 -3232
- package/lib/assets/{worker-BCcpCNJ7.js → worker-DGvzLstc.js} +9843 -9800
- package/lib/zudoku.components.js +174 -161
- package/lib/zudoku.openapi-worker.js +12 -12
- package/lib/zudoku.plugins.js +3722 -3712
- package/package.json +2 -1
- package/src/app/App.tsx +9 -7
- package/src/lib/authentication/authentication.ts +2 -5
- package/src/lib/components/DevPortal.tsx +12 -27
- package/src/lib/components/Header.tsx +4 -4
- package/src/lib/components/Heading.tsx +26 -7
- package/src/lib/components/Layout.tsx +1 -1
- package/src/lib/components/context/DevPortalProvider.ts +2 -2
- package/src/lib/core/DevPortalContext.ts +38 -10
- package/src/lib/core/plugins.ts +10 -5
- package/src/lib/oas/graphql/index.ts +2 -2
- package/src/lib/oas/parser/index.ts +3 -1
- package/src/lib/plugins/markdown/MdxPage.tsx +49 -32
- package/src/lib/plugins/markdown/generateRoutes.tsx +12 -2
- package/src/lib/plugins/markdown/index.tsx +8 -1
- package/src/lib/plugins/openapi/OperationList.tsx +9 -3
- package/src/lib/plugins/openapi/OperationListItem.tsx +39 -18
- package/src/lib/plugins/openapi/ParameterList.tsx +1 -1
- package/src/lib/plugins/openapi/ParameterListItem.tsx +3 -4
- package/src/lib/plugins/openapi/{MakeRequest.tsx → PlaygroundDialogWrapper.tsx} +3 -3
- package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +2 -17
- package/src/lib/plugins/openapi/ResponsesSidecarBox.tsx +3 -1
- package/src/lib/plugins/openapi/SchemaListView.tsx +15 -182
- package/src/lib/plugins/openapi/SchemaListViewItem.tsx +110 -0
- package/src/lib/plugins/openapi/SchemaListViewItemGroup.tsx +63 -0
- package/src/lib/plugins/openapi/Sidecar.tsx +2 -2
- package/src/lib/plugins/openapi/index.tsx +17 -4
- package/src/lib/plugins/openapi/playground/Playground.tsx +157 -187
- package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +34 -0
- package/src/lib/plugins/openapi/util/prose.ts +7 -0
- package/src/lib/plugins/openapi/worker/worker.ts +27 -1
- package/src/lib/util/MdxComponents.tsx +1 -1
- package/src/lib/util/objectEntries.ts +5 -0
- package/src/lib/util/renderIf.ts +4 -0
- package/dist/lib/plugins/openapi/MakeRequest.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zudoku",
|
|
3
|
-
"version": "0.3.0-dev.
|
|
3
|
+
"version": "0.3.0-dev.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
+
"@envelop/core": "5.0.1",
|
|
56
57
|
"@graphql-typed-document-node/core": "3.2.0",
|
|
57
58
|
"@lekoarts/rehype-meta-as-attributes": "3.0.1",
|
|
58
59
|
"@mdx-js/react": "3.0.1",
|
package/src/app/App.tsx
CHANGED
|
@@ -19,13 +19,15 @@ import { DevPortal } from "zudoku/components";
|
|
|
19
19
|
export default function App() {
|
|
20
20
|
return (
|
|
21
21
|
<DevPortal
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
pageTitle:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
page={{
|
|
23
|
+
logo: config.page?.logo ?? "https://cdn.zuplo.com/www/favicon.png",
|
|
24
|
+
pageTitle: "Developer Portal",
|
|
25
|
+
...config.page,
|
|
26
|
+
}}
|
|
27
|
+
metadata={{
|
|
28
|
+
favicon: "https://cdn.zuplo.com/www/favicon.png",
|
|
29
|
+
title: "%s | Developer Portal",
|
|
30
|
+
...config.metadata,
|
|
29
31
|
}}
|
|
30
32
|
navigation={config.navigation ?? []}
|
|
31
33
|
authentication={configuredAuthProvider}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
InitializationPlugin,
|
|
3
|
-
NavigationPlugin,
|
|
4
|
-
} from "../../lib/core/plugins.js";
|
|
1
|
+
import { CommonPlugin, NavigationPlugin } from "../../lib/core/plugins.js";
|
|
5
2
|
|
|
6
|
-
type AuthenticationPlugin = NavigationPlugin &
|
|
3
|
+
type AuthenticationPlugin = NavigationPlugin & CommonPlugin;
|
|
7
4
|
|
|
8
5
|
export interface AuthenticationProvider extends AuthenticationPlugin {
|
|
9
6
|
login(): Promise<void>;
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
import { MDXProvider } from "@mdx-js/react";
|
|
2
2
|
import { QueryClientProvider } from "@tanstack/react-query";
|
|
3
|
-
import { memo, Suspense, useEffect, useMemo } from "react";
|
|
3
|
+
import { Fragment, memo, Suspense, useEffect, useMemo } from "react";
|
|
4
4
|
import {
|
|
5
5
|
DevPortalContext,
|
|
6
6
|
queryClient,
|
|
7
|
-
|
|
7
|
+
ZudokuContextOptions,
|
|
8
8
|
} from "../core/DevPortalContext.js";
|
|
9
|
-
import { HelmetProvider } from "../core/helmet.js";
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
import { AuthenticationProvider } from "../authentication/authentication.js";
|
|
13
|
-
import {
|
|
14
|
-
MdxComponents,
|
|
15
|
-
type MdxComponentsType,
|
|
16
|
-
} from "../util/MdxComponents.js";
|
|
9
|
+
import { Helmet, HelmetProvider } from "../core/helmet.js";
|
|
10
|
+
import { hasHead } from "../core/plugins.js";
|
|
11
|
+
import { MdxComponents } from "../util/MdxComponents.js";
|
|
17
12
|
import {
|
|
18
13
|
ComponentsProvider,
|
|
19
14
|
DEFAULT_COMPONENTS,
|
|
20
|
-
type ComponentsContextType,
|
|
21
15
|
} from "./context/ComponentsContext.js";
|
|
22
16
|
import { DevPortalProvider } from "./context/DevPortalProvider.js";
|
|
23
17
|
import { ThemeProvider } from "./context/ThemeContext.js";
|
|
@@ -32,22 +26,7 @@ export type DevPortalPath =
|
|
|
32
26
|
| string
|
|
33
27
|
| (typeof DevPortalSystemPaths)[keyof typeof DevPortalSystemPaths];
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
meta?: Partial<{
|
|
37
|
-
headerTitle: string;
|
|
38
|
-
pageTitle: string;
|
|
39
|
-
description: string;
|
|
40
|
-
logo: string;
|
|
41
|
-
favicon: string;
|
|
42
|
-
}>;
|
|
43
|
-
authentication?: AuthenticationProvider;
|
|
44
|
-
navigation: NavigationItem[];
|
|
45
|
-
plugins?: DevPortalPlugin[];
|
|
46
|
-
mdxComponents?: MdxComponentsType;
|
|
47
|
-
overrides?: ComponentsContextType;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const DevPortalInner = (props: DevPortalProps) => {
|
|
29
|
+
const DevPortalInner = (props: ZudokuContextOptions) => {
|
|
51
30
|
const components = useMemo(
|
|
52
31
|
() => ({ ...DEFAULT_COMPONENTS, ...props.overrides }),
|
|
53
32
|
[props.overrides],
|
|
@@ -64,9 +43,15 @@ const DevPortalInner = (props: DevPortalProps) => {
|
|
|
64
43
|
void devPortalContext.initialize();
|
|
65
44
|
}, [devPortalContext]);
|
|
66
45
|
|
|
46
|
+
const heads = props.plugins
|
|
47
|
+
?.filter(hasHead)
|
|
48
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
49
|
+
.map((plugin, i) => <Fragment key={i}>{plugin.getHead?.()}</Fragment>);
|
|
50
|
+
|
|
67
51
|
return (
|
|
68
52
|
<QueryClientProvider client={queryClient}>
|
|
69
53
|
<HelmetProvider>
|
|
54
|
+
<Helmet>{heads}</Helmet>
|
|
70
55
|
<DevPortalProvider value={devPortalContext}>
|
|
71
56
|
<MDXProvider components={mdxComponents}>
|
|
72
57
|
<ThemeProvider>
|
|
@@ -9,7 +9,7 @@ import { useTheme } from "./context/ThemeContext.js";
|
|
|
9
9
|
export const Header = memo(function HeaderInner() {
|
|
10
10
|
const [isDark, toggleTheme] = useTheme();
|
|
11
11
|
const { isAuthenticated, profile, isAuthEnabled, login, logout } = useAuth();
|
|
12
|
-
const {
|
|
12
|
+
const { page } = useDevPortal();
|
|
13
13
|
|
|
14
14
|
const ThemeIcon = isDark ? MoonStarIcon : SunIcon;
|
|
15
15
|
|
|
@@ -18,11 +18,11 @@ export const Header = memo(function HeaderInner() {
|
|
|
18
18
|
<div className="max-w-screen-2xl mx-auto">
|
|
19
19
|
<div className="grid grid-cols-[calc(var(--side-nav-width))_1fr] lg:gap-12 items-center border-b border-border px-12 h-[--top-header-height]">
|
|
20
20
|
<div className="flex items-center gap-3.5">
|
|
21
|
-
{
|
|
22
|
-
<img src={
|
|
21
|
+
{page?.logo && (
|
|
22
|
+
<img src={page.logo} alt={page.pageTitle} className="h-10" />
|
|
23
23
|
)}
|
|
24
24
|
<span className="font-bold text-2xl text-foreground/85 tracking-wide">
|
|
25
|
-
{
|
|
25
|
+
{page?.pageTitle}
|
|
26
26
|
</span>
|
|
27
27
|
</div>
|
|
28
28
|
<div className="grid grid-cols-[--sidecar-grid-cols] items-center gap-8">
|
|
@@ -1,7 +1,24 @@
|
|
|
1
|
-
import { type ReactNode } from "react";
|
|
2
|
-
import { cn } from "../util/cn.js";
|
|
1
|
+
import React, { type ReactNode } from "react";
|
|
3
2
|
import { useRegisterAnchorElement } from "./context/ViewportAnchorContext.js";
|
|
4
3
|
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
5
|
+
|
|
6
|
+
const heading = cva("group relative", {
|
|
7
|
+
variants: {
|
|
8
|
+
level: {
|
|
9
|
+
6: "text-md",
|
|
10
|
+
5: "text-lg",
|
|
11
|
+
4: "text-xl",
|
|
12
|
+
3: "text-xl font-semibold",
|
|
13
|
+
2: "text-2xl font-bold",
|
|
14
|
+
1: "text-4xl font-extrabold",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
level: 1,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
5
22
|
const getComponent = (level: number) => {
|
|
6
23
|
switch (level) {
|
|
7
24
|
case 1:
|
|
@@ -21,27 +38,29 @@ const getComponent = (level: number) => {
|
|
|
21
38
|
}
|
|
22
39
|
};
|
|
23
40
|
|
|
24
|
-
export
|
|
41
|
+
export interface HeadingProps
|
|
42
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
43
|
+
VariantProps<typeof heading> {
|
|
25
44
|
children: ReactNode;
|
|
26
45
|
className?: string;
|
|
27
46
|
id?: string;
|
|
28
47
|
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
29
48
|
registerSidebarAnchor?: boolean;
|
|
30
|
-
}
|
|
49
|
+
}
|
|
31
50
|
|
|
32
|
-
export const Heading = ({
|
|
51
|
+
export const Heading: React.FC<HeadingProps> = ({
|
|
33
52
|
level,
|
|
34
53
|
children,
|
|
35
54
|
id,
|
|
36
55
|
className,
|
|
37
56
|
registerSidebarAnchor,
|
|
38
|
-
}
|
|
57
|
+
}) => {
|
|
39
58
|
const Component = getComponent(level ?? 1);
|
|
40
59
|
const { ref } = useRegisterAnchorElement();
|
|
41
60
|
|
|
42
61
|
return (
|
|
43
62
|
<Component
|
|
44
|
-
className={
|
|
63
|
+
className={heading({ className, level })}
|
|
45
64
|
ref={registerSidebarAnchor ? ref : undefined}
|
|
46
65
|
id={id}
|
|
47
66
|
>
|
|
@@ -29,7 +29,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
|
|
|
29
29
|
|
|
30
30
|
return (
|
|
31
31
|
<>
|
|
32
|
-
<Helmet titleTemplate={meta?.
|
|
32
|
+
<Helmet titleTemplate={meta?.title}>
|
|
33
33
|
<title>Home</title>
|
|
34
34
|
{meta?.description && (
|
|
35
35
|
<meta name="description" content={meta.description} />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useSuspenseQuery } from "@tanstack/react-query";
|
|
1
|
+
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
|
|
2
2
|
import { createContext, useContext } from "react";
|
|
3
3
|
import { matchPath, useLocation } from "react-router-dom";
|
|
4
4
|
import { DevPortalContext } from "../../core/DevPortalContext.js";
|
|
@@ -21,7 +21,7 @@ export const useDevPortal = () => {
|
|
|
21
21
|
|
|
22
22
|
export const useApiIdentities = () => {
|
|
23
23
|
const { getApiIdentities } = useDevPortal();
|
|
24
|
-
return
|
|
24
|
+
return useQuery({
|
|
25
25
|
queryFn: getApiIdentities,
|
|
26
26
|
queryKey: ["api-identities"],
|
|
27
27
|
});
|
|
@@ -2,16 +2,15 @@ import { QueryClient } from "@tanstack/react-query";
|
|
|
2
2
|
import { type ReactNode } from "react";
|
|
3
3
|
import { create } from "zustand";
|
|
4
4
|
import { type AuthenticationProvider } from "../authentication/authentication.js";
|
|
5
|
+
import type { ComponentsContextType } from "../components/context/ComponentsContext.js";
|
|
6
|
+
import { type DevPortalPath } from "../components/DevPortal.js";
|
|
7
|
+
import type { MdxComponentsType } from "../util/MdxComponents.js";
|
|
5
8
|
import {
|
|
6
|
-
type
|
|
7
|
-
type DevPortalProps,
|
|
8
|
-
} from "../components/DevPortal.js";
|
|
9
|
-
import {
|
|
9
|
+
type DevPortalPlugin,
|
|
10
10
|
isApiIdentityPlugin,
|
|
11
11
|
isNavigationPlugin,
|
|
12
|
-
needsInitialization,
|
|
13
|
-
type DevPortalPlugin,
|
|
14
12
|
type NavigationPlugin,
|
|
13
|
+
needsInitialization,
|
|
15
14
|
} from "./plugins.js";
|
|
16
15
|
|
|
17
16
|
export interface ApiIdentity {
|
|
@@ -66,21 +65,50 @@ export const useRoutingState = create<RoutingState>(() => ({}));
|
|
|
66
65
|
export type ApiKeyCache = "api-keys";
|
|
67
66
|
export type DevPortalCacheKey = ApiKeyCache | string;
|
|
68
67
|
|
|
68
|
+
export type ZudokuContextMetadataOptions = Partial<{
|
|
69
|
+
title: string;
|
|
70
|
+
description: string;
|
|
71
|
+
logo: string;
|
|
72
|
+
favicon: string;
|
|
73
|
+
generator: string;
|
|
74
|
+
applicationName: string;
|
|
75
|
+
referrer: string;
|
|
76
|
+
keywords: string[];
|
|
77
|
+
authors: string[];
|
|
78
|
+
creator: string;
|
|
79
|
+
publisher: string;
|
|
80
|
+
}>;
|
|
81
|
+
export type ZudokuContextPageOptions = Partial<{
|
|
82
|
+
pageTitle?: string;
|
|
83
|
+
logo?: string;
|
|
84
|
+
}>;
|
|
85
|
+
export type ZudokuContextOptions = {
|
|
86
|
+
metadata?: ZudokuContextMetadataOptions;
|
|
87
|
+
page?: ZudokuContextPageOptions;
|
|
88
|
+
authentication?: AuthenticationProvider;
|
|
89
|
+
navigation: NavigationItem[];
|
|
90
|
+
plugins?: DevPortalPlugin[];
|
|
91
|
+
mdxComponents?: MdxComponentsType;
|
|
92
|
+
overrides?: ComponentsContextType;
|
|
93
|
+
};
|
|
94
|
+
|
|
69
95
|
export class DevPortalContext {
|
|
70
96
|
private plugins: DevPortalPlugin[] = [];
|
|
71
97
|
private navigationPlugins: NavigationPlugin[];
|
|
72
98
|
|
|
73
99
|
public navigation: NavigationItem[];
|
|
74
|
-
public meta:
|
|
100
|
+
public meta: ZudokuContextOptions["metadata"];
|
|
101
|
+
public page: ZudokuContextOptions["page"];
|
|
75
102
|
public authentication?: AuthenticationProvider;
|
|
76
103
|
public state: typeof useRoutingState;
|
|
77
104
|
|
|
78
|
-
constructor(config:
|
|
105
|
+
constructor(config: ZudokuContextOptions) {
|
|
79
106
|
this.plugins = config.plugins ?? [];
|
|
80
107
|
this.navigation = config.navigation;
|
|
81
108
|
this.navigationPlugins = this.plugins.filter(isNavigationPlugin);
|
|
82
109
|
this.authentication = config.authentication;
|
|
83
|
-
this.meta = config.
|
|
110
|
+
this.meta = config.metadata;
|
|
111
|
+
this.page = config.page;
|
|
84
112
|
this.state = useRoutingState;
|
|
85
113
|
}
|
|
86
114
|
|
|
@@ -88,7 +116,7 @@ export class DevPortalContext {
|
|
|
88
116
|
await Promise.all([
|
|
89
117
|
this.plugins
|
|
90
118
|
.filter(needsInitialization)
|
|
91
|
-
.map((plugin) => plugin.initialize(this)),
|
|
119
|
+
.map((plugin) => plugin.initialize?.(this)),
|
|
92
120
|
]);
|
|
93
121
|
};
|
|
94
122
|
|
package/src/lib/core/plugins.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
1
2
|
import { type RouteObject } from "react-router-dom";
|
|
2
3
|
import {
|
|
3
4
|
DevPortalContext,
|
|
@@ -10,9 +11,9 @@ export type PluginNavigationCategory = {
|
|
|
10
11
|
} & NavigationCategory;
|
|
11
12
|
|
|
12
13
|
export type DevPortalPlugin =
|
|
14
|
+
| CommonPlugin
|
|
13
15
|
| NavigationPlugin
|
|
14
|
-
| ApiIdentityPlugin
|
|
15
|
-
| InitializationPlugin;
|
|
16
|
+
| ApiIdentityPlugin;
|
|
16
17
|
|
|
17
18
|
export interface NavigationPlugin {
|
|
18
19
|
getRoutes: () => RouteObject[];
|
|
@@ -23,8 +24,9 @@ export interface ApiIdentityPlugin {
|
|
|
23
24
|
getIdentities: (context: DevPortalContext) => Promise<ApiIdentity[]>;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
export interface
|
|
27
|
-
initialize
|
|
27
|
+
export interface CommonPlugin {
|
|
28
|
+
initialize?: (context: DevPortalContext) => Promise<void> | void;
|
|
29
|
+
getHead?: () => ReactElement | undefined;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
export const isNavigationPlugin = (
|
|
@@ -34,9 +36,12 @@ export const isNavigationPlugin = (
|
|
|
34
36
|
|
|
35
37
|
export const needsInitialization = (
|
|
36
38
|
obj: DevPortalPlugin,
|
|
37
|
-
): obj is
|
|
39
|
+
): obj is CommonPlugin =>
|
|
38
40
|
"initialize" in obj && typeof obj.initialize === "function";
|
|
39
41
|
|
|
42
|
+
export const hasHead = (obj: DevPortalPlugin): obj is CommonPlugin =>
|
|
43
|
+
"getHead" in obj && typeof obj.getHead === "function";
|
|
44
|
+
|
|
40
45
|
export const isApiIdentityPlugin = (
|
|
41
46
|
obj: DevPortalPlugin,
|
|
42
47
|
): obj is ApiIdentityPlugin =>
|
|
@@ -45,7 +45,7 @@ export const slugifyOperation = (operation: OperationLike, tag?: string) => {
|
|
|
45
45
|
);
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
const cache = new LRUCache<string, OpenAPIDocument
|
|
48
|
+
const cache = new LRUCache<string, Promise<OpenAPIDocument>>({
|
|
49
49
|
ttl: 60 * 10 * 1000,
|
|
50
50
|
ttlAutopurge: true,
|
|
51
51
|
});
|
|
@@ -384,7 +384,7 @@ const loadOpenAPISchema = async (input: NonNullable<unknown>) => {
|
|
|
384
384
|
return cache.get(hash)!;
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
-
const schema =
|
|
387
|
+
const schema = validate(input);
|
|
388
388
|
|
|
389
389
|
cache.set(hash, schema);
|
|
390
390
|
|
|
@@ -54,7 +54,9 @@ const parseSchemaInput = async (
|
|
|
54
54
|
return JSON.parse(schemaInput);
|
|
55
55
|
}
|
|
56
56
|
if (schemaInput.includes("://")) {
|
|
57
|
-
const response = await fetch(schemaInput
|
|
57
|
+
const response = await fetch(schemaInput, {
|
|
58
|
+
cache: "force-cache",
|
|
59
|
+
});
|
|
58
60
|
return (await response.json()) as JSONSchema;
|
|
59
61
|
}
|
|
60
62
|
const yaml = await import("yaml");
|
|
@@ -12,7 +12,7 @@ import { cn } from "../../util/cn.js";
|
|
|
12
12
|
import slugify from "../../util/slugify.js";
|
|
13
13
|
import { traverseNavigation } from "../../util/traverseNavigation.js";
|
|
14
14
|
import { Toc } from "./Toc.js";
|
|
15
|
-
import
|
|
15
|
+
import { MarkdownPluginDefaultOptions, MDXImport } from "./index.js";
|
|
16
16
|
|
|
17
17
|
const MarkdownHeadings = {
|
|
18
18
|
h2: ({ children, id }) => (
|
|
@@ -31,10 +31,12 @@ const MarkdownHeadings = {
|
|
|
31
31
|
export const MdxPage = ({
|
|
32
32
|
mdxComponent: MdxComponent,
|
|
33
33
|
frontmatter = {},
|
|
34
|
+
defaultOptions,
|
|
34
35
|
tableOfContents,
|
|
35
36
|
}: PropsWithChildren<
|
|
36
37
|
Omit<MDXImport, "default"> & {
|
|
37
38
|
mdxComponent: MDXImport["default"];
|
|
39
|
+
defaultOptions?: MarkdownPluginDefaultOptions;
|
|
38
40
|
}
|
|
39
41
|
>) => {
|
|
40
42
|
const navItem = useTopNavigationItem();
|
|
@@ -50,10 +52,11 @@ export const MdxPage = ({
|
|
|
50
52
|
|
|
51
53
|
const title = frontmatter.title;
|
|
52
54
|
const category = frontmatter.category ?? categoryTitle;
|
|
53
|
-
const hideToc = frontmatter.toc === false;
|
|
54
|
-
|
|
55
|
+
const hideToc = frontmatter.toc === false || defaultOptions?.toc === false;
|
|
55
56
|
const pageTitle =
|
|
56
57
|
tableOfContents.find((item) => item.depth === 1)?.value ?? title;
|
|
58
|
+
const hidePager =
|
|
59
|
+
frontmatter.disablePager ?? defaultOptions?.disablePager ?? false;
|
|
57
60
|
|
|
58
61
|
const tocEntries =
|
|
59
62
|
tableOfContents.find((item) => item.depth === 1)?.children ??
|
|
@@ -112,35 +115,49 @@ export const MdxPage = ({
|
|
|
112
115
|
<MdxComponent
|
|
113
116
|
components={{ ...useMDXComponents(), ...MarkdownHeadings }}
|
|
114
117
|
/>
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
118
|
+
{!hidePager && (
|
|
119
|
+
<>
|
|
120
|
+
<hr />
|
|
121
|
+
<div className="not-prose flex items-center justify-between gap-8">
|
|
122
|
+
{prev.path ? (
|
|
123
|
+
<Link
|
|
124
|
+
to={prev.path}
|
|
125
|
+
className="flex flex-col items-stretch gap-2 flex-1 truncate border border-border rounded px-6 py-4 text-start hover:border-primary/85 transition shadow-sm hover:shadow-md"
|
|
126
|
+
title={
|
|
127
|
+
typeof prev.label === "string" ? prev.label : undefined
|
|
128
|
+
}
|
|
129
|
+
>
|
|
130
|
+
<div className="text-sm text-muted-foreground">
|
|
131
|
+
← Previous page
|
|
132
|
+
</div>
|
|
133
|
+
<div className="text-lg text-primary truncate">
|
|
134
|
+
{prev.label}
|
|
135
|
+
</div>
|
|
136
|
+
</Link>
|
|
137
|
+
) : (
|
|
138
|
+
<div className="flex-1" />
|
|
139
|
+
)}
|
|
140
|
+
{next.path ? (
|
|
141
|
+
<Link
|
|
142
|
+
to={next.path}
|
|
143
|
+
className="flex flex-col items-stretch gap-2 flex-1 truncate border border-border rounded px-6 py-4 text-end hover:border-primary/85 transition shadow-sm hover:shadow-md"
|
|
144
|
+
title={
|
|
145
|
+
typeof next.label === "string" ? next.label : undefined
|
|
146
|
+
}
|
|
147
|
+
>
|
|
148
|
+
<div className="text-sm text-muted-foreground">
|
|
149
|
+
Next page →
|
|
150
|
+
</div>
|
|
151
|
+
<div className="text-lg text-primary truncate">
|
|
152
|
+
{next.label}
|
|
153
|
+
</div>
|
|
154
|
+
</Link>
|
|
155
|
+
) : (
|
|
156
|
+
<div className="flex-1" />
|
|
157
|
+
)}
|
|
158
|
+
</div>
|
|
159
|
+
</>
|
|
160
|
+
)}
|
|
144
161
|
</div>
|
|
145
162
|
<div className="hidden xl:block">
|
|
146
163
|
{showToc && <Toc entries={tocEntries} />}
|
|
@@ -3,10 +3,14 @@ import { isPathItem } from "../../components/navigation/util.js";
|
|
|
3
3
|
import { Navigate, type RouteObject } from "../../core/router.js";
|
|
4
4
|
import { traverseNavigation } from "../../util/traverseNavigation.js";
|
|
5
5
|
import { MdxPage } from "./MdxPage.js";
|
|
6
|
-
import
|
|
6
|
+
import {
|
|
7
|
+
MarkdownPluginDefaultOptions,
|
|
8
|
+
MarkdownPluginOptions,
|
|
9
|
+
} from "./index.js";
|
|
7
10
|
|
|
8
11
|
export const generateRoutes = (
|
|
9
12
|
markdownFiles: MarkdownPluginOptions["markdownFiles"],
|
|
13
|
+
defaultOptions?: MarkdownPluginDefaultOptions,
|
|
10
14
|
): RouteObject[] => {
|
|
11
15
|
const routes = Object.entries(markdownFiles).flatMap(
|
|
12
16
|
([file, importPromise]) => {
|
|
@@ -28,7 +32,13 @@ export const generateRoutes = (
|
|
|
28
32
|
const { default: Component, ...props } = await importPromise();
|
|
29
33
|
|
|
30
34
|
return {
|
|
31
|
-
element:
|
|
35
|
+
element: (
|
|
36
|
+
<MdxPage
|
|
37
|
+
mdxComponent={Component}
|
|
38
|
+
{...props}
|
|
39
|
+
defaultOptions={defaultOptions}
|
|
40
|
+
/>
|
|
41
|
+
),
|
|
32
42
|
};
|
|
33
43
|
},
|
|
34
44
|
} satisfies RouteObject;
|
|
@@ -5,13 +5,19 @@ import { generateRoutes } from "./generateRoutes.js";
|
|
|
5
5
|
|
|
6
6
|
export type MarkdownPluginOptions = {
|
|
7
7
|
markdownFiles: Record<string, () => Promise<MDXImport>>;
|
|
8
|
+
defaultOptions?: MarkdownPluginDefaultOptions;
|
|
8
9
|
};
|
|
10
|
+
export type MarkdownPluginDefaultOptions = Pick<
|
|
11
|
+
Frontmatter,
|
|
12
|
+
"toc" | "disablePager"
|
|
13
|
+
>;
|
|
9
14
|
|
|
10
15
|
export type Frontmatter = {
|
|
11
16
|
title?: string;
|
|
12
17
|
description?: string;
|
|
13
18
|
category?: string;
|
|
14
19
|
toc?: boolean;
|
|
20
|
+
disablePager?: boolean;
|
|
15
21
|
};
|
|
16
22
|
|
|
17
23
|
export type MDXImport = {
|
|
@@ -22,10 +28,11 @@ export type MDXImport = {
|
|
|
22
28
|
|
|
23
29
|
export const markdownPlugin = ({
|
|
24
30
|
markdownFiles,
|
|
31
|
+
defaultOptions,
|
|
25
32
|
}: MarkdownPluginOptions): DevPortalPlugin => {
|
|
26
33
|
return {
|
|
27
34
|
getRoutes() {
|
|
28
|
-
return generateRoutes(markdownFiles);
|
|
35
|
+
return generateRoutes(markdownFiles, defaultOptions);
|
|
29
36
|
},
|
|
30
37
|
};
|
|
31
38
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { ResultOf } from "@graphql-typed-document-node/core";
|
|
2
2
|
import { CategoryHeading } from "../../components/CategoryHeading.js";
|
|
3
3
|
import { Heading } from "../../components/Heading.js";
|
|
4
|
-
import { Markdown
|
|
4
|
+
import { Markdown } from "../../components/Markdown.js";
|
|
5
5
|
import { cn } from "../../util/cn.js";
|
|
6
6
|
import { OperationListItem } from "./OperationListItem.js";
|
|
7
7
|
import { graphql } from "./graphql/index.js";
|
|
8
8
|
import { useOasConfig } from "./index.js";
|
|
9
|
+
import { SchemaProseClasses } from "./util/prose.js";
|
|
9
10
|
import { useQuery } from "./util/urql.js";
|
|
10
11
|
|
|
11
12
|
export const OperationsFragment = graphql(/* GraphQL */ `
|
|
@@ -94,7 +95,12 @@ export const OperationList = () => {
|
|
|
94
95
|
|
|
95
96
|
return (
|
|
96
97
|
<div className="pt-[--padding-content-top]">
|
|
97
|
-
<div
|
|
98
|
+
<div
|
|
99
|
+
className={cn(
|
|
100
|
+
SchemaProseClasses,
|
|
101
|
+
"mb-16 max-w-full prose-img:max-w-prose",
|
|
102
|
+
)}
|
|
103
|
+
>
|
|
98
104
|
<CategoryHeading>Overview</CategoryHeading>
|
|
99
105
|
<Heading level={1} id="description" registerSidebarAnchor>
|
|
100
106
|
{result.data.schema.title}
|
|
@@ -108,7 +114,7 @@ export const OperationList = () => {
|
|
|
108
114
|
{tag.name && <CategoryHeading>{tag.name}</CategoryHeading>}
|
|
109
115
|
{tag.description && (
|
|
110
116
|
<Markdown
|
|
111
|
-
className={`${
|
|
117
|
+
className={`${SchemaProseClasses} mt-2 mb-12`}
|
|
112
118
|
content={tag.description}
|
|
113
119
|
/>
|
|
114
120
|
)}
|