Browse Source

Improve tablet layout, add sidebar animation

Make the sidebar not occupy the whole screen width. Also add transitions for sidebar opening/closing.
feature/transactions
TheoryOfNekomata 3 years ago
parent
commit
47bfd74297
4 changed files with 195 additions and 88 deletions
  1. +127
    -51
      src/components/Navbar/Navbar.tsx
  2. +1
    -0
      src/components/PrimaryNavItem/PrimaryNavItem.tsx
  3. +49
    -29
      src/components/SecondaryNavItem/SecondaryNavItem.tsx
  4. +18
    -8
      src/pages/notes.tsx

+ 127
- 51
src/components/Navbar/Navbar.tsx View File

@@ -1,7 +1,8 @@
import * as React from 'react'
import styled from 'styled-components'
import styled, { createGlobalStyle } from 'styled-components'
import SecondaryNavItem from '../SecondaryNavItem/SecondaryNavItem'
import PrimaryNavItem from '../PrimaryNavItem/PrimaryNavItem'
import Link from 'next/link'

const Base = styled('aside')({
width: 360,
@@ -59,9 +60,37 @@ const PrimaryNavItemGroup = styled('div')({
})

const SecondaryNavItems = styled('nav')({
width: '100%',
height: '100%',
position: 'fixed',
top: 0,
left: 0,
paddingBottom: '4rem',
boxSizing: 'border-box',
pointerEvents: 'none',
'@media (min-width: 1080px)': {
position: 'relative',
top: 'auto',
left: 'auto',
flex: 'auto',
width: 'auto',
paddingBottom: 0,
pointerEvents: 'initial',
},
})

const SecondaryNavItemsFg = styled('div')({
height: '100%',
position: 'relative',
backgroundColor: 'var(--color-bg)',
width: 360,
position: 'absolute',
top: 0,
left: -360,
paddingBottom: '4rem',
boxSizing: 'border-box',
transitionProperty: 'left',
transitionDuration: '350ms',
transitionTimingFunction: 'ease-out',
'::before': {
content: "''",
display: 'block',
@@ -73,27 +102,34 @@ const SecondaryNavItems = styled('nav')({
backgroundColor: 'black',
opacity: 0.03125,
},
'@media (min-width: 1080px)': {
flex: 'auto',
},
})

const VisibleSecondaryNavItems = styled(SecondaryNavItems)({
position: 'fixed',
top: 0,
left: 0,
width: '100%',
paddingBottom: '4rem',
boxSizing: 'border-box',
'@media (min-width: 1080px)': {
position: 'relative',
top: 'auto',
left: 'auto',
flex: 'auto',
width: 'auto',
paddingBottom: 0,
},
})

const SecondaryNavItemsBg = styled('a')({
opacity: 0,
transitionProperty: 'opacity',
transitionDuration: '350ms',
transitionTimingFunction: 'ease-out',
'::before': {
content: "''",
display: 'block',
top: 0,
left: 0,
width: '100%',
height: '100%',
position: 'absolute',
backgroundColor: 'black',
opacity: 0.75,
},
})

const SecondaryNavItemsOverflow = styled('div')({
overflow: 'auto',
width: '100%',
@@ -116,15 +152,40 @@ const NavbarContainer = styled('div')({
maxWidth: 360,
})

const SecondaryVisibleDummy = styled('div')({
display: 'none',
})

const Visible = createGlobalStyle({
[`div + ${SecondaryNavItems}`]: {
pointerEvents: 'initial',
},
[`div + ${SecondaryNavItems} ${SecondaryNavItemsFg}`]: {
left: 0,
},
[`div + ${SecondaryNavItems} ${SecondaryNavItemsBg}`]: {
opacity: 1,
},
'@media (min-width: 1080px)': {
[`div + ${SecondaryNavItems} ${SecondaryNavItemsFg}`]: {
left: 'auto',
},
[`div + ${SecondaryNavItems} ${SecondaryNavItemsBg}`]: {
opacity: 0,
},
}
})

const Navbar = ({
closeHref,
secondaryVisible,
primaryItemsStart = [],
primaryItemsEnd = [],
secondaryItemsHeader = [],
secondaryItems = [],
}) => {
const SecondaryNavItemsComponent = secondaryVisible ? VisibleSecondaryNavItems : SecondaryNavItems
return (
}) => (
<React.Fragment>
<Visible />
<Base>
<NavbarContainer>
<NavbarItems>
@@ -165,42 +226,57 @@ const Navbar = ({
}
</PrimaryNavItemsContainer>
</PrimaryNavItems>
<SecondaryNavItemsComponent>
<SecondaryNavItemsOverflow>
{
secondaryItemsHeader.map(i => (
<SecondaryNavItem
key={i.id}
active={i.active}
href={i.href}
replace={i.replace}
iconName={i.iconName}
title={i.title}
subtitle={i.subtitle}
actions={i.actions}
/>
))
}
{
secondaryItems.map(i => (
<SecondaryNavItem
key={i.id}
active={i.active}
href={i.href}
replace={i.replace}
iconName={i.iconName}
title={i.title}
subtitle={i.subtitle}
actions={i.actions}
/>
))
}
</SecondaryNavItemsOverflow>
</SecondaryNavItemsComponent>
{
secondaryVisible
&& (
<SecondaryVisibleDummy />
)
}
<SecondaryNavItems>
<Link
href={closeHref}
passHref
shallow
>
<SecondaryNavItemsBg />
</Link>
<SecondaryNavItemsFg>
<SecondaryNavItemsOverflow>
{
secondaryItemsHeader.map(i => (
<SecondaryNavItem
key={i.id}
active={i.active}
href={i.href}
replace={i.replace}
iconName={i.iconName}
title={i.title}
subtitle={i.subtitle}
actions={i.actions}
/>
))
}
{
secondaryItems.map(i => (
<SecondaryNavItem
key={i.id}
active={i.active}
href={i.href}
replace={i.replace}
iconName={i.iconName}
title={i.title}
subtitle={i.subtitle}
actions={i.actions}
/>
))
}
</SecondaryNavItemsOverflow>
</SecondaryNavItemsFg>
</SecondaryNavItems>
</NavbarItems>
</NavbarContainer>
</Base>
)
}
</React.Fragment>
)

export default Navbar

+ 1
- 0
src/components/PrimaryNavItem/PrimaryNavItem.tsx View File

@@ -89,6 +89,7 @@ const PrimaryNavItem: React.FC<Props> = ({
<Link
href={href}
passHref
shallow
>
<ClickArea
title={title}


+ 49
- 29
src/components/SecondaryNavItem/SecondaryNavItem.tsx View File

@@ -8,31 +8,54 @@ const NoteLink = styled('a')({
display: 'flex',
textDecoration: 'none',
color: 'inherit',
height: '4rem',
alignItems: 'center',
position: 'relative',
flex: 'auto',
padding: '0 1rem',
boxSizing: 'border-box',
})

const NoteLinkPrimary = styled('div')({
const NoteLinkPrimary = styled('span')({
display: 'block',
flex: 'auto',
})

const NoteLinkTitle = styled('strong')({
verticalAlign: 'middle',
display: 'block',
height: '1.25em',
position: 'relative',
})

const NoteLinkTitleOverflow = styled('span')({
whiteSpace: 'nowrap',
overflow: 'hidden',
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
textOverflow: 'ellipsis',
})

const LinkContainer = styled('div')({
position: 'relative',
color: 'var(--color-primary, blue)',
display: 'flex',
alignItems: 'stretch',
height: '4rem',
})

const NoteActions = styled('div')({
display: 'flex',
position: 'absolute',
alignItems: 'stretch',
top: 0,
right: 0,
height: '100%',
position: 'relative',
'@media (min-width: 1080px)': {
opacity: 0,
[`${LinkContainer}:hover &`]: {
opacity: 1,
},
},
})

const NoteAction = styled('button')({
@@ -43,6 +66,7 @@ const NoteAction = styled('button')({
color: 'inherit',
cursor: 'pointer',
outline: 0,
padding: 0,
})

const NoteLinkBackground = styled('span')({
@@ -74,11 +98,6 @@ const IconContainer = styled('span')({
marginRight: '0.5rem',
})

const NavbarItemContent = styled('span')({
padding: '0 1rem',
boxSizing: 'border-box',
})

const PostMeta = styled('small')({
opacity: 0.5,
height: '1.25rem',
@@ -122,26 +141,27 @@ const SecondaryNavItem: React.FC<Props> = ({
href={href}
replace={replace}
passHref
shallow
>
<NoteLink>
<NavbarItemContent>
<NoteLinkPrimary>
<IconContainer>
{
iconName
&& (
<Icon
name={iconName}
/>
)
}
</IconContainer>
<NoteLinkTitle
style={{ opacity: title.length > 0 ? 1 : 0.5, }}
>
<IconContainer>
{
iconName
&& (
<Icon
name={iconName}
/>
)
}
</IconContainer>
<NoteLinkPrimary>
<NoteLinkTitle
style={{ opacity: title.length > 0 ? 1 : 0.5, }}
>
<NoteLinkTitleOverflow>
{title.length > 0 ? title : '(untitled)'}
</NoteLinkTitle>
</NoteLinkPrimary>
</NoteLinkTitleOverflow>
</NoteLinkTitle>
{
subtitle
&& (
@@ -153,7 +173,7 @@ const SecondaryNavItem: React.FC<Props> = ({
</React.Fragment>
)
}
</NavbarItemContent>
</NoteLinkPrimary>
</NoteLink>
</Link>
{


+ 18
- 8
src/pages/notes.tsx View File

@@ -91,6 +91,19 @@ const Notes = ({ id: idProp }) => {
<link rel="icon" href="/favicon.ico" />
</Head>
<Navbar
closeHref={{
pathname: router.pathname,
query: Object
.entries(router.query)
.filter(([key]) => key !== 'navbar')
.reduce(
(theQuery, [key, value]) => ({
...theQuery,
[key]: value,
}),
{}
),
}}
secondaryVisible={Boolean(router.query.navbar)}
primaryItemsStart={[
{
@@ -213,14 +226,11 @@ const Notes = ({ id: idProp }) => {
replace: true,
title: n.title.trim(),
subtitle: (
<React.Fragment>
{'Last updated '}
<time
dateTime={new Date(n.updatedAt).toISOString()}
>
{formatDate(new Date(n.updatedAt))}
</time>
</React.Fragment>
<time
dateTime={new Date(n.updatedAt).toISOString()}
>
{formatDate(new Date(n.updatedAt))}
</time>
),
actions: [
{


Loading…
Cancel
Save