mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-16 18:46:57 +02:00
feat(theme-classic): new navbar item linking to a sidebar (#6139)
Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com> Co-authored-by: Joshua Chen <sidachen2003@gmail.com> Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
This commit is contained in:
parent
3cb99124de
commit
eade41a702
12 changed files with 396 additions and 13 deletions
|
@ -323,6 +323,14 @@ Object {
|
|||
"mainDocId": "hello",
|
||||
"name": "current",
|
||||
"path": "/docs",
|
||||
"sidebars": Object {
|
||||
"docs": Object {
|
||||
"link": Object {
|
||||
"label": "foo/bar",
|
||||
"path": "/docs/foo/bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -1007,6 +1015,14 @@ Object {
|
|||
"mainDocId": "hello",
|
||||
"name": "current",
|
||||
"path": "/docs",
|
||||
"sidebars": Object {
|
||||
"docs": Object {
|
||||
"link": Object {
|
||||
"label": "foo/bar",
|
||||
"path": "/docs/foo/bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -2359,6 +2375,14 @@ Object {
|
|||
"mainDocId": "team",
|
||||
"name": "current",
|
||||
"path": "/community/next",
|
||||
"sidebars": Object {
|
||||
"community": Object {
|
||||
"link": Object {
|
||||
"label": "team",
|
||||
"path": "/community/next/team",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"docs": Array [
|
||||
|
@ -2373,6 +2397,14 @@ Object {
|
|||
"mainDocId": "team",
|
||||
"name": "1.0.0",
|
||||
"path": "/community",
|
||||
"sidebars": Object {
|
||||
"version-1.0.0/community": Object {
|
||||
"link": Object {
|
||||
"label": "version-1.0.0/team",
|
||||
"path": "/community/team",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -3407,6 +3439,14 @@ Object {
|
|||
"mainDocId": "hello",
|
||||
"name": "current",
|
||||
"path": "/docs/next",
|
||||
"sidebars": Object {
|
||||
"docs": Object {
|
||||
"link": Object {
|
||||
"label": "foo/bar",
|
||||
"path": "/docs/next/foo/barSlug",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"docs": Array [
|
||||
|
@ -3426,6 +3466,14 @@ Object {
|
|||
"mainDocId": "hello",
|
||||
"name": "1.0.1",
|
||||
"path": "/docs",
|
||||
"sidebars": Object {
|
||||
"VersionedSideBarNameDoesNotMatter/docs": Object {
|
||||
"link": Object {
|
||||
"label": "foo/bar",
|
||||
"path": "/docs/foo/bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"docs": Array [
|
||||
|
@ -3450,6 +3498,14 @@ Object {
|
|||
"mainDocId": "hello",
|
||||
"name": "1.0.0",
|
||||
"path": "/docs/1.0.0",
|
||||
"sidebars": Object {
|
||||
"version-1.0.0/docs": Object {
|
||||
"link": Object {
|
||||
"label": "version-1.0.0/foo/bar",
|
||||
"path": "/docs/1.0.0/foo/barSlug",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"docs": Array [
|
||||
|
@ -3499,6 +3555,14 @@ Object {
|
|||
"mainDocId": "rootAbsoluteSlug",
|
||||
"name": "withSlugs",
|
||||
"path": "/docs/withSlugs",
|
||||
"sidebars": Object {
|
||||
"version-1.0.1/docs": Object {
|
||||
"link": Object {
|
||||
"label": "version-withSlugs/rootAbsoluteSlug",
|
||||
"path": "/docs/withSlugs/rootAbsoluteSlug",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -5,11 +5,16 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {mapValues} from 'lodash';
|
||||
import {normalizeUrl} from '@docusaurus/utils';
|
||||
import type {Sidebars} from './sidebars/types';
|
||||
import {createSidebarsUtils} from './sidebars/utils';
|
||||
import type {
|
||||
DocMetadata,
|
||||
GlobalDoc,
|
||||
LoadedVersion,
|
||||
GlobalVersion,
|
||||
GlobalSidebar,
|
||||
} from './types';
|
||||
|
||||
export function toGlobalDataDoc(doc: DocMetadata): GlobalDoc {
|
||||
|
@ -20,6 +25,31 @@ export function toGlobalDataDoc(doc: DocMetadata): GlobalDoc {
|
|||
};
|
||||
}
|
||||
|
||||
export function toGlobalSidebars(
|
||||
sidebars: Sidebars,
|
||||
version: LoadedVersion,
|
||||
): Record<string, GlobalSidebar> {
|
||||
const {getFirstLink} = createSidebarsUtils(sidebars);
|
||||
return mapValues(sidebars, (sidebar, sidebarId) => {
|
||||
const firstLink = getFirstLink(sidebarId);
|
||||
if (!firstLink) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
link: {
|
||||
path:
|
||||
firstLink.type === 'generated-index'
|
||||
? normalizeUrl([version.versionPath, firstLink.slug])
|
||||
: version.docs.find(
|
||||
(doc) =>
|
||||
doc.id === firstLink.id || doc.unversionedId === firstLink.id,
|
||||
)!.permalink,
|
||||
label: firstLink.label,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function toGlobalDataVersion(version: LoadedVersion): GlobalVersion {
|
||||
return {
|
||||
name: version.versionName,
|
||||
|
@ -28,5 +58,6 @@ export function toGlobalDataVersion(version: LoadedVersion): GlobalVersion {
|
|||
path: version.versionPath,
|
||||
mainDocId: version.mainDocId,
|
||||
docs: version.docs.map(toGlobalDataDoc),
|
||||
sidebars: toGlobalSidebars(version.sidebars, version),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@ declare module '@docusaurus/plugin-content-docs' {
|
|||
export type VersionBanner = import('./types').VersionBanner;
|
||||
type GlobalDataVersion = import('./types').GlobalVersion;
|
||||
type GlobalDataDoc = import('./types').GlobalDoc;
|
||||
type GlobalDataSidebar = import('./types').GlobalSidebar;
|
||||
type VersionTag = import('./types').VersionTag;
|
||||
|
||||
export type {GlobalDataVersion, GlobalDataDoc};
|
||||
export type {GlobalDataVersion, GlobalDataDoc, GlobalDataSidebar};
|
||||
|
||||
export type PropNavigationLink = {
|
||||
readonly title: string;
|
||||
|
|
|
@ -46,7 +46,7 @@ describe('createSidebarsUtils', () => {
|
|||
collapsible: true,
|
||||
label: 'S2 Category',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc3'},
|
||||
{type: 'doc', id: 'doc3', label: 'Doc 3'},
|
||||
{type: 'doc', id: 'doc4'},
|
||||
],
|
||||
},
|
||||
|
@ -95,7 +95,25 @@ describe('createSidebarsUtils', () => {
|
|||
},
|
||||
];
|
||||
|
||||
const sidebars: Sidebars = {sidebar1, sidebar2, sidebar3};
|
||||
const sidebar4: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
label: 'S4 Category',
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
slug: '/s4-category-slug',
|
||||
permalink: '/s4-category-permalink',
|
||||
},
|
||||
items: [
|
||||
{type: 'doc', id: 'doc8'},
|
||||
{type: 'doc', id: 'doc9'},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const sidebars: Sidebars = {sidebar1, sidebar2, sidebar3, sidebar4};
|
||||
|
||||
const {
|
||||
getFirstDocIdOfFirstSidebar,
|
||||
|
@ -103,6 +121,7 @@ describe('createSidebarsUtils', () => {
|
|||
getDocNavigation,
|
||||
getCategoryGeneratedIndexNavigation,
|
||||
getCategoryGeneratedIndexList,
|
||||
getFirstLink,
|
||||
} = createSidebarsUtils(sidebars);
|
||||
|
||||
test('getSidebarNameByDocId', async () => {
|
||||
|
@ -121,7 +140,7 @@ describe('createSidebarsUtils', () => {
|
|||
});
|
||||
|
||||
test('getDocNavigation', async () => {
|
||||
expect(getDocNavigation('doc1')).toEqual({
|
||||
expect(getDocNavigation('doc1', 'doc1')).toEqual({
|
||||
sidebarName: 'sidebar1',
|
||||
previous: undefined,
|
||||
next: {
|
||||
|
@ -129,7 +148,7 @@ describe('createSidebarsUtils', () => {
|
|||
id: 'doc2',
|
||||
},
|
||||
} as SidebarNavigation);
|
||||
expect(getDocNavigation('doc2')).toEqual({
|
||||
expect(getDocNavigation('doc2', 'doc2')).toEqual({
|
||||
sidebarName: 'sidebar1',
|
||||
previous: {
|
||||
type: 'doc',
|
||||
|
@ -138,7 +157,7 @@ describe('createSidebarsUtils', () => {
|
|||
next: undefined,
|
||||
} as SidebarNavigation);
|
||||
|
||||
expect(getDocNavigation('doc3')).toEqual({
|
||||
expect(getDocNavigation('doc3', 'doc3')).toEqual({
|
||||
sidebarName: 'sidebar2',
|
||||
previous: undefined,
|
||||
next: {
|
||||
|
@ -146,16 +165,17 @@ describe('createSidebarsUtils', () => {
|
|||
id: 'doc4',
|
||||
},
|
||||
} as SidebarNavigation);
|
||||
expect(getDocNavigation('doc4')).toEqual({
|
||||
expect(getDocNavigation('doc4', 'doc4')).toEqual({
|
||||
sidebarName: 'sidebar2',
|
||||
previous: {
|
||||
type: 'doc',
|
||||
id: 'doc3',
|
||||
label: 'Doc 3',
|
||||
},
|
||||
next: undefined,
|
||||
} as SidebarNavigation);
|
||||
|
||||
expect(getDocNavigation('doc5')).toMatchObject({
|
||||
expect(getDocNavigation('doc5', 'doc5')).toMatchObject({
|
||||
sidebarName: 'sidebar3',
|
||||
previous: undefined,
|
||||
next: {
|
||||
|
@ -163,7 +183,7 @@ describe('createSidebarsUtils', () => {
|
|||
label: 'S3 SubCategory',
|
||||
},
|
||||
} as SidebarNavigation);
|
||||
expect(getDocNavigation('doc6')).toMatchObject({
|
||||
expect(getDocNavigation('doc6', 'doc6')).toMatchObject({
|
||||
sidebarName: 'sidebar3',
|
||||
previous: {
|
||||
type: 'category',
|
||||
|
@ -174,7 +194,7 @@ describe('createSidebarsUtils', () => {
|
|||
id: 'doc7',
|
||||
},
|
||||
} as SidebarNavigation);
|
||||
expect(getDocNavigation('doc7')).toMatchObject({
|
||||
expect(getDocNavigation('doc7', 'doc7')).toMatchObject({
|
||||
sidebarName: 'sidebar3',
|
||||
previous: {
|
||||
type: 'doc',
|
||||
|
@ -224,8 +244,35 @@ describe('createSidebarsUtils', () => {
|
|||
type: 'category',
|
||||
label: 'S3 SubSubCategory',
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'S4 Category',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('getFirstLink', () => {
|
||||
expect(getFirstLink('sidebar1')).toEqual({
|
||||
id: 'doc1',
|
||||
type: 'doc',
|
||||
label: 'doc1',
|
||||
});
|
||||
expect(getFirstLink('sidebar2')).toEqual({
|
||||
id: 'doc3',
|
||||
type: 'doc',
|
||||
label: 'Doc 3',
|
||||
});
|
||||
expect(getFirstLink('sidebar3')).toEqual({
|
||||
id: 'doc5',
|
||||
type: 'doc',
|
||||
label: 'S3 Category',
|
||||
});
|
||||
expect(getFirstLink('sidebar4')).toEqual({
|
||||
type: 'generated-index',
|
||||
slug: '/s4-category-slug',
|
||||
label: 'S4 Category',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('collectSidebarDocItems', () => {
|
||||
|
|
|
@ -136,6 +136,18 @@ export type SidebarsUtils = {
|
|||
getCategoryGeneratedIndexNavigation: (
|
||||
categoryGeneratedIndexPermalink: string,
|
||||
) => SidebarNavigation;
|
||||
getFirstLink: (sidebarId: string) =>
|
||||
| {
|
||||
type: 'doc';
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
| {
|
||||
type: 'generated-index';
|
||||
slug: string;
|
||||
label: string;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
checkSidebarsDocIds: (validDocIds: string[], sidebarFilePath: string) => void;
|
||||
};
|
||||
|
@ -264,6 +276,50 @@ Available document ids are:
|
|||
}
|
||||
}
|
||||
|
||||
function getFirstLink(sidebar: Sidebar):
|
||||
| {
|
||||
type: 'doc';
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
| {
|
||||
type: 'generated-index';
|
||||
slug: string;
|
||||
label: string;
|
||||
}
|
||||
| undefined {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const item of sidebar) {
|
||||
if (item.type === 'doc') {
|
||||
return {
|
||||
type: 'doc',
|
||||
id: item.id,
|
||||
label: item.label ?? item.id,
|
||||
};
|
||||
} else if (item.type === 'category') {
|
||||
if (item.link?.type === 'doc') {
|
||||
return {
|
||||
type: 'doc',
|
||||
id: item.link.id,
|
||||
label: item.label,
|
||||
};
|
||||
} else if (item.link?.type === 'generated-index') {
|
||||
return {
|
||||
type: 'generated-index',
|
||||
slug: item.link.slug,
|
||||
label: item.label,
|
||||
};
|
||||
} else {
|
||||
const firstSubItem = getFirstLink(item.items);
|
||||
if (firstSubItem) {
|
||||
return firstSubItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
sidebars,
|
||||
getFirstDocIdOfFirstSidebar,
|
||||
|
@ -272,6 +328,7 @@ Available document ids are:
|
|||
getCategoryGeneratedIndexList,
|
||||
getCategoryGeneratedIndexNavigation,
|
||||
checkSidebarsDocIds,
|
||||
getFirstLink: (id) => getFirstLink(sidebars[id]),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -216,6 +216,17 @@ export type GlobalVersion = {
|
|||
path: string;
|
||||
mainDocId: string; // home doc (if docs homepage configured), or first doc
|
||||
docs: GlobalDoc[];
|
||||
sidebars?: Record<string, GlobalSidebar>;
|
||||
};
|
||||
|
||||
export type GlobalSidebarLink = {
|
||||
label: string;
|
||||
path: string;
|
||||
};
|
||||
|
||||
export type GlobalSidebar = {
|
||||
link?: GlobalSidebarLink;
|
||||
// ... we may add other things here later
|
||||
};
|
||||
|
||||
export type GlobalPluginData = {
|
||||
|
|
|
@ -477,10 +477,23 @@ declare module '@theme/NavbarItem/DocNavbarItem' {
|
|||
export default DocsSidebarNavbarItem;
|
||||
}
|
||||
|
||||
declare module '@theme/NavbarItem/DocSidebarNavbarItem' {
|
||||
import type {Props as DefaultNavbarItemProps} from '@theme/NavbarItem/DefaultNavbarItem';
|
||||
|
||||
export interface Props extends DefaultNavbarItemProps {
|
||||
readonly sidebarId: string;
|
||||
readonly docsPluginId?: string;
|
||||
}
|
||||
|
||||
const DocSidebarNavbarItem: (props: Props) => JSX.Element;
|
||||
export default DocSidebarNavbarItem;
|
||||
}
|
||||
|
||||
declare module '@theme/NavbarItem' {
|
||||
import type {ComponentProps} from 'react';
|
||||
import type {Props as DefaultNavbarItemProps} from '@theme/NavbarItem/DefaultNavbarItem';
|
||||
import type {Props as DocNavbarItemProps} from '@theme/NavbarItem/DocNavbarItem';
|
||||
import type {Props as DocSidebarNavbarItemProps} from '@theme/NavbarItem/DocSidebarNavbarItem';
|
||||
import type {Props as DocsVersionNavbarItemProps} from '@theme/NavbarItem/DocsVersionNavbarItem';
|
||||
import type {Props as DropdownNavbarItemProps} from '@theme/NavbarItem/DropdownNavbarItem';
|
||||
import type {Props as DocsVersionDropdownNavbarItemProps} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem';
|
||||
|
@ -490,7 +503,8 @@ declare module '@theme/NavbarItem' {
|
|||
export type LinkLikeNavbarItemProps =
|
||||
| ({readonly type?: 'default'} & DefaultNavbarItemProps)
|
||||
| ({readonly type: 'doc'} & DocNavbarItemProps)
|
||||
| ({readonly type: 'docsVersion'} & DocsVersionNavbarItemProps);
|
||||
| ({readonly type: 'docsVersion'} & DocsVersionNavbarItemProps)
|
||||
| ({readonly type: 'docSidebar'} & DocSidebarNavbarItemProps);
|
||||
|
||||
export type Props = ComponentProps<'a'> & {
|
||||
readonly position?: 'left' | 'right';
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
|
||||
import {useLatestVersion, useActiveDocContext} from '@theme/hooks/useDocs';
|
||||
import clsx from 'clsx';
|
||||
import {getInfimaActiveClassName} from './index';
|
||||
import type {Props} from '@theme/NavbarItem/DocSidebarNavbarItem';
|
||||
import {useDocsPreferredVersion, uniq} from '@docusaurus/theme-common';
|
||||
import type {
|
||||
GlobalDataVersion,
|
||||
GlobalDataSidebar,
|
||||
} from '@docusaurus/plugin-content-docs';
|
||||
|
||||
function getSidebarLink(versions: GlobalDataVersion[], sidebarId: string) {
|
||||
const allSidebars = versions
|
||||
.flatMap((version) => {
|
||||
if (version.sidebars) {
|
||||
return Object.entries(version.sidebars);
|
||||
}
|
||||
return undefined;
|
||||
})
|
||||
.filter(
|
||||
(sidebarItem): sidebarItem is [string, GlobalDataSidebar] =>
|
||||
!!sidebarItem,
|
||||
);
|
||||
const sidebarEntry = allSidebars.find((sidebar) => sidebar[0] === sidebarId);
|
||||
if (!sidebarEntry) {
|
||||
throw new Error(
|
||||
`DocSidebarNavbarItem: couldn't find any sidebar with id "${sidebarId}" in version${
|
||||
versions.length ? 's' : ''
|
||||
} ${versions.map((version) => version.name).join(', ')}".
|
||||
Available sidebar ids are:
|
||||
- ${Object.keys(allSidebars).join('\n- ')}`,
|
||||
);
|
||||
}
|
||||
if (!sidebarEntry[1].link) {
|
||||
throw new Error(
|
||||
`DocSidebarNavbarItem: couldn't find any document for sidebar with id "${sidebarId}"`,
|
||||
);
|
||||
}
|
||||
return sidebarEntry[1].link;
|
||||
}
|
||||
|
||||
export default function DocSidebarNavbarItem({
|
||||
sidebarId,
|
||||
label,
|
||||
docsPluginId,
|
||||
...props
|
||||
}: Props): JSX.Element {
|
||||
const {activeVersion, activeDoc} = useActiveDocContext(docsPluginId);
|
||||
const {preferredVersion} = useDocsPreferredVersion(docsPluginId);
|
||||
const latestVersion = useLatestVersion(docsPluginId);
|
||||
|
||||
// Versions used to look for the doc to link to, ordered + no duplicate
|
||||
const versions = uniq(
|
||||
[activeVersion, preferredVersion, latestVersion].filter(
|
||||
Boolean,
|
||||
) as GlobalDataVersion[],
|
||||
);
|
||||
const sidebarLink = getSidebarLink(versions, sidebarId);
|
||||
const activeDocInfimaClassName = getInfimaActiveClassName(props.mobile);
|
||||
|
||||
return (
|
||||
<DefaultNavbarItem
|
||||
exact
|
||||
{...props}
|
||||
className={clsx(props.className, {
|
||||
[activeDocInfimaClassName]: activeDoc?.sidebar === sidebarId,
|
||||
})}
|
||||
activeClassName={activeDocInfimaClassName}
|
||||
label={label ?? sidebarLink.label}
|
||||
to={sidebarLink.path}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -32,6 +32,7 @@ const NavbarItemComponents: Record<
|
|||
docsVersionDropdown: () =>
|
||||
require('@theme/NavbarItem/DocsVersionDropdownNavbarItem').default,
|
||||
doc: () => require('@theme/NavbarItem/DocNavbarItem').default,
|
||||
docSidebar: () => require('@theme/NavbarItem/DocSidebarNavbarItem').default,
|
||||
/* eslint-enable @typescript-eslint/no-var-requires, global-require */
|
||||
} as const;
|
||||
|
||||
|
|
|
@ -85,6 +85,12 @@ const DocItemSchema = NavbarItemBaseSchema.append({
|
|||
docsPluginId: Joi.string(),
|
||||
});
|
||||
|
||||
const DocSidebarItemSchema = NavbarItemBaseSchema.append({
|
||||
type: Joi.string().equal('docSidebar').required(),
|
||||
sidebarId: Joi.string().required(),
|
||||
docsPluginId: Joi.string(),
|
||||
});
|
||||
|
||||
const itemWithType = (type: string | undefined) => {
|
||||
// because equal(undefined) is not supported :/
|
||||
const typeSchema = type
|
||||
|
@ -172,6 +178,10 @@ const NavbarItemSchema = Joi.object({
|
|||
is: itemWithType('doc'),
|
||||
then: DocItemSchema,
|
||||
},
|
||||
{
|
||||
is: itemWithType('docSidebar'),
|
||||
then: DocSidebarItemSchema,
|
||||
},
|
||||
{
|
||||
is: itemWithType('localeDropdown'),
|
||||
then: LocaleDropdownNavbarItemSchema,
|
||||
|
|
|
@ -325,6 +325,7 @@ Navbar dropdown items only accept the following **"link-like" item types**:
|
|||
- [Navbar link](#navbar-link)
|
||||
- [Navbar doc link](#navbar-doc-link)
|
||||
- [Navbar docs version](#navbar-docs-version)
|
||||
- [Navbar doc sidebar](#navbar-doc-sidebar)
|
||||
|
||||
Note that the dropdown base item is a clickable link as well, so this item can receive any of the props of a [plain navbar link](#navbar-link).
|
||||
|
||||
|
@ -412,6 +413,71 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
#### Navbar linked to a sidebar {#navbar-doc-sidebar}
|
||||
|
||||
You can link a navbar item to the first document link (which can be a doc link or a generated category index) of a given sidebar without having to hardcode a doc ID.
|
||||
|
||||
Accepted fields:
|
||||
|
||||
<APITable name="navbar-doc-sidebar">
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `type` | `'docSidebar'` | **Required** | Sets the type of this navbar item to a sidebar's first document. |
|
||||
| `sidebarId` | `string` | **Required** | The ID of the sidebar that this item is linked to. |
|
||||
| `label` | `string` | First document link's sidebar label | The name to be shown for this item. |
|
||||
| `position` | <code>'left' \| 'right'</code> | `'left'` | The side of the navbar this item should appear on. |
|
||||
| `docsPluginId` | `string` | `'default'` | The ID of the docs plugin that the sidebar belongs to. |
|
||||
|
||||
</APITable>
|
||||
|
||||
:::tip
|
||||
|
||||
Use this navbar item type if your sidebar is updated often and the order is not stable.
|
||||
|
||||
:::
|
||||
|
||||
Example configuration:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
items: [
|
||||
// highlight-start
|
||||
{
|
||||
type: 'docSidebar',
|
||||
position: 'left',
|
||||
sidebarId: 'api',
|
||||
label: 'API',
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
tutorial: [
|
||||
{
|
||||
type: 'autogenerated',
|
||||
dirName: 'guides',
|
||||
},
|
||||
],
|
||||
api: [
|
||||
// highlight-next-line
|
||||
'cli', // The navbar item will be linking to this doc
|
||||
'docusaurus-core',
|
||||
{
|
||||
type: 'autogenerated',
|
||||
dirName: 'api',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
#### Navbar docs version dropdown {#navbar-docs-version-dropdown}
|
||||
|
||||
If you use docs with versioning, this special navbar item type that will render a dropdown with all your site's available versions.
|
||||
|
|
|
@ -366,9 +366,9 @@ const config = {
|
|||
label: 'Docs',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
type: 'docSidebar',
|
||||
position: 'left',
|
||||
docId: 'cli',
|
||||
sidebarId: 'api',
|
||||
label: 'API',
|
||||
},
|
||||
{to: 'blog', label: 'Blog', position: 'left'},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue