Browse Source

Improve navigation on mobile

Make sidebar toggleable on mobile.
tags/0.3.0
TheoryOfNekomata 3 years ago
parent
commit
1166e17118
6 changed files with 180 additions and 68 deletions
  1. +1
    -2
      .gitignore
  2. +13
    -0
      packages/react-common-docs/brand.tsx
  3. +6
    -0
      packages/react-common-docs/public/global.css
  4. +153
    -63
      packages/react-common-docs/src/components/Sidebar/Sidebar.tsx
  5. +6
    -2
      packages/react-common-docs/src/pages/_app.tsx
  6. +1
    -1
      packages/react-common-docs/src/pages/index.md

+ 1
- 2
.gitignore View File

@@ -64,6 +64,5 @@ typings/
*.tgz
.yarn-integrity
.env
.next
dist/
.next/
dist/

+ 13
- 0
packages/react-common-docs/brand.tsx View File

@@ -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 (
<Base>
{org && (
<Org>
{org}
</Org>
)}
<Title>
{name}
</Title>


+ 6
- 0
packages/react-common-docs/public/global.css View File

@@ -50,3 +50,9 @@ a:focus {
:root {
caret-color: var(--color-active);
}

pre {
overflow: auto;
margin: 0 -1rem;
padding: 0 1rem;
}

+ 153
- 63
packages/react-common-docs/src/components/Sidebar/Sidebar.tsx View File

@@ -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<HTMLDivElement>(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 (
<Base>
<NavWrapper>
<Link
href="/"
passHref
>
<StyledLink>
<Container>
<Brand />
</Container>
</StyledLink>
</Link>
<Container>
<Actions>
<ToggleWrapper>
<ToggleInput
type="checkbox"
defaultChecked={theme === 'Dark'}
onChange={toggleDarkMode(theme === 'Dark' ? 'Light' : 'Dark')}
/>
<ToggleIcon>
{
theme === 'Dark'
&& (
<Icon
label="Set Light Mode"
name="moon"
/>
)
}
{
theme === 'Light'
&& (
<Icon
label="Set Dark Mode"
name="sun"
/>
)
}
</ToggleIcon>
</ToggleWrapper>
<RepoLink
href={pkg.repository}
target="_blank"
rel="noopener noreferer"
>
<Icon
name="code"
label="Visit Repository"
/>
</RepoLink>
</Actions>
</Container>
<Nav
data={data.nav}
/>
</NavWrapper>
</Base>
<React.Fragment>
<SidebarToggle
onClick={toggleSidebar(!sidebar)}
>
{
!sidebar && (
<Icon
name="menu"
/>
)
}
{
sidebar && (
<Icon
name="x"
/>
)
}
</SidebarToggle>
<Base
ref={navRef}
style={{
left: sidebar ? 0 : '-100%',
}}
>
<NavWrapper>
<Link
href="/"
passHref
>
<StyledLink>
<Container>
<Brand />
</Container>
</StyledLink>
</Link>
<Container>
<Actions>
<ToggleWrapper>
<ToggleInput
type="checkbox"
defaultChecked={theme === 'Dark'}
onChange={toggleDarkMode(theme === 'Dark' ? 'Light' : 'Dark')}
/>
<ToggleIcon>
{
theme === 'Dark'
&& (
<Icon
label="Set Light Mode"
name="moon"
/>
)
}
{
theme === 'Light'
&& (
<Icon
label="Set Dark Mode"
name="sun"
/>
)
}
</ToggleIcon>
</ToggleWrapper>
<RepoLink
href={pkg.repository}
target="_blank"
rel="noopener noreferer"
>
<Icon
name="code"
label="Visit Repository"
/>
</RepoLink>
</Actions>
</Container>
<Nav
data={data.nav}
/>
</NavWrapper>
</Base>
</React.Fragment>
)
}



+ 6
- 2
packages/react-common-docs/src/pages/_app.tsx View File

@@ -13,6 +13,10 @@ const Container = styled('div')({
boxSizing: 'border-box',
})

const Main = styled('main')({
margin: '4rem 0',
})

type AppProps = {
Component: React.ElementType,
pageProps: Record<string, unknown>,
@@ -27,13 +31,13 @@ const App: React.FC<AppProps> = ({
brand={brand}
data={sidebar}
/>
<main>
<Main>
<Container>
<Component
{...pageProps}
/>
</Container>
</main>
</Main>
</React.Fragment>
)



+ 1
- 1
packages/react-common-docs/src/pages/index.md View File

@@ -1,4 +1,4 @@
# Tesseract Web - React Common
# Tesseract Design - React Common

Common front-end components for Web using the [Tesseract design system](https://make.modal.sh/tesseract/design), written for [React](https://reactjs.org).



Loading…
Cancel
Save