diff --git a/packages/docusaurus-theme-classic/src/index.js b/packages/docusaurus-theme-classic/src/index.js index ff0d71749fff..e304d363ea70 100644 --- a/packages/docusaurus-theme-classic/src/index.js +++ b/packages/docusaurus-theme-classic/src/index.js @@ -99,6 +99,11 @@ module.exports = function (context, options) { .join('|'); return { + resolve: { + alias: { + '@theme-init': this.getTypeScriptThemePath(), + }, + }, stats: { warningsFilter: [ // See https://github.com/facebook/docusaurus/pull/3382 diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx index eab7e8988070..9e4025237ade 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx @@ -78,110 +78,108 @@ function DocItem(props: Props): JSX.Element { {permalink && } {permalink && } -
-
-
- -
-
- {showVersionBadge && ( -
- - Version: {version.label} - -
- )} - {!hideTitle && ( -
-

{title}

-
- )} -
- + +
+
+ +
+
+ {showVersionBadge && ( +
+ + Version: {version.label} +
-
- {(editUrl || lastUpdatedAt || lastUpdatedBy) && ( -
-
-
- {editUrl && ( - - - - - - - Edit this page - - )} -
- {(lastUpdatedAt || lastUpdatedBy) && ( -
- - - Last updated{' '} - {lastUpdatedAt && ( - <> - on{' '} - - {lastUpdatedBy && ' '} - - )} - {lastUpdatedBy && ( - <> - by {lastUpdatedBy} - - )} - {process.env.NODE_ENV === 'development' && ( -
- - {' '} - (Simulated during dev for better perf) - -
- )} -
-
-
+ )} + {!hideTitle && ( +
+

{title}

+
+ )} +
+ +
+
+ {(editUrl || lastUpdatedAt || lastUpdatedBy) && ( +
+
+
+ {editUrl && ( + + + + + + + Edit this page + )}
+ {(lastUpdatedAt || lastUpdatedBy) && ( +
+ + + Last updated{' '} + {lastUpdatedAt && ( + <> + on{' '} + + {lastUpdatedBy && ' '} + + )} + {lastUpdatedBy && ( + <> + by {lastUpdatedBy} + + )} + {process.env.NODE_ENV === 'development' && ( +
+ + {' '} + (Simulated during dev for better perf) + +
+ )} +
+
+
+ )}
- )} -
-
+ )} +
+
- {!hideTableOfContents && DocContent.rightToc && ( -
- -
- )}
+ {!hideTableOfContents && DocContent.rightToc && ( +
+ +
+ )}
); diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocItem/styles.module.css index a671e34f5019..6c365bdf7455 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/styles.module.css @@ -21,14 +21,6 @@ } } -@media (min-width: 997px) and (max-width: 1320px) { - .docItemWrapper { - max-width: calc( - var(--ifm-container-width) - 300px - var(--ifm-spacing-horizontal) * 2 - ); - } -} - @media only screen and (max-width: 996px) { .docItemContainer { padding: 0 0.3rem; diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx index 8d122c58a24e..7a5e08d08e68 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/index.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {ReactNode} from 'react'; +import React, {ReactNode, useState, useCallback} from 'react'; import {MDXProvider} from '@mdx-js/react'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; @@ -19,6 +19,7 @@ import type {DocumentRoute} from '@theme/DocItem'; import type {Props} from '@theme/DocPage'; import {matchPath} from '@docusaurus/router'; +import clsx from 'clsx'; import styles from './styles.module.css'; import {docVersionSearchTag} from '../../utils/searchUtils'; @@ -37,6 +38,17 @@ function DocPageContent({ const {pluginId, permalinkToSidebar, docsSidebars, version} = versionMetadata; const sidebarName = permalinkToSidebar[currentDocRoute.path]; const sidebar = docsSidebars[sidebarName]; + + const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false); + const [hiddenSidebar, setHiddenSidebar] = useState(false); + const toggleSidebar = useCallback(() => { + if (hiddenSidebar) { + setHiddenSidebar(false); + } + + setHiddenSidebarContainer(!hiddenSidebarContainer); + }, [hiddenSidebar]); + return (
{sidebar && ( -
+
{ + if ( + !e.currentTarget.classList.contains(styles.docSidebarContainer) + ) { + return; + } + + if (hiddenSidebarContainer) { + setHiddenSidebar(true); + } + }} + role="complementary"> + + {hiddenSidebar && ( +
+ )}
)}
- {children} +
+ {children} +
diff --git a/packages/docusaurus-theme-classic/src/theme/DocPage/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocPage/styles.module.css index 9e3427363d81..bfa8f5ab6bfd 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPage/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocPage/styles.module.css @@ -5,20 +5,64 @@ * LICENSE file in the root directory of this source tree. */ -.docPage { - display: flex; +:root { + --doc-sidebar-width: 300px; } -.docSidebarContainer { - border-right: 1px solid var(--ifm-toc-border-color); - box-sizing: border-box; - width: 300px; - position: relative; - margin-top: calc(-1 * var(--ifm-navbar-height)); -} +@media (min-width: 997px) { + .docPage { + display: flex; + } + + .docSidebarContainer { + width: var(--doc-sidebar-width); + margin-top: calc(-1 * var(--ifm-navbar-height)); + border-right: 1px solid var(--ifm-toc-border-color); + will-change: width; + transition: width var(--ifm-transition-fast) ease; + clip-path: inset(0); + } + + .docSidebarContainerHidden { + width: 30px; + cursor: e-resize; + } + + .collapsedDocSidebar { + position: sticky; + top: 0; + height: 100%; + max-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + transition: background-color var(--ifm-transition-fast) ease; + } + + .collapsedDocSidebar:hover, + .collapsedDocSidebar:focus { + background-color: var(--ifm-color-emphasis-200); + } -.docMainContainer { - flex-grow: 1; + html[data-theme='dark'] .collapsedDocSidebar:hover, + html[data-theme='dark'] .collapsedDocSidebar:focus { + background-color: var(--collapse-button-bg-color-dark); + } + + .collapsedDocSidebar:before { + content: ''; + background-image: url('~!file-loader!@theme-init/icons/arrow.svg'); + width: 20px; + height: 20px; + } + + .docMainContainer { + flex-grow: 1; + } + + .docItemWrapperEnhanced { + max-width: calc(var(--ifm-container-width) + var(--doc-sidebar-width)); + } } @media (max-width: 996px) { @@ -30,3 +74,18 @@ margin-top: 0; } } + +@media (min-width: 997px) and (max-width: 1320px) { + .docItemWrapper { + max-width: calc( + var(--ifm-container-width) - var(--doc-sidebar-width) - + var(--ifm-spacing-horizontal) * 2 + ); + } + + .docItemWrapperEnhanced { + max-width: calc( + var(--ifm-container-width) - var(--ifm-spacing-horizontal) * 2 + ); + } +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx index 96a98a7028b9..18f3d40f8578 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/index.tsx @@ -164,10 +164,13 @@ function DocSidebar({ path, sidebar, sidebarCollapsible = true, + onCollapse, + isHidden, }: Props): JSX.Element | null { const [showResponsiveSidebar, setShowResponsiveSidebar] = useState(false); const { navbar: {title, hideOnScroll}, + hideableSidebar, } = useThemeConfig(); const {isClient} = useDocusaurusContext(); const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo(); @@ -187,6 +190,7 @@ function DocSidebar({
{hideOnScroll && (
+ + {hideableSidebar && ( +
); } diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebar/styles.module.css b/packages/docusaurus-theme-classic/src/theme/DocSidebar/styles.module.css index f304742cc9dd..63951daecbc5 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebar/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebar/styles.module.css @@ -5,21 +5,32 @@ * LICENSE file in the root directory of this source tree. */ +:root { + --collapse-button-bg-color-dark: #2e333a; +} + @media (min-width: 997px) { .sidebar { display: flex; flex-direction: column; height: 100vh; - overflow-y: auto; 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; + } + .sidebarLogo { display: flex !important; align-items: center; @@ -69,9 +80,33 @@ .menuWithAnnouncementBar { margin-bottom: var(--docusaurus-announcement-bar-height); } + + .collapseSidebarButton { + display: block !important; + background: url('~!file-loader!@theme-init/icons/arrow.svg') no-repeat + center center; + background-color: var(--ifm-button-background-color); + height: 40px; + position: sticky; + bottom: 0; + border-radius: 0; + transform: rotate(180deg); + } + + html[data-theme='dark'] .collapseSidebarButton { + background-color: var(--collapse-button-bg-color-dark); + border: none; + border-left: 1px solid var(--ifm-toc-border-color); + } + + html[data-theme='dark'] .collapseSidebarButton:hover, + html[data-theme='dark'] .collapseSidebarButton:focus { + background-color: var(--ifm-color-emphasis-200); + } } -.sidebarLogo { +.sidebarLogo, +.collapseSidebarButton { display: none; } diff --git a/packages/docusaurus-theme-classic/src/theme/icons/arrow.svg b/packages/docusaurus-theme-classic/src/theme/icons/arrow.svg new file mode 100644 index 000000000000..b30c53e17b8b --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/icons/arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/docusaurus-theme-classic/src/types.d.ts b/packages/docusaurus-theme-classic/src/types.d.ts index cbcf1cc9b04d..59cb29b859d5 100644 --- a/packages/docusaurus-theme-classic/src/types.d.ts +++ b/packages/docusaurus-theme-classic/src/types.d.ts @@ -79,6 +79,8 @@ declare module '@theme/DocSidebar' { readonly path: string; readonly sidebar: readonly PropSidebarItem[]; readonly sidebarCollapsible?: boolean; + readonly onCollapse: () => void; + readonly isHidden: boolean; }; const DocSidebar: (props: Props) => JSX.Element; diff --git a/packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts b/packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts index d8497b2f9451..00d775aafafe 100644 --- a/packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts +++ b/packages/docusaurus-theme-classic/src/utils/useThemeConfig.ts @@ -23,6 +23,7 @@ export type ThemeConfig = { announcementBar: any; prism: any; footer: any; + hideableSidebar: any; }; export default function useThemeConfig(): ThemeConfig { diff --git a/packages/docusaurus-theme-classic/src/validateThemeConfig.js b/packages/docusaurus-theme-classic/src/validateThemeConfig.js index 2b2f954b4aac..61253c8ef604 100644 --- a/packages/docusaurus-theme-classic/src/validateThemeConfig.js +++ b/packages/docusaurus-theme-classic/src/validateThemeConfig.js @@ -40,6 +40,7 @@ const DEFAULT_CONFIG = { hideOnScroll: false, items: [], }, + hideableSidebar: false, }; exports.DEFAULT_CONFIG = DEFAULT_CONFIG; @@ -283,6 +284,7 @@ const ThemeConfigSchema = Joi.object({ }) .default(DEFAULT_CONFIG.prism) .unknown(), + hideableSidebar: Joi.bool().default(DEFAULT_CONFIG.hideableSidebar), }); exports.ThemeConfigSchema = ThemeConfigSchema; diff --git a/website/docs/docs.md b/website/docs/docs.md index a46ff9c6fde6..adda552d0378 100644 --- a/website/docs/docs.md +++ b/website/docs/docs.md @@ -82,6 +82,20 @@ module.exports = { }; ``` +### Hideable sidebar + +Using the enabled `themeConfig.hideableSidebar` option, you can make the entire sidebar hided, allowing you to better focus your users on the content. This is especially useful when content consumption on medium screens (e.g. on tablets). + +```js {4} title="docusaurus.config.js" +module.exports = { + // ... + themeConfig: { + hideableSidebar: true, + // ... + }, +}; +``` + ### Sidebar object A sidebar object is defined like this: diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index b63be75e0d62..61f20bb75b87 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -229,6 +229,7 @@ module.exports = { ], ], themeConfig: { + hideableSidebar: true, colorMode: { defaultMode: 'light', disableSwitch: false,