Skip to content

Commit

Permalink
feat(website): animate navigation toggle button
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc committed Jan 12, 2022
1 parent f23c5eb commit 16f89bb
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 30 deletions.
33 changes: 3 additions & 30 deletions website/src/components/nav/HeaderNav.tsx
Expand Up @@ -2,10 +2,11 @@ import React from 'react'
import styled, { css } from 'styled-components'
import { Link } from 'gatsby'
import { FaGithub, FaTwitter } from 'react-icons/fa'
import { FiX, FiMenu, FiExternalLink, FiChevronDown } from 'react-icons/fi'
import { FiExternalLink, FiChevronDown } from 'react-icons/fi'
import media from '../../theming/mediaQueries'
import ThemeSelector from '../ThemeSelector'
import * as nav from '../../data/nav'
import { NavToggleButton } from './NavToggleButton'

interface HeaderNavProps {
isNavOpen: boolean
Expand Down Expand Up @@ -66,10 +67,7 @@ export const HeaderNav = ({ isNavOpen, toggleNav }: HeaderNavProps) => {
>
<FaTwitter />
</IconExternalLink>
<NavToggleButton onClick={toggleNav}>
{isNavOpen && <FiX />}
{!isNavOpen && <FiMenu />}
</NavToggleButton>
<NavToggleButton isOpen={isNavOpen} onClick={toggleNav} />
</Container>
)
}
Expand Down Expand Up @@ -197,28 +195,3 @@ const IconExternalLink = styled.a`
}
`}
`

const NavToggleButton = styled.div`
height: ${({ theme }) => theme.dimensions.headerHeight}px;
width: ${({ theme }) => theme.dimensions.headerHeight}px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
user-select: none;
margin-left: 12px;
font-size: 24px;
color: white;
${media.tablet`
& {
margin-left: 0;
}
`}
${media.mobile`
& {
margin-left: 0;
}
`}
`
87 changes: 87 additions & 0 deletions website/src/components/nav/NavToggleButton.tsx
@@ -0,0 +1,87 @@
import React from 'react'
import styled from 'styled-components'
import { useSpring, animated, to, config } from '@react-spring/web'
import media from '../../theming/mediaQueries'

interface NavToggleButtonProps {
isOpen: boolean
onClick: () => void
}

const SIZE = 32
const HALF_LENGTH = 11
const SPACING = 7

export const NavToggleButton = ({ isOpen, onClick }: NavToggleButtonProps) => {
const first = useSpring({
y: isOpen ? 0 : -SPACING,
rotation: isOpen ? 45 : 0,
config: config.wobbly,
})
const second = useSpring({
x1: isOpen ? -HALF_LENGTH - 10 : -HALF_LENGTH,
x2: isOpen ? 0 : HALF_LENGTH,
opacity: isOpen ? 0 : 1,
config: config.wobbly,
})
const third = useSpring({
y: isOpen ? 0 : SPACING,
rotation: isOpen ? -45 : 0,
config: config.wobbly,
})

return (
<Container onClick={onClick}>
<svg width={SIZE} height={SIZE}>
<g transform={`translate(${SIZE / 2}, ${SIZE / 2})`}>
<animated.line
x1={-HALF_LENGTH}
x2={HALF_LENGTH}
transform={to(
[first.y, first.rotation],
(y, rotation) => `translate(0, ${y}) rotate(${rotation})`
)}
/>
<animated.line x1={second.x1} x2={second.x2} opacity={second.opacity} />
<animated.line
x1={-HALF_LENGTH}
x2={HALF_LENGTH}
transform={to(
[third.y, third.rotation],
(y, rotation) => `translate(0, ${y}) rotate(${rotation})`
)}
/>
</g>
</svg>
</Container>
)
}

const Container = styled.div`
height: ${({ theme }) => theme.dimensions.headerHeight}px;
width: ${({ theme }) => theme.dimensions.headerHeight}px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
user-select: none;
margin-left: 12px;
& svg {
stroke: #ffffff;
stroke-width: 2;
stroke-linecap: round;
}
${media.tablet`
& {
margin-left: 0;
}
`}
${media.mobile`
& {
margin-left: 0;
}
`}
`

0 comments on commit 16f89bb

Please sign in to comment.