forked from crowetic/commerce
sticky nav, better dropdown exit
This commit is contained in:
parent
316801627b
commit
c22789176d
@ -1,4 +1,4 @@
|
|||||||
import { FC, useState } from 'react'
|
import { FC, useEffect, useState } from 'react'
|
||||||
import cn from 'classnames'
|
import cn from 'classnames'
|
||||||
import type { Page } from '@lib/bigcommerce/api/operations/get-all-pages'
|
import type { Page } from '@lib/bigcommerce/api/operations/get-all-pages'
|
||||||
import { CommerceProvider } from '@lib/bigcommerce'
|
import { CommerceProvider } from '@lib/bigcommerce'
|
||||||
@ -18,13 +18,37 @@ interface Props {
|
|||||||
const Layout: FC<Props> = ({ children, pageProps }) => {
|
const Layout: FC<Props> = ({ children, pageProps }) => {
|
||||||
const { displaySidebar, closeSidebar } = useUI()
|
const { displaySidebar, closeSidebar } = useUI()
|
||||||
const [acceptedCookies, setAcceptedCookies] = useState(false)
|
const [acceptedCookies, setAcceptedCookies] = useState(false)
|
||||||
|
const [hasScrolled, setHasScrolled] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const offset = 0
|
||||||
|
function handleScroll() {
|
||||||
|
const { scrollTop } = document.documentElement
|
||||||
|
if (scrollTop > offset) setHasScrolled(true)
|
||||||
|
else setHasScrolled(false)
|
||||||
|
}
|
||||||
|
document.addEventListener('scroll', handleScroll)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('scroll', handleScroll)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CommerceProvider locale="en-us">
|
<CommerceProvider locale="en-us">
|
||||||
<div className={cn(s.root)}>
|
<div className={cn(s.root)}>
|
||||||
<Container>
|
<header
|
||||||
<Navbar />
|
className={cn(
|
||||||
</Container>
|
'sticky top-0 bg-primary z-40 transition-shadow duration-200',
|
||||||
|
{
|
||||||
|
'shadow-magical': hasScrolled,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Container>
|
||||||
|
<Navbar />
|
||||||
|
</Container>
|
||||||
|
</header>
|
||||||
<main className="fit">{children}</main>
|
<main className="fit">{children}</main>
|
||||||
<Footer pages={pageProps.pages} />
|
<Footer pages={pageProps.pages} />
|
||||||
<Sidebar show={displaySidebar} close={closeSidebar}>
|
<Sidebar show={displaySidebar} close={closeSidebar}>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { FC, useState } from 'react'
|
import { FC, useEffect, useState } from 'react'
|
||||||
import cn from 'classnames'
|
import cn from 'classnames'
|
||||||
import useCart from '@lib/bigcommerce/cart/use-cart'
|
import useCart from '@lib/bigcommerce/cart/use-cart'
|
||||||
import { Avatar } from '@components/core'
|
import { Avatar } from '@components/core'
|
||||||
@ -21,6 +21,30 @@ const UserNav: FC<Props> = ({ className }) => {
|
|||||||
const { openSidebar, closeSidebar, displaySidebar } = useUI()
|
const { openSidebar, closeSidebar, displaySidebar } = useUI()
|
||||||
const itemsCount = Object.values(data?.line_items ?? {}).reduce(countItems, 0)
|
const itemsCount = Object.values(data?.line_items ?? {}).reduce(countItems, 0)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function handleClick(e: any) {
|
||||||
|
const isInside = e?.target?.closest(`#user-dropdown`) !== null
|
||||||
|
if (isInside) return
|
||||||
|
setDisplayDropdown(false)
|
||||||
|
document.removeEventListener('click', handleClick)
|
||||||
|
}
|
||||||
|
function handleKeyPress(e: KeyboardEvent) {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
setDisplayDropdown(false)
|
||||||
|
document.removeEventListener('keydown', handleKeyPress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayDropdown) {
|
||||||
|
document.addEventListener('click', handleClick)
|
||||||
|
document.addEventListener('keydown', handleKeyPress)
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('click', handleClick)
|
||||||
|
document.removeEventListener('keydown', handleKeyPress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [displayDropdown])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className={cn(s.root, className)}>
|
<nav className={cn(s.root, className)}>
|
||||||
<ul className={s.list}>
|
<ul className={s.list}>
|
||||||
@ -40,18 +64,21 @@ const UserNav: FC<Props> = ({ className }) => {
|
|||||||
<Heart />
|
<Heart />
|
||||||
</li>
|
</li>
|
||||||
</Link>
|
</Link>
|
||||||
<li
|
<button
|
||||||
className={s.item}
|
className={cn(
|
||||||
|
s.item,
|
||||||
|
'rounded-full focus:shadow-outline-blue focus:outline-none'
|
||||||
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDisplayDropdown((i) => !i)
|
setDisplayDropdown((i) => !i)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Avatar />
|
<Avatar />
|
||||||
</li>
|
</button>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{displayDropdown && (
|
{displayDropdown && (
|
||||||
<div className={s.dropdownMenu}>
|
<div className={cn(s.dropdownMenu, 'shadow-lg')} id="user-dropdown">
|
||||||
<nav className={s.dropdownMenuContainer}>
|
<nav className={s.dropdownMenuContainer}>
|
||||||
<Link href="#">
|
<Link href="#">
|
||||||
<a className={s.link}>My Purchases</a>
|
<a className={s.link}>My Purchases</a>
|
||||||
@ -59,8 +86,9 @@ const UserNav: FC<Props> = ({ className }) => {
|
|||||||
<Link href="#">
|
<Link href="#">
|
||||||
<a className={s.link}>My Account</a>
|
<a className={s.link}>My Account</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
<div className="my-1 h-px w-full bg-accents-2" />
|
||||||
<Link href="#">
|
<Link href="#">
|
||||||
<a className={cn(s.link, 'mt-4')}>Logout</a>
|
<a className={cn(s.link)}>Logout</a>
|
||||||
</Link>
|
</Link>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nameBox {
|
.nameBox {
|
||||||
@apply absolute top-6 left-0 z-50;
|
@apply absolute top-6 left-0 z-30;
|
||||||
|
|
||||||
& .name {
|
& .name {
|
||||||
@apply px-6 py-2 bg-primary text-primary font-bold;
|
@apply px-6 py-2 bg-primary text-primary font-bold;
|
||||||
|
@ -37,6 +37,10 @@ module.exports = {
|
|||||||
primary: 'var(--text-primary)',
|
primary: 'var(--text-primary)',
|
||||||
secondary: 'var(--text-secondary)',
|
secondary: 'var(--text-secondary)',
|
||||||
},
|
},
|
||||||
|
boxShadow: {
|
||||||
|
magical:
|
||||||
|
'rgba(0, 0, 0, 0.02) 0px 30px 30px, rgba(0, 0, 0, 0.03) 0px 0px 8px, rgba(0, 0, 0, 0.05) 0px 1px 0px',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
variants: {},
|
variants: {},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user