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:
B
2021-06-15 20:23:17 -03:00
committed by GitHub
parent 3c9b90f453
commit 78cc378a72
202 changed files with 15406 additions and 2201 deletions

View File

@@ -1,9 +1,14 @@
.root {
@apply bg-secondary text-accents-1 cursor-pointer inline-flex px-10 rounded-sm leading-6 transition ease-in-out duration-150 shadow-sm font-semibold text-center justify-center uppercase py-4 border border-transparent items-center;
@apply bg-accent-9 text-accent-0 cursor-pointer inline-flex
px-10 py-5 leading-6 transition ease-in-out duration-150
shadow-sm text-center justify-center uppercase
border border-transparent items-center text-sm font-semibold
tracking-wide;
max-height: 64px;
}
.root:hover {
@apply bg-accents-0 text-primary border border-secondary;
@apply border-accent-9 bg-accent-6;
}
.root:focus {
@@ -11,22 +16,33 @@
}
.root[data-active] {
@apply bg-gray-600;
@apply bg-accent-6;
}
.loading {
@apply bg-accents-1 text-accents-3 border-accents-2 cursor-not-allowed;
@apply bg-accent-1 text-accent-3 border-accent-2 cursor-not-allowed;
}
.slim {
@apply py-2 transform-none normal-case;
}
.ghost {
@apply border border-accent-2 bg-accent-0 text-accent-9 text-sm;
}
.ghost:hover {
@apply border-accent-9 bg-accent-9 text-accent-0;
}
.disabled,
.disabled:hover {
@apply text-accents-4 border-accents-2 bg-accents-1 cursor-not-allowed;
@apply text-accent-4 border-accent-2 bg-accent-1 cursor-not-allowed;
filter: grayscale(1);
-webkit-transform: translateZ(0);
-webkit-perspective: 1000;
-webkit-backface-visibility: hidden;
}
.progress {
}

View File

@@ -12,7 +12,7 @@ import { LoadingDots } from '@components/ui'
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
href?: string
className?: string
variant?: 'flat' | 'slim'
variant?: 'flat' | 'slim' | 'ghost'
active?: boolean
type?: 'submit' | 'reset' | 'button'
Component?: string | JSXElementConstructor<any>
@@ -39,6 +39,7 @@ const Button: React.FC<ButtonProps> = forwardRef((props, buttonRef) => {
const rootClassName = cn(
s.root,
{
[s.ghost]: variant === 'ghost',
[s.slim]: variant === 'slim',
[s.loading]: loading,
[s.disabled]: disabled,

View File

@@ -0,0 +1,25 @@
.root {
@apply border-b border-accent-2 py-4 flex flex-col outline-none;
}
.header {
@apply flex flex-row items-center;
}
.header .label {
@apply text-base font-medium;
}
.content {
@apply pt-3 overflow-hidden pl-8;
}
.icon {
@apply mr-3 text-accent-6;
margin-left: -6px;
transition: transform 0.2s ease;
}
.icon.open {
transform: rotate(90deg);
}

View File

@@ -0,0 +1,46 @@
import cn from 'classnames'
import React, { FC, ReactNode, useState } from 'react'
import s from './Collapse.module.css'
import { ChevronRight } from '@components/icons'
import { useSpring, a } from '@react-spring/web'
import useMeasure from 'react-use-measure'
export interface CollapseProps {
title: string
children: ReactNode
}
const Collapse: FC<CollapseProps> = React.memo(({ title, children }) => {
const [isActive, setActive] = useState(false)
const [ref, { height: viewHeight }] = useMeasure()
const animProps = useSpring({
height: isActive ? viewHeight : 0,
config: { tension: 250, friction: 32, clamp: true, duration: 150 },
opacity: isActive ? 1 : 0,
})
const toggle = () => setActive((x) => !x)
return (
<div
className={s.root}
role="button"
tabIndex={0}
aria-expanded={isActive}
onClick={toggle}
>
<div className={s.header}>
<ChevronRight className={cn(s.icon, { [s.open]: isActive })} />
<span className={s.label}>{title}</span>
</div>
<a.div style={{ overflow: 'hidden', ...animProps }}>
<div ref={ref} className={s.content}>
{children}
</div>
</a.div>
</div>
)
})
export default Collapse

View File

@@ -0,0 +1,2 @@
export { default } from './Collapse'
export * from './Collapse'

View File

@@ -1,14 +1,19 @@
import cn from 'classnames'
import React, { FC } from 'react'
interface Props {
interface ContainerProps {
className?: string
children?: any
el?: HTMLElement
clean?: boolean
}
const Container: FC<Props> = ({ children, className, el = 'div', clean }) => {
const Container: FC<ContainerProps> = ({
children,
className,
el = 'div',
clean,
}) => {
const rootClassName = cn(className, {
'mx-auto max-w-8xl px-6': !clean,
})

View File

@@ -1,7 +1,9 @@
.root {
--row-height: calc(100vh - 88px);
@apply grid grid-cols-1 gap-0;
min-height: var(--row-height);
@screen lg {
@apply grid-cols-3 grid-rows-2;
}
& > * {
@apply row-span-1 bg-transparent box-border overflow-hidden;
@@ -15,17 +17,6 @@
}
}
@screen lg {
.root {
@apply grid-cols-3 grid-rows-2;
}
.root & > * {
@apply col-span-1;
height: inherit;
}
}
.default {
& > * {
@apply bg-transparent;
@@ -34,9 +25,17 @@
.layoutNormal {
@apply gap-3;
}
& > * {
min-height: 325px;
@screen md {
.layoutNormal > * {
max-height: min-content !important;
}
}
@screen lg {
.layoutNormal > * {
max-height: 400px;
}
}
@@ -52,13 +51,12 @@
}
&.filled {
& > *:nth-child(6n + 1),
& > *:nth-child(6n + 5) {
& > *:nth-child(6n + 1) {
@apply bg-violet;
}
& > *:nth-child(6n + 5) {
@apply bg-blue;
& > *:nth-child(6n + 2) {
@apply bg-accent-8;
}
& > *:nth-child(6n + 3) {
@@ -83,12 +81,12 @@
}
&.filled {
& > *:nth-child(6n + 2) {
@apply bg-blue;
& > *:nth-child(6n + 1) {
@apply bg-violet;
}
& > *:nth-child(6n + 4) {
@apply bg-violet;
& > *:nth-child(6n + 2) {
@apply bg-accent-8;
}
& > *:nth-child(6n + 3) {

View File

@@ -2,14 +2,14 @@ import cn from 'classnames'
import { FC, ReactNode, Component } from 'react'
import s from './Grid.module.css'
interface Props {
interface GridProps {
className?: string
children?: ReactNode[] | Component[] | any[]
layout?: 'A' | 'B' | 'C' | 'D' | 'normal'
variant?: 'default' | 'filled'
}
const Grid: FC<Props> = ({
const Grid: FC<GridProps> = ({
className,
layout = 'A',
children,

View File

@@ -1,9 +1,30 @@
.root {
@apply mx-auto grid grid-cols-1 py-32 gap-4;
@apply flex flex-col py-16 mx-auto;
}
@screen md {
.title {
@apply text-accent-0 font-extrabold text-4xl leading-none tracking-tight;
}
.description {
@apply mt-4 text-xl leading-8 text-accent-2 mb-1 lg:max-w-4xl;
}
@screen lg {
.root {
@apply grid-cols-2;
@apply flex-row items-start justify-center py-32;
}
.title {
@apply text-5xl max-w-xl text-right leading-10 -mt-3;
line-height: 3.5rem;
}
.description {
@apply mt-0 ml-6;
}
}
@screen xl {
.title {
@apply text-6xl;
}
}

View File

@@ -1,30 +1,26 @@
import React, { FC } from 'react'
import { Container } from '@components/ui'
import { RightArrow } from '@components/icons'
import { ArrowRight } from '@components/icons'
import s from './Hero.module.css'
import Link from 'next/link'
interface Props {
interface HeroProps {
className?: string
headline: string
description: string
}
const Hero: FC<Props> = ({ headline, description }) => {
const Hero: FC<HeroProps> = ({ headline, description }) => {
return (
<div className="bg-black">
<div className="bg-accent-9 border-b border-t border-accent-2">
<Container>
<div className={s.root}>
<h2 className="text-4xl leading-10 font-extrabold text-white sm:text-5xl sm:leading-none sm:tracking-tight lg:text-6xl">
{headline}
</h2>
<div className="flex flex-col justify-between">
<p className="mt-5 text-xl leading-7 text-accent-2 text-white">
{description}
</p>
<h2 className={s.title}>{headline}</h2>
<div className={s.description}>
<p>{description}</p>
<Link href="/">
<a className="text-white pt-3 font-bold hover:underline flex flex-row cursor-pointer w-max-content">
<a className="flex items-center text-accent-0 pt-3 font-bold hover:underline cursor-pointer w-max-content">
Read it here
<RightArrow width="20" heigh="20" className="ml-1" />
<ArrowRight width="20" heigh="20" className="ml-1" />
</a>
</Link>
</div>

View File

@@ -1,5 +1,5 @@
.root {
@apply bg-primary py-2 px-6 w-full appearance-none transition duration-150 ease-in-out pr-10 border border-accents-3 text-accents-6;
@apply bg-primary py-2 px-6 w-full appearance-none transition duration-150 ease-in-out pr-10 border border-accent-3 text-accent-6;
}
.root:focus {

View File

@@ -2,12 +2,12 @@ import cn from 'classnames'
import s from './Input.module.css'
import React, { InputHTMLAttributes } from 'react'
export interface Props extends InputHTMLAttributes<HTMLInputElement> {
export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
className?: string
onChange?: (...args: any[]) => any
}
const Input: React.FC<Props> = (props) => {
const Input: React.FC<InputProps> = (props) => {
const { className, children, onChange, ...rest } = props
const rootClassName = cn(s.root, {}, className)

View File

@@ -1,22 +1,23 @@
.root {
@apply inline-flex text-center items-center leading-7;
}
& span {
@apply bg-accents-6 rounded-full h-2 w-2;
animation-name: blink;
animation-duration: 1.4s;
animation-iteration-count: infinite;
animation-fill-mode: both;
margin: 0 2px;
.root .dot {
@apply rounded-full h-2 w-2;
background-color: currentColor;
animation-name: blink;
animation-duration: 1.4s;
animation-iteration-count: infinite;
animation-fill-mode: both;
margin: 0 2px;
}
&:nth-of-type(2) {
animation-delay: 0.2s;
}
.root .dot:nth-of-type(2) {
animation-delay: 0.2s;
}
&:nth-of-type(3) {
animation-delay: 0.4s;
}
}
.root .dot::nth-of-type(3) {
animation-delay: 0.4s;
}
@keyframes blink {

View File

@@ -3,9 +3,9 @@ import s from './LoadingDots.module.css'
const LoadingDots: React.FC = () => {
return (
<span className={s.root}>
<span />
<span />
<span />
<span className={s.dot} key={`dot_1`} />
<span className={s.dot} key={`dot_2`} />
<span className={s.dot} key={`dot_3`} />
</span>
)
}

View File

@@ -1,22 +1,22 @@
.root {
@apply w-full relative;
height: 320px;
min-width: 100%;
@apply w-full min-w-full relative flex flex-row items-center overflow-hidden py-0;
max-height: 320px;
}
.container {
@apply flex flex-row items-center;
.root > div {
max-height: 320px;
padding: 0;
margin: 0;
}
.container > * {
@apply relative flex-1 px-16 py-4 h-full;
min-height: 320px;
.root > div > * > *:nth-child(2) * {
max-height: 100%;
}
.primary {
@apply bg-white;
@apply bg-accent-0;
}
.secondary {
@apply bg-black;
@apply bg-accent-9;
}

View File

@@ -1,15 +1,15 @@
import cn from 'classnames'
import s from './Marquee.module.css'
import { FC, ReactNode, Component } from 'react'
import Ticker from 'react-ticker'
import { FC, ReactNode, Component, Children } from 'react'
import { default as FastMarquee } from 'react-fast-marquee'
interface Props {
interface MarqueeProps {
className?: string
children?: ReactNode[] | Component[] | any[]
variant?: 'primary' | 'secondary'
}
const Marquee: FC<Props> = ({
const Marquee: FC<MarqueeProps> = ({
className = '',
children,
variant = 'primary',
@@ -24,11 +24,15 @@ const Marquee: FC<Props> = ({
)
return (
<div className={rootClassName}>
<Ticker offset={80}>
{() => <div className={s.container}>{children}</div>}
</Ticker>
</div>
<FastMarquee gradient={false} className={rootClassName}>
{Children.map(children, (child) => ({
...child,
props: {
...child.props,
className: cn(child.props.className, `${variant}`),
},
}))}
</FastMarquee>
)
}

View File

@@ -1,12 +1,17 @@
.root {
@apply fixed bg-primary text-primary flex items-center inset-0 z-50 justify-center;
background-color: rgba(0, 0, 0, 0.35);
@apply fixed bg-black bg-opacity-40 flex items-center inset-0 z-50 justify-center;
backdrop-filter: blur(0.8px);
-webkit-backdrop-filter: blur(0.8px);
}
.modal {
@apply bg-primary p-12 border border-accents-2 relative;
@apply bg-primary p-12 border border-accent-2 relative;
}
.modal:focus {
@apply outline-none;
}
.close {
@apply hover:text-accent-5 transition ease-in-out duration-150 focus:outline-none absolute right-0 top-0 m-6;
}

View File

@@ -1,22 +1,20 @@
import { FC, useRef, useEffect, useCallback } from 'react'
import Portal from '@reach/portal'
import s from './Modal.module.css'
import FocusTrap from '@lib/focus-trap'
import { Cross } from '@components/icons'
import {
disableBodyScroll,
enableBodyScroll,
clearAllBodyScrollLocks,
enableBodyScroll,
} from 'body-scroll-lock'
import FocusTrap from '@lib/focus-trap'
interface Props {
interface ModalProps {
className?: string
children?: any
open?: boolean
onClose: () => void
onEnter?: () => void | null
}
const Modal: FC<Props> = ({ children, open, onClose, onEnter = null }) => {
const Modal: FC<ModalProps> = ({ children, onClose }) => {
const ref = useRef() as React.MutableRefObject<HTMLDivElement>
const handleKey = useCallback(
@@ -30,36 +28,31 @@ const Modal: FC<Props> = ({ children, open, onClose, onEnter = null }) => {
useEffect(() => {
if (ref.current) {
if (open) {
disableBodyScroll(ref.current)
window.addEventListener('keydown', handleKey)
} else {
enableBodyScroll(ref.current)
}
disableBodyScroll(ref.current, { reserveScrollBarGap: true })
window.addEventListener('keydown', handleKey)
}
return () => {
window.removeEventListener('keydown', handleKey)
if (ref && ref.current) {
enableBodyScroll(ref.current)
}
clearAllBodyScrollLocks()
window.removeEventListener('keydown', handleKey)
}
}, [open, handleKey])
}, [handleKey])
return (
<Portal>
{open ? (
<div className={s.root}>
<div className={s.modal} role="dialog" ref={ref}>
<button
onClick={() => onClose()}
aria-label="Close panel"
className="hover:text-gray-500 transition ease-in-out duration-150 focus:outline-none absolute right-0 top-0 m-6"
>
<Cross className="h-6 w-6" />
</button>
<FocusTrap focusFirst>{children}</FocusTrap>
</div>
</div>
) : null}
</Portal>
<div className={s.root}>
<div className={s.modal} role="dialog" ref={ref}>
<button
onClick={() => onClose()}
aria-label="Close panel"
className={s.close}
>
<Cross className="h-6 w-6" />
</button>
<FocusTrap focusFirst>{children}</FocusTrap>
</div>
</div>
)
}

View File

@@ -0,0 +1,27 @@
.actions {
@apply flex p-1 border-accent-2 border items-center justify-center
w-12 text-accent-7;
transition-property: border-color, background, color, transform, box-shadow;
transition-duration: 0.15s;
transition-timing-function: ease;
user-select: none;
}
.actions:hover {
@apply border bg-accent-1 border-accent-3 text-accent-9;
transition: border-color;
z-index: 10;
}
.actions:focus {
@apply outline-none;
}
.actions:disabled {
@apply cursor-not-allowed;
}
.input {
@apply bg-transparent px-4 w-full h-full focus:outline-none select-none pointer-events-auto;
}

View File

@@ -0,0 +1,62 @@
import React, { FC } from 'react'
import s from './Quantity.module.css'
import { Cross, Plus, Minus } from '@components/icons'
import cn from 'classnames'
export interface QuantityProps {
value: number
increase: () => any
decrease: () => any
handleRemove: React.MouseEventHandler<HTMLButtonElement>
handleChange: React.ChangeEventHandler<HTMLInputElement>
max?: number
}
const Quantity: FC<QuantityProps> = ({
value,
increase,
decrease,
handleChange,
handleRemove,
max = 6,
}) => {
return (
<div className="flex flex-row h-9">
<button className={s.actions} onClick={handleRemove}>
<Cross width={20} height={20} />
</button>
<label className="w-full border-accent-2 border ml-2">
<input
className={s.input}
onChange={(e) =>
Number(e.target.value) < max + 1 ? handleChange(e) : () => {}
}
value={value}
type="number"
max={max}
min="0"
readOnly
/>
</label>
<button
type="button"
onClick={decrease}
className={s.actions}
style={{ marginLeft: '-1px' }}
disabled={value <= 1}
>
<Minus width={18} height={18} />
</button>
<button
type="button"
onClick={increase}
className={cn(s.actions)}
style={{ marginLeft: '-1px' }}
disabled={value < 1 || value >= max}
>
<Plus width={18} height={18} />
</button>
</div>
)
}
export default Quantity

View File

@@ -0,0 +1,2 @@
export { default } from './Quantity'
export * from './Quantity'

View File

View File

@@ -0,0 +1,27 @@
import React, { FC } from 'react'
import rangeMap from '@lib/range-map'
import { Star } from '@components/icons'
import cn from 'classnames'
export interface RatingProps {
value: number
}
const Quantity: React.FC<RatingProps> = React.memo(({ value = 5 }) => {
return (
<div className="flex flex-row py-6 text-accent-9">
{rangeMap(5, (i) => (
<span
key={`star_${i}`}
className={cn('inline-block ml-1 ', {
'text-accent-5': i >= Math.floor(value),
})}
>
<Star />
</span>
))}
</div>
)
})
export default Quantity

View File

@@ -0,0 +1,2 @@
export { default } from './Rating'
export * from './Rating'

View File

@@ -1,3 +1,14 @@
.root {
@apply fixed inset-0 overflow-hidden h-full z-50;
@apply fixed inset-0 h-full z-50 box-border;
}
.sidebar {
@apply h-full flex flex-col text-base bg-accent-0 shadow-xl overflow-y-auto overflow-x-hidden;
-webkit-overflow-scrolling: touch !important;
}
.backdrop {
@apply absolute inset-0 bg-black bg-opacity-40 duration-100 ease-linear;
backdrop-filter: blur(0.8px);
-webkit-backdrop-filter: blur(0.8px);
}

View File

@@ -1,54 +1,45 @@
import s from './Sidebar.module.css'
import Portal from '@reach/portal'
import { FC, useEffect, useRef } from 'react'
import s from './Sidebar.module.css'
import cn from 'classnames'
import {
disableBodyScroll,
enableBodyScroll,
clearAllBodyScrollLocks,
} from 'body-scroll-lock'
interface Props {
interface SidebarProps {
children: any
open: boolean
onClose: () => void
}
const Sidebar: FC<Props> = ({ children, open = false, onClose }) => {
const Sidebar: FC<SidebarProps> = ({ children, onClose }) => {
const ref = useRef() as React.MutableRefObject<HTMLDivElement>
useEffect(() => {
if (ref.current) {
if (open) {
disableBodyScroll(ref.current)
} else {
enableBodyScroll(ref.current)
}
disableBodyScroll(ref.current, { reserveScrollBarGap: true })
}
return () => {
if (ref && ref.current) {
enableBodyScroll(ref.current)
}
clearAllBodyScrollLocks()
}
}, [open])
}, [])
return (
<Portal>
{open ? (
<div className={s.root} ref={ref}>
<div className="absolute inset-0 overflow-hidden">
<div
className="absolute inset-0 bg-black bg-opacity-50 transition-opacity"
onClick={onClose}
/>
<section className="absolute inset-y-0 right-0 pl-10 max-w-full flex sm:pl-16 outline-none">
<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>
</section>
<div className={cn(s.root)}>
<div className="absolute inset-0 overflow-hidden">
<div className={s.backdrop} onClick={onClose} />
<section className="absolute inset-y-0 right-0 max-w-full flex outline-none pl-10">
<div className="h-full w-full md:w-screen md:max-w-md">
<div className={s.sidebar} ref={ref}>
{children}
</div>
</div>
</div>
) : null}
</Portal>
</section>
</div>
</div>
)
}

View File

@@ -2,10 +2,10 @@
@apply block;
background-image: linear-gradient(
270deg,
var(--accents-1),
var(--accents-2),
var(--accents-2),
var(--accents-1)
var(--accent-0),
var(--accent-2),
var(--accent-0),
var(--accent-1)
);
background-size: 400% 100%;
animation: loading 8s ease-in-out infinite;
@@ -28,10 +28,10 @@
z-index: 100;
background-image: linear-gradient(
270deg,
var(--accents-1),
var(--accents-2),
var(--accents-2),
var(--accents-1)
var(--accent-0),
var(--accent-2),
var(--accent-0),
var(--accent-1)
);
background-size: 400% 100%;
animation: loading 8s ease-in-out infinite;

View File

@@ -3,17 +3,17 @@ import cn from 'classnames'
import px from '@lib/to-pixels'
import s from './Skeleton.module.css'
interface Props {
width?: string | number
height?: string | number
boxHeight?: string | number
style?: CSSProperties
interface SkeletonProps {
show?: boolean
block?: boolean
className?: string
style?: CSSProperties
width?: string | number
height?: string | number
boxHeight?: string | number
}
const Skeleton: React.FC<Props> = ({
const Skeleton: React.FC<SkeletonProps> = ({
style,
width,
height,

View File

@@ -1,9 +1,9 @@
.body {
@apply text-lg leading-7 font-medium max-w-6xl mx-auto;
@apply text-base leading-7 max-w-6xl mx-auto;
}
.heading {
@apply text-5xl mb-12;
@apply text-5xl pt-1 pb-2 font-semibold tracking-wide cursor-pointer mb-2;
}
.pageHeading {
@@ -11,5 +11,5 @@
}
.sectionHeading {
@apply pt-1 pb-2 font-semibold leading-7 tracking-wider uppercase border-b border-accents-2 mb-3;
@apply pt-1 pb-2 text-2xl font-bold tracking-wide cursor-pointer mb-2;
}

View File

@@ -6,22 +6,24 @@ import React, {
import cn from 'classnames'
import s from './Text.module.css'
interface Props {
interface TextProps {
variant?: Variant
className?: string
style?: CSSProperties
children?: React.ReactNode | any
html?: string
onClick?: () => any
}
type Variant = 'heading' | 'body' | 'pageHeading' | 'sectionHeading'
const Text: FunctionComponent<Props> = ({
const Text: FunctionComponent<TextProps> = ({
style,
className = '',
variant = 'body',
children,
html,
onClick,
}) => {
const componentsMap: {
[P in Variant]: React.ComponentType<any> | string
@@ -56,6 +58,7 @@ const Text: FunctionComponent<Props> = ({
},
className
)}
onClick={onClick}
style={style}
{...htmlContentProps}
>

View File

@@ -1,13 +1,12 @@
import React, { FC, useMemo } from 'react'
import React, { FC, useCallback, useMemo } from 'react'
import { ThemeProvider } from 'next-themes'
export interface State {
displaySidebar: boolean
displayDropdown: boolean
displayModal: boolean
displayToast: boolean
sidebarView: string
modalView: string
toastText: string
userAvatar: string
}
@@ -16,8 +15,7 @@ const initialState = {
displayDropdown: false,
displayModal: false,
modalView: 'LOGIN_VIEW',
displayToast: false,
toastText: '',
sidebarView: 'CART_VIEW',
userAvatar: '',
}
@@ -28,16 +26,6 @@ type Action =
| {
type: 'CLOSE_SIDEBAR'
}
| {
type: 'OPEN_TOAST'
}
| {
type: 'CLOSE_TOAST'
}
| {
type: 'SET_TOAST_TEXT'
text: ToastText
}
| {
type: 'OPEN_DROPDOWN'
}
@@ -54,6 +42,10 @@ type Action =
type: 'SET_MODAL_VIEW'
view: MODAL_VIEWS
}
| {
type: 'SET_SIDEBAR_VIEW'
view: SIDEBAR_VIEWS
}
| {
type: 'SET_USER_AVATAR'
value: string
@@ -65,7 +57,8 @@ type MODAL_VIEWS =
| 'FORGOT_VIEW'
| 'NEW_SHIPPING_ADDRESS'
| 'NEW_PAYMENT_METHOD'
type ToastText = string
type SIDEBAR_VIEWS = 'CART_VIEW' | 'CHECKOUT_VIEW' | 'PAYMENT_METHOD_VIEW'
export const UIContext = React.createContext<State | any>(initialState)
@@ -110,28 +103,16 @@ function uiReducer(state: State, action: Action) {
displayModal: false,
}
}
case 'OPEN_TOAST': {
return {
...state,
displayToast: true,
}
}
case 'CLOSE_TOAST': {
return {
...state,
displayToast: false,
}
}
case 'SET_MODAL_VIEW': {
return {
...state,
modalView: action.view,
}
}
case 'SET_TOAST_TEXT': {
case 'SET_SIDEBAR_VIEW': {
return {
...state,
toastText: action.text,
sidebarView: action.view,
}
}
case 'SET_USER_AVATAR': {
@@ -146,29 +127,58 @@ function uiReducer(state: State, action: Action) {
export const UIProvider: FC = (props) => {
const [state, dispatch] = React.useReducer(uiReducer, initialState)
const openSidebar = () => dispatch({ type: 'OPEN_SIDEBAR' })
const closeSidebar = () => dispatch({ type: 'CLOSE_SIDEBAR' })
const toggleSidebar = () =>
state.displaySidebar
? dispatch({ type: 'CLOSE_SIDEBAR' })
: dispatch({ type: 'OPEN_SIDEBAR' })
const closeSidebarIfPresent = () =>
state.displaySidebar && dispatch({ type: 'CLOSE_SIDEBAR' })
const openSidebar = useCallback(
() => dispatch({ type: 'OPEN_SIDEBAR' }),
[dispatch]
)
const closeSidebar = useCallback(
() => dispatch({ type: 'CLOSE_SIDEBAR' }),
[dispatch]
)
const toggleSidebar = useCallback(
() =>
state.displaySidebar
? dispatch({ type: 'CLOSE_SIDEBAR' })
: dispatch({ type: 'OPEN_SIDEBAR' }),
[dispatch, state.displaySidebar]
)
const closeSidebarIfPresent = useCallback(
() => state.displaySidebar && dispatch({ type: 'CLOSE_SIDEBAR' }),
[dispatch, state.displaySidebar]
)
const openDropdown = () => dispatch({ type: 'OPEN_DROPDOWN' })
const closeDropdown = () => dispatch({ type: 'CLOSE_DROPDOWN' })
const openDropdown = useCallback(
() => dispatch({ type: 'OPEN_DROPDOWN' }),
[dispatch]
)
const closeDropdown = useCallback(
() => dispatch({ type: 'CLOSE_DROPDOWN' }),
[dispatch]
)
const openModal = () => dispatch({ type: 'OPEN_MODAL' })
const closeModal = () => dispatch({ type: 'CLOSE_MODAL' })
const openModal = useCallback(
() => dispatch({ type: 'OPEN_MODAL' }),
[dispatch]
)
const closeModal = useCallback(
() => dispatch({ type: 'CLOSE_MODAL' }),
[dispatch]
)
const openToast = () => dispatch({ type: 'OPEN_TOAST' })
const closeToast = () => dispatch({ type: 'CLOSE_TOAST' })
const setUserAvatar = useCallback(
(value: string) => dispatch({ type: 'SET_USER_AVATAR', value }),
[dispatch]
)
const setUserAvatar = (value: string) =>
dispatch({ type: 'SET_USER_AVATAR', value })
const setModalView = useCallback(
(view: MODAL_VIEWS) => dispatch({ type: 'SET_MODAL_VIEW', view }),
[dispatch]
)
const setModalView = (view: MODAL_VIEWS) =>
dispatch({ type: 'SET_MODAL_VIEW', view })
const setSidebarView = useCallback(
(view: SIDEBAR_VIEWS) => dispatch({ type: 'SET_SIDEBAR_VIEW', view }),
[dispatch]
)
const value = useMemo(
() => ({
@@ -182,8 +192,7 @@ export const UIProvider: FC = (props) => {
openModal,
closeModal,
setModalView,
openToast,
closeToast,
setSidebarView,
setUserAvatar,
}),
[state]

View File

@@ -10,4 +10,7 @@ export { default as Skeleton } from './Skeleton'
export { default as Modal } from './Modal'
export { default as Text } from './Text'
export { default as Input } from './Input'
export { default as Collapse } from './Collapse'
export { default as Quantity } from './Quantity'
export { default as Rating } from './Rating'
export { useUI } from './context'