mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-12 00:27:21 +02:00
feat(v2): allow user to customize/enhance the default sidebar items generator (#4658)
* allow and document how to wrap/enhance the default docusaurus sidebar items generator * improve doc * doc * doc
This commit is contained in:
parent
e11597aba9
commit
792f4ac6fb
7 changed files with 250 additions and 50 deletions
|
@ -662,6 +662,7 @@ Array [
|
||||||
|
|
||||||
exports[`site with custom sidebar items generator sidebarItemsGenerator is called with appropriate data 1`] = `
|
exports[`site with custom sidebar items generator sidebarItemsGenerator is called with appropriate data 1`] = `
|
||||||
Object {
|
Object {
|
||||||
|
"defaultSidebarItemsGenerator": [Function],
|
||||||
"docs": Array [
|
"docs": Array [
|
||||||
Object {
|
Object {
|
||||||
"frontMatter": Object {},
|
"frontMatter": Object {},
|
||||||
|
|
|
@ -24,11 +24,18 @@ import {DEFAULT_PLUGIN_ID} from '@docusaurus/core/lib/constants';
|
||||||
import * as cliDocs from '../cli';
|
import * as cliDocs from '../cli';
|
||||||
import {OptionsSchema} from '../options';
|
import {OptionsSchema} from '../options';
|
||||||
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
import {normalizePluginOptions} from '@docusaurus/utils-validation';
|
||||||
import {DocMetadata, LoadedVersion, SidebarItemsGenerator} from '../types';
|
import {
|
||||||
|
DocMetadata,
|
||||||
|
LoadedVersion,
|
||||||
|
SidebarItem,
|
||||||
|
SidebarItemsGeneratorOption,
|
||||||
|
SidebarItemsGeneratorOptionArgs,
|
||||||
|
} from '../types';
|
||||||
import {toSidebarsProp} from '../props';
|
import {toSidebarsProp} from '../props';
|
||||||
|
|
||||||
// @ts-expect-error: TODO typedefs missing?
|
// @ts-expect-error: TODO typedefs missing?
|
||||||
import {validate} from 'webpack';
|
import {validate} from 'webpack';
|
||||||
|
import {DefaultSidebarItemsGenerator} from '../sidebarItemsGenerator';
|
||||||
|
|
||||||
function findDocById(version: LoadedVersion, unversionedId: string) {
|
function findDocById(version: LoadedVersion, unversionedId: string) {
|
||||||
return version.docs.find((item) => item.unversionedId === unversionedId);
|
return version.docs.find((item) => item.unversionedId === unversionedId);
|
||||||
|
@ -1576,7 +1583,7 @@ describe('site with partial autogenerated sidebars 2 (fix #4638)', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('site with custom sidebar items generator', () => {
|
describe('site with custom sidebar items generator', () => {
|
||||||
async function loadSite(sidebarItemsGenerator: SidebarItemsGenerator) {
|
async function loadSite(sidebarItemsGenerator: SidebarItemsGeneratorOption) {
|
||||||
const siteDir = path.join(
|
const siteDir = path.join(
|
||||||
__dirname,
|
__dirname,
|
||||||
'__fixtures__',
|
'__fixtures__',
|
||||||
|
@ -1594,42 +1601,19 @@ describe('site with custom sidebar items generator', () => {
|
||||||
return {content, siteDir};
|
return {content, siteDir};
|
||||||
}
|
}
|
||||||
|
|
||||||
test('sidebar is autogenerated according to custom sidebarItemsGenerator', async () => {
|
|
||||||
const customSidebarItemsGenerator: SidebarItemsGenerator = async () => {
|
|
||||||
return [
|
|
||||||
{type: 'doc', id: 'API/api-overview'},
|
|
||||||
{type: 'doc', id: 'API/api-end'},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const customSidebarItemsGeneratorMock: SidebarItemsGenerator = jest.fn(
|
|
||||||
customSidebarItemsGenerator,
|
|
||||||
);
|
|
||||||
|
|
||||||
const {content} = await loadSite(customSidebarItemsGeneratorMock);
|
|
||||||
const version = content.loadedVersions[0];
|
|
||||||
|
|
||||||
expect(version.sidebars).toEqual({
|
|
||||||
defaultSidebar: [
|
|
||||||
{type: 'doc', id: 'API/api-overview'},
|
|
||||||
{type: 'doc', id: 'API/api-end'},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('sidebarItemsGenerator is called with appropriate data', async () => {
|
test('sidebarItemsGenerator is called with appropriate data', async () => {
|
||||||
type GeneratorArg = Parameters<SidebarItemsGenerator>[0];
|
|
||||||
|
|
||||||
const customSidebarItemsGeneratorMock = jest.fn(
|
const customSidebarItemsGeneratorMock = jest.fn(
|
||||||
async (_arg: GeneratorArg) => [],
|
async (_arg: SidebarItemsGeneratorOptionArgs) => [],
|
||||||
);
|
);
|
||||||
const {siteDir} = await loadSite(customSidebarItemsGeneratorMock);
|
const {siteDir} = await loadSite(customSidebarItemsGeneratorMock);
|
||||||
|
|
||||||
const generatorArg: GeneratorArg =
|
const generatorArg: SidebarItemsGeneratorOptionArgs =
|
||||||
customSidebarItemsGeneratorMock.mock.calls[0][0];
|
customSidebarItemsGeneratorMock.mock.calls[0][0];
|
||||||
|
|
||||||
// Make test pass even if docs are in different order and paths are absolutes
|
// Make test pass even if docs are in different order and paths are absolutes
|
||||||
function makeDeterministic(arg: GeneratorArg): GeneratorArg {
|
function makeDeterministic(
|
||||||
|
arg: SidebarItemsGeneratorOptionArgs,
|
||||||
|
): SidebarItemsGeneratorOptionArgs {
|
||||||
return {
|
return {
|
||||||
...arg,
|
...arg,
|
||||||
docs: orderBy(arg.docs, 'id'),
|
docs: orderBy(arg.docs, 'id'),
|
||||||
|
@ -1641,5 +1625,140 @@ describe('site with custom sidebar items generator', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(makeDeterministic(generatorArg)).toMatchSnapshot();
|
expect(makeDeterministic(generatorArg)).toMatchSnapshot();
|
||||||
|
expect(generatorArg.defaultSidebarItemsGenerator).toEqual(
|
||||||
|
DefaultSidebarItemsGenerator,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('sidebar is autogenerated according to a custom sidebarItemsGenerator', async () => {
|
||||||
|
const customSidebarItemsGenerator: SidebarItemsGeneratorOption = async () => {
|
||||||
|
return [
|
||||||
|
{type: 'doc', id: 'API/api-overview'},
|
||||||
|
{type: 'doc', id: 'API/api-end'},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const {content} = await loadSite(customSidebarItemsGenerator);
|
||||||
|
const version = content.loadedVersions[0];
|
||||||
|
|
||||||
|
expect(version.sidebars).toEqual({
|
||||||
|
defaultSidebar: [
|
||||||
|
{type: 'doc', id: 'API/api-overview'},
|
||||||
|
{type: 'doc', id: 'API/api-end'},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('sidebarItemsGenerator can wrap/enhance/sort/reverse the default sidebar generator', async () => {
|
||||||
|
function reverseSidebarItems(items: SidebarItem[]): SidebarItem[] {
|
||||||
|
const result: SidebarItem[] = items.map((item) => {
|
||||||
|
if (item.type === 'category') {
|
||||||
|
return {...item, items: reverseSidebarItems(item.items)};
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
result.reverse();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reversedSidebarItemsGenerator: SidebarItemsGeneratorOption = async ({
|
||||||
|
defaultSidebarItemsGenerator,
|
||||||
|
...args
|
||||||
|
}) => {
|
||||||
|
const sidebarItems = await defaultSidebarItemsGenerator(args);
|
||||||
|
return reverseSidebarItems(sidebarItems);
|
||||||
|
};
|
||||||
|
|
||||||
|
const {content} = await loadSite(reversedSidebarItemsGenerator);
|
||||||
|
const version = content.loadedVersions[0];
|
||||||
|
|
||||||
|
expect(version.sidebars).toEqual({
|
||||||
|
defaultSidebar: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
label: 'API (label from _category_.json)',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'API/api-end',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
label: 'Extension APIs (label from _category_.yml)',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'API/Extension APIs/Theme API',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'API/Extension APIs/Plugin API',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
label: 'Core APIs',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'API/Core APIs/Server API',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'API/Core APIs/Client API',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'API/api-overview',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
label: 'Guides',
|
||||||
|
collapsed: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'Guides/guide5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'Guides/guide4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'Guides/guide3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'Guides/guide2.5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'Guides/guide2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'Guides/guide1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'installation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
id: 'getting-started',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,6 +24,7 @@ import {
|
||||||
Sidebars,
|
Sidebars,
|
||||||
UnprocessedSidebars,
|
UnprocessedSidebars,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
import {DefaultSidebarItemsGenerator} from '../sidebarItemsGenerator';
|
||||||
|
|
||||||
/* eslint-disable global-require, import/no-dynamic-require */
|
/* eslint-disable global-require, import/no-dynamic-require */
|
||||||
|
|
||||||
|
@ -534,16 +535,19 @@ describe('processSidebars', () => {
|
||||||
|
|
||||||
expect(StaticSidebarItemsGenerator).toHaveBeenCalledTimes(3);
|
expect(StaticSidebarItemsGenerator).toHaveBeenCalledTimes(3);
|
||||||
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
||||||
|
defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
||||||
item: {type: 'autogenerated', dirName: 'dir1'},
|
item: {type: 'autogenerated', dirName: 'dir1'},
|
||||||
docs: [],
|
docs: [],
|
||||||
version: {},
|
version: {},
|
||||||
});
|
});
|
||||||
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
||||||
|
defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
||||||
item: {type: 'autogenerated', dirName: 'dir2'},
|
item: {type: 'autogenerated', dirName: 'dir2'},
|
||||||
docs: [],
|
docs: [],
|
||||||
version: {},
|
version: {},
|
||||||
});
|
});
|
||||||
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
expect(StaticSidebarItemsGenerator).toHaveBeenCalledWith({
|
||||||
|
defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
||||||
item: {type: 'autogenerated', dirName: 'dir3'},
|
item: {type: 'autogenerated', dirName: 'dir3'},
|
||||||
docs: [],
|
docs: [],
|
||||||
version: {},
|
version: {},
|
||||||
|
|
|
@ -21,14 +21,15 @@ import {
|
||||||
UnprocessedSidebar,
|
UnprocessedSidebar,
|
||||||
DocMetadataBase,
|
DocMetadataBase,
|
||||||
VersionMetadata,
|
VersionMetadata,
|
||||||
SidebarItemsGenerator,
|
|
||||||
SidebarItemsGeneratorDoc,
|
SidebarItemsGeneratorDoc,
|
||||||
SidebarItemsGeneratorVersion,
|
SidebarItemsGeneratorVersion,
|
||||||
NumberPrefixParser,
|
NumberPrefixParser,
|
||||||
|
SidebarItemsGeneratorOption,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {mapValues, flatten, flatMap, difference, pick, memoize} from 'lodash';
|
import {mapValues, flatten, flatMap, difference, pick, memoize} from 'lodash';
|
||||||
import {getElementsAround} from '@docusaurus/utils';
|
import {getElementsAround} from '@docusaurus/utils';
|
||||||
import combinePromises from 'combine-promises';
|
import combinePromises from 'combine-promises';
|
||||||
|
import {DefaultSidebarItemsGenerator} from './sidebarItemsGenerator';
|
||||||
|
|
||||||
type SidebarItemCategoryJSON = SidebarItemBase & {
|
type SidebarItemCategoryJSON = SidebarItemBase & {
|
||||||
type: 'category';
|
type: 'category';
|
||||||
|
@ -295,7 +296,7 @@ export async function processSidebar({
|
||||||
docs,
|
docs,
|
||||||
version,
|
version,
|
||||||
}: {
|
}: {
|
||||||
sidebarItemsGenerator: SidebarItemsGenerator;
|
sidebarItemsGenerator: SidebarItemsGeneratorOption;
|
||||||
numberPrefixParser: NumberPrefixParser;
|
numberPrefixParser: NumberPrefixParser;
|
||||||
unprocessedSidebar: UnprocessedSidebar;
|
unprocessedSidebar: UnprocessedSidebar;
|
||||||
docs: DocMetadataBase[];
|
docs: DocMetadataBase[];
|
||||||
|
@ -322,6 +323,7 @@ export async function processSidebar({
|
||||||
return sidebarItemsGenerator({
|
return sidebarItemsGenerator({
|
||||||
item,
|
item,
|
||||||
numberPrefixParser,
|
numberPrefixParser,
|
||||||
|
defaultSidebarItemsGenerator: DefaultSidebarItemsGenerator,
|
||||||
...getSidebarItemsGeneratorDocsAndVersion(),
|
...getSidebarItemsGeneratorDocsAndVersion(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -338,7 +340,7 @@ export async function processSidebars({
|
||||||
docs,
|
docs,
|
||||||
version,
|
version,
|
||||||
}: {
|
}: {
|
||||||
sidebarItemsGenerator: SidebarItemsGenerator;
|
sidebarItemsGenerator: SidebarItemsGeneratorOption;
|
||||||
numberPrefixParser: NumberPrefixParser;
|
numberPrefixParser: NumberPrefixParser;
|
||||||
unprocessedSidebars: UnprocessedSidebars;
|
unprocessedSidebars: UnprocessedSidebars;
|
||||||
docs: DocMetadataBase[];
|
docs: DocMetadataBase[];
|
||||||
|
|
|
@ -84,7 +84,7 @@ export type PluginOptions = MetadataOptions &
|
||||||
disableVersioning: boolean;
|
disableVersioning: boolean;
|
||||||
excludeNextVersionDocs?: boolean;
|
excludeNextVersionDocs?: boolean;
|
||||||
includeCurrentVersion: boolean;
|
includeCurrentVersion: boolean;
|
||||||
sidebarItemsGenerator: SidebarItemsGenerator;
|
sidebarItemsGenerator: SidebarItemsGeneratorOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SidebarItemBase = {
|
export type SidebarItemBase = {
|
||||||
|
@ -151,12 +151,25 @@ export type SidebarItemsGeneratorVersion = Pick<
|
||||||
VersionMetadata,
|
VersionMetadata,
|
||||||
'versionName' | 'contentPath'
|
'versionName' | 'contentPath'
|
||||||
>;
|
>;
|
||||||
export type SidebarItemsGenerator = (generatorArgs: {
|
|
||||||
|
export type SidebarItemsGeneratorArgs = {
|
||||||
item: UnprocessedSidebarItemAutogenerated;
|
item: UnprocessedSidebarItemAutogenerated;
|
||||||
version: SidebarItemsGeneratorVersion;
|
version: SidebarItemsGeneratorVersion;
|
||||||
docs: SidebarItemsGeneratorDoc[];
|
docs: SidebarItemsGeneratorDoc[];
|
||||||
numberPrefixParser: NumberPrefixParser;
|
numberPrefixParser: NumberPrefixParser;
|
||||||
}) => Promise<SidebarItem[]>;
|
};
|
||||||
|
export type SidebarItemsGenerator = (
|
||||||
|
generatorArgs: SidebarItemsGeneratorArgs,
|
||||||
|
) => Promise<SidebarItem[]>;
|
||||||
|
|
||||||
|
// Also inject the default generator to conveniently wrap/enhance/sort the default sidebar gen logic
|
||||||
|
// see https://github.com/facebook/docusaurus/issues/4640#issuecomment-822292320
|
||||||
|
export type SidebarItemsGeneratorOptionArgs = {
|
||||||
|
defaultSidebarItemsGenerator: SidebarItemsGenerator;
|
||||||
|
} & SidebarItemsGeneratorArgs;
|
||||||
|
export type SidebarItemsGeneratorOption = (
|
||||||
|
generatorArgs: SidebarItemsGeneratorOptionArgs,
|
||||||
|
) => Promise<SidebarItem[]>;
|
||||||
|
|
||||||
export type OrderMetadata = {
|
export type OrderMetadata = {
|
||||||
previous?: string;
|
previous?: string;
|
||||||
|
|
|
@ -76,14 +76,25 @@ module.exports = {
|
||||||
* Function used to replace the sidebar items of type "autogenerated"
|
* Function used to replace the sidebar items of type "autogenerated"
|
||||||
* by real sidebar items (docs, categories, links...)
|
* by real sidebar items (docs, categories, links...)
|
||||||
*/
|
*/
|
||||||
sidebarItemsGenerator: function ({
|
sidebarItemsGenerator: async function ({
|
||||||
item,
|
defaultSidebarItemsGenerator, // useful to re-use/enhance default sidebar generation logic from Docusaurus
|
||||||
version,
|
numberPrefixParser, // numberPrefixParser configured for this plugin
|
||||||
docs,
|
item, // the sidebar item with type "autogenerated"
|
||||||
numberPrefixParser,
|
version, // the current version
|
||||||
|
docs, // all the docs of that version (unfiltered)
|
||||||
}) {
|
}) {
|
||||||
// Use the provided data to create a custom "sidebar slice"
|
// Use the provided data to generate a custom sidebar slice
|
||||||
return [{type: 'doc', id: 'doc1'}];
|
return [
|
||||||
|
{type: 'doc', id: 'intro'},
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
label: 'Tutorials',
|
||||||
|
items: [
|
||||||
|
{type: 'doc', id: 'tutorial1'},
|
||||||
|
{type: 'doc', id: 'tutorial2'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* The Docs plugin supports number prefixes like "01-My Folder/02.My Doc.md".
|
* The Docs plugin supports number prefixes like "01-My Folder/02.My Doc.md".
|
||||||
|
|
|
@ -521,14 +521,19 @@ module.exports = {
|
||||||
[
|
[
|
||||||
'@docusaurus/plugin-content-docs',
|
'@docusaurus/plugin-content-docs',
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Function used to replace the sidebar items of type "autogenerated"
|
|
||||||
* by real sidebar items (docs, categories, links...)
|
|
||||||
*/
|
|
||||||
// highlight-start
|
// highlight-start
|
||||||
sidebarItemsGenerator: function ({item, version, docs}) {
|
sidebarItemsGenerator: async function ({
|
||||||
// Use the provided data to create a custom "sidebar slice"
|
defaultSidebarItemsGenerator,
|
||||||
return [{type: 'doc', id: 'doc1'}];
|
numberPrefixParser,
|
||||||
|
item,
|
||||||
|
version,
|
||||||
|
docs,
|
||||||
|
}) {
|
||||||
|
// Example: return an hardcoded list of static sidebar items
|
||||||
|
return [
|
||||||
|
{type: 'doc', id: 'doc1'},
|
||||||
|
{type: 'doc', id: 'doc2'},
|
||||||
|
];
|
||||||
},
|
},
|
||||||
// highlight-end
|
// highlight-end
|
||||||
},
|
},
|
||||||
|
@ -537,6 +542,51 @@ module.exports = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
|
||||||
|
**Re-use and enhance the default generator** instead of writing a generator from scratch.
|
||||||
|
|
||||||
|
**Add, update, filter, re-order** the sidebar items according to your use-case:
|
||||||
|
|
||||||
|
```js title="docusaurus.config.js"
|
||||||
|
// highlight-start
|
||||||
|
// Reverse the sidebar items ordering (including nested category items)
|
||||||
|
function reverseSidebarItems(items) {
|
||||||
|
// Reverse items in categories
|
||||||
|
const result = items.map((item) => {
|
||||||
|
if (item.type === 'category') {
|
||||||
|
return {...item, items: reverseSidebarItems(item.items)};
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
// Reverse items at current level
|
||||||
|
result.reverse();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// highlight-end
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
'@docusaurus/plugin-content-docs',
|
||||||
|
{
|
||||||
|
// highlight-start
|
||||||
|
sidebarItemsGenerator: async function ({
|
||||||
|
defaultSidebarItemsGenerator,
|
||||||
|
...args
|
||||||
|
}) {
|
||||||
|
const sidebarItems = await defaultSidebarItemsGenerator(args);
|
||||||
|
return reverseSidebarItems(sidebarItems);
|
||||||
|
},
|
||||||
|
// highlight-end
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
## Hideable sidebar {#hideable-sidebar}
|
## Hideable sidebar {#hideable-sidebar}
|
||||||
|
|
||||||
Using the enabled `themeConfig.hideableSidebar` option, you can make the entire sidebar hidden, allowing you to better focus your users on the content. This is especially useful when content consumption on medium screens (e.g. on tablets).
|
Using the enabled `themeConfig.hideableSidebar` option, you can make the entire sidebar hidden, allowing you to better focus your users on the content. This is especially useful when content consumption on medium screens (e.g. on tablets).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue