fix(v2): enable scrolling for sidebar menu only (#2645)

* fix(v2): enable scrolling for sidebar menu only

* Add support for announcement bar

* fix: remove redundant styles
This commit is contained in:
Alexey Pyltsyn 2020-05-25 20:47:40 +03:00 committed by GitHub
parent 34e664ac27
commit d391a2bcdb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 186 additions and 65 deletions

View file

@ -5,44 +5,23 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import React, {useState, useEffect} from 'react'; import React from 'react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useAnnouncementBarContext from '@theme/hooks/useAnnouncementBarContext';
import styles from './styles.module.css'; import styles from './styles.module.css';
const STORAGE_DISMISS_KEY = 'docusaurus.announcement.dismiss';
const STORAGE_ID_KEY = 'docusaurus.announcement.id';
function AnnouncementBar() { function AnnouncementBar() {
const { const {
siteConfig: {themeConfig: {announcementBar = {}}} = {}, siteConfig: {themeConfig: {announcementBar = {}}} = {},
} = useDocusaurusContext(); } = useDocusaurusContext();
const {id, content, backgroundColor, textColor} = announcementBar; const {content, backgroundColor, textColor} = announcementBar;
const [isClosed, setClosed] = useState(true); const {
const handleClose = () => { isAnnouncementBarClosed,
localStorage.setItem(STORAGE_DISMISS_KEY, true); closeAnnouncementBar,
setClosed(true); } = useAnnouncementBarContext();
};
useEffect(() => { if (!content || isAnnouncementBarClosed) {
const viewedId = localStorage.getItem(STORAGE_ID_KEY);
const isNewAnnouncement = id !== viewedId;
localStorage.setItem(STORAGE_ID_KEY, id);
if (isNewAnnouncement) {
localStorage.setItem(STORAGE_DISMISS_KEY, false);
}
if (
isNewAnnouncement ||
localStorage.getItem(STORAGE_DISMISS_KEY) === 'false'
) {
setClosed(false);
}
}, []);
if (!content || isClosed) {
return null; return null;
} }
@ -59,7 +38,7 @@ function AnnouncementBar() {
<button <button
type="button" type="button"
className={styles.announcementBarClose} className={styles.announcementBarClose}
onClick={handleClose} onClick={closeAnnouncementBar}
aria-label="Close"> aria-label="Close">
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>

View file

@ -5,13 +5,24 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
:root {
--docusaurus-announcement-bar-height: auto;
}
.announcementBar { .announcementBar {
position: relative; position: relative;
width: 100%; width: 100%;
height: var(--docusaurus-announcement-bar-height);
background-color: var(--ifm-color-primary); background-color: var(--ifm-color-primary);
color: var(--ifm-color-black); color: var(--ifm-color-black);
} }
@media screen and (min-width: 1024px) {
:root {
--docusaurus-announcement-bar-height: 30px;
}
}
.announcementBarClose { .announcementBarClose {
position: absolute; position: absolute;
right: 0; right: 0;

View file

@ -0,0 +1,15 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {createContext} from 'react';
const AnnouncementBarContext = createContext({
isAnnouncementBarClosed: false,
closeAnnouncementBar: () => {},
});
export default AnnouncementBarContext;

View file

@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import AnnouncementBarContext from '@theme/AnnouncementBarContext';
import useAnnouncementBar from '@theme/hooks/useAnnouncementBar';
function AnnouncementBarProvider(props) {
const {isAnnouncementBarClosed, closeAnnouncementBar} = useAnnouncementBar();
return (
<AnnouncementBarContext.Provider
value={{isAnnouncementBarClosed, closeAnnouncementBar}}>
{props.children}
</AnnouncementBarContext.Provider>
);
}
export default AnnouncementBarProvider;

View file

@ -8,8 +8,10 @@
import React, {useState, useCallback} from 'react'; import React, {useState, useCallback} from 'react';
import classnames from 'classnames'; import classnames from 'classnames';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useAnnouncementBarContext from '@theme/hooks/useAnnouncementBarContext';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll'; import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import useLogo from '@theme/hooks/useLogo'; import useLogo from '@theme/hooks/useLogo';
import useScrollPosition from '@theme/hooks/useScrollPosition';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import isInternalUrl from '@docusaurus/isInternalUrl'; import isInternalUrl from '@docusaurus/isInternalUrl';
@ -134,6 +136,8 @@ function DocSidebar(props) {
isClient, isClient,
} = useDocusaurusContext(); } = useDocusaurusContext();
const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo(); const {logoLink, logoLinkProps, logoImageUrl, logoAlt} = useLogo();
const {isAnnouncementBarClosed} = useAnnouncementBarContext();
const {scrollY} = useScrollPosition();
const { const {
docsSidebars, docsSidebars,
@ -163,7 +167,10 @@ function DocSidebar(props) {
} }
return ( return (
<div className={styles.sidebar}> <div
className={classnames(styles.sidebar, {
[styles.sidebarWithHideableNavbar]: hideOnScroll,
})}>
{hideOnScroll && ( {hideOnScroll && (
<Link <Link
tabIndex="-1" tabIndex="-1"
@ -179,6 +186,8 @@ function DocSidebar(props) {
<div <div
className={classnames('menu', 'menu--responsive', styles.menu, { className={classnames('menu', 'menu--responsive', styles.menu, {
'menu--show': showResponsiveSidebar, 'menu--show': showResponsiveSidebar,
[styles.menuWithAnnouncementBar]:
!isAnnouncementBarClosed && scrollY === 0,
})}> })}>
<button <button
aria-label={showResponsiveSidebar ? 'Close Menu' : 'Open Menu'} aria-label={showResponsiveSidebar ? 'Close Menu' : 'Open Menu'}

View file

@ -7,6 +7,8 @@
@media (min-width: 997px) { @media (min-width: 997px) {
.sidebar { .sidebar {
display: flex;
flex-direction: column;
height: 100vh; height: 100vh;
overflow-y: auto; overflow-y: auto;
position: sticky; position: sticky;
@ -14,6 +16,10 @@
padding-top: var(--ifm-navbar-height); padding-top: var(--ifm-navbar-height);
} }
.sidebarWithHideableNavbar {
padding-top: 0;
}
.sidebar::-webkit-scrollbar { .sidebar::-webkit-scrollbar {
width: 7px; width: 7px;
} }
@ -35,10 +41,9 @@
.sidebarLogo { .sidebarLogo {
display: flex !important; display: flex !important;
align-items: center; align-items: center;
position: absolute;
top: 0;
margin: 0 var(--ifm-navbar-padding-horizontal); margin: 0 var(--ifm-navbar-padding-horizontal);
height: var(--ifm-navbar-height); min-height: var(--ifm-navbar-height);
max-height: var(--ifm-navbar-height);
color: inherit !important; color: inherit !important;
text-decoration: none !important; text-decoration: none !important;
} }
@ -49,8 +54,13 @@
} }
.menu { .menu {
flex-grow: 1;
padding: 0.5rem; padding: 0.5rem;
} }
.menuWithAnnouncementBar {
margin-bottom: var(--docusaurus-announcement-bar-height);
}
} }
.sidebarLogo { .sidebarLogo {

View file

@ -13,6 +13,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
import ThemeProvider from '@theme/ThemeProvider'; import ThemeProvider from '@theme/ThemeProvider';
import TabGroupChoiceProvider from '@theme/TabGroupChoiceProvider'; import TabGroupChoiceProvider from '@theme/TabGroupChoiceProvider';
import AnnouncementBarProvider from '@theme/AnnouncementBarProvider';
import AnnouncementBar from '@theme/AnnouncementBar'; import AnnouncementBar from '@theme/AnnouncementBar';
import Navbar from '@theme/Navbar'; import Navbar from '@theme/Navbar';
import Footer from '@theme/Footer'; import Footer from '@theme/Footer';
@ -50,6 +51,7 @@ function Layout(props) {
return ( return (
<ThemeProvider> <ThemeProvider>
<TabGroupChoiceProvider> <TabGroupChoiceProvider>
<AnnouncementBarProvider>
<Head> <Head>
{/* TODO: Do not assume that it is in english language */} {/* TODO: Do not assume that it is in english language */}
<html lang="en" /> <html lang="en" />
@ -70,7 +72,10 @@ function Layout(props) {
<meta property="twitter:image" content={metaImageUrl} /> <meta property="twitter:image" content={metaImageUrl} />
)} )}
{metaImage && ( {metaImage && (
<meta name="twitter:image:alt" content={`Image for ${metaTitle}`} /> <meta
name="twitter:image:alt"
content={`Image for ${metaTitle}`}
/>
)} )}
{permalink && ( {permalink && (
<meta property="og:url" content={siteUrl + permalink} /> <meta property="og:url" content={siteUrl + permalink} />
@ -82,6 +87,7 @@ function Layout(props) {
<Navbar /> <Navbar />
<div className="main-wrapper">{children}</div> <div className="main-wrapper">{children}</div>
{!noFooter && <Footer />} {!noFooter && <Footer />}
</AnnouncementBarProvider>
</TabGroupChoiceProvider> </TabGroupChoiceProvider>
</ThemeProvider> </ThemeProvider>
); );

View file

@ -0,0 +1,52 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {useState, useEffect} from 'react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
const STORAGE_DISMISS_KEY = 'docusaurus.announcement.dismiss';
const STORAGE_ID_KEY = 'docusaurus.announcement.id';
const useAnnouncementBar = () => {
const {
siteConfig: {
themeConfig: {
announcementBar: {id},
},
} = {},
} = useDocusaurusContext();
const [isClosed, setClosed] = useState(true);
const handleClose = () => {
localStorage.setItem(STORAGE_DISMISS_KEY, true);
setClosed(true);
};
useEffect(() => {
const viewedId = localStorage.getItem(STORAGE_ID_KEY);
const isNewAnnouncement = id !== viewedId;
localStorage.setItem(STORAGE_ID_KEY, id);
if (isNewAnnouncement) {
localStorage.setItem(STORAGE_DISMISS_KEY, false);
}
if (
isNewAnnouncement ||
localStorage.getItem(STORAGE_DISMISS_KEY) === 'false'
) {
setClosed(false);
}
}, []);
return {
isAnnouncementBarClosed: isClosed,
closeAnnouncementBar: handleClose,
};
};
export default useAnnouncementBar;

View file

@ -0,0 +1,15 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {useContext} from 'react';
import AnnouncementBarContext from '@theme/AnnouncementBarContext';
function useAnnouncementBarContext() {
return useContext(AnnouncementBarContext);
}
export default useAnnouncementBarContext;