4
0
forked from crowetic/commerce

Removing HeadlessUI and React-Aria

This commit is contained in:
Belen Curcio 2020-11-26 13:13:30 -03:00
parent 9dbd606eef
commit b5fd6bd38e
20 changed files with 417 additions and 2587 deletions

View File

@ -1,11 +1,9 @@
import { FC } from 'react'
import cn from 'classnames' import cn from 'classnames'
import { useRouter } from 'next/router'
import Link from 'next/link' import Link from 'next/link'
import { Menu } from '@headlessui/react' import { FC, useState } from 'react'
import { DoubleChevron } from '@components/icons' import { useRouter } from 'next/router'
import s from './I18nWidget.module.css' import s from './I18nWidget.module.css'
import { Cross } from '@components/icons'
interface LOCALE_DATA { interface LOCALE_DATA {
name: string name: string
img: { img: {
@ -32,6 +30,7 @@ const LOCALES_MAP: Record<string, LOCALE_DATA> = {
} }
const I18nWidget: FC = () => { const I18nWidget: FC = () => {
const [display, setDisplay] = useState(false)
const { const {
locale, locale,
locales, locales,
@ -39,42 +38,61 @@ const I18nWidget: FC = () => {
asPath: currentPath, asPath: currentPath,
} = useRouter() } = useRouter()
const options = locales?.filter((val) => val !== locale) const options = locales?.filter((val) => val !== locale)
const currentLocale = locale || defaultLocale const currentLocale = locale || defaultLocale
return ( return (
<nav className={s.root}> <nav className={s.root}>
<Menu> <div className="flex items-center relative">
<Menu.Button className={s.button} aria-label="Language selector"> <button className={s.button} aria-label="Language selector" />
<img <img
className="block mr-2 w-5" className="block mr-2 w-5"
src={`/${LOCALES_MAP[currentLocale].img.filename}`} src={`/${LOCALES_MAP[currentLocale].img.filename}`}
alt={LOCALES_MAP[currentLocale].img.alt} alt={LOCALES_MAP[currentLocale].img.alt}
/> />
<span className="mr-2">{LOCALES_MAP[currentLocale].name}</span> {options && (
{options && ( <span className="cursor-pointer" onClick={() => setDisplay(!display)}>
<span> <svg
<DoubleChevron /> viewBox="0 0 24 24"
</span> width="24"
)} height="24"
</Menu.Button> stroke="currentColor"
strokeWidth="1.5"
{options?.length ? ( strokeLinecap="round"
<Menu.Items className={s.dropdownMenu}> strokeLinejoin="round"
{options.map((locale) => ( fill="none"
<Menu.Item key={locale}> shapeRendering="geometricPrecision"
{({ active }) => ( >
<path d="M6 9l6 6 6-6" />
</svg>
</span>
)}
</div>
<div className="absolute top-0 right-0">
{options?.length && display ? (
<div className={s.dropdownMenu}>
<div className="flex flex-row justify-end px-6">
<button
onClick={() => setDisplay(false)}
aria-label="Close panel"
className={s.closeButton}
>
<Cross className="h-6 w-6" />
</button>
</div>
<ul>
{options.map((locale) => (
<li key={locale}>
<Link href={currentPath} locale={locale}> <Link href={currentPath} locale={locale}>
<a className={cn(s.item, { [s.active]: active })}> <a className={cn(s.item)} onClick={() => setDisplay(false)}>
{LOCALES_MAP[locale].name} {LOCALES_MAP[locale].name}
</a> </a>
</Link> </Link>
)} </li>
</Menu.Item> ))}
))} </ul>
</Menu.Items> </div>
) : null} ) : null}
</Menu> </div>
</nav> </nav>
) )
} }

View File

@ -5,7 +5,6 @@ import { useRouter } from 'next/router'
import React, { FC } from 'react' import React, { FC } from 'react'
import { useUI } from '@components/ui/context' import { useUI } from '@components/ui/context'
import { Navbar, Footer } from '@components/common' import { Navbar, Footer } from '@components/common'
import { usePreventScroll } from '@react-aria/overlays'
import { useAcceptCookies } from '@lib/hooks/useAcceptCookies' import { useAcceptCookies } from '@lib/hooks/useAcceptCookies'
import { CommerceProvider } from '@bigcommerce/storefront-data-hooks' import { CommerceProvider } from '@bigcommerce/storefront-data-hooks'
import { Sidebar, Button, Modal, LoadingDots } from '@components/ui' import { Sidebar, Button, Modal, LoadingDots } from '@components/ui'
@ -56,10 +55,6 @@ const Layout: FC<Props> = ({ children, pageProps }) => {
const { acceptedCookies, onAcceptCookies } = useAcceptCookies() const { acceptedCookies, onAcceptCookies } = useAcceptCookies()
const { locale = 'en-US' } = useRouter() const { locale = 'en-US' } = useRouter()
usePreventScroll({
isDisabled: !(displaySidebar || displayModal),
})
return ( return (
<CommerceProvider locale={locale}> <CommerceProvider locale={locale}>
<div className={cn(s.root)}> <div className={cn(s.root)}>

View File

@ -1,2 +0,0 @@
.root {
}

View File

@ -1,55 +0,0 @@
import React, { FC } from 'react'
import { Switch } from '@headlessui/react'
import { Moon, Sun } from '@components/icons'
interface Props {
className?: string
checked: boolean
onChange: any
}
const Toggle: FC<Props> = ({ className, checked, onChange }) => {
return (
<Switch
checked={checked}
onChange={onChange}
className="focus:outline-none"
>
<span
role="checkbox"
aria-checked="false"
tabIndex={0}
className={`${
checked ? 'bg-gray-800' : 'bg-gray-200'
} relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-150 focus:outline-none focus:shadow-outline`}
>
<span
aria-hidden="true"
className={`${
checked ? 'translate-x-5' : 'translate-x-0'
} translate-x-0 relative inline-block h-5 w-5 rounded-full bg-white shadow transform transition ease-in-out duration-150`}
>
<span
className={`${
checked
? 'opacity-0 ease-out duration-150'
: 'opacity-100 ease-in duration-150'
} absolute inset-0 h-full w-full flex items-center justify-center transition-opacity`}
>
<Sun className="h-3 w-3 text-accent-3" />
</span>
<span
className={`${
checked
? 'opacity-100 ease-in duration-150'
: 'opacity-0 ease-out duration-150'
} opacity-0 ease-out duration-150 absolute inset-0 h-full w-full flex items-center justify-center transition-opacity`}
>
<Moon className="h-3 w-3 text-yellow-400" />
</span>
</span>
</span>
</Switch>
)
}
export default Toggle

View File

@ -1 +0,0 @@
export { default } from './Toggle'

View File

@ -1,16 +1,16 @@
import { FC } from 'react'
import Link from 'next/link'
import { useTheme } from 'next-themes'
import cn from 'classnames' import cn from 'classnames'
import Link from 'next/link'
import { FC, useState } from 'react'
import { useTheme } from 'next-themes'
import { useRouter } from 'next/router'
import s from './DropdownMenu.module.css' import s from './DropdownMenu.module.css'
import { Avatar } from '@components/common'
import { Moon, Sun } from '@components/icons' import { Moon, Sun } from '@components/icons'
import { useUI } from '@components/ui/context' import { useUI } from '@components/ui/context'
import { Menu, Transition } from '@headlessui/react'
import useLogout from '@bigcommerce/storefront-data-hooks/use-logout'
import { useRouter } from 'next/router'
import useLogout from '@bigcommerce/storefront-data-hooks/use-logout'
interface DropdownMenuProps { interface DropdownMenuProps {
open: boolean open?: boolean
} }
const LINKS = [ const LINKS = [
@ -29,68 +29,70 @@ const LINKS = [
] ]
const DropdownMenu: FC<DropdownMenuProps> = ({ open = false }) => { const DropdownMenu: FC<DropdownMenuProps> = ({ open = false }) => {
const { theme, setTheme } = useTheme()
const logout = useLogout() const logout = useLogout()
const { pathname } = useRouter() const { pathname } = useRouter()
const { theme, setTheme } = useTheme()
const [display, setDisplay] = useState(false)
const { closeSidebarIfPresent } = useUI() const { closeSidebarIfPresent } = useUI()
return ( return (
<Transition <div>
show={open} <button
enter="transition ease-out duration-150 z-20" className={s.avatarButton}
enterFrom="transform opacity-0 scale-95" onClick={() => setDisplay(!display)}
enterTo="transform opacity-100 scale-100" aria-label="Menu"
leave="transition ease-in duration-75" >
leaveFrom="transform opacity-100 scale-100" <Avatar />
leaveTo="transform opacity-0 scale-95" </button>
>
<Menu.Items className={s.dropdownMenu}> {display && (
{LINKS.map(({ name, href }) => ( <ul className={s.dropdownMenu}>
<Menu.Item key={href}> {LINKS.map(({ name, href }) => (
<div> <li key={href}>
<Link href={href}> <div>
<a <Link href={href}>
className={cn(s.link, { <a
[s.active]: pathname === href, className={cn(s.link, {
})} [s.active]: pathname === href,
onClick={closeSidebarIfPresent} })}
> onClick={closeSidebarIfPresent}
{name} >
</a> {name}
</Link> </a>
</div> </Link>
</Menu.Item> </div>
))} </li>
<Menu.Item> ))}
<a <li>
className={cn(s.link, 'justify-between')} <a
onClick={() => className={cn(s.link, 'justify-between')}
theme === 'dark' ? setTheme('light') : setTheme('dark') onClick={() =>
} theme === 'dark' ? setTheme('light') : setTheme('dark')
> }
<div> >
Theme: <strong>{theme}</strong>{' '} <div>
</div> Theme: <strong>{theme}</strong>{' '}
<div className="ml-3"> </div>
{theme == 'dark' ? ( <div className="ml-3">
<Moon width={20} height={20} /> {theme == 'dark' ? (
) : ( <Moon width={20} height={20} />
<Sun width="20" height={20} /> ) : (
)} <Sun width="20" height={20} />
</div> )}
</a> </div>
</Menu.Item> </a>
<Menu.Item> </li>
<a <li>
className={cn(s.link, 'border-t border-accents-2 mt-4')} <a
onClick={() => logout()} className={cn(s.link, 'border-t border-accents-2 mt-4')}
> onClick={() => logout()}
Logout >
</a> Logout
</Menu.Item> </a>
</Menu.Items> </li>
</Transition> </ul>
)}
</div>
) )
} }

View File

@ -3,12 +3,11 @@ import Link from 'next/link'
import cn from 'classnames' import cn from 'classnames'
import useCart from '@bigcommerce/storefront-data-hooks/cart/use-cart' import useCart from '@bigcommerce/storefront-data-hooks/cart/use-cart'
import useCustomer from '@bigcommerce/storefront-data-hooks/use-customer' import useCustomer from '@bigcommerce/storefront-data-hooks/use-customer'
import { Menu } from '@headlessui/react'
import { Heart, Bag } from '@components/icons' import { Heart, Bag } from '@components/icons'
import { Avatar } from '@components/common'
import { useUI } from '@components/ui/context' import { useUI } from '@components/ui/context'
import DropdownMenu from './DropdownMenu' import DropdownMenu from './DropdownMenu'
import s from './UserNav.module.css' import s from './UserNav.module.css'
import { Avatar } from '@components/common'
interface Props { interface Props {
className?: string className?: string
@ -21,9 +20,9 @@ const countItems = (count: number, items: any[]) =>
const UserNav: FC<Props> = ({ className, children, ...props }) => { const UserNav: FC<Props> = ({ className, children, ...props }) => {
const { data } = useCart() const { data } = useCart()
const { data: customer } = useCustomer() const { data: customer } = useCustomer()
const { toggleSidebar, closeSidebarIfPresent, openModal } = useUI() const { toggleSidebar, closeSidebarIfPresent, openModal } = useUI()
const itemsCount = Object.values(data?.line_items ?? {}).reduce(countItems, 0) const itemsCount = Object.values(data?.line_items ?? {}).reduce(countItems, 0)
return ( return (
<nav className={cn(s.root, className)}> <nav className={cn(s.root, className)}>
<div className={s.mainContainer}> <div className={s.mainContainer}>
@ -41,16 +40,7 @@ const UserNav: FC<Props> = ({ className, children, ...props }) => {
</li> </li>
<li className={s.item}> <li className={s.item}>
{customer ? ( {customer ? (
<Menu> <DropdownMenu />
{({ open }) => (
<>
<Menu.Button className={s.avatarButton} aria-label="Menu">
<Avatar />
</Menu.Button>
<DropdownMenu open={open} />
</>
)}
</Menu>
) : ( ) : (
<button <button
className={s.avatarButton} className={s.avatarButton}

View File

@ -5,7 +5,6 @@ export { default as Layout } from './Layout'
export { default as Navbar } from './Navbar' export { default as Navbar } from './Navbar'
export { default as Searchbar } from './Searchbar' export { default as Searchbar } from './Searchbar'
export { default as UserNav } from './UserNav' export { default as UserNav } from './UserNav'
export { default as Toggle } from './Toggle'
export { default as Head } from './Head' export { default as Head } from './Head'
export { default as HTMLContent } from './HTMLContent' export { default as HTMLContent } from './HTMLContent'
export { default as I18nWidget } from './I18nWidget' export { default as I18nWidget } from './I18nWidget'

View File

@ -6,7 +6,6 @@ import React, {
useRef, useRef,
} from 'react' } from 'react'
import mergeRefs from 'react-merge-refs' import mergeRefs from 'react-merge-refs'
import { useButton } from 'react-aria'
import s from './Button.module.css' import s from './Button.module.css'
import { LoadingDots } from '@components/ui' import { LoadingDots } from '@components/ui'
@ -34,19 +33,8 @@ const Button: React.FC<ButtonProps> = forwardRef((props, buttonRef) => {
loading = false, loading = false,
disabled = false, disabled = false,
style = {}, style = {},
...rest
} = props } = props
const ref = useRef<typeof Component>(null) const ref = useRef<typeof Component>(null)
const { buttonProps, isPressed } = useButton(
{
...rest,
// @ts-ignore onClick === onPress for our purposes
onPress: onClick,
isDisabled: disabled,
elementType: Component,
},
ref
)
const rootClassName = cn( const rootClassName = cn(
s.root, s.root,
@ -63,8 +51,6 @@ const Button: React.FC<ButtonProps> = forwardRef((props, buttonRef) => {
aria-pressed={active} aria-pressed={active}
data-variant={variant} data-variant={variant}
ref={mergeRefs([ref, buttonRef])} ref={mergeRefs([ref, buttonRef])}
{...buttonProps}
data-active={isPressed ? '' : undefined}
className={rootClassName} className={rootClassName}
disabled={disabled} disabled={disabled}
style={{ style={{

View File

@ -1,10 +1,13 @@
import { FC, useRef } from 'react' import { FC, useRef, useEffect } from 'react'
import s from './Modal.module.css'
import { FocusScope } from '@react-aria/focus'
import { Transition } from '@headlessui/react'
import { Cross } from '@components/icons'
import { useOverlay, OverlayContainer } from '@react-aria/overlays'
import Portal from '@reach/portal' import Portal from '@reach/portal'
import s from './Modal.module.css'
import { Cross } from '@components/icons'
import {
disableBodyScroll,
enableBodyScroll,
clearAllBodyScrollLocks,
} from 'body-scroll-lock'
interface Props { interface Props {
className?: string className?: string
children?: any children?: any
@ -12,48 +15,41 @@ interface Props {
onClose: () => void onClose: () => void
} }
const Modal: FC<Props> = ({ children, open = false, onClose, ...props }) => { const Modal: FC<Props> = ({ children, open, onClose }) => {
let ref = useRef() as React.MutableRefObject<HTMLInputElement> const ref = useRef() as React.MutableRefObject<HTMLDivElement>
let { overlayProps } = useOverlay(
{ useEffect(() => {
isOpen: open, if (ref.current) {
isDismissable: false, if (open) {
onClose: onClose, disableBodyScroll(ref.current)
...props, } else {
}, enableBodyScroll(ref.current)
ref }
) }
return () => {
clearAllBodyScrollLocks()
}
}, [open])
return ( return (
<Transition show={open}> <Portal>
<OverlayContainer> {open ? (
<FocusScope contain restoreFocus autoFocus> <div className={s.root} ref={ref}>
<div className={s.root}> <div className={s.modal}>
<Transition.Child <div className="h-7 flex items-center justify-end w-full">
enter="transition-opacity ease-linear duration-300" <button
enterFrom="opacity-0" onClick={() => onClose()}
enterTo="opacity-100" aria-label="Close panel"
leave="transition-opacity ease-linear duration-300" className="hover:text-gray-500 transition ease-in-out duration-150 focus:outline-none"
leaveFrom="opacity-100" >
leaveTo="opacity-0" <Cross className="h-6 w-6" />
> </button>
<div className={s.modal} {...overlayProps} ref={ref}> </div>
<div className="h-7 flex items-center justify-end w-full"> {children}
<button
onClick={() => onClose()}
aria-label="Close panel"
className="hover:text-gray-500 transition ease-in-out duration-150 focus:outline-none"
>
<Cross className="h-6 w-6" />
</button>
</div>
{children}
</div>
</Transition.Child>
</div> </div>
</FocusScope> </div>
</OverlayContainer> ) : null}
</Transition> </Portal>
) )
} }

View File

@ -1,9 +1,11 @@
import { FC, useRef } from 'react'
import s from './Sidebar.module.css' import s from './Sidebar.module.css'
import { Transition } from '@headlessui/react'
import { useOverlay, OverlayContainer } from '@react-aria/overlays'
import { FocusScope } from '@react-aria/focus'
import Portal from '@reach/portal' import Portal from '@reach/portal'
import { FC, useEffect, useRef } from 'react'
import {
disableBodyScroll,
enableBodyScroll,
clearAllBodyScrollLocks,
} from 'body-scroll-lock'
interface Props { interface Props {
children: any children: any
@ -12,62 +14,40 @@ interface Props {
} }
const Sidebar: FC<Props> = ({ children, open = false, onClose }) => { const Sidebar: FC<Props> = ({ children, open = false, onClose }) => {
const ref = useRef<HTMLDivElement>(null) const ref = useRef() as React.MutableRefObject<HTMLDivElement>
const { overlayProps } = useOverlay(
{ useEffect(() => {
isOpen: open, if (ref.current) {
isDismissable: true, if (open) {
onClose: onClose, disableBodyScroll(ref.current)
}, } else {
ref enableBodyScroll(ref.current)
) }
}
return () => {
clearAllBodyScrollLocks()
}
}, [open])
return ( return (
<Portal> <Portal>
<Transition show={open}> {open ? (
<OverlayContainer> <div className={s.root} ref={ref}>
<FocusScope contain restoreFocus autoFocus> <div className="absolute inset-0 overflow-hidden">
<div className={s.root}> <div
<div className="absolute inset-0 overflow-hidden"> className="absolute inset-0 bg-black bg-opacity-50 transition-opacity"
<Transition.Child onClick={onClose}
enter="transition-opacity ease-linear duration-300" />
enterFrom="opacity-0" <section className="absolute inset-y-0 right-0 pl-10 max-w-full flex sm:pl-16 outline-none">
enterTo="opacity-100" <div className="h-full md:w-screen md:max-w-md">
leave="transition-opacity ease-linear duration-300" <div className="h-full flex flex-col text-base bg-accents-1 shadow-xl overflow-y-auto">
leaveFrom="opacity-100" {children}
leaveTo="opacity-0" </div>
>
<div
className="absolute inset-0 bg-black bg-opacity-50 transition-opacity"
// Close the sidebar when clicking on the backdrop
onClick={onClose}
/>
</Transition.Child>
<section
className="absolute inset-y-0 right-0 pl-10 max-w-full flex sm:pl-16 outline-none"
{...overlayProps}
ref={ref}
>
<Transition.Child
enter="transition ease-in-out duration-300 transform"
enterFrom="translate-x-full"
enterTo="translate-x-0"
leave="transition ease-in-out duration-300 transform"
leaveFrom="translate-x-0"
leaveTo="translate-x-full"
>
<div className="h-full md:w-screen md:max-w-md">
<div className="h-full flex flex-col text-base bg-accents-1 shadow-xl overflow-y-auto">
{children}
</div>
</div>
</Transition.Child>
</section>
</div> </div>
</div> </section>
</FocusScope> </div>
</OverlayContainer> </div>
</Transition> ) : null}
</Portal> </Portal>
) )
} }

View File

@ -1,9 +0,0 @@
.root {
}
.toast {
@apply absolute bg-primary text-primary flex items-center border border-accents-1
rounded-md z-50 shadow-2xl top-0 right-0 p-6 my-6 mx-3;
width: 420px;
z-index: 20000;
}

View File

@ -1,73 +0,0 @@
import cn from 'classnames'
import { FC, useRef, useEffect, useCallback } from 'react'
import s from './Toast.module.css'
import { useDialog } from '@react-aria/dialog'
import { FocusScope } from '@react-aria/focus'
import { Transition } from '@headlessui/react'
import { useOverlay, useModal, OverlayContainer } from '@react-aria/overlays'
interface Props {
className?: string
children?: any
open?: boolean
onClose: () => void
}
const Toast: FC<Props> = ({
className,
children,
open = false,
onClose,
...props
}) => {
const rootClassName = cn(s.root, className)
let ref = useRef() as React.MutableRefObject<HTMLInputElement>
let { modalProps } = useModal()
let { dialogProps } = useDialog({}, ref)
let { overlayProps } = useOverlay(
{
isOpen: open,
isDismissable: true,
onClose: onClose,
...props,
},
ref
)
// useEffect(() => {
// setTimeout(() => {
// useCallback(onClose, [])
// }, 400)
// })
return (
<Transition show={open}>
<OverlayContainer>
<FocusScope contain restoreFocus autoFocus>
<div className={rootClassName}>
<Transition.Child
enter="transition-opacity ease-linear duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="transition-opacity ease-linear duration-300"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div
className={s.toast}
{...overlayProps}
{...dialogProps}
{...modalProps}
ref={ref}
>
{children}
</div>
</Transition.Child>
</div>
</FocusScope>
</OverlayContainer>
</Transition>
)
}
export default Toast

View File

@ -1 +0,0 @@
export { default } from './Toast'

View File

@ -1,6 +1,5 @@
import React, { FC, useMemo } from 'react' import React, { FC, useMemo } from 'react'
import { ThemeProvider } from 'next-themes' import { ThemeProvider } from 'next-themes'
import { SSRProvider, OverlayProvider } from 'react-aria'
export interface State { export interface State {
displaySidebar: boolean displaySidebar: boolean
@ -181,10 +180,6 @@ export const useUI = () => {
export const ManagedUIContext: FC = ({ children }) => ( export const ManagedUIContext: FC = ({ children }) => (
<UIProvider> <UIProvider>
<ThemeProvider> <ThemeProvider>{children}</ThemeProvider>
<SSRProvider>
<OverlayProvider>{children}</OverlayProvider>
</SSRProvider>
</ThemeProvider>
</UIProvider> </UIProvider>
) )

View File

@ -10,4 +10,3 @@ export { default as Skeleton } from './Skeleton'
export { default as Modal } from './Modal' export { default as Modal } from './Modal'
export { default as Text } from './Text' export { default as Text } from './Text'
export { default as Input } from './Input' export { default as Input } from './Input'
export { default as Toast } from './Toast'

14
lib/defaults.ts Normal file
View File

@ -0,0 +1,14 @@
// Fallback to CMS Data
export const defatultPageProps = {
header: {
links: [
{
link: {
title: 'New Arrivals',
url: '/',
},
},
],
},
}

View File

@ -43,25 +43,25 @@
}, },
"dependencies": { "dependencies": {
"@bigcommerce/storefront-data-hooks": "^1.0.2", "@bigcommerce/storefront-data-hooks": "^1.0.2",
"@headlessui/react": "^0.2.0",
"@reach/portal": "^0.11.2", "@reach/portal": "^0.11.2",
"@react-aria/overlays": "^3.4.0",
"@tailwindcss/ui": "^0.6.2", "@tailwindcss/ui": "^0.6.2",
"@types/body-scroll-lock": "^2.6.1",
"@types/lodash.throttle": "^4.1.6", "@types/lodash.throttle": "^4.1.6",
"@vercel/fetch": "^6.1.0", "@vercel/fetch": "^6.1.0",
"body-scroll-lock": "^3.1.5",
"bowser": "^2.11.0", "bowser": "^2.11.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"contentstack": "^3.11.0",
"email-validator": "^2.0.4", "email-validator": "^2.0.4",
"js-cookie": "^2.2.1", "js-cookie": "^2.2.1",
"keen-slider": "^5.2.4", "keen-slider": "^5.2.4",
"lodash.random": "^3.2.0", "lodash.random": "^3.2.0",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"next": "^10.0.1-canary.7", "next": "^10.0.2-canary.18",
"next-seo": "^4.11.0", "next-seo": "^4.11.0",
"next-themes": "^0.0.4", "next-themes": "^0.0.4",
"postcss-nesting": "^7.0.1", "postcss-nesting": "^7.0.1",
"react": "^16.14.0", "react": "^16.14.0",
"react-aria": "^3.0.0",
"react-dom": "^16.14.0", "react-dom": "^16.14.0",
"react-intersection-observer": "^8.30.1", "react-intersection-observer": "^8.30.1",
"react-merge-refs": "^1.1.0", "react-merge-refs": "^1.1.0",

View File

@ -4,9 +4,9 @@ import getAllPages from '@bigcommerce/storefront-data-hooks/api/operations/get-a
import useWishlist from '@bigcommerce/storefront-data-hooks/wishlist/use-wishlist' import useWishlist from '@bigcommerce/storefront-data-hooks/wishlist/use-wishlist'
import { Layout } from '@components/common' import { Layout } from '@components/common'
import { Heart } from '@components/icons' import { Heart } from '@components/icons'
import { Container, Text } from '@components/ui' import { Text } from '@components/ui'
import { WishlistCard } from '@components/wishlist' import { WishlistCard } from '@components/wishlist'
import { Transition } from '@headlessui/react' import { defatultPageProps } from '@lib/defaults'
export async function getStaticProps({ export async function getStaticProps({
preview, preview,
@ -15,7 +15,7 @@ export async function getStaticProps({
const config = getConfig({ locale }) const config = getConfig({ locale })
const { pages } = await getAllPages({ config, preview }) const { pages } = await getAllPages({ config, preview })
return { return {
props: { pages }, props: { ...defatultPageProps, pages },
} }
} }
@ -23,54 +23,27 @@ export default function Wishlist() {
const { data, isEmpty } = useWishlist({ includeProducts: true }) const { data, isEmpty } = useWishlist({ includeProducts: true })
return ( return (
<Container> <div className="mt-3 mb-20 px-3">
<div className="mt-3 mb-20"> <Text variant="pageHeading">My Wishlist</Text>
<Text variant="pageHeading">My Wishlist</Text> <div className="group flex flex-col">
<div className="group flex flex-col"> {isEmpty ? (
{isEmpty ? ( <div className="flex-1 px-12 py-24 flex flex-col justify-center items-center ">
<Transition show> <span className="border border-dashed border-secondary rounded-full flex items-center justify-center w-16 h-16 bg-primary p-12 rounded-lg text-primary">
<Transition.Child <Heart className="absolute" />
enter="transition-opacity ease-linear duration-300" </span>
enterFrom="opacity-0" <h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
enterTo="opacity-100" Your wishlist is empty
leave="transition-opacity ease-linear duration-300" </h2>
leaveFrom="opacity-100" <p className="text-accents-6 px-10 text-center pt-2">
leaveTo="opacity-0" Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
> </p>
<div className="flex-1 px-12 py-24 flex flex-col justify-center items-center "> </div>
<span className="border border-dashed border-secondary rounded-full flex items-center justify-center w-16 h-16 bg-primary p-12 rounded-lg text-primary"> ) : (
<Heart className="absolute" /> data &&
</span> data.items?.map((item) => <WishlistCard key={item.id} item={item} />)
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center"> )}
Your wishlist is empty
</h2>
<p className="text-accents-6 px-10 text-center pt-2">
Biscuit oat cake wafer icing ice cream tiramisu pudding
cupcake.
</p>
</div>
</Transition.Child>
</Transition>
) : (
<Transition show>
{data &&
data.items?.map((item) => (
<Transition.Child
enter="transition-opacity ease-linear duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="transition-opacity ease-linear duration-300"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<WishlistCard key={item.id} item={item} />
</Transition.Child>
))}
</Transition>
)}
</div>
</div> </div>
</Container> </div>
) )
} }

2334
yarn.lock

File diff suppressed because it is too large Load Diff