fix sidebar's expand/collapse bug, remove default expand and collapse buttons, and link mobile sidebar to header's toggle button.

This commit is contained in:
Hossein Mehrabi
2022-10-08 00:39:41 +03:30
parent cc808e9991
commit 6a4df0b7cc
7 changed files with 199 additions and 16 deletions
@@ -0,0 +1,54 @@
import { useLocation } from '@docusaurus/router'
import { ThemeClassNames } from '@docusaurus/theme-common'
import { useDocsSidebar } from '@docusaurus/theme-common/internal'
import {
globalStore,
selectHiddenSidebar,
} from '@site/src/containers/GlobalStore'
import type { Props } from '@theme/DocPage/Layout/Sidebar'
import DocSidebar from '@theme/DocSidebar'
import clsx from 'clsx'
import React, { ReactNode } from 'react'
import styles from './styles.module.css'
// Reset sidebar state when sidebar changes
// Use React key to unmount/remount the children
// See https://github.com/facebook/docusaurus/issues/3414
function ResetOnSidebarChange({ children }: { children: ReactNode }) {
const sidebar = useDocsSidebar()
return (
<React.Fragment key={sidebar?.name ?? 'noSidebar'}>
{children}
</React.Fragment>
)
}
export default function DocPageLayoutSidebar({ sidebar }: Props): JSX.Element {
const { pathname } = useLocation()
const dispatch = globalStore.useDispatch()
const hiddenSidebar = globalStore.useSelector(selectHiddenSidebar)
return (
<aside
className={clsx(
ThemeClassNames.docs.docSidebarContainer,
styles.docSidebarContainer,
hiddenSidebar && styles.docSidebarContainerHidden,
)}
onTransitionEnd={(e) => {
if (!e.currentTarget.classList.contains(styles.docSidebarContainer!)) {
return
}
}}
>
<ResetOnSidebarChange>
<DocSidebar
sidebar={sidebar}
path={pathname}
onCollapse={() => dispatch.setHiddenSidebar(true)}
isHidden={hiddenSidebar}
/>
</ResetOnSidebarChange>
</aside>
)
}
@@ -0,0 +1,24 @@
:root {
--doc-sidebar-width: 300px;
--doc-sidebar-hidden-width: 30px;
}
.docSidebarContainer {
display: none;
}
@media (min-width: 997px) {
.docSidebarContainer {
display: block;
width: var(--doc-sidebar-width);
margin-top: calc(-1 * var(--ifm-navbar-height));
will-change: width;
transition: width var(--ifm-transition-fast) ease;
clip-path: inset(0);
}
.docSidebarContainerHidden {
width: var(--doc-sidebar-hidden-width);
cursor: pointer;
}
}
+29
View File
@@ -0,0 +1,29 @@
import { useThemeConfig } from '@docusaurus/theme-common'
import type { Props } from '@theme/DocSidebar/Desktop'
import Content from '@theme/DocSidebar/Desktop/Content'
import Logo from '@theme/Logo'
import clsx from 'clsx'
import React from 'react'
import styles from './styles.module.css'
function DocSidebarDesktop({ path, sidebar, onCollapse, isHidden }: Props) {
const {
navbar: { hideOnScroll },
docs: {},
} = useThemeConfig()
return (
<div
className={clsx(
styles.sidebar,
hideOnScroll && styles.sidebarWithHideableNavbar,
isHidden && styles.sidebarHidden,
)}
>
{hideOnScroll && <Logo tabIndex={-1} className={styles.sidebarLogo} />}
<Content path={path} sidebar={sidebar} />
</div>
)
}
export default React.memo(DocSidebarDesktop)
@@ -0,0 +1,43 @@
@media (min-width: 997px) {
.sidebar {
display: flex;
flex-direction: column;
max-height: 100vh;
height: 100%;
position: sticky;
top: 0;
padding-top: var(--ifm-navbar-height);
width: var(--doc-sidebar-width);
transition: opacity 50ms ease;
}
.sidebarWithHideableNavbar {
padding-top: 0;
}
.sidebarHidden {
opacity: 0;
height: 0;
overflow: hidden;
visibility: hidden;
}
.sidebarLogo {
display: flex !important;
align-items: center;
margin: 0 var(--ifm-navbar-padding-horizontal);
min-height: var(--ifm-navbar-height);
max-height: var(--ifm-navbar-height);
color: inherit !important;
text-decoration: none !important;
}
.sidebarLogo img {
margin-right: 0.5rem;
height: 2rem;
}
}
.sidebarLogo {
display: none;
}
+30 -14
View File
@@ -31,31 +31,47 @@ function NavbarItems({ items }: { items: NavbarItemConfig[] }): JSX.Element {
)
}
const SidebarToggleButton: React.FC<{
className: string
onToggle: () => void
shown: boolean
}> = ({ className, onToggle, shown }) => {
return (
<button
onClick={onToggle}
className={clsx(styles.sidebarButton, !shown && styles.expand, className)}
>
{shown ? <ChevronIcon /> : <HamburgerIcon />}
</button>
)
}
export default function NavbarContent(): JSX.Element {
const mobileSidebar = useNavbarMobileSidebar()
const items = useNavbarItems()
const dispatch = globalStore.useDispatch()
const hiddenDesktopSidebar = globalStore.useSelector(selectHiddenSidebar)
const localeDropdown = items.find((item) => item.type === 'localeDropdown')
const links = items.filter(
(item) => item.type === 'doc' || !!(item as any).to,
)
const mobileSidebar = useNavbarMobileSidebar()
const dispatch = globalStore.useDispatch()
const hiddenDesktopSidebar = globalStore.useSelector(selectHiddenSidebar)
return (
<div className={clsx('row', styles.root)}>
<div className="col col--2">
<button
onClick={dispatch.toggleSidebar}
className={clsx(
styles.sidebarButton,
hiddenDesktopSidebar && styles.expand,
)}
>
{!hiddenDesktopSidebar ? <ChevronIcon /> : <HamburgerIcon />}
</button>
<SidebarToggleButton
onToggle={mobileSidebar.toggle}
shown={mobileSidebar.shown}
className={styles.mobile}
/>
<SidebarToggleButton
onToggle={dispatch.toggleSidebar}
shown={!hiddenDesktopSidebar}
className={styles.desktop}
/>
</div>
<div className={clsx('col', styles.headerMiddle)}>
@@ -145,3 +145,15 @@ Hide color mode toggle in small viewports
display: none;
}
}
@include utils.responsive('lg', 'up') {
.sidebarButton.mobile {
display: none;
}
}
@include utils.responsive('lg', 'down') {
.sidebarButton.desktop {
display: none;
}
}
+7 -2
View File
@@ -1,9 +1,14 @@
.navbar-sidebar__brand {
--ifm-navbar-padding-horizontal: 1rem;
}
.navbar {
--ifm-navbar-height: 3.875rem;
--ifm-navbar-background-color: none;
--ifm-navbar-shadow: none;
--ifm-navbar-padding-horizontal: 0px;
--ifm-navbar-padding-vertical: 8px;
--ifm-navbar-padding-vertical: 0.5rem;
background: none;
}
:root {