From 1166e1711864f5aee4ab28aed07b2bbd2ca5b56c Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Sat, 26 Dec 2020 20:17:17 +0800 Subject: [PATCH] Improve navigation on mobile Make sidebar toggleable on mobile. --- .gitignore | 3 +- packages/react-common-docs/brand.tsx | 13 ++ packages/react-common-docs/public/global.css | 6 + .../src/components/Sidebar/Sidebar.tsx | 216 +++++++++++++----- packages/react-common-docs/src/pages/_app.tsx | 8 +- packages/react-common-docs/src/pages/index.md | 2 +- 6 files changed, 180 insertions(+), 68 deletions(-) diff --git a/.gitignore b/.gitignore index 2659df7..e7ac459 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,5 @@ typings/ *.tgz .yarn-integrity .env -.next -dist/ .next/ +dist/ diff --git a/packages/react-common-docs/brand.tsx b/packages/react-common-docs/brand.tsx index a5ef71b..527d3d8 100644 --- a/packages/react-common-docs/brand.tsx +++ b/packages/react-common-docs/brand.tsx @@ -16,6 +16,13 @@ const Title = styled('strong')({ whiteSpace: 'nowrap', }) +const Org = styled('small')({ + position: 'absolute', + top: '-0.25em', + right: 0, + fontWeight: 'bolder', +}) + const Subtitle = styled('small')({ position: 'absolute', bottom: '-1em', @@ -24,9 +31,15 @@ const Subtitle = styled('small')({ }) const Brand = () => { + const org = pkg.name.includes('@') ? pkg.name.split('/')[0].slice(1) : null const name = pkg.name.includes('@') ? pkg.name.split('/')[1] : pkg.name return ( + {org && ( + + {org} + + )} {name} diff --git a/packages/react-common-docs/public/global.css b/packages/react-common-docs/public/global.css index a9d61e3..4ef079a 100644 --- a/packages/react-common-docs/public/global.css +++ b/packages/react-common-docs/public/global.css @@ -50,3 +50,9 @@ a:focus { :root { caret-color: var(--color-active); } + +pre { + overflow: auto; + margin: 0 -1rem; + padding: 0 1rem; +} diff --git a/packages/react-common-docs/src/components/Sidebar/Sidebar.tsx b/packages/react-common-docs/src/components/Sidebar/Sidebar.tsx index 0d414c4..ac93157 100644 --- a/packages/react-common-docs/src/components/Sidebar/Sidebar.tsx +++ b/packages/react-common-docs/src/components/Sidebar/Sidebar.tsx @@ -1,14 +1,15 @@ +import * as React from 'react' import { Icon } from '../../../../react-common/src' import pkg from '../../../../../package.json' import styled from 'styled-components' import Link from 'next/link' -import * as React from 'react' import Nav from '../Nav/Nav' +import { MouseEventHandler } from 'react' const StyledLink = styled('a')({ display: 'block', textDecoration: 'none', - marginTop: '3rem', + marginTop: '4rem', marginBottom: '3rem', }) @@ -28,16 +29,16 @@ const Base = styled('aside')({ '--max-width': 240, position: 'fixed', top: 0, - left: '-100%', width: '100%', height: '100%', backgroundColor: 'var(--color-bg)', zIndex: 4, - transitionProperty: 'color, background-color', + transitionProperty: 'color, background-color, left', transitionTimingFunction: 'ease', transitionDuration: '350ms', + overflow: 'auto', '@media (min-width: 720px)': { - left: 0, + left: '0 !important', width: `${100 / 4}%`, maxWidth: 'none', height: '100%', @@ -48,6 +49,31 @@ const Base = styled('aside')({ }, }) +const SidebarToggle = styled('a')({ + width: '4rem', + height: '4rem', + position: 'fixed', + top: 0, + left: 0, + display: 'grid', + placeContent: 'center', + zIndex: 5, + '@media (min-width: 720px)': { + display: 'none', + }, + '::before': { + backgroundColor: 'var(--color-bg)', + content: "''", + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%', + opacity: 0.75, + zIndex: -1, + }, +}) + const Actions = styled('div')({ marginBottom: '4rem', display: 'flex', @@ -72,6 +98,7 @@ const ToggleInput = styled('input')({ const NavWrapper = styled('nav')({ '--size-link': '3rem', + marginBottom: '4rem', }) const RepoLink = styled('a')({ @@ -87,10 +114,18 @@ const Sidebar = ({ initialTheme = 'Dark', }) => { const [theme, setTheme] = React.useState(initialTheme) + const [sidebar, setSidebar] = React.useState(false) + const navRef = React.useRef(null) + const toggleDarkMode = (b: string) => () => { setTheme(b) } + const toggleSidebar = (b: boolean) => (e) => { + e.preventDefault() + setSidebar(b) + } + React.useEffect(() => { let storageTheme = window.localStorage.getItem('tesseract-theme') || ( @@ -104,6 +139,36 @@ const Sidebar = ({ }) }, []) + React.useEffect(() => { + const eventListener: MouseEventHandler = (e) => { + let currentElement = e.target as HTMLElement + while (currentElement !== e.currentTarget) { + if (currentElement.tagName === 'A') { + setSidebar(false) + break + } + const { parentElement } = currentElement + if (parentElement as HTMLElement === null) { + break + } + currentElement = parentElement as HTMLElement + } + } + + if (navRef.current === null) { + return + } + + navRef.current.addEventListener('click', eventListener, { capture: true }) + return () => { + if (navRef.current === null) { + return + } + + navRef.current.removeEventListener('click', eventListener, { capture: true }) + } + }, []) + React.useEffect(() => { window.localStorage.setItem('tesseract-theme', theme) }, [theme]) @@ -122,64 +187,89 @@ const Sidebar = ({ }, [theme]) return ( - - - - - - - - - - - - - - - { - theme === 'Dark' - && ( - - ) - } - { - theme === 'Light' - && ( - - ) - } - - - - - - - -