diff --git a/.changeset/pretty-apples-relate.md b/.changeset/pretty-apples-relate.md new file mode 100644 index 00000000..8607bde5 --- /dev/null +++ b/.changeset/pretty-apples-relate.md @@ -0,0 +1,5 @@ +--- +'docusaurus-theme-redoc': minor +--- + +Add ApiOperation component to import and display the definitions of API operations within your Docusaurus docs diff --git a/packages/docusaurus-theme-redoc/src/theme/ApiOperation/ApiOperation.tsx b/packages/docusaurus-theme-redoc/src/theme/ApiOperation/ApiOperation.tsx new file mode 100644 index 00000000..4b5ee76c --- /dev/null +++ b/packages/docusaurus-theme-redoc/src/theme/ApiOperation/ApiOperation.tsx @@ -0,0 +1,63 @@ +import React, { useEffect } from 'react'; +import clsx from 'clsx'; +import { ThemeProvider } from 'styled-components'; +import '../../global'; +import { Operation, OperationModel, Section } from 'redoc'; +import { useSpec } from '../../utils/useSpec'; +import { useSpecData } from '../useSpecData'; +import type { ApiOperationProps as Props } from '../../types/common'; +import '../Redoc/styles.css'; +import './styles.css'; + +const ApiOperation: React.FC = ({ + id, + example, + pointer, + ...rest +}: Props): JSX.Element => { + const specProps = useSpecData(id); + const { store } = useSpec(specProps); + + // The # at the start is not included + const operationPointer = + pointer.charAt(0) === '#' ? pointer.substring(1) : pointer; + + // The menu contains a flattened list of spec items for easy searching + const model = store.menu.flatItems.find( + (item) => + item instanceof OperationModel && item.pointer === operationPointer, + ) as OperationModel | undefined; + + if (!model) { + throw new Error(`Failed to resolve reference "${pointer}"`); + } + + useEffect(() => { + /** + * @see https://github.com/Redocly/redoc/blob/823be24b313c3a2445df7e0801a0cc79c20bacd1/src/services/MenuStore.ts#L273-L276 + */ + store.menu.dispose(); + }, [store]); + + return ( + +
+
+ +
+
+
+ ); +}; + +ApiOperation.defaultProps = { + example: false, +}; + +export default ApiOperation; diff --git a/packages/docusaurus-theme-redoc/src/theme/ApiOperation/index.ts b/packages/docusaurus-theme-redoc/src/theme/ApiOperation/index.ts new file mode 100644 index 00000000..f88f69ad --- /dev/null +++ b/packages/docusaurus-theme-redoc/src/theme/ApiOperation/index.ts @@ -0,0 +1,3 @@ +import ApiOperation from './ApiOperation'; + +export default ApiOperation; diff --git a/packages/docusaurus-theme-redoc/src/theme/ApiOperation/styles.css b/packages/docusaurus-theme-redoc/src/theme/ApiOperation/styles.css new file mode 100644 index 00000000..2a76d254 --- /dev/null +++ b/packages/docusaurus-theme-redoc/src/theme/ApiOperation/styles.css @@ -0,0 +1,14 @@ +.redocusaurus-operation.hide-example > div > div > div:nth-child(2) { + display: none; +} +.redocusaurus-operation.hide-example > div > div > div:nth-child(1) { + width: 100%; +} + +.redocusaurus-operation h3 { + color: var(--ifm-color-white); +} + +.redocusaurus-operation > div:last-child { + min-height: 0; +} diff --git a/packages/docusaurus-theme-redoc/src/types/common.ts b/packages/docusaurus-theme-redoc/src/types/common.ts index eb52549b..8a9059d2 100644 --- a/packages/docusaurus-theme-redoc/src/types/common.ts +++ b/packages/docusaurus-theme-redoc/src/types/common.ts @@ -37,6 +37,18 @@ export type ApiSchemaProps = Omit< pointer: ObjectDescriptionProps['schemaRef']; }; +export type ApiOperationProps = MdxProps & { + /** + * Show the example or not + */ + example?: boolean; + + /** + * Ref to the operation + */ + pointer: string; +}; + export type ApiDocProps = { specProps: SpecProps; layoutProps?: Omit; diff --git a/packages/docusaurus-theme-redoc/src/types/modules.ts b/packages/docusaurus-theme-redoc/src/types/modules.ts index 4108f1f1..944fc79e 100644 --- a/packages/docusaurus-theme-redoc/src/types/modules.ts +++ b/packages/docusaurus-theme-redoc/src/types/modules.ts @@ -71,6 +71,29 @@ declare module '@theme/ApiSchema' { export default ApiSchema; } +declare module '@theme/ApiOperation' { + interface ApiOperationProps { + /** + * If you have multiple apis, then add a `id` field in the specs array + * And pass the same here + */ + id?: string; + + /** + * Show the example or not + */ + example?: boolean; + + /** + * Ref to the operation + */ + pointer: string; + } + + const ApiOperation: (props: ApiOperationProps) => JSX.Element; + export default ApiOperation; +} + declare module '@theme/useSpecData' { /** * Load redocusaurus plugin data by ID diff --git a/website/docs/guides/build-time-rendering.md b/website/docs/guides/build-time-rendering.md index 8dff201a..e6516dba 100644 --- a/website/docs/guides/build-time-rendering.md +++ b/website/docs/guides/build-time-rendering.md @@ -1,7 +1,7 @@ --- title: Build Time Rendering description: Parse the OpenAPI schema at build time and skip the loading screen -sidebar_position: 3 +sidebar_position: 4 --- :::warning diff --git a/website/docs/guides/migrating-to-v1.md b/website/docs/guides/migrating-to-v1.md index d3380fc5..68046436 100644 --- a/website/docs/guides/migrating-to-v1.md +++ b/website/docs/guides/migrating-to-v1.md @@ -1,6 +1,6 @@ --- title: Migrating to V1 -sidebar_position: 4 +sidebar_position: 5 --- ## Options Changed diff --git a/website/docs/guides/multiple-apis.md b/website/docs/guides/multiple-apis.md index b872f571..29e3224e 100644 --- a/website/docs/guides/multiple-apis.md +++ b/website/docs/guides/multiple-apis.md @@ -1,6 +1,6 @@ --- title: Showing Multiple APIs -sidebar_position: 2 +sidebar_position: 3 --- ## Nested View with MDX diff --git a/website/docs/guides/operation-imports.mdx b/website/docs/guides/operation-imports.mdx new file mode 100644 index 00000000..297d34f5 --- /dev/null +++ b/website/docs/guides/operation-imports.mdx @@ -0,0 +1,96 @@ +--- +title: Operation Imports +sidebar_position: 2 +--- + +import ApiOperation from '@theme/ApiOperation'; + +# Operation Imports + +You can import operation definitions from your API schema and render them in your Docusaurus Docs. You'll need to create an `.mdx` file and import the React Component. Read more [here about MDX in Docusaurus](https://docusaurus.io/docs/markdown-features/react). + +# Import Operation Model in Docs + +The `pointer` prop is passed on to [Redoc](https://redoc.ly/docs/resources/ref-guide/#pointer). + +Note that `/` is escaped as `~1`. + +```tsx +import ApiOperation from '@theme/ApiOperation'; + +; +``` + +### Results + + + +## Import Operation Model (with example) in Docs + +```tsx +import ApiOperation from '@theme/ApiOperation'; + +; +``` + +### Results + + + +## Importing Operation Model with multiple OpenAPI schemas + +If you have multiple APIs loaded with redocusaurus, then it is recommended to add `id`s to the config so that you can refer them when loading operation models. + +```js title="docusaurus.config.js" +const config = { + presets: [ + '@docusaurus/preset-classic', + [ + 'redocusaurus', + { + specs: [ + { + id: 'using-single-yaml', + spec: 'openapi/single-file/openapi.yaml', + route: '/examples/using-single-yaml/', + }, + { + id: 'using-remote-url', + spec: 'https://redocly.github.io/redoc/openapi.yaml', + route: '/examples/using-remote-url/', + }, + ], + theme: { + /** + * Highlight color for docs + */ + primaryColor: '#1890ff', + /** + * Options to pass to redoc + * @see https://github.com/redocly/redoc#redoc-options-object + */ + options: { disableSearch: true }, + }, + }, + ], + ], + title: 'Redocusaurus', +}; +``` + +```tsx +import ApiOperation from '@theme/ApiOperation'; + + + +``` + +### Results + +#### For ID `id="using-single-yaml"` + + + +#### For ID `id="using-remote-url"` + +