mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-10 15:47:23 +02:00
feat(v2): expanded sidebar categories by default (#2682)
* feat: update sidebar categ to take collapsed prop * feat: add extra sidebars collapsed test * fix: only mutate item.collapsed if necessary * feat: update docs for SidebarItemCategory * fix: update snapshots * fix: update json to match new sidebar schema * fix: update last snapshot * refactor: check if item should be expanded * docs: update sidebar categories section * refactor: use new collpased on docusaurus * feat: only highlight category for active page * fix: check for window * refactor: use ExecutionEnviornment * refactor: make isCategoryOfActivePage pure * fix: rename docs to docs-introduction in sidebars * Update docs.md * misc: remove setting for every sidebar Co-authored-by: Yangshun Tay <tay.yang.shun@gmail.com>
This commit is contained in:
parent
d8ebe8b2e4
commit
07b9e9cd62
12 changed files with 273 additions and 26 deletions
|
@ -9,25 +9,30 @@ module.exports = {
|
|||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: true,
|
||||
label: 'level 1',
|
||||
items: [
|
||||
'a',
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: true,
|
||||
label: 'level 2',
|
||||
items: [
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: true,
|
||||
label: 'level 3',
|
||||
items: [
|
||||
'c',
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: true,
|
||||
label: 'level 4',
|
||||
items: [
|
||||
'd',
|
||||
{
|
||||
type: 'category',
|
||||
collapsed: true,
|
||||
label: 'deeper more more',
|
||||
items: ['e'],
|
||||
},
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"docs": [
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Introduction",
|
||||
"items": [
|
||||
"doc1"
|
||||
],
|
||||
"collapsed": false
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Powering MDX",
|
||||
"items": [
|
||||
"doc2"
|
||||
],
|
||||
"collapsed": false
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Introduction",
|
||||
"items": ["doc1"],
|
||||
"collapsed": false
|
||||
}
|
||||
],
|
||||
"Reference": [
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Powering MDX",
|
||||
"items": ["doc2"],
|
||||
"collapsed": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ exports[`simple website content 1`] = `
|
|||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
|
@ -36,6 +37,7 @@ Object {
|
|||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/hello",
|
||||
|
@ -236,6 +238,7 @@ exports[`versioned website content: all sidebars 1`] = `
|
|||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/next/foo/bar",
|
||||
|
@ -247,6 +250,7 @@ Object {
|
|||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/next/hello",
|
||||
|
@ -260,6 +264,7 @@ Object {
|
|||
],
|
||||
"version-1.0.0/docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/1.0.0/foo/bar",
|
||||
|
@ -276,6 +281,7 @@ Object {
|
|||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/1.0.0/hello",
|
||||
|
@ -289,6 +295,7 @@ Object {
|
|||
],
|
||||
"version-1.0.1/docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/foo/bar",
|
||||
|
@ -300,6 +307,7 @@ Object {
|
|||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/hello",
|
||||
|
@ -319,6 +327,7 @@ Object {
|
|||
"docsSidebars": Object {
|
||||
"version-1.0.0/docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/1.0.0/foo/bar",
|
||||
|
@ -335,6 +344,7 @@ Object {
|
|||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/1.0.0/hello",
|
||||
|
@ -361,6 +371,7 @@ Object {
|
|||
"docsSidebars": Object {
|
||||
"version-1.0.1/docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/foo/bar",
|
||||
|
@ -372,6 +383,7 @@ Object {
|
|||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/hello",
|
||||
|
@ -397,6 +409,7 @@ Object {
|
|||
"docsSidebars": Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/next/foo/bar",
|
||||
|
@ -408,6 +421,7 @@ Object {
|
|||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "/docs/next/hello",
|
||||
|
|
|
@ -4,6 +4,7 @@ exports[`loadSidebars sidebars link 1`] = `
|
|||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "https://github.com",
|
||||
|
@ -18,30 +19,107 @@ Object {
|
|||
}
|
||||
`;
|
||||
|
||||
exports[`loadSidebars sidebars with category.collapsed property 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"collapsed": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "doc1",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "Introduction",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
"label": "Test",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"collapsed": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "doc2",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "Powering MDX",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
"label": "Reference",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`loadSidebars sidebars with category.collapsed property at first level 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "doc1",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "Introduction",
|
||||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "doc2",
|
||||
"type": "doc",
|
||||
},
|
||||
],
|
||||
"label": "Powering MDX",
|
||||
"type": "category",
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`loadSidebars sidebars with deep level of category 1`] = `
|
||||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "a",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "c",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "d",
|
||||
"type": "doc",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "e",
|
||||
|
@ -100,6 +178,7 @@ exports[`loadSidebars sidebars with known sidebar item type 1`] = `
|
|||
Object {
|
||||
"docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "foo/bar",
|
||||
|
@ -123,6 +202,7 @@ Object {
|
|||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "hello",
|
||||
|
|
|
@ -4,6 +4,7 @@ exports[`docsVersion first time versioning 1`] = `
|
|||
Object {
|
||||
"version-1.0.0/docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
|
@ -33,6 +34,7 @@ Object {
|
|||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "version-1.0.0/hello",
|
||||
|
@ -50,6 +52,7 @@ exports[`docsVersion not the first time versioning 1`] = `
|
|||
Object {
|
||||
"version-2.0.0/docs": Array [
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "version-2.0.0/foo/bar",
|
||||
|
@ -60,6 +63,7 @@ Object {
|
|||
"type": "category",
|
||||
},
|
||||
Object {
|
||||
"collapsed": true,
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "version-2.0.0/hello",
|
||||
|
|
|
@ -126,4 +126,19 @@ describe('loadSidebars', () => {
|
|||
const result = loadSidebars(null);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
test('sidebars with category.collapsed property', async () => {
|
||||
const sidebarPath = path.join(fixtureDir, 'sidebars-collapsed.json');
|
||||
const result = loadSidebars([sidebarPath]);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('sidebars with category.collapsed property at first level', async () => {
|
||||
const sidebarPath = path.join(
|
||||
fixtureDir,
|
||||
'sidebars-collapsed-first-level.json',
|
||||
);
|
||||
const result = loadSidebars([sidebarPath]);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -33,6 +33,7 @@ function normalizeCategoryShorthand(
|
|||
): SidebarItemCategoryRaw[] {
|
||||
return Object.entries(sidebar).map(([label, items]) => ({
|
||||
type: 'category',
|
||||
collapsed: true,
|
||||
label,
|
||||
items,
|
||||
}));
|
||||
|
@ -56,7 +57,7 @@ function assertItem(item: Object, keys: string[]): void {
|
|||
}
|
||||
|
||||
function assertIsCategory(item: any): asserts item is SidebarItemCategoryRaw {
|
||||
assertItem(item, ['items', 'label']);
|
||||
assertItem(item, ['items', 'label', 'collapsed']);
|
||||
if (typeof item.label !== 'string') {
|
||||
throw new Error(
|
||||
`Error loading ${JSON.stringify(item)}. "label" must be a string.`,
|
||||
|
@ -67,6 +68,12 @@ function assertIsCategory(item: any): asserts item is SidebarItemCategoryRaw {
|
|||
`Error loading ${JSON.stringify(item)}. "items" must be an array.`,
|
||||
);
|
||||
}
|
||||
// "collapsed" is an optional property
|
||||
if (item.hasOwnProperty('collapsed') && typeof item.collapsed !== 'boolean') {
|
||||
throw new Error(
|
||||
`Error loading ${JSON.stringify(item)}. "collapsed" must be a boolean.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function assertIsDoc(item: any): asserts item is SidebarItemDoc {
|
||||
|
|
|
@ -42,12 +42,14 @@ export interface SidebarItemCategory {
|
|||
type: 'category';
|
||||
label: string;
|
||||
items: SidebarItem[];
|
||||
collapsed?: boolean;
|
||||
}
|
||||
|
||||
export interface SidebarItemCategoryRaw {
|
||||
type: 'category';
|
||||
label: string;
|
||||
items: SidebarItemRaw[];
|
||||
collapsed?: boolean;
|
||||
}
|
||||
|
||||
export type SidebarItem =
|
||||
|
@ -83,6 +85,7 @@ export interface DocsSidebarItemCategory {
|
|||
type: 'category';
|
||||
label: string;
|
||||
items: DocsSidebarItem[];
|
||||
collapsed?: boolean;
|
||||
}
|
||||
|
||||
export type DocsSidebarItem = SidebarItemLink | DocsSidebarItemCategory;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import React, {useState, useCallback} from 'react';
|
||||
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
||||
import classnames from 'classnames';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import useAnnouncementBarContext from '@theme/hooks/useAnnouncementBarContext';
|
||||
|
@ -44,6 +45,28 @@ function DocSidebarItem({
|
|||
setCollapsed((state) => !state);
|
||||
});
|
||||
|
||||
// Make sure we have access to the window
|
||||
const activePageRelativeUrl = ExecutionEnvironment.canUseDOM
|
||||
? window.location.pathname + window.location.search
|
||||
: null;
|
||||
|
||||
// We need to know if the category item
|
||||
// is the parent of the active page
|
||||
// If it is, this returns true and make sure to highlight this category
|
||||
const isCategoryOfActivePage = (_items, _activePageRelativeUrl) => {
|
||||
// Make sure we have items
|
||||
if (typeof _items !== 'undefined') {
|
||||
return _items.some((categoryItem) => {
|
||||
// Grab the category item's href
|
||||
const childHref = categoryItem.href;
|
||||
// Compare it to the current active page
|
||||
return _activePageRelativeUrl === childHref;
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
case 'category':
|
||||
return (
|
||||
|
@ -56,7 +79,10 @@ function DocSidebarItem({
|
|||
<a
|
||||
className={classnames('menu__link', {
|
||||
'menu__link--sublist': collapsible,
|
||||
'menu__link--active': collapsible && !item.collapsed,
|
||||
'menu__link--active':
|
||||
collapsible &&
|
||||
!item.collapsed &&
|
||||
isCategoryOfActivePage(items, activePageRelativeUrl),
|
||||
})}
|
||||
href="#!"
|
||||
onClick={collapsible ? handleItemClick : undefined}
|
||||
|
@ -116,8 +142,18 @@ function mutateSidebarCollapsingState(item, path) {
|
|||
items
|
||||
.map((childItem) => mutateSidebarCollapsingState(childItem, path))
|
||||
.filter((val) => val).length > 0;
|
||||
|
||||
// Check if the user wants the category to be expanded by default
|
||||
const shouldExpand = item.collapsed === false;
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item.collapsed = !anyChildItemsActive;
|
||||
|
||||
if (shouldExpand) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item.collapsed = false;
|
||||
}
|
||||
|
||||
return anyChildItemsActive;
|
||||
}
|
||||
|
||||
|
|
|
@ -243,6 +243,7 @@ type SidebarItemCategory = {
|
|||
type: 'category';
|
||||
label: string; // Sidebar label text.
|
||||
items: SidebarItem[]; // Array of sidebar items.
|
||||
collapsed: boolean; // Set the category to be collapsed or open by default
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -292,6 +293,26 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
#### Expanded categories by default
|
||||
|
||||
For docs that have collapsible categories, you may want more fine-grain control over certain categories. If you want specific categories to be always expanded, you can set `collapsed` to `false`:
|
||||
|
||||
```js title="sidebars.js"
|
||||
module.exports = {
|
||||
docs: {
|
||||
Guides: [
|
||||
'creating-pages',
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Docs',
|
||||
collapsed: false,
|
||||
items: ['markdown-features', 'sidebar', 'versioning'],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Docs-only mode
|
||||
|
||||
If you just want the documentation feature, you can enable "docs-only mode".
|
||||
|
|
|
@ -6,10 +6,22 @@
|
|||
*/
|
||||
|
||||
module.exports = {
|
||||
docs: {
|
||||
Docusaurus: ['introduction', 'design-principles', 'contributing'],
|
||||
'Getting Started': ['installation', 'configuration'],
|
||||
Guides: [
|
||||
docs: [
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Docusaurus',
|
||||
items: ['introduction', 'design-principles', 'contributing'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Getting Started',
|
||||
collapsed: false,
|
||||
items: ['installation', 'configuration'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Guides',
|
||||
items: [
|
||||
'creating-pages',
|
||||
'styling-layout',
|
||||
'static-assets',
|
||||
|
@ -21,8 +33,16 @@ module.exports = {
|
|||
'deployment',
|
||||
'migrating-from-v1-to-v2',
|
||||
],
|
||||
'Advanced Guides': ['using-plugins', 'using-themes', 'presets'],
|
||||
'API Reference': [
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Advanced Guides',
|
||||
items: ['using-plugins', 'using-themes', 'presets'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'API Reference',
|
||||
items: [
|
||||
'cli',
|
||||
'docusaurus-core',
|
||||
'docusaurus.config.js',
|
||||
|
@ -30,6 +50,7 @@ module.exports = {
|
|||
'theme-classic',
|
||||
],
|
||||
},
|
||||
],
|
||||
community: [
|
||||
'support',
|
||||
'team',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue