Skip to content

Commit eb69763

Browse files
authored
Add ApiDocMdx component for nested apis (#180)
1 parent 2d09476 commit eb69763

16 files changed

+1607
-1458
lines changed

.changeset/thick-cheetahs-love.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'docusaurus-theme-redoc': minor
3+
---
4+
5+
Add support for multiple apis in MDX
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React, { useMemo } from 'react';
2+
import Redoc from '../Redoc';
3+
import { useSpecData } from '../useSpecData';
4+
import { MdxProps as Props } from '../../types/common';
5+
import '../ApiSchema/styles.css';
6+
7+
const ApiDocMdx: React.FC<Props> = ({ id }: Props): JSX.Element => {
8+
const specProps = useSpecData(id);
9+
const optionsOverrides = useMemo(() => {
10+
return {
11+
theme: {
12+
// TODO: Investigate what the best breakpoints should be
13+
breakpoints: {
14+
medium: '130rem',
15+
large: '130rem',
16+
},
17+
},
18+
};
19+
}, []);
20+
21+
return <Redoc {...specProps} optionsOverrides={optionsOverrides} />;
22+
};
23+
24+
export default ApiDocMdx;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import ApiDocMdx from './ApiDocMdx';
2+
3+
export default ApiDocMdx;

packages/docusaurus-theme-redoc/src/theme/Redoc/Redoc.tsx

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import clsx from 'clsx';
33
import '../../global';
4-
import { Redoc as RedocComponent } from 'redoc';
4+
import { Redoc as RedocComponent, RedocRawOptions } from 'redoc';
55
import { SpecProps } from '../../types/common';
66
import { useSpec } from '../../utils/useSpec';
77
import { ServerStyles } from './Styles';
@@ -13,8 +13,17 @@ import './styles.css';
1313
* (c) 2022 Rohit Gohri
1414
* Released under the MIT License
1515
*/
16-
function Redoc(props: SpecProps & { className?: string }): JSX.Element {
17-
const { store, darkStore, lightStore, hasLogo } = useSpec(props);
16+
function Redoc(
17+
props: SpecProps & {
18+
className?: string;
19+
optionsOverrides?: RedocRawOptions;
20+
},
21+
): JSX.Element {
22+
const { className, optionsOverrides, ...specProps } = props;
23+
const { store, darkStore, lightStore, hasLogo } = useSpec(
24+
specProps,
25+
optionsOverrides,
26+
);
1827

1928
return (
2029
<>
@@ -23,7 +32,7 @@ function Redoc(props: SpecProps & { className?: string }): JSX.Element {
2332
className={clsx([
2433
'redocusaurus',
2534
hasLogo && 'redocusaurus-has-logo',
26-
props.className,
35+
className,
2736
])}
2837
>
2938
<RedocComponent store={store} />

packages/docusaurus-theme-redoc/src/types/common.d.ts

+17-10
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,28 @@ export interface SpecProps {
1111

1212
export type RedocProps = SpecProps;
1313

14-
export type ApiSchemaProps = Omit<
15-
ObjectDescriptionProps,
16-
'parser' | 'options' | 'schemaRef'
17-
> & {
14+
export interface MdxProps {
1815
/**
1916
* If you have multiple apis, then add a `id` field in the specs array
2017
* And pass the same here
2118
*/
2219
id?: string;
23-
pointer: ObjectDescriptionProps['schemaRef'];
24-
/**
25-
* Show the example or not
26-
*/
27-
example?: boolean;
28-
};
20+
}
21+
22+
export type ApiSchemaProps = Omit<
23+
ObjectDescriptionProps,
24+
'parser' | 'options' | 'schemaRef'
25+
> &
26+
MdxProps & {
27+
/**
28+
* Show the example or not
29+
*/
30+
example?: boolean;
31+
/**
32+
* Ref to the schema
33+
*/
34+
pointer: ObjectDescriptionProps['schemaRef'];
35+
};
2936

3037
export type ApiDocProps = {
3138
specProps: SpecProps;

packages/docusaurus-theme-redoc/src/types/modules.d.ts

+35
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,41 @@ declare module '@theme/ApiDoc' {
2727
export default ApiDoc;
2828
}
2929

30+
declare module '@theme/ApiDocMdx' {
31+
interface MdxProps {
32+
/**
33+
* If you have multiple apis, then add a `id` field in the specs array
34+
* And pass the same here
35+
*/
36+
id?: string;
37+
}
38+
39+
const ApiDocMdx: (props: MdxProps) => JSX.Element;
40+
export default ApiDocMdx;
41+
}
42+
43+
declare module '@theme/ApiSchema' {
44+
interface ApiSchemaProps {
45+
/**
46+
* If you have multiple apis, then add a `id` field in the specs array
47+
* And pass the same here
48+
*/
49+
id?: string;
50+
/**
51+
* Show the example or not
52+
*/
53+
example?: boolean;
54+
55+
/**
56+
* Ref to the schema
57+
*/
58+
pointer: string;
59+
}
60+
61+
const ApiSchema: (props: ApiSchemaProps) => JSX.Element;
62+
export default ApiSchema;
63+
}
64+
3065
declare module '@theme/useSpecData' {
3166
/**
3267
* Load redocusaurus plugin data by ID

packages/docusaurus-theme-redoc/src/utils/useSpec.ts

+33-14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
33
import useIsBrowser from '@docusaurus/useIsBrowser';
44
import { usePluginData } from '@docusaurus/useGlobalData';
55
import { useColorMode } from '@docusaurus/theme-common';
6+
import merge from 'lodash/merge';
67
import '../global';
78
import { AppStore, RedocRawOptions } from 'redoc';
89
import { SpecProps } from '../types/common';
@@ -14,7 +15,10 @@ import { GlobalData } from '../types/options';
1415
* (c) 2022 Rohit Gohri
1516
* Released under the MIT License
1617
*/
17-
export function useSpec({ spec, url }: SpecProps) {
18+
export function useSpec(
19+
{ spec, url }: SpecProps,
20+
optionsOverrides?: RedocRawOptions,
21+
) {
1822
const fullUrl = useBaseUrl(url, { absolute: true });
1923
const isBrowser = useIsBrowser();
2024
const isDarkTheme = useColorMode().colorMode === 'dark';
@@ -31,24 +35,39 @@ export function useSpec({ spec, url }: SpecProps) {
3135
: redocOptions.scrollYOffset,
3236
};
3337

34-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
35-
const lightStore = new AppStore(spec as any, fullUrl, {
36-
...redocOptions,
37-
...commonOptions,
38-
theme: lightTheme,
39-
});
40-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
41-
const darkStore = new AppStore(spec as any, fullUrl, {
42-
...redocOptions,
43-
...commonOptions,
44-
theme: darkTheme,
45-
});
38+
const lightStore = new AppStore(
39+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
40+
spec as any,
41+
fullUrl,
42+
merge(
43+
{
44+
...redocOptions,
45+
...commonOptions,
46+
theme: lightTheme,
47+
},
48+
optionsOverrides,
49+
),
50+
);
51+
52+
const darkStore = new AppStore(
53+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
54+
spec as any,
55+
fullUrl,
56+
merge(
57+
{
58+
...redocOptions,
59+
...commonOptions,
60+
theme: darkTheme,
61+
},
62+
optionsOverrides,
63+
),
64+
);
4665

4766
return {
4867
lightStore,
4968
darkStore,
5069
};
51-
}, [isBrowser, spec, fullUrl, themeOptions]);
70+
}, [isBrowser, spec, fullUrl, themeOptions, optionsOverrides]);
5271

5372
const result = useMemo(() => {
5473
return {

website/docs/guides/build-time-rendering.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Build Time Rendering
33
description: Parse the OpenAPI schema at build time and skip the loading screen
4+
sidebar_position: 3
45
---
56

67
:::caution

website/docs/guides/migrating-to-v1.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
title: Migrating to V1
3+
sidebar_position: 4
34
---
45

56
## Options Changed

website/docs/guides/multiple-apis.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
title: Showing Multiple APIs
3+
sidebar_position: 2
4+
---
5+
6+
## Nested View with MDX
7+
8+
To display multiple API docs with the Docusaurus sidebar for navigation you can use the MDX component `@theme/ApiDocMdx` along with the setting `hide_table_of_contents` for the file. For an example check the "Nested Docs Example" section in the sidebar.
9+
10+
```mdx
11+
---
12+
title: API 1 - Swagger Petstore
13+
hide_table_of_contents: true
14+
---
15+
16+
import ApiDocMdx from '@theme/ApiDocMdx';
17+
18+
<ApiDocMdx id="using-single-yaml" />
19+
```
20+
21+
The output of the above is viewable here: [Nested API 1](/docs/nested/nested-1).
22+
23+
## Full Pages with links in Dropdown
24+
25+
For a simpler solution just add all the routes in a Navbar Dropdown (see [docs](https://docusaurus.io/docs/api/themes/configuration#navbar-dropdown)). This is how the "Examples" of this website is structured.

website/docs/guides/schema-imports.mdx

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
title: Schema Imports
3+
sidebar_position: 1
34
---
45

56
import ApiSchema from '@theme/ApiSchema';

website/docs/nested/_category_.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
label: 'Nested Docs Example'
2+
position: 10

website/docs/nested/nested-1.mdx

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: API 1 - Swagger Petstore
3+
hide_table_of_contents: true
4+
---
5+
6+
import ApiDocMdx from '@theme/ApiDocMdx';
7+
8+
<ApiDocMdx id="using-single-yaml" />

website/docs/nested/nested-2.mdx

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: API 2 - Swagger Petstore
3+
hide_table_of_contents: true
4+
---
5+
6+
import ApiDocMdx from '@theme/ApiDocMdx';
7+
8+
<ApiDocMdx id="using-swagger-json" />

website/snapshots.js

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const urls = [
44
path: '/examples/using-single-yaml/',
55
},
66
{ name: 'URL Spec', path: '/examples/using-remote-url/' },
7+
{ name: 'Nested Example', path: '/docs/nested/nested-1' },
78
{ name: 'Schema Imports', path: '/docs/guides/schema-imports' },
89
];
910

0 commit comments

Comments
 (0)