mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 20:26:49 +00:00
New Release (#371)
* Custom Checkout Progress * Updates to Checkout * Custom Checkout Progress * Adding tabs * Adding Collapse * Adding Collapse * Improving Sidebar Scroll * Modif footer * Changes * More design updates * sidebar cart * More design updates * More design updates * More design updates * More design updates * Types * Types * Design Updates * More changes * More changes * More changes * Changes * Changes * Changes * New tailwind required changes * Sidebar Styling issues with Mobile * Latest changes - Normalizing cart * Styling Fixes * New changes * Changes * latest * Refactor and Renaming some UI Props * Adding Quantity Component * Adding Rating Component * Rating Component * More updates * User Select disabled, plus hidding horizontal scroll bars * Changes * Adding ProductOptions Component and more helpers * Styling updates * Styling updates * Fix for slim tags * Missmatch with RightArrow * Footer updates and some styles * Latest Updates * Latest Updates * Latest Updates * Removing Portal, since it's not needed. We might add it later I'd rather not to. * Removing Portal, since it's not needed. We might add it later I'd rather not to. * Sam backdrop filter * General UI Improvements * General UI Improvements * Search now with Geist Colors * Now with Geist Colors * Changes * Scroll for Mobile on IOs devises * LoadingDots Working (: * Changes * More Changes * Perf changes * More perf changes * Fade to the Nametags in the ProductCard * changes * Search issue ui * Search issue ui * Make sure to only refresh navbar and modals when required * Index revalidate * Fixed image issue * hide album scroll on windows * Fix scrollbar * Changing * Adding 404 with Layout * Removing Toast * Adding Assets * Adding Assets * Progress with LocalProvider * New productTag * Only images for the drop * changes * Empty SWRhooks * Adding Local Provider * Working local * Working view of a LocalProvider * More updates * Changes * Removed react-ticker * default to local if no env available * default to local if no env available * add missing `@` to css import * rewrite search rewrites to multiple pages * allow requests in getStaticProps to execute in parallel * make type import explicit * add a tsconfig.js file * use local provider in tsconfig.js * avoid a circular dependency * Saleor was not in the providers list * avoid circular dependency in bigcommerce * Adding more to the Local Provider (#366) * Adding more data * Adding more data * optimize assets (#370) * Optimize assets (#372) * optimize assets * remove assets * remove assets * cart enabled * Adding saleor * Changes with Webpack * Changes Co-authored-by: Luis Alvarez <luis@vercel.com> Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com> Co-authored-by: Shu Ding <g@shud.in>
This commit is contained in:
@@ -14,7 +14,7 @@ const Avatar: FC<Props> = ({}) => {
|
||||
<div
|
||||
ref={ref}
|
||||
style={{ backgroundImage: userAvatar }}
|
||||
className="inline-block h-8 w-8 rounded-full border-2 border-primary hover:border-secondary focus:border-secondary transition linear-out duration-150"
|
||||
className="inline-block h-8 w-8 rounded-full border-2 border-primary hover:border-secondary focus:border-secondary transition-colors ease-linear"
|
||||
>
|
||||
{/* Add an image - We're generating a gradient as placeholder <img></img> */}
|
||||
</div>
|
||||
|
@@ -1,9 +1,7 @@
|
||||
.root {
|
||||
@apply text-center p-6 bg-primary text-sm flex-row justify-center items-center font-medium fixed bottom-0 w-full z-30 transition-all duration-300 ease-out;
|
||||
}
|
||||
|
||||
@screen md {
|
||||
.root {
|
||||
@screen md {
|
||||
@apply flex text-left;
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,7 @@
|
||||
.root {
|
||||
@apply border-t border-accent-2;
|
||||
}
|
||||
|
||||
.link {
|
||||
& > svg {
|
||||
@apply transform duration-75 ease-linear;
|
||||
|
@@ -15,65 +15,50 @@ interface Props {
|
||||
pages?: Page[]
|
||||
}
|
||||
|
||||
const LEGAL_PAGES = ['terms-of-use', 'shipping-returns', 'privacy-policy']
|
||||
const links = [
|
||||
{
|
||||
name: 'Home',
|
||||
url: '/',
|
||||
},
|
||||
]
|
||||
|
||||
const Footer: FC<Props> = ({ className, pages }) => {
|
||||
const { sitePages, legalPages } = usePages(pages)
|
||||
const rootClassName = cn(className)
|
||||
const { sitePages } = usePages(pages)
|
||||
const rootClassName = cn(s.root, className)
|
||||
|
||||
return (
|
||||
<footer className={rootClassName}>
|
||||
<Container>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 border-b border-accents-2 py-12 text-primary bg-primary transition-colors duration-150">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 border-b border-accent-2 py-12 text-primary bg-primary transition-colors duration-150">
|
||||
<div className="col-span-1 lg:col-span-2">
|
||||
<Link href="/">
|
||||
<a className="flex flex-initial items-center font-bold md:mr-24">
|
||||
<span className="rounded-full border border-gray-700 mr-2">
|
||||
<span className="rounded-full border border-accent-6 mr-2">
|
||||
<Logo />
|
||||
</span>
|
||||
<span>ACME</span>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="col-span-1 lg:col-span-2">
|
||||
<ul className="flex flex-initial flex-col md:flex-1">
|
||||
<li className="py-3 md:py-0 md:pb-4">
|
||||
<Link href="/">
|
||||
<a className="text-primary hover:text-accents-6 transition ease-in-out duration-150">
|
||||
Home
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{sitePages.map((page) => (
|
||||
<li key={page.url} className="py-3 md:py-0 md:pb-4">
|
||||
<div className="col-span-1 lg:col-span-8">
|
||||
<div className="grid md:grid-rows-4 md:grid-cols-3 md:grid-flow-col">
|
||||
{[...links, ...sitePages].map((page) => (
|
||||
<span key={page.url} className="py-3 md:py-0 md:pb-4">
|
||||
<Link href={page.url!}>
|
||||
<a className="text-primary hover:text-accents-6 transition ease-in-out duration-150">
|
||||
<a className="text-accent-9 hover:text-accent-6 transition ease-in-out duration-150">
|
||||
{page.name}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
</span>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-1 lg:col-span-2">
|
||||
<ul className="flex flex-initial flex-col md:flex-1">
|
||||
{legalPages.map((page) => (
|
||||
<li key={page.url} className="py-3 md:py-0 md:pb-4">
|
||||
<Link href={page.url!}>
|
||||
<a className="text-primary hover:text-accents-6 transition ease-in-out duration-150">
|
||||
{page.name}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col-span-1 lg:col-span-6 flex items-start lg:justify-end text-primary">
|
||||
<div className="col-span-1 lg:col-span-2 flex items-start lg:justify-end text-primary">
|
||||
<div className="flex space-x-6 items-center h-10">
|
||||
<a
|
||||
className={s.link}
|
||||
aria-label="Github Repository"
|
||||
href="https://github.com/vercel/commerce"
|
||||
className={s.link}
|
||||
>
|
||||
<Github />
|
||||
</a>
|
||||
@@ -81,12 +66,12 @@ const Footer: FC<Props> = ({ className, pages }) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="py-12 flex flex-col md:flex-row justify-between items-center space-y-4">
|
||||
<div className="pt-6 pb-10 flex flex-col md:flex-row justify-between items-center space-y-4 text-accent-6 text-sm">
|
||||
<div>
|
||||
<span>© 2020 ACME, Inc. All rights reserved.</span>
|
||||
</div>
|
||||
<div className="flex items-center text-primary">
|
||||
<span className="text-primary">Crafted by</span>
|
||||
<div className="flex items-center text-primary text-sm">
|
||||
<span className="text-primary">Created by</span>
|
||||
<a
|
||||
rel="noopener"
|
||||
href="https://vercel.com"
|
||||
@@ -95,7 +80,7 @@ const Footer: FC<Props> = ({ className, pages }) => {
|
||||
className="text-primary"
|
||||
>
|
||||
<Vercel
|
||||
className="inline-block h-6 ml-4 text-primary"
|
||||
className="inline-block h-6 ml-3 text-primary"
|
||||
alt="Vercel.com Logo"
|
||||
/>
|
||||
</a>
|
||||
@@ -109,34 +94,21 @@ const Footer: FC<Props> = ({ className, pages }) => {
|
||||
function usePages(pages?: Page[]) {
|
||||
const { locale } = useRouter()
|
||||
const sitePages: Page[] = []
|
||||
const legalPages: Page[] = []
|
||||
|
||||
if (pages) {
|
||||
pages.forEach((page) => {
|
||||
const slug = page.url && getSlug(page.url)
|
||||
|
||||
if (!slug) return
|
||||
if (locale && !slug.startsWith(`${locale}/`)) return
|
||||
|
||||
if (isLegalPage(slug, locale)) {
|
||||
legalPages.push(page)
|
||||
} else {
|
||||
sitePages.push(page)
|
||||
}
|
||||
sitePages.push(page)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
sitePages: sitePages.sort(bySortOrder),
|
||||
legalPages: legalPages.sort(bySortOrder),
|
||||
}
|
||||
}
|
||||
|
||||
const isLegalPage = (slug: string, locale?: string) =>
|
||||
locale
|
||||
? LEGAL_PAGES.some((p) => `${locale}/${p}` === slug)
|
||||
: LEGAL_PAGES.includes(slug)
|
||||
|
||||
// Sort pages by the sort order assigned in the BC dashboard
|
||||
function bySortOrder(a: Page, b: Page) {
|
||||
return (a.sort_order ?? 0) - (b.sort_order ?? 0)
|
||||
|
@@ -28,7 +28,7 @@ const HomeAllProductsGrid: FC<Props> = ({
|
||||
</Link>
|
||||
</li>
|
||||
{categories.map((cat: any) => (
|
||||
<li key={cat.path} className="py-1 text-accents-8 text-base">
|
||||
<li key={cat.path} className="py-1 text-accent-8 text-base">
|
||||
<Link href={getCategoryPath(cat.path)}>
|
||||
<a>{cat.name}</a>
|
||||
</Link>
|
||||
@@ -42,7 +42,7 @@ const HomeAllProductsGrid: FC<Props> = ({
|
||||
</Link>
|
||||
</li>
|
||||
{brands.flatMap(({ node }: any) => (
|
||||
<li key={node.path} className="py-1 text-accents-8 text-base">
|
||||
<li key={node.path} className="py-1 text-accent-8 text-base">
|
||||
<Link href={getDesignerPath(node.path)}>
|
||||
<a>{node.name}</a>
|
||||
</Link>
|
||||
|
@@ -3,11 +3,11 @@
|
||||
}
|
||||
|
||||
.button {
|
||||
@apply h-10 px-2 rounded-md border border-accents-2 flex items-center justify-center;
|
||||
@apply h-10 px-2 rounded-md border border-accent-2 flex items-center justify-center transition-colors ease-linear;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
@apply border-accents-4 shadow-sm;
|
||||
@apply border-accent-3 shadow-sm;
|
||||
}
|
||||
|
||||
.button:focus {
|
||||
@@ -16,16 +16,14 @@
|
||||
|
||||
.dropdownMenu {
|
||||
@apply fixed right-0 top-12 mt-2 origin-top-right outline-none bg-primary z-40 w-full h-full;
|
||||
}
|
||||
|
||||
@screen lg {
|
||||
.dropdownMenu {
|
||||
@apply absolute border border-accents-1 shadow-lg w-56 h-auto;
|
||||
@screen lg {
|
||||
@apply absolute border border-accent-1 shadow-lg w-56 h-auto;
|
||||
}
|
||||
}
|
||||
|
||||
@screen md {
|
||||
.closeButton {
|
||||
.closeButton {
|
||||
@screen md {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
@@ -36,9 +34,13 @@
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
@apply bg-accents-1;
|
||||
@apply bg-accent-1;
|
||||
}
|
||||
|
||||
.icon {
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.icon.active {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
@@ -59,7 +59,7 @@ const I18nWidget: FC = () => {
|
||||
/>
|
||||
{options && (
|
||||
<span className="cursor-pointer">
|
||||
<ChevronUp className={cn({ [s.icon]: display })} />
|
||||
<ChevronUp className={cn(s.icon, { [s.active]: display })} />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
|
@@ -1,15 +1,19 @@
|
||||
import React, { FC } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import dynamic from 'next/dynamic'
|
||||
import cn from 'classnames'
|
||||
import type { Page } from '@commerce/types/page'
|
||||
import type { Category } from '@commerce/types/site'
|
||||
import React, { FC } from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useRouter } from 'next/router'
|
||||
import { CommerceProvider } from '@framework'
|
||||
import { useAcceptCookies } from '@lib/hooks/useAcceptCookies'
|
||||
import { useUI } from '@components/ui/context'
|
||||
import type { Page } from '@commerce/types/page'
|
||||
import { Navbar, Footer } from '@components/common'
|
||||
import { Sidebar, Button, Modal, LoadingDots } from '@components/ui'
|
||||
import type { Category } from '@commerce/types/site'
|
||||
import ShippingView from '@components/checkout/ShippingView'
|
||||
import CartSidebarView from '@components/cart/CartSidebarView'
|
||||
import { useAcceptCookies } from '@lib/hooks/useAcceptCookies'
|
||||
import { Sidebar, Button, Modal, LoadingDots } from '@components/ui'
|
||||
import PaymentMethodView from '@components/checkout/PaymentMethodView'
|
||||
import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView'
|
||||
|
||||
import LoginView from '@components/auth/LoginView'
|
||||
import s from './Layout.module.css'
|
||||
|
||||
@@ -45,15 +49,53 @@ interface Props {
|
||||
}
|
||||
}
|
||||
|
||||
const ModalView: FC<{ modalView: string; closeModal(): any }> = ({
|
||||
modalView,
|
||||
closeModal,
|
||||
}) => {
|
||||
return (
|
||||
<Modal onClose={closeModal}>
|
||||
{modalView === 'LOGIN_VIEW' && <LoginView />}
|
||||
{modalView === 'SIGNUP_VIEW' && <SignUpView />}
|
||||
{modalView === 'FORGOT_VIEW' && <ForgotPassword />}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
const ModalUI: FC = () => {
|
||||
const { displayModal, closeModal, modalView } = useUI()
|
||||
return displayModal ? (
|
||||
<ModalView modalView={modalView} closeModal={closeModal} />
|
||||
) : null
|
||||
}
|
||||
|
||||
const SidebarView: FC<{ sidebarView: string; closeSidebar(): any }> = ({
|
||||
sidebarView,
|
||||
closeSidebar,
|
||||
}) => {
|
||||
return (
|
||||
<Sidebar onClose={closeSidebar}>
|
||||
{sidebarView === 'CART_VIEW' && <CartSidebarView />}
|
||||
{sidebarView === 'CHECKOUT_VIEW' && <CheckoutSidebarView />}
|
||||
{sidebarView === 'PAYMENT_VIEW' && <PaymentMethodView />}
|
||||
{sidebarView === 'SHIPPING_VIEW' && <ShippingView />}
|
||||
</Sidebar>
|
||||
)
|
||||
}
|
||||
|
||||
const SidebarUI: FC = () => {
|
||||
const { displaySidebar, closeSidebar, sidebarView } = useUI()
|
||||
return displaySidebar ? (
|
||||
<SidebarView sidebarView={sidebarView} closeSidebar={closeSidebar} />
|
||||
) : null
|
||||
}
|
||||
|
||||
const Layout: FC<Props> = ({
|
||||
children,
|
||||
pageProps: { categories = [], ...pageProps },
|
||||
}) => {
|
||||
const { displaySidebar, displayModal, closeSidebar, closeModal, modalView } =
|
||||
useUI()
|
||||
const { acceptedCookies, onAcceptCookies } = useAcceptCookies()
|
||||
const { locale = 'en-US' } = useRouter()
|
||||
|
||||
const navBarlinks = categories.slice(0, 2).map((c) => ({
|
||||
label: c.name,
|
||||
href: `/search/${c.slug}`,
|
||||
@@ -65,17 +107,8 @@ const Layout: FC<Props> = ({
|
||||
<Navbar links={navBarlinks} />
|
||||
<main className="fit">{children}</main>
|
||||
<Footer pages={pageProps.pages} />
|
||||
|
||||
<Modal open={displayModal} onClose={closeModal}>
|
||||
{modalView === 'LOGIN_VIEW' && <LoginView />}
|
||||
{modalView === 'SIGNUP_VIEW' && <SignUpView />}
|
||||
{modalView === 'FORGOT_VIEW' && <ForgotPassword />}
|
||||
</Modal>
|
||||
|
||||
<Sidebar open={displaySidebar} onClose={closeSidebar}>
|
||||
<CartSidebarView />
|
||||
</Sidebar>
|
||||
|
||||
<ModalUI />
|
||||
<SidebarUI />
|
||||
<FeatureBar
|
||||
title="This site uses cookies to improve your experience. By clicking, you agree to our Privacy Policy."
|
||||
hide={acceptedCookies}
|
||||
|
@@ -2,16 +2,26 @@
|
||||
@apply sticky top-0 bg-primary z-40 transition-all duration-150;
|
||||
}
|
||||
|
||||
.nav {
|
||||
@apply relative flex flex-row justify-between py-4 md:py-4;
|
||||
}
|
||||
|
||||
.navMenu {
|
||||
@apply hidden ml-6 space-x-4 lg:block;
|
||||
}
|
||||
|
||||
.link {
|
||||
@apply inline-flex items-center text-primary leading-6 font-medium transition ease-in-out duration-75 cursor-pointer text-accents-6;
|
||||
@apply inline-flex items-center leading-6
|
||||
transition ease-in-out duration-75 cursor-pointer
|
||||
text-accent-5;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
@apply text-accents-9;
|
||||
@apply text-accent-9;
|
||||
}
|
||||
|
||||
.link:focus {
|
||||
@apply outline-none text-accents-8;
|
||||
@apply outline-none text-accent-8;
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import { FC } from 'react'
|
||||
import Link from 'next/link'
|
||||
import s from './Navbar.module.css'
|
||||
import NavbarRoot from './NavbarRoot'
|
||||
import { Logo, Container } from '@components/ui'
|
||||
import { Searchbar, UserNav } from '@components/common'
|
||||
import NavbarRoot from './NavbarRoot'
|
||||
import s from './Navbar.module.css'
|
||||
|
||||
interface Link {
|
||||
href: string
|
||||
@@ -16,14 +16,14 @@ interface NavbarProps {
|
||||
const Navbar: FC<NavbarProps> = ({ links }) => (
|
||||
<NavbarRoot>
|
||||
<Container>
|
||||
<div className="relative flex flex-row justify-between py-4 align-center md:py-6">
|
||||
<div className={s.nav}>
|
||||
<div className="flex items-center flex-1">
|
||||
<Link href="/">
|
||||
<a className={s.logo} aria-label="Logo">
|
||||
<Logo />
|
||||
</a>
|
||||
</Link>
|
||||
<nav className="hidden ml-6 space-x-4 lg:block">
|
||||
<nav className={s.navMenu}>
|
||||
<Link href="/search">
|
||||
<a className={s.link}>All</a>
|
||||
</Link>
|
||||
@@ -34,16 +34,13 @@ const Navbar: FC<NavbarProps> = ({ links }) => (
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div className="justify-center flex-1 hidden lg:flex">
|
||||
<Searchbar />
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end flex-1 space-x-8">
|
||||
<div className="flex items-center justify-end flex-1 space-x-8">
|
||||
<UserNav />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex pb-4 lg:px-6 lg:hidden">
|
||||
<Searchbar id="mobile-search" />
|
||||
</div>
|
||||
|
@@ -1,9 +1,13 @@
|
||||
.root {
|
||||
@apply relative text-sm bg-accent-0 text-base w-full transition-colors duration-150 border border-accent-2;
|
||||
}
|
||||
|
||||
.input {
|
||||
@apply bg-transparent px-3 py-2 appearance-none w-full transition duration-150 ease-in-out pr-10;
|
||||
}
|
||||
|
||||
@screen sm {
|
||||
min-width: 300px;
|
||||
}
|
||||
.input::placeholder {
|
||||
@apply text-accent-3;
|
||||
}
|
||||
|
||||
.input:focus {
|
||||
@@ -17,3 +21,9 @@
|
||||
.icon {
|
||||
@apply h-5 w-5;
|
||||
}
|
||||
|
||||
@screen sm {
|
||||
.input {
|
||||
min-width: 300px;
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { FC, useEffect, useMemo } from 'react'
|
||||
import { FC, InputHTMLAttributes, useEffect, useMemo } from 'react'
|
||||
import cn from 'classnames'
|
||||
import s from './Searchbar.module.css'
|
||||
import { useRouter } from 'next/router'
|
||||
@@ -15,14 +15,26 @@ const Searchbar: FC<Props> = ({ className, id = 'search' }) => {
|
||||
router.prefetch('/search')
|
||||
}, [])
|
||||
|
||||
const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
e.preventDefault()
|
||||
|
||||
if (e.key === 'Enter') {
|
||||
const q = e.currentTarget.value
|
||||
|
||||
router.push(
|
||||
{
|
||||
pathname: `/search`,
|
||||
query: q ? { q } : {},
|
||||
},
|
||||
undefined,
|
||||
{ shallow: true }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return useMemo(
|
||||
() => (
|
||||
<div
|
||||
className={cn(
|
||||
'relative text-sm bg-accents-1 text-base w-full transition-colors duration-150',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className={cn(s.root, className)}>
|
||||
<label className="hidden" htmlFor={id}>
|
||||
Search
|
||||
</label>
|
||||
@@ -31,22 +43,7 @@ const Searchbar: FC<Props> = ({ className, id = 'search' }) => {
|
||||
className={s.input}
|
||||
placeholder="Search for products..."
|
||||
defaultValue={router.query.q}
|
||||
onKeyUp={(e) => {
|
||||
e.preventDefault()
|
||||
|
||||
if (e.key === 'Enter') {
|
||||
const q = e.currentTarget.value
|
||||
|
||||
router.push(
|
||||
{
|
||||
pathname: `/search`,
|
||||
query: q ? { q } : {},
|
||||
},
|
||||
undefined,
|
||||
{ shallow: true }
|
||||
)
|
||||
}
|
||||
}}
|
||||
onKeyUp={handleKeyUp}
|
||||
/>
|
||||
<div className={s.iconContainer}>
|
||||
<svg className={s.icon} fill="currentColor" viewBox="0 0 20 20">
|
||||
|
20
components/common/SidebarLayout/SidebarLayout.module.css
Normal file
20
components/common/SidebarLayout/SidebarLayout.module.css
Normal file
@@ -0,0 +1,20 @@
|
||||
.root {
|
||||
@apply relative h-full flex flex-col;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply sticky top-0 pl-4 py-4 pr-6
|
||||
flex items-center justify-between
|
||||
bg-accent-0 box-border w-full z-10;
|
||||
min-height: 66px;
|
||||
}
|
||||
|
||||
.container {
|
||||
@apply flex flex-col flex-1 box-border;
|
||||
}
|
||||
|
||||
@screen lg {
|
||||
.header {
|
||||
min-height: 74px;
|
||||
}
|
||||
}
|
50
components/common/SidebarLayout/SidebarLayout.tsx
Normal file
50
components/common/SidebarLayout/SidebarLayout.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import React, { FC } from 'react'
|
||||
import { Cross, ChevronLeft } from '@components/icons'
|
||||
import { UserNav } from '@components/common'
|
||||
import cn from 'classnames'
|
||||
import s from './SidebarLayout.module.css'
|
||||
|
||||
type ComponentProps = { className?: string } & (
|
||||
| { handleClose: () => any; handleBack?: never }
|
||||
| { handleBack: () => any; handleClose?: never }
|
||||
)
|
||||
|
||||
const SidebarLayout: FC<ComponentProps> = ({
|
||||
children,
|
||||
className,
|
||||
handleClose,
|
||||
handleBack,
|
||||
}) => {
|
||||
return (
|
||||
<div className={cn(s.root, className)}>
|
||||
<header className={s.header}>
|
||||
{handleClose && (
|
||||
<button
|
||||
onClick={handleClose}
|
||||
aria-label="Close"
|
||||
className="hover:text-accent-5 transition ease-in-out duration-150 flex items-center focus:outline-none"
|
||||
>
|
||||
<Cross className="h-6 w-6 hover:text-accent-3" />
|
||||
<span className="ml-2 text-accent-7 text-sm ">Close</span>
|
||||
</button>
|
||||
)}
|
||||
{handleBack && (
|
||||
<button
|
||||
onClick={handleBack}
|
||||
aria-label="Go back"
|
||||
className="hover:text-accent-5 transition ease-in-out duration-150 flex items-center focus:outline-none"
|
||||
>
|
||||
<ChevronLeft className="h-6 w-6 hover:text-accent-3" />
|
||||
<span className="ml-2 text-accent-7 text-xs">Back</span>
|
||||
</button>
|
||||
)}
|
||||
<span className={s.nav}>
|
||||
<UserNav />
|
||||
</span>
|
||||
</header>
|
||||
<div className={s.container}>{children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SidebarLayout
|
1
components/common/SidebarLayout/index.ts
Normal file
1
components/common/SidebarLayout/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './SidebarLayout'
|
@@ -1,10 +1,8 @@
|
||||
.dropdownMenu {
|
||||
@apply fixed right-0 mt-2 origin-top-right outline-none bg-primary z-40 w-full h-full;
|
||||
}
|
||||
|
||||
@screen lg {
|
||||
.dropdownMenu {
|
||||
@apply absolute top-10 border border-accents-1 shadow-lg w-56 h-auto;
|
||||
@screen lg {
|
||||
@apply absolute top-10 border border-accent-1 shadow-lg w-56 h-auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +12,11 @@
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
@apply bg-accents-1;
|
||||
@apply bg-accent-1;
|
||||
}
|
||||
|
||||
.link.active {
|
||||
@apply font-bold bg-accents-2;
|
||||
@apply font-bold bg-accent-2;
|
||||
}
|
||||
|
||||
.off {
|
||||
|
@@ -109,7 +109,7 @@ const DropdownMenu: FC<DropdownMenuProps> = ({ open = false }) => {
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className={cn(s.link, 'border-t border-accents-2 mt-4')}
|
||||
className={cn(s.link, 'border-t border-accent-2 mt-4')}
|
||||
onClick={() => logout()}
|
||||
>
|
||||
Logout
|
||||
|
@@ -10,7 +10,7 @@
|
||||
@apply mr-6 cursor-pointer relative transition ease-in-out duration-100 flex items-center outline-none text-primary;
|
||||
|
||||
&:hover {
|
||||
@apply text-accents-6 transition scale-110 duration-100;
|
||||
@apply text-accent-6 transition scale-110 duration-100;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@@ -24,7 +24,7 @@
|
||||
}
|
||||
|
||||
.bagCount {
|
||||
@apply border border-accents-1 bg-secondary text-secondary absolute rounded-full right-3 top-3 flex items-center justify-center font-bold text-xs;
|
||||
@apply border border-accent-1 bg-secondary text-secondary absolute rounded-full right-3 top-3 flex items-center justify-center font-bold text-xs;
|
||||
padding-left: 2.5px;
|
||||
padding-right: 2.5px;
|
||||
min-width: 1.25rem;
|
||||
|
@@ -24,21 +24,21 @@ const UserNav: FC<Props> = ({ className }) => {
|
||||
|
||||
return (
|
||||
<nav className={cn(s.root, className)}>
|
||||
<div className={s.mainContainer}>
|
||||
<ul className={s.list}>
|
||||
<li className={s.item} onClick={toggleSidebar}>
|
||||
<Bag />
|
||||
{itemsCount > 0 && <span className={s.bagCount}>{itemsCount}</span>}
|
||||
<ul className={s.list}>
|
||||
<li className={s.item} onClick={toggleSidebar}>
|
||||
<Bag />
|
||||
{itemsCount > 0 && <span className={s.bagCount}>{itemsCount}</span>}
|
||||
</li>
|
||||
{process.env.COMMERCE_WISHLIST_ENABLED && (
|
||||
<li className={s.item}>
|
||||
<Link href="/wishlist">
|
||||
<a onClick={closeSidebarIfPresent} aria-label="Wishlist">
|
||||
<Heart />
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
{process.env.COMMERCE_WISHLIST_ENABLED && (
|
||||
<li className={s.item}>
|
||||
<Link href="/wishlist">
|
||||
<a onClick={closeSidebarIfPresent} aria-label="Wishlist">
|
||||
<Heart />
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
)}
|
||||
{process.env.COMMERCE_CUSTOMER_ENABLED && (
|
||||
<li className={s.item}>
|
||||
{customer ? (
|
||||
<DropdownMenu />
|
||||
@@ -52,8 +52,8 @@ const UserNav: FC<Props> = ({ className }) => {
|
||||
</button>
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user