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:
Minh Pham 2022-01-06 05:52:25 -05:00 committed by GitHub
parent 3cb99124de
commit eade41a702
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 396 additions and 13 deletions

View file

@ -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",
},
},
},
},
],
},

View file

@ -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),
};
}

View file

@ -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;

View file

@ -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', () => {

View file

@ -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]),
};
}

View file

@ -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 = {