mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-12 00:27:21 +02:00
feat(content-docs): sidebar category linking to document or auto-generated index page (#5830)
Co-authored-by: Joshua Chen <sidachen2003@gmail.com> Co-authored-by: Armano <armano2@users.noreply.github.com> Co-authored-by: Alexey Pyltsyn <lex61rus@gmail.com>
This commit is contained in:
parent
95f911efef
commit
cfae5d0933
105 changed files with 3904 additions and 816 deletions
|
@ -12,8 +12,12 @@ import {
|
|||
collectSidebarLinks,
|
||||
transformSidebarItems,
|
||||
collectSidebarsDocIds,
|
||||
SidebarNavigation,
|
||||
toDocNavigationLink,
|
||||
toNavigationLink,
|
||||
} from '../utils';
|
||||
import type {Sidebar, Sidebars} from '../types';
|
||||
import {DocMetadataBase, DocNavLink} from '../../types';
|
||||
|
||||
describe('createSidebarsUtils', () => {
|
||||
const sidebar1: Sidebar = [
|
||||
|
@ -21,13 +25,13 @@ describe('createSidebarsUtils', () => {
|
|||
type: 'category',
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
label: 'Category1',
|
||||
label: 'S1 Category',
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
label: 'Subcategory 1',
|
||||
label: 'S1 Subcategory',
|
||||
items: [{type: 'doc', id: 'doc1'}],
|
||||
},
|
||||
{type: 'doc', id: 'doc2'},
|
||||
|
@ -40,7 +44,7 @@ describe('createSidebarsUtils', () => {
|
|||
type: 'category',
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
label: 'Category2',
|
||||
label: 'S2 Category',
|
||||
items: [
|
||||
{type: 'doc', id: 'doc3'},
|
||||
{type: 'doc', id: 'doc4'},
|
||||
|
@ -48,10 +52,58 @@ describe('createSidebarsUtils', () => {
|
|||
},
|
||||
];
|
||||
|
||||
const sidebars: Sidebars = {sidebar1, sidebar2};
|
||||
const sidebar3: Sidebar = [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
label: 'S3 Category',
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'doc5',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
label: 'S3 SubCategory',
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
slug: '/s3-subcategory-index-slug',
|
||||
permalink: '/s3-subcategory-index-permalink',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: false,
|
||||
collapsible: true,
|
||||
label: 'S3 SubSubCategory',
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
slug: '/s3-subsubcategory-slug',
|
||||
permalink: '/s3-subsubcategory-index-permalink',
|
||||
},
|
||||
items: [
|
||||
{type: 'doc', id: 'doc6'},
|
||||
{type: 'doc', id: 'doc7'},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const {getFirstDocIdOfFirstSidebar, getSidebarNameByDocId, getDocNavigation} =
|
||||
createSidebarsUtils(sidebars);
|
||||
const sidebars: Sidebars = {sidebar1, sidebar2, sidebar3};
|
||||
|
||||
const {
|
||||
getFirstDocIdOfFirstSidebar,
|
||||
getSidebarNameByDocId,
|
||||
getDocNavigation,
|
||||
getCategoryGeneratedIndexNavigation,
|
||||
getCategoryGeneratedIndexList,
|
||||
} = createSidebarsUtils(sidebars);
|
||||
|
||||
test('getSidebarNameByDocId', async () => {
|
||||
expect(getFirstDocIdOfFirstSidebar()).toEqual('doc1');
|
||||
|
@ -62,32 +114,117 @@ describe('createSidebarsUtils', () => {
|
|||
expect(getSidebarNameByDocId('doc2')).toEqual('sidebar1');
|
||||
expect(getSidebarNameByDocId('doc3')).toEqual('sidebar2');
|
||||
expect(getSidebarNameByDocId('doc4')).toEqual('sidebar2');
|
||||
expect(getSidebarNameByDocId('doc5')).toEqual(undefined);
|
||||
expect(getSidebarNameByDocId('doc6')).toEqual(undefined);
|
||||
expect(getSidebarNameByDocId('doc5')).toEqual('sidebar3');
|
||||
expect(getSidebarNameByDocId('doc6')).toEqual('sidebar3');
|
||||
expect(getSidebarNameByDocId('doc7')).toEqual('sidebar3');
|
||||
expect(getSidebarNameByDocId('unknown_id')).toEqual(undefined);
|
||||
});
|
||||
|
||||
test('getDocNavigation', async () => {
|
||||
expect(getDocNavigation('doc1')).toEqual({
|
||||
sidebarName: 'sidebar1',
|
||||
previousId: undefined,
|
||||
nextId: 'doc2',
|
||||
});
|
||||
previous: undefined,
|
||||
next: {
|
||||
type: 'doc',
|
||||
id: 'doc2',
|
||||
},
|
||||
} as SidebarNavigation);
|
||||
expect(getDocNavigation('doc2')).toEqual({
|
||||
sidebarName: 'sidebar1',
|
||||
previousId: 'doc1',
|
||||
nextId: undefined,
|
||||
});
|
||||
previous: {
|
||||
type: 'doc',
|
||||
id: 'doc1',
|
||||
},
|
||||
next: undefined,
|
||||
} as SidebarNavigation);
|
||||
|
||||
expect(getDocNavigation('doc3')).toEqual({
|
||||
sidebarName: 'sidebar2',
|
||||
previousId: undefined,
|
||||
nextId: 'doc4',
|
||||
});
|
||||
previous: undefined,
|
||||
next: {
|
||||
type: 'doc',
|
||||
id: 'doc4',
|
||||
},
|
||||
} as SidebarNavigation);
|
||||
expect(getDocNavigation('doc4')).toEqual({
|
||||
sidebarName: 'sidebar2',
|
||||
previousId: 'doc3',
|
||||
nextId: undefined,
|
||||
});
|
||||
previous: {
|
||||
type: 'doc',
|
||||
id: 'doc3',
|
||||
},
|
||||
next: undefined,
|
||||
} as SidebarNavigation);
|
||||
|
||||
expect(getDocNavigation('doc5')).toMatchObject({
|
||||
sidebarName: 'sidebar3',
|
||||
previous: undefined,
|
||||
next: {
|
||||
type: 'category',
|
||||
label: 'S3 SubCategory',
|
||||
},
|
||||
} as SidebarNavigation);
|
||||
expect(getDocNavigation('doc6')).toMatchObject({
|
||||
sidebarName: 'sidebar3',
|
||||
previous: {
|
||||
type: 'category',
|
||||
label: 'S3 SubSubCategory',
|
||||
},
|
||||
next: {
|
||||
type: 'doc',
|
||||
id: 'doc7',
|
||||
},
|
||||
} as SidebarNavigation);
|
||||
expect(getDocNavigation('doc7')).toMatchObject({
|
||||
sidebarName: 'sidebar3',
|
||||
previous: {
|
||||
type: 'doc',
|
||||
id: 'doc6',
|
||||
},
|
||||
next: undefined,
|
||||
} as SidebarNavigation);
|
||||
});
|
||||
|
||||
test('getCategoryGeneratedIndexNavigation', async () => {
|
||||
expect(
|
||||
getCategoryGeneratedIndexNavigation('/s3-subcategory-index-permalink'),
|
||||
).toMatchObject({
|
||||
sidebarName: 'sidebar3',
|
||||
previous: {
|
||||
type: 'category',
|
||||
label: 'S3 Category',
|
||||
},
|
||||
next: {
|
||||
type: 'category',
|
||||
label: 'S3 SubSubCategory',
|
||||
},
|
||||
} as SidebarNavigation);
|
||||
|
||||
expect(
|
||||
getCategoryGeneratedIndexNavigation('/s3-subsubcategory-index-permalink'),
|
||||
).toMatchObject({
|
||||
sidebarName: 'sidebar3',
|
||||
previous: {
|
||||
type: 'category',
|
||||
label: 'S3 SubCategory',
|
||||
},
|
||||
next: {
|
||||
type: 'doc',
|
||||
id: 'doc6',
|
||||
},
|
||||
} as SidebarNavigation);
|
||||
});
|
||||
|
||||
test('getCategoryGeneratedIndexList', async () => {
|
||||
expect(getCategoryGeneratedIndexList()).toMatchObject([
|
||||
{
|
||||
type: 'category',
|
||||
label: 'S3 SubCategory',
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'S3 SubSubCategory',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -393,3 +530,166 @@ describe('transformSidebarItems', () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toDocNavigationLink', () => {
|
||||
type TestDoc = Pick<DocMetadataBase, 'permalink' | 'title' | 'frontMatter'>;
|
||||
function testDoc(data: TestDoc) {
|
||||
return data as DocMetadataBase;
|
||||
}
|
||||
|
||||
test('with no frontmatter', () => {
|
||||
expect(
|
||||
toDocNavigationLink(
|
||||
testDoc({
|
||||
title: 'Doc Title',
|
||||
permalink: '/docPermalink',
|
||||
frontMatter: {},
|
||||
}),
|
||||
),
|
||||
).toEqual({
|
||||
title: 'Doc Title',
|
||||
permalink: '/docPermalink',
|
||||
} as DocNavLink);
|
||||
});
|
||||
|
||||
test('with pagination_label frontmatter', () => {
|
||||
expect(
|
||||
toDocNavigationLink(
|
||||
testDoc({
|
||||
title: 'Doc Title',
|
||||
permalink: '/docPermalink',
|
||||
frontMatter: {
|
||||
pagination_label: 'pagination_label',
|
||||
},
|
||||
}),
|
||||
),
|
||||
).toEqual({
|
||||
title: 'pagination_label',
|
||||
permalink: '/docPermalink',
|
||||
} as DocNavLink);
|
||||
});
|
||||
|
||||
test('with sidebar_label frontmatter', () => {
|
||||
expect(
|
||||
toDocNavigationLink(
|
||||
testDoc({
|
||||
title: 'Doc Title',
|
||||
permalink: '/docPermalink',
|
||||
frontMatter: {
|
||||
sidebar_label: 'sidebar_label',
|
||||
},
|
||||
}),
|
||||
),
|
||||
).toEqual({
|
||||
title: 'sidebar_label',
|
||||
permalink: '/docPermalink',
|
||||
} as DocNavLink);
|
||||
});
|
||||
|
||||
test('with pagination_label + sidebar_label frontmatter', () => {
|
||||
expect(
|
||||
toDocNavigationLink(
|
||||
testDoc({
|
||||
title: 'Doc Title',
|
||||
permalink: '/docPermalink',
|
||||
frontMatter: {
|
||||
pagination_label: 'pagination_label',
|
||||
sidebar_label: 'sidebar_label',
|
||||
},
|
||||
}),
|
||||
),
|
||||
).toEqual({
|
||||
title: 'pagination_label',
|
||||
permalink: '/docPermalink',
|
||||
} as DocNavLink);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toNavigationLink', () => {
|
||||
type TestDoc = Pick<DocMetadataBase, 'permalink' | 'title'>;
|
||||
function testDoc(data: TestDoc) {
|
||||
return {...data, frontMatter: {}} as DocMetadataBase;
|
||||
}
|
||||
|
||||
const docsById: Record<string, DocMetadataBase> = {
|
||||
doc1: testDoc({
|
||||
title: 'Doc 1',
|
||||
permalink: '/doc1',
|
||||
}),
|
||||
doc2: testDoc({
|
||||
title: 'Doc 1',
|
||||
permalink: '/doc1',
|
||||
}),
|
||||
};
|
||||
|
||||
test('with doc items', () => {
|
||||
expect(toNavigationLink({type: 'doc', id: 'doc1'}, docsById)).toEqual(
|
||||
toDocNavigationLink(docsById.doc1),
|
||||
);
|
||||
expect(toNavigationLink({type: 'doc', id: 'doc2'}, docsById)).toEqual(
|
||||
toDocNavigationLink(docsById.doc2),
|
||||
);
|
||||
expect(() =>
|
||||
toNavigationLink({type: 'doc', id: 'doc3'}, docsById),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Can't create navigation link: no doc found with id=doc3"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('with category item and doc link', () => {
|
||||
expect(
|
||||
toNavigationLink(
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category',
|
||||
items: [],
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'doc1',
|
||||
},
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
},
|
||||
docsById,
|
||||
),
|
||||
).toEqual(toDocNavigationLink(docsById.doc1));
|
||||
expect(() =>
|
||||
toNavigationLink(
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category',
|
||||
items: [],
|
||||
link: {
|
||||
type: 'doc',
|
||||
id: 'doc3',
|
||||
},
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
},
|
||||
docsById,
|
||||
),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Can't create navigation link: no doc found with id=doc3"`,
|
||||
);
|
||||
});
|
||||
|
||||
test('with category item and generated-index link', () => {
|
||||
expect(
|
||||
toNavigationLink(
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Category',
|
||||
items: [],
|
||||
link: {
|
||||
type: 'generated-index',
|
||||
slug: 'slug',
|
||||
permalink: 'generated-index-permalink',
|
||||
},
|
||||
collapsed: true,
|
||||
collapsible: true,
|
||||
},
|
||||
docsById,
|
||||
),
|
||||
).toEqual({title: 'Category', permalink: 'generated-index-permalink'});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue