Skip to content

Commit aab2075

Browse files
committed
feat(): Separate Doc State, lazy load doc sidebar on mobile
1 parent a8683a9 commit aab2075

File tree

7 files changed

+97
-56
lines changed

7 files changed

+97
-56
lines changed

docusaurus-theme/src/theme/DocSidebar/index.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { ChevronDown } from '@theme/icons';
3232
import { useActiveVersion } from '@theme/hooks/useDocs';
3333

3434
import styles from './styles.module.scss';
35-
import Backdrop from '@theme/Backdrop';
35+
import useDocStateContext from '@theme/hooks/useDocStateContext';
3636

3737
const MOBILE_TOGGLE_SIZE = 24;
3838

@@ -292,9 +292,14 @@ function DocSidebar({
292292
const { hideableSidebar } = useThemeConfig();
293293
const { isClosed: isAnnouncementBarClosed } = useAnnouncementBar();
294294

295-
const { setSidebarOpen, sidebarOpen } = useUserPreferencesContext();
295+
const { setMobileSidebarOpen, mobileSidebarOpen, mobileSidebarLoaded } =
296+
useDocStateContext();
297+
const windowSize = useWindowSize();
298+
299+
useLockBodyScroll(mobileSidebarOpen);
296300

297-
useLockBodyScroll(sidebarOpen);
301+
if (windowSize === windowSizes.mobile && !mobileSidebarLoaded)
302+
return <div></div>;
298303

299304
return (
300305
<aside
@@ -311,7 +316,7 @@ function DocSidebar({
311316
'thin-scrollbar',
312317
styles.menu,
313318
{
314-
'menu--show': sidebarOpen,
319+
'menu--show': mobileSidebarOpen,
315320
[styles.menuWithAnnouncementBar]:
316321
!isAnnouncementBarClosed && showAnnouncementBar,
317322
},
@@ -333,7 +338,7 @@ function DocSidebar({
333338
<ul className={clsx('menu__list', styles.menuList)}>
334339
<DocSidebarItems
335340
items={sidebar}
336-
onItemClick={() => setSidebarOpen(false)}
341+
onItemClick={() => setMobileSidebarOpen(false)}
337342
collapsible={sidebarCollapsible}
338343
activePath={path}
339344
/>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import { createContext } from 'react';
9+
10+
const DocStateContext = createContext(undefined);
11+
12+
export default DocStateContext;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import React, { useState } from 'react';
9+
10+
import DocStateContext from '@theme/DocStateContext';
11+
import type { Props } from '@theme/DocStateProvider';
12+
13+
function DocStateProvider(props: Props): JSX.Element {
14+
const [mobileSidebarLoaded, setMobileSidebarLoaded] = useState(false);
15+
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
16+
17+
return (
18+
<DocStateContext.Provider
19+
value={{
20+
mobileSidebarLoaded,
21+
setMobileSidebarLoaded,
22+
mobileSidebarOpen,
23+
setMobileSidebarOpen,
24+
}}
25+
>
26+
{props.children}
27+
</DocStateContext.Provider>
28+
);
29+
}
30+
31+
export default DocStateProvider;

docusaurus-theme/src/theme/Layout/index.tsx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import LayoutHead from '@theme/LayoutHead';
1616
import type { Props } from '@theme/Layout';
1717
import useKeyboardNavigation from '@theme/hooks/useKeyboardNavigation';
1818
import { ThemeClassNames } from '@docusaurus/theme-common';
19+
import DocStateProvider from '@theme/DocStateProvider';
1920
import './styles.css';
2021

2122
function Layout(props: Props): JSX.Element {
@@ -25,23 +26,25 @@ function Layout(props: Props): JSX.Element {
2526

2627
return (
2728
<LayoutProviders>
28-
<LayoutHead {...props} />
29+
<DocStateProvider>
30+
<LayoutHead {...props} />
2931

30-
<SkipToContent />
32+
<SkipToContent />
3133

32-
<AnnouncementBar />
34+
<AnnouncementBar />
3335

34-
<div
35-
className={clsx(
36-
ThemeClassNames.wrapper.main,
37-
wrapperClassName,
38-
pageClassName,
39-
)}
40-
>
41-
{children}
42-
</div>
36+
<div
37+
className={clsx(
38+
ThemeClassNames.wrapper.main,
39+
wrapperClassName,
40+
pageClassName,
41+
)}
42+
>
43+
{children}
44+
</div>
4345

44-
{!noFooter && <Footer />}
46+
{!noFooter && <Footer />}
47+
</DocStateProvider>
4548
</LayoutProviders>
4649
);
4750
}

docusaurus-theme/src/theme/UserPreferencesProvider/index.tsx

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { useContext } from 'react';
2+
3+
import DocStateContext from '@theme/DocStateContext';
4+
import type { DocStateContextProps } from '@theme/hooks/useDocStateContext';
5+
6+
function useDocStateContext(): DocStateContextProps {
7+
const context = useContext<DocStateContextProps | undefined>(DocStateContext);
8+
if (context == null) {
9+
throw new Error(
10+
'"useDocStateContext" is used outside of "Layout" component.',
11+
);
12+
}
13+
return context;
14+
}
15+
16+
export default useDocStateContext;

src/theme/Navbar/index.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import useThemeContext from '@theme/hooks/useThemeContext';
1414
import { useThemeConfig } from '@docusaurus/theme-common';
1515
import useHideableNavbar from '@theme/hooks/useHideableNavbar';
1616
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
17-
import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext';
17+
import useDocStateContext from '@theme/hooks/useDocStateContext';
1818
import { useActiveVersion } from '@theme/hooks/useDocs';
1919
import useWindowSize, { windowSizes } from '@theme/hooks/useWindowSize';
2020
import NavbarItem from '@theme/NavbarItem';
@@ -60,18 +60,23 @@ function Navbar(): JSX.Element {
6060
} = useDocusaurusContext();
6161
const { path: homePath } = useActiveVersion();
6262
const [navbarSidebarOpen, setNavbarSidebarOpen] = useState(false);
63-
const { sidebarOpen, setSidebarOpen } = useUserPreferencesContext();
63+
const {
64+
mobileSidebarOpen,
65+
setMobileSidebarOpen,
66+
setMobileSidebarLoaded,
67+
} = useDocStateContext();
6468
const { isDarkTheme, setLightTheme, setDarkTheme } = useThemeContext();
6569
const { navbarRef, isNavbarVisible } = useHideableNavbar(hideOnScroll);
6670

67-
useLockBodyScroll(sidebarOpen);
71+
useLockBodyScroll(mobileSidebarOpen);
6872
useLockBodyScroll(navbarSidebarOpen);
6973

7074
const showSidebar = useCallback(() => {
71-
setSidebarOpen(true);
75+
setMobileSidebarLoaded(true);
76+
setMobileSidebarOpen(true);
7277
}, []);
7378
const hideSidebar = useCallback(() => {
74-
setSidebarOpen(false);
79+
setMobileSidebarOpen(false);
7580
}, []);
7681

7782
const showNavbarSidebar = useCallback(() => {
@@ -119,6 +124,7 @@ function Navbar(): JSX.Element {
119124
tabIndex={0}
120125
onClick={showSidebar}
121126
onKeyDown={showSidebar}
127+
onMouseEnter={() => setMobileSidebarLoaded(true)}
122128
>
123129
<IconMenu />
124130
</button>
@@ -185,7 +191,7 @@ function Navbar(): JSX.Element {
185191
hideSidebar();
186192
hideNavbarSidebar();
187193
}}
188-
visible={sidebarOpen || navbarSidebarOpen}
194+
visible={mobileSidebarOpen || navbarSidebarOpen}
189195
/>
190196
<div className={clsx('navbar-sidebar', styles.navbarSidebar)}>
191197
<div className="navbar-sidebar__brand">

0 commit comments

Comments
 (0)