diff --git a/packages/theme-default/src/assets/panel-left-close.svg b/packages/theme-default/src/assets/panel-left-close.svg
new file mode 100644
index 000000000..7ec44f678
--- /dev/null
+++ b/packages/theme-default/src/assets/panel-left-close.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/theme-default/src/assets/panel-left-open.svg b/packages/theme-default/src/assets/panel-left-open.svg
new file mode 100644
index 000000000..36c0dc972
--- /dev/null
+++ b/packages/theme-default/src/assets/panel-left-open.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/theme-default/src/components/Nav/index.tsx b/packages/theme-default/src/components/Nav/index.tsx
index e87e07371..ac735ff45 100644
--- a/packages/theme-default/src/components/Nav/index.tsx
+++ b/packages/theme-default/src/components/Nav/index.tsx
@@ -1,10 +1,15 @@
import { useLocation, usePageData, useWindowSize } from '@rspress/runtime';
import type { NavItem } from '@rspress/shared';
import { Search } from '@theme';
+import PanelLeftClose from '@theme-assets/panel-left-close';
+import PanelLeftOpen from '@theme-assets/panel-left-open';
import { useHiddenNav } from '../../logic/useHiddenNav';
+import { useMediaQuery } from '../../logic/useMediaQuery';
import { useNavData } from '../../logic/useNav';
+import { useUISwitch } from '../../logic/useUISwitch';
import { NavHamburger } from '../NavHamburger';
import { SocialLinks } from '../SocialLinks';
+import { SvgWrapper } from '../SvgWrapper';
import { SwitchAppearance } from '../SwitchAppearance';
import { NavBarTitle } from './NavBarTitle';
import { NavMenuGroup } from './NavMenuGroup';
@@ -19,13 +24,23 @@ export interface NavProps {
navTitle?: React.ReactNode;
afterNavTitle?: React.ReactNode;
afterNavMenu?: React.ReactNode;
+ showSidebar?: boolean;
+ toggleShowSidebar?: () => void;
}
const DEFAULT_NAV_POSITION = 'right';
export function Nav(props: NavProps) {
- const { beforeNavTitle, afterNavTitle, beforeNav, afterNavMenu, navTitle } =
- props;
+ const {
+ beforeNavTitle,
+ afterNavTitle,
+ beforeNav,
+ afterNavMenu,
+ navTitle,
+ showSidebar,
+ toggleShowSidebar,
+ } = props;
+ const uiSwitch = useUISwitch();
const { siteData, page } = usePageData();
const { base } = siteData;
const { pathname } = useLocation();
@@ -122,6 +137,11 @@ export function Nav(props: NavProps) {
}
return styles.relative;
};
+ // sync opacity with sidebar
+ const is960 = useMediaQuery('(min-width: 960px)');
+ const showToggleBtn =
+ uiSwitch.showSidebar && page.pageType === 'doc' && is960;
+ const toggleSidebarIcon = showSidebar ? PanelLeftClose : PanelLeftOpen;
return (
<>
@@ -133,11 +153,23 @@ export function Nav(props: NavProps) {
} ${computeNavPosition()}`}
>
{beforeNavTitle}
{navTitle ||
}
{afterNavTitle}
+
+ {showToggleBtn ? (
+
+ ) : null}
+
{leftNav()}
{rightNav()}
diff --git a/packages/theme-default/src/layout/Layout/index.tsx b/packages/theme-default/src/layout/Layout/index.tsx
index ade29f248..b199f75ad 100644
--- a/packages/theme-default/src/layout/Layout/index.tsx
+++ b/packages/theme-default/src/layout/Layout/index.tsx
@@ -9,6 +9,7 @@ import {
import { useHead } from '@unhead/react';
import { Head } from '@unhead/react';
import type React from 'react';
+import { useMemo, useState } from 'react';
import type { NavProps } from '../../components/Nav';
import { useSetup } from '../../logic/sideEffects';
import { useLocaleSiteData } from '../../logic/useLocaleSiteData';
@@ -129,12 +130,24 @@ export function Layout(props: LayoutProps) {
siteData.description ||
localesData.description;
+ const [showSidebar, setShowSidebar] = useState(
+ page.frontmatter.sidebar !== false,
+ );
+
+ const toggleShowSideBar = () => setShowSidebar(prev => !prev);
+
// Control whether or not to display the navbar, sidebar, outline and footer
// `props.uiSwitch` has higher priority and allows user to override the default value
- const uiSwitch = {
- ...useUISwitch(),
- ...props.uiSwitch,
- };
+ const defaultUiSwitch = useUISwitch();
+
+ const uiSwitch = useMemo(
+ () => ({
+ ...defaultUiSwitch,
+ showSidebar: defaultUiSwitch.showSidebar !== false && showSidebar,
+ ...props.uiSwitch,
+ }),
+ [defaultUiSwitch, showSidebar, props.uiSwitch],
+ );
// Use doc layout by default
const getContentLayout = () => {
@@ -177,6 +190,8 @@ export function Layout(props: LayoutProps) {
navTitle={navTitle}
beforeNav={beforeNav}
afterNavMenu={afterNavMenu}
+ showSidebar={uiSwitch.showSidebar}
+ toggleShowSidebar={toggleShowSideBar}
/>
)}
diff --git a/packages/theme-default/src/logic/useUISwitch.ts b/packages/theme-default/src/logic/useUISwitch.ts
index dd55a4459..fb7ca5942 100644
--- a/packages/theme-default/src/logic/useUISwitch.ts
+++ b/packages/theme-default/src/logic/useUISwitch.ts
@@ -47,9 +47,15 @@ export function useUISwitch(): UISwitchResult {
// 1. frontmatter.sidebar
// 2. themeConfig.locales.sidebar
// 3. themeConfig.sidebar
- const showSidebar =
+ const calcShowSidebar =
frontmatter?.sidebar !== false && Object.keys(sidebar).length > 0;
+ const [showSidebar, setShowSidebar] = useState(calcShowSidebar);
+
+ useEffect(() => {
+ setShowSidebar(calcShowSidebar);
+ }, [calcShowSidebar]);
+
const { width } = useWindowSize();
const showSidebarMenu =
@@ -80,6 +86,7 @@ export function useUISwitch(): UISwitchResult {
if (sidebar === QueryStatus.Hide) {
document.documentElement.style.setProperty('--rp-sidebar-width', '0px');
+ setShowSidebar(false);
}
if (aside === QueryStatus.Hide) {