Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(theme-classic): auto-collapse sibling categories in doc sidebar #3811

Merged
merged 15 commits into from
Jan 20, 2022
3 changes: 3 additions & 0 deletions packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ function DocPageContent({
sidebarCollapsible={
siteConfig.themeConfig?.sidebarCollapsible ?? true
}
autoCollapseSidebar={
siteConfig.themeConfig?.autoCollapseSidebar ?? true
}
onCollapse={toggleSidebar}
isHidden={hiddenSidebar}
/>
Expand Down
55 changes: 40 additions & 15 deletions packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import React, {useState, useCallback, useEffect, useRef} from 'react';
import React, {useState, useEffect, useRef} from 'react';
import clsx from 'clsx';
import {useThemeConfig, isSamePath} from '@docusaurus/theme-common';
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
Expand Down Expand Up @@ -46,6 +46,8 @@ function DocSidebarItemCategory({
onItemClick,
collapsible,
activePath,
collapseItems,
autoCollapsed,
slorber marked this conversation as resolved.
Show resolved Hide resolved
...props
}) {
const {items, label} = item;
Expand Down Expand Up @@ -80,18 +82,13 @@ function DocSidebarItemCategory({
}
}, [isActive, wasActive, collapsed]);

const handleItemClick = useCallback(
(e) => {
e.preventDefault();
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved

if (!menuListHeight) {
handleMenuListHeight();
}
const handleItemClick = (category) => {
if (!menuListHeight) {
handleMenuListHeight();
}

setTimeout(() => setCollapsed((state) => !state), 100);
},
[menuListHeight],
);
collapseItems(category);
};

if (items.length === 0) {
return null;
Expand All @@ -100,7 +97,7 @@ function DocSidebarItemCategory({
return (
<li
className={clsx('menu__list-item', {
'menu__list-item--collapsed': collapsed,
'menu__list-item--collapsed': item.collapsed,
})}
key={label}>
<a
Expand All @@ -109,7 +106,7 @@ function DocSidebarItemCategory({
'menu__link--active': collapsible && isActive,
[styles.menuLinkText]: !collapsible,
})}
onClick={collapsible ? handleItemClick : undefined}
onClick={collapsible ? () => handleItemClick(item) : undefined}
slorber marked this conversation as resolved.
Show resolved Hide resolved
href={collapsible ? '#!' : undefined}
{...props}>
{label}
Expand All @@ -130,6 +127,8 @@ function DocSidebarItemCategory({
tabIndex={collapsed ? '-1' : '0'}
key={childItem.label}
item={childItem}
autoCollapsed={autoCollapsed}
parent={items}
onItemClick={onItemClick}
collapsible={collapsible}
activePath={activePath}
Expand Down Expand Up @@ -174,9 +173,32 @@ function DocSidebarItemLink({
}

function DocSidebarItem(props) {
const {autoCollapsed, parent} = props;

const collapseItems = (item) => {
const isCollapsed = item.collapsed;

if (!isCollapsed) {
item.collapsed = !item.collapsed;
} else {
if (autoCollapsed) {
for (const s in parent) {
if (parent[s].type !== 'link') {
parent[s].collapsed = true;
} else {
parent[s].collapsed = false;
}
}
}
item.collapsed = !item.collapsed;
}
};

Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved
switch (props.item.type) {
case 'category':
return <DocSidebarItemCategory {...props} />;
return (
<DocSidebarItemCategory {...props} collapseItems={collapseItems} />
);
case 'link':
default:
return <DocSidebarItemLink {...props} />;
Expand All @@ -187,6 +209,7 @@ function DocSidebar({
path,
sidebar,
sidebarCollapsible = true,
autoCollapseSidebar = true,
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved
onCollapse,
isHidden,
}: Props): JSX.Element | null {
Expand Down Expand Up @@ -273,6 +296,8 @@ function DocSidebar({
setShowResponsiveSidebar(false);
}}
collapsible={sidebarCollapsible}
parent={sidebar}
autoCollapsed={autoCollapseSidebar}
activePath={path}
/>
))}
Expand Down
1 change: 1 addition & 0 deletions packages/docusaurus-theme-classic/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ declare module '@theme/DocSidebar' {
readonly path: string;
readonly sidebar: readonly PropSidebarItem[];
readonly sidebarCollapsible?: boolean;
readonly autoCollapseSidebar?: boolean;
readonly onCollapse: () => void;
readonly isHidden: boolean;
};
Expand Down
14 changes: 14 additions & 0 deletions website/docs/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ module.exports = {
};
```

### Auto Collapsable Sidebar

Using the enabled `themeConfig.autoCollapseSidebar` option, you can make the sidebar only have one parent category open at a time, helping users not get cluttered and only focus on the content they selected. This is enabled by default, If you want them to be always opened, set `themeConfig.autoCollapseSidebar` to `false`:
slorber marked this conversation as resolved.
Show resolved Hide resolved

```js {4} title="docusaurus.config.js"
module.exports = {
// ...
themeConfig: {
autoCollapseSidebar: false,
// ...
},
};
```

### Sidebar object

A sidebar object is defined like this:
Expand Down