Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/component/navbar/useNavbarCollapsed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useEffect, useState } from 'react';

/**
* Width below which the full desktop navbar (logo, wordmark, GitHub stars, all
* section links, Login/Sign up and search) no longer fits, so the navigation
* links collapse into the hamburger sidebar. Keep in sync with the matching
* media queries in src/css/custom.css and Content/styles.module.css.
*/
export const NAVBAR_COLLAPSE_QUERY = '(max-width: 1320px)';

export function useNavbarCollapsed(): boolean {
const [collapsed, setCollapsed] = useState(false);

useEffect(() => {
const mql = window.matchMedia(NAVBAR_COLLAPSE_QUERY);
const update = () => setCollapsed(mql.matches);
update();
mql.addEventListener('change', update);
return () => mql.removeEventListener('change', update);
}, []);

return collapsed;
}
16 changes: 16 additions & 0 deletions src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,22 @@ html[data-theme='dark'] .navbar__title {
color: unset;
}

/* Logo, wordmark and GitHub stars stay visible at every width. */
.navbar-github-button {
display: flex;
align-items: center;
}

@media (max-width: 1320px) {
.navbar__toggle {
display: inherit;
}

.navbar__items > .navbar__item {
display: none;
}
}

.navbar .dropdown__menu {
display: grid;
grid-auto-flow: column;
Expand Down
14 changes: 12 additions & 2 deletions src/theme/Navbar/Content/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { type ReactNode } from 'react';
import React, { type ReactNode, useEffect } from 'react';
import { useThemeConfig, ErrorCauseBoundary } from '@docusaurus/theme-common';
import {
splitNavbarItems,
Expand All @@ -13,6 +13,7 @@ import NavbarSearch from '@theme/Navbar/Search';

import styles from './styles.module.css';
import { GithubButton } from '../../../component/githubButton/GithubButton';
import { useNavbarCollapsed } from '../../../component/navbar/useNavbarCollapsed';

function useNavbarItems() {
// TODO temporary casting until ThemeConfig type is improved
Expand Down Expand Up @@ -58,6 +59,15 @@ function NavbarContentLayout({

export default function NavbarContent(): ReactNode {
const mobileSidebar = useNavbarMobileSidebar();
const collapsed = useNavbarCollapsed();

// Close the drawer if the viewport widens past the collapse breakpoint while
// it's open (Docusaurus only auto-closes on the mobile→desktop transition).
useEffect(() => {
if (!collapsed && mobileSidebar.shown) {
mobileSidebar.toggle();
}
}, [collapsed, mobileSidebar]);

const items = useNavbarItems();
const [leftItems, rightItems] = splitNavbarItems(items);
Expand All @@ -71,7 +81,7 @@ export default function NavbarContent(): ReactNode {
<>
{!mobileSidebar.disabled && <NavbarMobileSidebarToggle />}
<NavbarLogo />
<div className="hidden xl:flex">
<div className="navbar-github-button">
<GithubButton />
</div>
<NavbarItems items={leftItems} />
Expand Down
6 changes: 4 additions & 2 deletions src/theme/Navbar/Content/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/*
Hide color mode toggle in small viewports
Hide color mode toggle while the navbar is collapsed (it moves into the
hamburger drawer header). Mirrors NAVBAR_COLLAPSE_QUERY in
src/component/navbar/useNavbarCollapsed.ts.
*/
@media (max-width: 996px) {
@media (max-width: 1320px) {
.colorModeToggle {
display: none;
}
Expand Down
32 changes: 32 additions & 0 deletions src/theme/Navbar/MobileSidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { type ReactNode } from 'react';
import {
useLockBodyScroll,
useNavbarMobileSidebar,
} from '@docusaurus/theme-common/internal';
import NavbarMobileSidebarLayout from '@theme/Navbar/MobileSidebar/Layout';
import NavbarMobileSidebarHeader from '@theme/Navbar/MobileSidebar/Header';
import NavbarMobileSidebarPrimaryMenu from '@theme/Navbar/MobileSidebar/PrimaryMenu';
import NavbarMobileSidebarSecondaryMenu from '@theme/Navbar/MobileSidebar/SecondaryMenu';

import { useNavbarCollapsed } from '../../../component/navbar/useNavbarCollapsed';

export default function NavbarMobileSidebar(): ReactNode {
const mobileSidebar = useNavbarMobileSidebar();
const collapsed = useNavbarCollapsed();
useLockBodyScroll(mobileSidebar.shown);

// Docusaurus only renders the drawer below its hardcoded 996px breakpoint
// (mobileSidebar.shouldRender). We render it whenever the navbar is collapsed
// so the hamburger works across the whole sub-1320px range, not just mobile.
if (!collapsed && !mobileSidebar.shown) {
return null;
}

return (
<NavbarMobileSidebarLayout
header={<NavbarMobileSidebarHeader />}
primaryMenu={<NavbarMobileSidebarPrimaryMenu />}
secondaryMenu={<NavbarMobileSidebarSecondaryMenu />}
/>
);
}
Loading