From cf354d0edf0b601900236dccfbabc32d04799b94 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Wed, 11 Sep 2024 15:45:00 +1200 Subject: [PATCH 1/2] Add support for custom sidebar DocItem generators supporting customisation Similarly to markdownGenerators, the optional createDocItem() method in sidebarOptions allows users to configure a custom generator function for sidebar items. This allows customisation of class names or custom props, for example, based on each item. --- README.md | 15 ++-- .../src/options.ts | 1 + .../src/sidebars/index.ts | 86 ++++++++++--------- .../src/types.ts | 7 ++ 4 files changed, 62 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 34e010647..d750dab56 100644 --- a/README.md +++ b/README.md @@ -174,13 +174,14 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following `sidebarOptions` can be configured with the following options: -| Name | Type | Default | Description | -| -------------------- | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag` and `tagGroup`. | -| `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag.

The supported options are as follows:

`tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description.

`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios).

`none`: Does not create pages for categories, only groups that can be expanded/collapsed. | -| `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. | -| `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. | -| `customProps` | `object` | `null` | Additional props for customizing a sidebar item. | +| Name | Type | Default | Description | +| -------------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag` and `tagGroup`. | +| `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag.

The supported options are as follows:

`tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description.

`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios).

`none`: Does not create pages for categories, only groups that can be expanded/collapsed. | +| `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. | +| `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. | +| `customProps` | `object` | `null` | Additional props for customizing a sidebar item. | +| `createDocItem` | `function` | `null` | Optional: Returns a `SidebarItemDoc` object, which allows for customisation of sidebar items. For example, add a class name in certain conditions, or add `customProps` to provide custom rendering. | > You may optionally configure a `sidebarOptions`. In doing so, an individual `sidebar.js` slice with the configured options will be generated within the respective `outputDir`. diff --git a/packages/docusaurus-plugin-openapi-docs/src/options.ts b/packages/docusaurus-plugin-openapi-docs/src/options.ts index e3f11ddec..98821ca0a 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/options.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/options.ts @@ -13,6 +13,7 @@ const sidebarOptions = Joi.object({ customProps: Joi.object(), sidebarCollapsible: Joi.boolean(), sidebarCollapsed: Joi.boolean(), + createDocItem: Joi.function(), }); const markdownGenerators = Joi.object({ diff --git a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts index def167105..1c31a7452 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts @@ -12,7 +12,6 @@ import { ProcessedSidebar, SidebarItemCategory, SidebarItemCategoryLinkConfig, - SidebarItemDoc, } from "@docusaurus/plugin-content-docs/src/sidebars/types"; import { posixPath } from "@docusaurus/utils"; import clsx from "clsx"; @@ -27,6 +26,7 @@ import type { ApiMetadata, InfoPageMetadata, SchemaPageMetadata, + ApiDocItemGenerator, } from "../types"; function isApiItem(item: ApiMetadata): item is ApiMetadata { @@ -41,6 +41,37 @@ function isSchemaItem(item: ApiMetadata): item is ApiMetadata { return item.type === "schema"; } +const createDocItem: ApiDocItemGenerator = ( + item, + { sidebarOptions: { customProps }, basePath } +) => { + const sidebar_label = item.frontMatter.sidebar_label; + const title = item.title; + const id = item.type === "schema" ? `schemas/${item.id}` : item.id; + const className = + item.type === "api" + ? clsx( + { + "menu__list-item--deprecated": item.api.deprecated, + "api-method": !!item.api.method, + }, + item.api.method + ) + : clsx( + { + "menu__list-item--deprecated": item.schema.deprecated, + }, + "schema" + ); + return { + type: "doc" as const, + id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`, + label: (sidebar_label as string) ?? title ?? id, + customProps: customProps, + className: className ? className : undefined, + }; +}; + function groupByTags( items: ApiMetadata[], sidebarOptions: SidebarOptions, @@ -53,12 +84,8 @@ function groupByTags( // Remove trailing slash before proceeding outputDir = outputDir.replace(/\/$/, ""); - const { - sidebarCollapsed, - sidebarCollapsible, - customProps, - categoryLinkSource, - } = sidebarOptions; + const { sidebarCollapsed, sidebarCollapsible, categoryLinkSource } = + sidebarOptions; const apiItems = items.filter(isApiItem) as ApiPageMetadata[]; const infoItems = items.filter(isInfoItem) as InfoPageMetadata[]; @@ -101,35 +128,12 @@ function groupByTags( const basePath = docPath ? outputDir.split(docPath!)[1].replace(/^\/+/g, "") : outputDir.slice(outputDir.indexOf("/", 1)).replace(/^\/+/g, ""); - function createDocItem( - item: ApiPageMetadata | SchemaPageMetadata - ): SidebarItemDoc { - const sidebar_label = item.frontMatter.sidebar_label; - const title = item.title; - const id = item.type === "schema" ? `schemas/${item.id}` : item.id; - const className = - item.type === "api" - ? clsx( - { - "menu__list-item--deprecated": item.api.deprecated, - "api-method": !!item.api.method, - }, - item.api.method - ) - : clsx( - { - "menu__list-item--deprecated": item.schema.deprecated, - }, - "schema" - ); - return { - type: "doc" as const, - id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`, - label: (sidebar_label as string) ?? title ?? id, - customProps: customProps, - className: className ? className : undefined, - }; - } + + const createDocItemFnContext = { + sidebarOptions, + basePath, + }; + const createDocItemFn = sidebarOptions.createDocItem ?? createDocItem; let rootIntroDoc = undefined; if (infoItems.length === 1) { @@ -208,7 +212,9 @@ function groupByTags( link: linkConfig, collapsible: sidebarCollapsible, collapsed: sidebarCollapsed, - items: [...taggedSchemaItems, ...taggedApiItems].map(createDocItem), + items: [...taggedSchemaItems, ...taggedApiItems].map((item) => + createDocItemFn(item, createDocItemFnContext) + ), }; }) .filter((item) => item.items.length > 0); // Filter out any categories with no items. @@ -216,7 +222,7 @@ function groupByTags( // Handle items with no tag const untaggedItems = apiItems .filter(({ api }) => api.tags === undefined || api.tags.length === 0) - .map(createDocItem); + .map((item) => createDocItemFn(item, createDocItemFnContext)); let untagged: SidebarItemCategory[] = []; if (untaggedItems.length > 0) { untagged = [ @@ -227,7 +233,7 @@ function groupByTags( collapsed: sidebarCollapsed!, items: apiItems .filter(({ api }) => api.tags === undefined || api.tags.length === 0) - .map(createDocItem), + .map((item) => createDocItemFn(item, createDocItemFnContext)), }, ]; } @@ -242,7 +248,7 @@ function groupByTags( collapsed: sidebarCollapsed!, items: schemaItems .filter(({ schema }) => !schema["x-tags"]) - .map(createDocItem), + .map((item) => createDocItemFn(item, createDocItemFnContext)), }, ]; } diff --git a/packages/docusaurus-plugin-openapi-docs/src/types.ts b/packages/docusaurus-plugin-openapi-docs/src/types.ts index 8eee4a0e1..1ab785822 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/types.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/types.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. * ========================================================================== */ +import { SidebarItemDoc } from "@docusaurus/plugin-content-docs/src/sidebars/types"; import type Request from "postman-collection"; import { @@ -57,12 +58,18 @@ export interface MarkdownGenerator { createSchemaPageMD?: (pageData: SchemaPageMetadata) => string; } +export type ApiDocItemGenerator = ( + item: ApiPageMetadata | SchemaPageMetadata, + context: { sidebarOptions: SidebarOptions; basePath: string } +) => SidebarItemDoc; + export interface SidebarOptions { groupPathsBy?: string; categoryLinkSource?: "info" | "tag" | "auto"; customProps?: { [key: string]: unknown }; sidebarCollapsible?: boolean; sidebarCollapsed?: boolean; + createDocItem?: ApiDocItemGenerator; } export interface APIVersionOptions { From ee9790c9a295490c90eac3ed2c7bdfaf00b9b310 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Fri, 13 Sep 2024 09:47:05 +1200 Subject: [PATCH 2/2] Move createDocItem() into a `sidebarGenerators` object --- README.md | 11 ++++++++- .../docusaurus-plugin-openapi-docs/README.md | 24 +++++++++++++------ .../src/options.ts | 6 ++++- .../src/sidebars/index.ts | 3 ++- .../src/types.ts | 6 ++++- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d750dab56..0b05bbc7c 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,8 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following | `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. | | `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. | | `customProps` | `object` | `null` | Additional props for customizing a sidebar item. | -| `createDocItem` | `function` | `null` | Optional: Returns a `SidebarItemDoc` object, which allows for customisation of sidebar items. For example, add a class name in certain conditions, or add `customProps` to provide custom rendering. | +| `sidebarGenerators` | `object` | `null` | Optional: Customize sidebar rendering with callback functions. | +| `createDocItem` | `function` | `null` | Optional: Returns a `SidebarItemDoc` object, which allows for customisation of sidebar items. For example, add a class name in certain conditions, or add `customProps` to provide custom rendering. See below for a list of supported operations. | > You may optionally configure a `sidebarOptions`. In doing so, an individual `sidebar.js` slice with the configured options will be generated within the respective `outputDir`. @@ -208,6 +209,14 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following | `createTagPageMD` | `function` | `null` | _Optional:_ Returns a string of the raw markdown body for tag pages.

**Function type:** `(pageData: TagPageMetadata) => string` | | `createSchemaPageMD` | `function` | `null` | _Optional:_ Returns a string of the raw markdown body for schema pages.

**Function type:** `(pageData: SchemaPageMetadata) => string` | +### sidebarGenerators + +`sidebarGenerators` can be configured with the following options: + +| Name | Type | Default | Description | +| --------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | +| `createDocItem` | `function` | `null` | Optional: Returns a `SidebarItemDoc` object containing metadata for a sidebar item.

**Function type** `(item: ApiPageMetadata | SchemaPageMetadata, context: { sidebarOptions: SidebarOptions; basePath: string }) => SidebarItemDoc` | + ## CLI Usage ```bash diff --git a/packages/docusaurus-plugin-openapi-docs/README.md b/packages/docusaurus-plugin-openapi-docs/README.md index 427522e4c..4be1b093a 100644 --- a/packages/docusaurus-plugin-openapi-docs/README.md +++ b/packages/docusaurus-plugin-openapi-docs/README.md @@ -174,13 +174,15 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following `sidebarOptions` can be configured with the following options: -| Name | Type | Default | Description | -| -------------------- | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag` and `tagGroup`. | -| `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag.

The supported options are as follows:

`tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description.

`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios).

`none`: Does not create pages for categories, only groups that can be expanded/collapsed. | -| `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. | -| `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. | -| `customProps` | `object` | `null` | Additional props for customizing a sidebar item. | +| Name | Type | Default | Description | +| -------------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag` and `tagGroup`. | +| `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag.

The supported options are as follows:

`tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description.

`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios).

`none`: Does not create pages for categories, only groups that can be expanded/collapsed. | +| `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. | +| `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. | +| `customProps` | `object` | `null` | Additional props for customizing a sidebar item. | +| `sidebarGenerators` | `object` | `null` | Optional: Customize sidebar rendering with callback functions. | +| `createDocItem` | `function` | `null` | Optional: Returns a `SidebarItemDoc` object, which allows for customisation of sidebar items. For example, add a class name in certain conditions, or add `customProps` to provide custom rendering. See below for a list of supported operations. | > You may optionally configure a `sidebarOptions`. In doing so, an individual `sidebar.js` slice with the configured options will be generated within the respective `outputDir`. @@ -206,6 +208,14 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following | `createTagPageMD` | `function` | `null` | _Optional:_ Returns a string of the raw markdown body for tag pages.

**Function type:** `(pageData: TagPageMetadata) => string` | | `createSchemaPageMD` | `function` | `null` | _Optional:_ Returns a string of the raw markdown body for schema pages.

**Function type:** `(pageData: SchemaPageMetadata) => string` | +### sidebarGenerators + +`sidebarGenerators` can be configured with the following options: + +| Name | Type | Default | Description | +| --------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | +| `createDocItem` | `function` | `null` | Optional: Returns a `SidebarItemDoc` object containing metadata for a sidebar item.

**Function type** `(item: ApiPageMetadata | SchemaPageMetadata, context: { sidebarOptions: SidebarOptions; basePath: string }) => SidebarItemDoc` | + ## CLI Usage ```bash diff --git a/packages/docusaurus-plugin-openapi-docs/src/options.ts b/packages/docusaurus-plugin-openapi-docs/src/options.ts index 98821ca0a..4cb8ad69f 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/options.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/options.ts @@ -7,13 +7,17 @@ import { Joi } from "@docusaurus/utils-validation"; +const sidebarGenerators = Joi.object({ + createDocItem: Joi.function(), +}); + const sidebarOptions = Joi.object({ groupPathsBy: Joi.string().valid("tag", "tagGroup"), categoryLinkSource: Joi.string().valid("tag", "info", "auto"), customProps: Joi.object(), sidebarCollapsible: Joi.boolean(), sidebarCollapsed: Joi.boolean(), - createDocItem: Joi.function(), + sidebarGenerators: sidebarGenerators, }); const markdownGenerators = Joi.object({ diff --git a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts index 1c31a7452..47080839e 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts @@ -133,7 +133,8 @@ function groupByTags( sidebarOptions, basePath, }; - const createDocItemFn = sidebarOptions.createDocItem ?? createDocItem; + const createDocItemFn = + sidebarOptions.sidebarGenerators?.createDocItem ?? createDocItem; let rootIntroDoc = undefined; if (infoItems.length === 1) { diff --git a/packages/docusaurus-plugin-openapi-docs/src/types.ts b/packages/docusaurus-plugin-openapi-docs/src/types.ts index 1ab785822..43367bbaa 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/types.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/types.ts @@ -63,13 +63,17 @@ export type ApiDocItemGenerator = ( context: { sidebarOptions: SidebarOptions; basePath: string } ) => SidebarItemDoc; +export interface SidebarGenerators { + createDocItem?: ApiDocItemGenerator; +} + export interface SidebarOptions { groupPathsBy?: string; categoryLinkSource?: "info" | "tag" | "auto"; customProps?: { [key: string]: unknown }; sidebarCollapsible?: boolean; sidebarCollapsed?: boolean; - createDocItem?: ApiDocItemGenerator; + sidebarGenerators?: SidebarGenerators; } export interface APIVersionOptions {