Skip to content

Commit cf354d0

Browse files
committed
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.
1 parent c6acf9e commit cf354d0

File tree

4 files changed

+62
-47
lines changed

4 files changed

+62
-47
lines changed

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,14 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following
174174

175175
`sidebarOptions` can be configured with the following options:
176176

177-
| Name | Type | Default | Description |
178-
| -------------------- | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
179-
| `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag` and `tagGroup`. |
180-
| `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag. <br/><br/>The supported options are as follows: <br/><br/> `tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description. <br/><br/>`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). <br/><br/>`none`: Does not create pages for categories, only groups that can be expanded/collapsed. |
181-
| `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. |
182-
| `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. |
183-
| `customProps` | `object` | `null` | Additional props for customizing a sidebar item. |
177+
| Name | Type | Default | Description |
178+
| -------------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
179+
| `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag` and `tagGroup`. |
180+
| `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag. <br/><br/>The supported options are as follows: <br/><br/> `tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description. <br/><br/>`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). <br/><br/>`none`: Does not create pages for categories, only groups that can be expanded/collapsed. |
181+
| `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. |
182+
| `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. |
183+
| `customProps` | `object` | `null` | Additional props for customizing a sidebar item. |
184+
| `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. |
184185

185186
> 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`.
186187

packages/docusaurus-plugin-openapi-docs/src/options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const sidebarOptions = Joi.object({
1313
customProps: Joi.object(),
1414
sidebarCollapsible: Joi.boolean(),
1515
sidebarCollapsed: Joi.boolean(),
16+
createDocItem: Joi.function(),
1617
});
1718

1819
const markdownGenerators = Joi.object({

packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
ProcessedSidebar,
1313
SidebarItemCategory,
1414
SidebarItemCategoryLinkConfig,
15-
SidebarItemDoc,
1615
} from "@docusaurus/plugin-content-docs/src/sidebars/types";
1716
import { posixPath } from "@docusaurus/utils";
1817
import clsx from "clsx";
@@ -27,6 +26,7 @@ import type {
2726
ApiMetadata,
2827
InfoPageMetadata,
2928
SchemaPageMetadata,
29+
ApiDocItemGenerator,
3030
} from "../types";
3131

3232
function isApiItem(item: ApiMetadata): item is ApiMetadata {
@@ -41,6 +41,37 @@ function isSchemaItem(item: ApiMetadata): item is ApiMetadata {
4141
return item.type === "schema";
4242
}
4343

44+
const createDocItem: ApiDocItemGenerator = (
45+
item,
46+
{ sidebarOptions: { customProps }, basePath }
47+
) => {
48+
const sidebar_label = item.frontMatter.sidebar_label;
49+
const title = item.title;
50+
const id = item.type === "schema" ? `schemas/${item.id}` : item.id;
51+
const className =
52+
item.type === "api"
53+
? clsx(
54+
{
55+
"menu__list-item--deprecated": item.api.deprecated,
56+
"api-method": !!item.api.method,
57+
},
58+
item.api.method
59+
)
60+
: clsx(
61+
{
62+
"menu__list-item--deprecated": item.schema.deprecated,
63+
},
64+
"schema"
65+
);
66+
return {
67+
type: "doc" as const,
68+
id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`,
69+
label: (sidebar_label as string) ?? title ?? id,
70+
customProps: customProps,
71+
className: className ? className : undefined,
72+
};
73+
};
74+
4475
function groupByTags(
4576
items: ApiMetadata[],
4677
sidebarOptions: SidebarOptions,
@@ -53,12 +84,8 @@ function groupByTags(
5384
// Remove trailing slash before proceeding
5485
outputDir = outputDir.replace(/\/$/, "");
5586

56-
const {
57-
sidebarCollapsed,
58-
sidebarCollapsible,
59-
customProps,
60-
categoryLinkSource,
61-
} = sidebarOptions;
87+
const { sidebarCollapsed, sidebarCollapsible, categoryLinkSource } =
88+
sidebarOptions;
6289

6390
const apiItems = items.filter(isApiItem) as ApiPageMetadata[];
6491
const infoItems = items.filter(isInfoItem) as InfoPageMetadata[];
@@ -101,35 +128,12 @@ function groupByTags(
101128
const basePath = docPath
102129
? outputDir.split(docPath!)[1].replace(/^\/+/g, "")
103130
: outputDir.slice(outputDir.indexOf("/", 1)).replace(/^\/+/g, "");
104-
function createDocItem(
105-
item: ApiPageMetadata | SchemaPageMetadata
106-
): SidebarItemDoc {
107-
const sidebar_label = item.frontMatter.sidebar_label;
108-
const title = item.title;
109-
const id = item.type === "schema" ? `schemas/${item.id}` : item.id;
110-
const className =
111-
item.type === "api"
112-
? clsx(
113-
{
114-
"menu__list-item--deprecated": item.api.deprecated,
115-
"api-method": !!item.api.method,
116-
},
117-
item.api.method
118-
)
119-
: clsx(
120-
{
121-
"menu__list-item--deprecated": item.schema.deprecated,
122-
},
123-
"schema"
124-
);
125-
return {
126-
type: "doc" as const,
127-
id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`,
128-
label: (sidebar_label as string) ?? title ?? id,
129-
customProps: customProps,
130-
className: className ? className : undefined,
131-
};
132-
}
131+
132+
const createDocItemFnContext = {
133+
sidebarOptions,
134+
basePath,
135+
};
136+
const createDocItemFn = sidebarOptions.createDocItem ?? createDocItem;
133137

134138
let rootIntroDoc = undefined;
135139
if (infoItems.length === 1) {
@@ -208,15 +212,17 @@ function groupByTags(
208212
link: linkConfig,
209213
collapsible: sidebarCollapsible,
210214
collapsed: sidebarCollapsed,
211-
items: [...taggedSchemaItems, ...taggedApiItems].map(createDocItem),
215+
items: [...taggedSchemaItems, ...taggedApiItems].map((item) =>
216+
createDocItemFn(item, createDocItemFnContext)
217+
),
212218
};
213219
})
214220
.filter((item) => item.items.length > 0); // Filter out any categories with no items.
215221

216222
// Handle items with no tag
217223
const untaggedItems = apiItems
218224
.filter(({ api }) => api.tags === undefined || api.tags.length === 0)
219-
.map(createDocItem);
225+
.map((item) => createDocItemFn(item, createDocItemFnContext));
220226
let untagged: SidebarItemCategory[] = [];
221227
if (untaggedItems.length > 0) {
222228
untagged = [
@@ -227,7 +233,7 @@ function groupByTags(
227233
collapsed: sidebarCollapsed!,
228234
items: apiItems
229235
.filter(({ api }) => api.tags === undefined || api.tags.length === 0)
230-
.map(createDocItem),
236+
.map((item) => createDocItemFn(item, createDocItemFnContext)),
231237
},
232238
];
233239
}
@@ -242,7 +248,7 @@ function groupByTags(
242248
collapsed: sidebarCollapsed!,
243249
items: schemaItems
244250
.filter(({ schema }) => !schema["x-tags"])
245-
.map(createDocItem),
251+
.map((item) => createDocItemFn(item, createDocItemFnContext)),
246252
},
247253
];
248254
}

packages/docusaurus-plugin-openapi-docs/src/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
* ========================================================================== */
77

8+
import { SidebarItemDoc } from "@docusaurus/plugin-content-docs/src/sidebars/types";
89
import type Request from "postman-collection";
910

1011
import {
@@ -57,12 +58,18 @@ export interface MarkdownGenerator {
5758
createSchemaPageMD?: (pageData: SchemaPageMetadata) => string;
5859
}
5960

61+
export type ApiDocItemGenerator = (
62+
item: ApiPageMetadata | SchemaPageMetadata,
63+
context: { sidebarOptions: SidebarOptions; basePath: string }
64+
) => SidebarItemDoc;
65+
6066
export interface SidebarOptions {
6167
groupPathsBy?: string;
6268
categoryLinkSource?: "info" | "tag" | "auto";
6369
customProps?: { [key: string]: unknown };
6470
sidebarCollapsible?: boolean;
6571
sidebarCollapsed?: boolean;
72+
createDocItem?: ApiDocItemGenerator;
6673
}
6774

6875
export interface APIVersionOptions {

0 commit comments

Comments
 (0)