mirror of
https://github.com/vercel/commerce.git
synced 2025-05-18 07:26:59 +00:00
Custom Checkout Progress
This commit is contained in:
parent
8fb6c7b206
commit
7c1344a19e
@ -20,16 +20,20 @@
|
|||||||
--blue: #0070f3;
|
--blue: #0070f3;
|
||||||
--violet: #5f3dc4;
|
--violet: #5f3dc4;
|
||||||
--violet-light: #7048e8;
|
--violet-light: #7048e8;
|
||||||
--accents-0: #f8f9fa;
|
|
||||||
--accents-1: #f1f3f5;
|
--accent-0: #fff;
|
||||||
--accents-2: #e9ecef;
|
--accent-05: #f8f9fa;
|
||||||
--accents-3: #dee2e6;
|
--accent-1: #f1f3f5;
|
||||||
--accents-4: #ced4da;
|
--accent-2: #e9ecef;
|
||||||
--accents-5: #adb5bd;
|
--accent-3: #dee2e6;
|
||||||
--accents-6: #868e96;
|
--accent-4: #ced4da;
|
||||||
--accents-7: #495057;
|
--accent-5: #adb5bd;
|
||||||
--accents-8: #343a40;
|
--accent-6: #868e96;
|
||||||
--accents-9: #212529;
|
--accent-7: #495057;
|
||||||
|
--accent-8: #343a40;
|
||||||
|
--accent-9: #212529;
|
||||||
|
--accent-10: #000;
|
||||||
|
|
||||||
--font-sans: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue',
|
--font-sans: -apple-system, system-ui, BlinkMacSystemFont, 'Helvetica Neue',
|
||||||
'Helvetica', sans-serif;
|
'Helvetica', sans-serif;
|
||||||
}
|
}
|
||||||
@ -48,16 +52,18 @@
|
|||||||
--text-primary: white;
|
--text-primary: white;
|
||||||
--text-secondary: black;
|
--text-secondary: black;
|
||||||
|
|
||||||
--accents-0: #212529;
|
--accent-0: #000;
|
||||||
--accents-1: #343a40;
|
--accent-05: #212529;
|
||||||
--accents-2: #495057;
|
--accent-1: #343a40;
|
||||||
--accents-3: #868e96;
|
--accent-2: #495057;
|
||||||
--accents-4: #adb5bd;
|
--accent-3: #868e96;
|
||||||
--accents-5: #ced4da;
|
--accent-4: #adb5bd;
|
||||||
--accents-6: #dee2e6;
|
--accent-5: #ced4da;
|
||||||
--accents-7: #e9ecef;
|
--accent-6: #dee2e6;
|
||||||
--accents-8: #f1f3f5;
|
--accent-7: #e9ecef;
|
||||||
--accents-9: #f8f9fa;
|
--accent-8: #f1f3f5;
|
||||||
|
--accent-9: #f8f9fa;
|
||||||
|
--accent-10: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
*,
|
*,
|
||||||
@ -127,4 +133,3 @@ a {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ const ForgotPassword: FC<Props> = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span className="pt-3 text-center text-sm">
|
<span className="pt-3 text-center text-sm">
|
||||||
<span className="text-accents-7">Do you have an account?</span>
|
<span className="text-accent-7">Do you have an account?</span>
|
||||||
{` `}
|
{` `}
|
||||||
<a
|
<a
|
||||||
className="text-accent-9 font-bold hover:underline cursor-pointer"
|
className="text-accent-9 font-bold hover:underline cursor-pointer"
|
||||||
|
@ -87,7 +87,7 @@ const LoginView: FC<Props> = () => {
|
|||||||
Log In
|
Log In
|
||||||
</Button>
|
</Button>
|
||||||
<div className="pt-1 text-center text-sm">
|
<div className="pt-1 text-center text-sm">
|
||||||
<span className="text-accents-7">Don't have an account?</span>
|
<span className="text-accent-7">Don't have an account?</span>
|
||||||
{` `}
|
{` `}
|
||||||
<a
|
<a
|
||||||
className="text-accent-9 font-bold hover:underline cursor-pointer"
|
className="text-accent-9 font-bold hover:underline cursor-pointer"
|
||||||
|
@ -76,7 +76,7 @@ const SignUpView: FC<Props> = () => {
|
|||||||
<Input placeholder="Last Name" onChange={setLastName} />
|
<Input placeholder="Last Name" onChange={setLastName} />
|
||||||
<Input type="email" placeholder="Email" onChange={setEmail} />
|
<Input type="email" placeholder="Email" onChange={setEmail} />
|
||||||
<Input type="password" placeholder="Password" onChange={setPassword} />
|
<Input type="password" placeholder="Password" onChange={setPassword} />
|
||||||
<span className="text-accents-8">
|
<span className="text-accent-8">
|
||||||
<span className="inline-block align-middle ">
|
<span className="inline-block align-middle ">
|
||||||
<Info width="15" height="15" />
|
<Info width="15" height="15" />
|
||||||
</span>{' '}
|
</span>{' '}
|
||||||
@ -97,7 +97,7 @@ const SignUpView: FC<Props> = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span className="pt-1 text-center text-sm">
|
<span className="pt-1 text-center text-sm">
|
||||||
<span className="text-accents-7">Do you have an account?</span>
|
<span className="text-accent-7">Do you have an account?</span>
|
||||||
{` `}
|
{` `}
|
||||||
<a
|
<a
|
||||||
className="text-accent-9 font-bold hover:underline cursor-pointer"
|
className="text-accent-9 font-bold hover:underline cursor-pointer"
|
||||||
|
@ -1,6 +1,31 @@
|
|||||||
|
.root {
|
||||||
|
@apply flex flex-col py-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root:first-child {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
@apply flex p-1 border-accent-3 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions:hover {
|
||||||
|
@apply bg-accent-1 border-accent-4 text-accent-9;
|
||||||
|
transition: border-color;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions:focus {
|
||||||
|
@apply bg-accent-2 outline-none;
|
||||||
|
}
|
||||||
|
|
||||||
.quantity {
|
.quantity {
|
||||||
appearance: textfield;
|
appearance: textfield;
|
||||||
@apply w-8 border-accents-2 border mx-3 rounded text-center text-sm text-black;
|
@apply w-8 border-accent-2 border mx-3 rounded text-center text-sm text-black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.quantity::-webkit-outer-spin-button,
|
.quantity::-webkit-outer-spin-button,
|
||||||
|
@ -3,7 +3,7 @@ import cn from 'classnames'
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import s from './CartItem.module.css'
|
import s from './CartItem.module.css'
|
||||||
import { Trash, Plus, Minus } from '@components/icons'
|
import { Trash, Plus, Minus, Cross } from '@components/icons'
|
||||||
import { useUI } from '@components/ui/context'
|
import { useUI } from '@components/ui/context'
|
||||||
import type { LineItem } from '@framework/types'
|
import type { LineItem } from '@framework/types'
|
||||||
import usePrice from '@framework/product/use-price'
|
import usePrice from '@framework/product/use-price'
|
||||||
@ -20,8 +20,10 @@ type ItemOption = {
|
|||||||
const CartItem = ({
|
const CartItem = ({
|
||||||
item,
|
item,
|
||||||
currencyCode,
|
currencyCode,
|
||||||
|
noEdit = false,
|
||||||
...rest
|
...rest
|
||||||
}: {
|
}: {
|
||||||
|
noEdit?: boolean
|
||||||
item: LineItem
|
item: LineItem
|
||||||
currencyCode: string
|
currencyCode: string
|
||||||
}) => {
|
}) => {
|
||||||
@ -49,6 +51,7 @@ const CartItem = ({
|
|||||||
setQuantity(Number(e.target.value))
|
setQuantity(Number(e.target.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleBlur = () => {
|
const handleBlur = () => {
|
||||||
const val = Number(quantity)
|
const val = Number(quantity)
|
||||||
|
|
||||||
@ -56,6 +59,7 @@ const CartItem = ({
|
|||||||
updateQuantity(val)
|
updateQuantity(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const increaseQuantity = (n = 1) => {
|
const increaseQuantity = (n = 1) => {
|
||||||
const val = Number(quantity) + n
|
const val = Number(quantity) + n
|
||||||
|
|
||||||
@ -64,6 +68,7 @@ const CartItem = ({
|
|||||||
updateQuantity(val)
|
updateQuantity(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRemove = async () => {
|
const handleRemove = async () => {
|
||||||
setRemoving(true)
|
setRemoving(true)
|
||||||
|
|
||||||
@ -87,11 +92,12 @@ const CartItem = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
className={cn('flex flex-row space-x-8 py-8', {
|
className={cn(s.root, {
|
||||||
'opacity-75 pointer-events-none': removing,
|
'opacity-50 pointer-events-none': removing,
|
||||||
})}
|
})}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
|
<div className="flex flex-row space-x-4 py-4">
|
||||||
<div className="w-16 h-16 bg-violet relative overflow-hidden cursor-pointer">
|
<div className="w-16 h-16 bg-violet relative overflow-hidden cursor-pointer">
|
||||||
<Link href={`/product/${item.path}`}>
|
<Link href={`/product/${item.path}`}>
|
||||||
<Image
|
<Image
|
||||||
@ -108,7 +114,7 @@ const CartItem = ({
|
|||||||
<div className="flex-1 flex flex-col text-base">
|
<div className="flex-1 flex flex-col text-base">
|
||||||
<Link href={`/product/${item.path}`}>
|
<Link href={`/product/${item.path}`}>
|
||||||
<span
|
<span
|
||||||
className="font-bold text-lg cursor-pointer leading-6"
|
className="font-medium cursor-pointer leading-6"
|
||||||
onClick={() => closeSidebarIfPresent()}
|
onClick={() => closeSidebarIfPresent()}
|
||||||
>
|
>
|
||||||
{item.name}
|
{item.name}
|
||||||
@ -117,45 +123,69 @@ const CartItem = ({
|
|||||||
{options && options.length > 0 ? (
|
{options && options.length > 0 ? (
|
||||||
<div className="">
|
<div className="">
|
||||||
{options.map((option: ItemOption, i: number) => (
|
{options.map((option: ItemOption, i: number) => (
|
||||||
<span
|
<div
|
||||||
key={`${item.id}-${option.name}`}
|
key={`${item.id}-${option.name}`}
|
||||||
className="text-sm font-semibold text-accents-7"
|
className="text-sm font-semibold text-accent-7 inline-flex items-center justify-center"
|
||||||
>
|
>
|
||||||
|
{option.name}
|
||||||
|
{option.name === 'Color' ? (
|
||||||
|
<span
|
||||||
|
className="mx-2 rounded-full bg-transparent border w-5 h-5 p-1 text-accent-9 inline-flex items-center justify-center overflow-hidden"
|
||||||
|
style={{
|
||||||
|
backgroundColor: `${option.value}`,
|
||||||
|
}}
|
||||||
|
></span>
|
||||||
|
) : (
|
||||||
|
<span className="mx-2 rounded-full bg-transparent border h-5 p-1 text-accent-9 inline-flex items-center justify-center overflow-hidden">
|
||||||
{option.value}
|
{option.value}
|
||||||
{i === options.length - 1 ? '' : ', '}
|
|
||||||
</span>
|
</span>
|
||||||
|
)}
|
||||||
|
{i === options.length - 1 ? '' : <span className="mr-3" />}
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="flex items-center mt-3">
|
</div>
|
||||||
<button type="button" onClick={() => increaseQuantity(-1)}>
|
<div className="flex flex-col justify-between space-y-2 text-sm">
|
||||||
<Minus width={18} height={18} />
|
<span>{price}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{!noEdit ? (
|
||||||
|
<div className="flex flex-row h-9">
|
||||||
|
<button className={s.actions} onClick={handleRemove}>
|
||||||
|
<Cross width={20} height={20} />
|
||||||
</button>
|
</button>
|
||||||
<label>
|
<label className="w-full border-accent-3 border ml-2">
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
max={99}
|
max={99}
|
||||||
min={0}
|
min={0}
|
||||||
className={s.quantity}
|
className="bg-transparent px-4 w-full h-full focus:outline-none"
|
||||||
value={quantity}
|
value={quantity}
|
||||||
onChange={handleQuantity}
|
onChange={handleQuantity}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<button type="button" onClick={() => increaseQuantity(1)}>
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => increaseQuantity(-1)}
|
||||||
|
className={s.actions}
|
||||||
|
style={{ marginLeft: '-1px' }}
|
||||||
|
>
|
||||||
|
<Minus width={18} height={18} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => increaseQuantity(1)}
|
||||||
|
className={cn(s.actions)}
|
||||||
|
style={{ marginLeft: '-1px' }}
|
||||||
|
>
|
||||||
<Plus width={18} height={18} />
|
<Plus width={18} height={18} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : (
|
||||||
<div className="flex flex-col justify-between space-y-2 text-base">
|
<div>x{quantity}</div>
|
||||||
<span>{price}</span>
|
)}
|
||||||
<button
|
|
||||||
className="flex justify-end outline-none"
|
|
||||||
onClick={handleRemove}
|
|
||||||
>
|
|
||||||
<Trash />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.root {
|
.root {
|
||||||
@apply h-full flex flex-col;
|
@apply h-full flex flex-col relative w-full relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root.empty {
|
.root.empty {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { FC } from 'react'
|
|
||||||
import cn from 'classnames'
|
import cn from 'classnames'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import CartItem from '../CartItem'
|
import { FC } from 'react'
|
||||||
import s from './CartSidebarView.module.css'
|
import s from './CartSidebarView.module.css'
|
||||||
|
import CartItem from '../CartItem'
|
||||||
import { Button } from '@components/ui'
|
import { Button } from '@components/ui'
|
||||||
import { UserNav } from '@components/common'
|
import { UserNav } from '@components/common'
|
||||||
import { useUI } from '@components/ui/context'
|
import { useUI } from '@components/ui/context'
|
||||||
@ -11,7 +11,7 @@ import useCart from '@framework/cart/use-cart'
|
|||||||
import usePrice from '@framework/product/use-price'
|
import usePrice from '@framework/product/use-price'
|
||||||
|
|
||||||
const CartSidebarView: FC = () => {
|
const CartSidebarView: FC = () => {
|
||||||
const { closeSidebar } = useUI()
|
const { closeSidebar, setSidebarView } = useUI()
|
||||||
const { data, isLoading, isEmpty } = useCart()
|
const { data, isLoading, isEmpty } = useCart()
|
||||||
|
|
||||||
const { price: subTotal } = usePrice(
|
const { price: subTotal } = usePrice(
|
||||||
@ -27,6 +27,7 @@ const CartSidebarView: FC = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
const handleClose = () => closeSidebar()
|
const handleClose = () => closeSidebar()
|
||||||
|
const goToCheckout = () => setSidebarView('CHECKOUT_VIEW')
|
||||||
|
|
||||||
const error = null
|
const error = null
|
||||||
const success = null
|
const success = null
|
||||||
@ -43,9 +44,12 @@ const CartSidebarView: FC = () => {
|
|||||||
<button
|
<button
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
aria-label="Close panel"
|
aria-label="Close panel"
|
||||||
className="hover:text-gray-500 transition ease-in-out duration-150"
|
className="hover:text-gray-500 transition ease-in-out duration-150 flex items-center focus:outline-none"
|
||||||
>
|
>
|
||||||
<Cross className="h-6 w-6" />
|
<Cross className="h-6 w-6" />
|
||||||
|
<span className="ml-2 text-accent-7 text-xs hover:text-gray-500">
|
||||||
|
Close
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
@ -62,7 +66,7 @@ const CartSidebarView: FC = () => {
|
|||||||
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
||||||
Your cart is empty
|
Your cart is empty
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-accents-3 px-10 text-center pt-2">
|
<p className="text-accent-3 px-10 text-center pt-2">
|
||||||
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -90,13 +94,13 @@ const CartSidebarView: FC = () => {
|
|||||||
<div className="px-4 sm:px-6 flex-1">
|
<div className="px-4 sm:px-6 flex-1">
|
||||||
<Link href="/cart">
|
<Link href="/cart">
|
||||||
<h2
|
<h2
|
||||||
className="pt-1 pb-4 text-2xl leading-7 font-bold text-base tracking-wide cursor-pointer inline-block"
|
className="pt-1 pb-8 text-2xl font-semibold tracking-wide cursor-pointer inline-block"
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
>
|
>
|
||||||
My Cart
|
My Cart
|
||||||
</h2>
|
</h2>
|
||||||
</Link>
|
</Link>
|
||||||
<ul className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accents-3 border-t border-accents-3">
|
<ul className="py-4 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accent-3 border-accent-3">
|
||||||
{data!.lineItems.map((item: any) => (
|
{data!.lineItems.map((item: any) => (
|
||||||
<CartItem
|
<CartItem
|
||||||
key={item.id}
|
key={item.id}
|
||||||
@ -107,9 +111,8 @@ const CartSidebarView: FC = () => {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-shrink-0 px-4 py-5 sm:px-6">
|
<div className="flex-shrink-0 px-6 py-6 sm:px-6 sticky z-20 bottom-0 w-full right-0 left-0 bg-accent-0 shadow-outline-normal text-sm">
|
||||||
<div className="border-t border-accents-3">
|
<ul className="pb-2">
|
||||||
<ul className="py-3">
|
|
||||||
<li className="flex justify-between py-1">
|
<li className="flex justify-between py-1">
|
||||||
<span>Subtotal</span>
|
<span>Subtotal</span>
|
||||||
<span>{subTotal}</span>
|
<span>{subTotal}</span>
|
||||||
@ -119,18 +122,30 @@ const CartSidebarView: FC = () => {
|
|||||||
<span>Calculated at checkout</span>
|
<span>Calculated at checkout</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex justify-between py-1">
|
<li className="flex justify-between py-1">
|
||||||
<span>Estimated Shipping</span>
|
<span>Shipping</span>
|
||||||
<span className="font-bold tracking-wide">FREE</span>
|
<span className="font-bold tracking-wide">FREE</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className="flex justify-between border-t border-accents-3 py-3 font-bold mb-10">
|
<div className="flex justify-between border-t border-accent-3 py-3 font-bold mb-2">
|
||||||
<span>Total</span>
|
<span>Total</span>
|
||||||
<span>{total}</span>
|
<span>{total}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div>
|
||||||
|
{process.env.COMMERCE_CHECKOUT_ENABLED ? (
|
||||||
|
<Button
|
||||||
|
Component="a"
|
||||||
|
width="100%"
|
||||||
|
variant="ghost"
|
||||||
|
onClick={goToCheckout}
|
||||||
|
>
|
||||||
|
Continue to Checkout
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
<Button href="/checkout" Component="a" width="100%">
|
<Button href="/checkout" Component="a" width="100%">
|
||||||
Proceed to Checkout
|
Proceed to Checkout
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
.root {
|
||||||
|
@apply h-full flex flex-col relative w-full relative;
|
||||||
|
}
|
190
components/checkout/CheckoutSidebarView/CheckoutSidebarView.tsx
Normal file
190
components/checkout/CheckoutSidebarView/CheckoutSidebarView.tsx
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
import cn from 'classnames'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { FC } from 'react'
|
||||||
|
import s from './CheckoutSidebarView.module.css'
|
||||||
|
import CartItem from '@components/cart/CartItem'
|
||||||
|
import { Button } from '@components/ui'
|
||||||
|
import { UserNav } from '@components/common'
|
||||||
|
import { useUI } from '@components/ui/context'
|
||||||
|
import {
|
||||||
|
Bag,
|
||||||
|
Cross,
|
||||||
|
Check,
|
||||||
|
MapPin,
|
||||||
|
CreditCard,
|
||||||
|
ChevronLeft,
|
||||||
|
ChevronRight,
|
||||||
|
} from '@components/icons'
|
||||||
|
import useCart from '@framework/cart/use-cart'
|
||||||
|
import usePrice from '@framework/product/use-price'
|
||||||
|
|
||||||
|
const CheckoutSidebarView: FC = () => {
|
||||||
|
const { closeSidebar, setSidebarView } = useUI()
|
||||||
|
const { data, isLoading, isEmpty } = useCart()
|
||||||
|
|
||||||
|
const { price: subTotal } = usePrice(
|
||||||
|
data && {
|
||||||
|
amount: Number(data.subtotalPrice),
|
||||||
|
currencyCode: data.currency.code,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const { price: total } = usePrice(
|
||||||
|
data && {
|
||||||
|
amount: Number(data.totalPrice),
|
||||||
|
currencyCode: data.currency.code,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const handleClose = () => closeSidebar()
|
||||||
|
|
||||||
|
const error = null
|
||||||
|
const success = null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(s.root, {
|
||||||
|
[s.empty]: error || success || isLoading || isEmpty,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<header className="px-4 pt-6 pb-4 sm:px-6">
|
||||||
|
<div className="flex items-start justify-between space-x-3">
|
||||||
|
<div className="h-7 flex items-center">
|
||||||
|
<button
|
||||||
|
onClick={() => setSidebarView('CART_VIEW')}
|
||||||
|
aria-label="Close panel"
|
||||||
|
className="hover:text-gray-500 transition ease-in-out duration-150 flex items-center focus:outline-none"
|
||||||
|
>
|
||||||
|
<ChevronLeft className="h-6 w-6" />
|
||||||
|
<span className="ml-2 text-accent-7 text-xs hover:text-gray-500">
|
||||||
|
Back
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<UserNav />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{isLoading || isEmpty ? (
|
||||||
|
<div className="flex-1 px-4 flex flex-col justify-center items-center">
|
||||||
|
<span className="border border-dashed border-primary rounded-full flex items-center justify-center w-16 h-16 p-12 bg-secondary text-secondary">
|
||||||
|
<Bag className="absolute" />
|
||||||
|
</span>
|
||||||
|
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
||||||
|
Your cart is empty
|
||||||
|
</h2>
|
||||||
|
<p className="text-accent-3 px-10 text-center pt-2">
|
||||||
|
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : error ? (
|
||||||
|
<div className="flex-1 px-4 flex flex-col justify-center items-center">
|
||||||
|
<span className="border border-white rounded-full flex items-center justify-center w-16 h-16">
|
||||||
|
<Cross width={24} height={24} />
|
||||||
|
</span>
|
||||||
|
<h2 className="pt-6 text-xl font-light text-center">
|
||||||
|
We couldn’t process the purchase. Please check your card information
|
||||||
|
and try again.
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
) : success ? (
|
||||||
|
<div className="flex-1 px-4 flex flex-col justify-center items-center">
|
||||||
|
<span className="border border-white rounded-full flex items-center justify-center w-16 h-16">
|
||||||
|
<Check />
|
||||||
|
</span>
|
||||||
|
<h2 className="pt-6 text-xl font-light text-center">
|
||||||
|
Thank you for your order.
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className="px-4 sm:px-6 flex-1">
|
||||||
|
<Link href="/cart">
|
||||||
|
<h2 className="pt-1 pb-8 text-2xl font-semibold tracking-wide cursor-pointer inline-block">
|
||||||
|
Checkout
|
||||||
|
</h2>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Payment Method */}
|
||||||
|
{/* Only available with checkout set to true - Meaning that the provider does offer checkout functionality. */}
|
||||||
|
<div
|
||||||
|
onClick={() => setSidebarView('PAYMENT_VIEW')}
|
||||||
|
className="border border-accent-2 px-6 py-5 mb-4 text-center flex items-center cursor-pointer hover:border-accent-4"
|
||||||
|
>
|
||||||
|
<div className="flex flex-1 items-center">
|
||||||
|
<CreditCard className="w-5 flex" />
|
||||||
|
<span className="ml-5 text-sm text-center font-medium">
|
||||||
|
Add Payment Method
|
||||||
|
</span>
|
||||||
|
{/* <span>VISA #### #### #### 2345</span> */}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ChevronRight />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Shipping Address */}
|
||||||
|
{/* Only available with checkout set to true - Meaning that the provider does offer checkout functionality. */}
|
||||||
|
<div
|
||||||
|
onClick={() => setSidebarView('SHIPPING_VIEW')}
|
||||||
|
className="border border-accent-2 px-6 py-5 mb-4 text-center flex items-center cursor-pointer hover:border-accent-4"
|
||||||
|
>
|
||||||
|
<div className="flex flex-1 items-center">
|
||||||
|
<MapPin className="w-5 flex" />
|
||||||
|
<span className="ml-5 text-sm text-center font-medium">
|
||||||
|
Add Shipping Address
|
||||||
|
</span>
|
||||||
|
{/* <span>
|
||||||
|
1046 Kearny Street.<br/>
|
||||||
|
San Franssisco, California
|
||||||
|
</span> */}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ChevronRight />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className="py-4 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accent-3 border-accent-3">
|
||||||
|
{data!.lineItems.map((item: any) => (
|
||||||
|
<CartItem
|
||||||
|
key={item.id}
|
||||||
|
item={item}
|
||||||
|
currencyCode={data!.currency.code}
|
||||||
|
noEdit
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-shrink-0 px-6 py-6 sm:px-6 sticky z-20 bottom-0 w-full right-0 left-0 bg-accent-0 shadow-outline-normal text-sm">
|
||||||
|
<ul className="pb-2">
|
||||||
|
<li className="flex justify-between py-1">
|
||||||
|
<span>Subtotal</span>
|
||||||
|
<span>{subTotal}</span>
|
||||||
|
</li>
|
||||||
|
<li className="flex justify-between py-1">
|
||||||
|
<span>Taxes</span>
|
||||||
|
<span>Calculated at checkout</span>
|
||||||
|
</li>
|
||||||
|
<li className="flex justify-between py-1">
|
||||||
|
<span>Shipping</span>
|
||||||
|
<span className="font-bold tracking-wide">FREE</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div className="flex justify-between border-t border-accent-3 py-3 font-bold mb-2">
|
||||||
|
<span>Total</span>
|
||||||
|
<span>{total}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button href="/checkout" Component="a" width="100%">
|
||||||
|
Confirm Purchase
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CheckoutSidebarView
|
1
components/checkout/CheckoutSidebarView/index.ts
Normal file
1
components/checkout/CheckoutSidebarView/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './CheckoutSidebarView'
|
@ -0,0 +1,21 @@
|
|||||||
|
.root {
|
||||||
|
@apply h-full flex flex-col relative w-full relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldset {
|
||||||
|
@apply flex flex-col my-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldset .label {
|
||||||
|
@apply text-accent-7 uppercase text-xs font-medium mb-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldset .input,
|
||||||
|
.fieldset .select {
|
||||||
|
@apply p-2 border border-accent-3 w-full text-sm font-normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldset .input:focus,
|
||||||
|
.fieldset .select:focus {
|
||||||
|
@apply outline-none shadow-outline-normal;
|
||||||
|
}
|
106
components/checkout/PaymentMethodView/PaymentMethodView.tsx
Normal file
106
components/checkout/PaymentMethodView/PaymentMethodView.tsx
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { FC } from 'react'
|
||||||
|
import s from './PaymentMethodView.module.css'
|
||||||
|
import { ChevronLeft } from '@components/icons'
|
||||||
|
import { UserNav } from '@components/common'
|
||||||
|
import { useUI } from '@components/ui/context'
|
||||||
|
import Button from '@components/ui/Button'
|
||||||
|
import cn from 'classnames'
|
||||||
|
|
||||||
|
const PaymentMethodView: FC = () => {
|
||||||
|
const { setSidebarView } = useUI()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s.root}>
|
||||||
|
<header className="px-4 pt-6 pb-4 sm:px-6">
|
||||||
|
<div className="flex items-start justify-between space-x-3">
|
||||||
|
<div className="h-7 flex items-center">
|
||||||
|
<button
|
||||||
|
onClick={() => setSidebarView('CHECKOUT_VIEW')}
|
||||||
|
aria-label="Close panel"
|
||||||
|
className="hover:text-gray-500 transition ease-in-out duration-150 flex items-center focus:outline-none"
|
||||||
|
>
|
||||||
|
<ChevronLeft className="h-6 w-6" />
|
||||||
|
<span className="ml-2 text-accent-7 text-xs hover:text-gray-500">
|
||||||
|
Back
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<UserNav />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div className="px-4 sm:px-6 flex-1">
|
||||||
|
<h2 className="pt-1 pb-6 text-2xl font-semibold tracking-wide cursor-pointer inline-block">
|
||||||
|
Payment Method
|
||||||
|
</h2>
|
||||||
|
<div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Cardholder Name</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className="grid gap-3 grid-flow-row grid-cols-12">
|
||||||
|
<div className={cn(s.fieldset, 'col-span-7')}>
|
||||||
|
<label className={s.label}>Card Number</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className={cn(s.fieldset, 'col-span-3')}>
|
||||||
|
<label className={s.label}>Expires</label>
|
||||||
|
<input className={s.input} placeholder="MM/YY" />
|
||||||
|
</div>
|
||||||
|
<div className={cn(s.fieldset, 'col-span-2')}>
|
||||||
|
<label className={s.label}>CVC</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr className="border-accent-3 my-6" />
|
||||||
|
<div className="grid gap-3 grid-flow-row grid-cols-12">
|
||||||
|
<div className={cn(s.fieldset, 'col-span-6')}>
|
||||||
|
<label className={s.label}>First Name</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className={cn(s.fieldset, 'col-span-6')}>
|
||||||
|
<label className={s.label}>Last Name</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Company (Optional)</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Street and House Number</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Apartment, Suite, Etc. (Optional)</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className="grid gap-3 grid-flow-row grid-cols-12">
|
||||||
|
<div className={cn(s.fieldset, 'col-span-6')}>
|
||||||
|
<label className={s.label}>Postal Code</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className={cn(s.fieldset, 'col-span-6')}>
|
||||||
|
<label className={s.label}>City</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Country/Region</label>
|
||||||
|
<select className={s.select}>
|
||||||
|
<option>Hong Kong</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="mt-10 sticky z-20 bottom-0 w-full right-0 left-0 ">
|
||||||
|
<Button Component="a" width="100%" variant="ghost">
|
||||||
|
Continue
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PaymentMethodView
|
1
components/checkout/PaymentMethodView/index.ts
Normal file
1
components/checkout/PaymentMethodView/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './PaymentMethodView'
|
12
components/checkout/README.md
Normal file
12
components/checkout/README.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Checkout
|
||||||
|
|
||||||
|
Checkout is only enabled in those providers that specify Custom Checkout to be enabled.
|
||||||
|
|
||||||
|
This feature enables:
|
||||||
|
|
||||||
|
- Shipping
|
||||||
|
- Payment
|
||||||
|
|
||||||
|
```
|
||||||
|
COMMERCE_CHECKOUT_ENABLED
|
||||||
|
```
|
25
components/checkout/ShippingView/ShippingView.module.css
Normal file
25
components/checkout/ShippingView/ShippingView.module.css
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
.root {
|
||||||
|
@apply h-full flex flex-col relative w-full relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldset {
|
||||||
|
@apply flex flex-col my-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldset .label {
|
||||||
|
@apply text-accent-7 uppercase text-xs font-medium mb-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldset .input,
|
||||||
|
.fieldset .select {
|
||||||
|
@apply p-2 border border-accent-3 w-full text-sm font-normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fieldset .input:focus,
|
||||||
|
.fieldset .select:focus {
|
||||||
|
@apply outline-none shadow-outline-normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio {
|
||||||
|
@apply bg-black;
|
||||||
|
}
|
98
components/checkout/ShippingView/ShippingView.tsx
Normal file
98
components/checkout/ShippingView/ShippingView.tsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { FC } from 'react'
|
||||||
|
import s from './ShippingView.module.css'
|
||||||
|
import { ChevronLeft } from '@components/icons'
|
||||||
|
import { UserNav } from '@components/common'
|
||||||
|
import { useUI } from '@components/ui/context'
|
||||||
|
import Button from '@components/ui/Button'
|
||||||
|
import cn from 'classnames'
|
||||||
|
|
||||||
|
const PaymentMethodView: FC = () => {
|
||||||
|
const { setSidebarView } = useUI()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s.root}>
|
||||||
|
<header className="px-4 pt-6 pb-4 sm:px-6">
|
||||||
|
<div className="flex items-start justify-between space-x-3">
|
||||||
|
<div className="h-7 flex items-center">
|
||||||
|
<button
|
||||||
|
onClick={() => setSidebarView('CHECKOUT_VIEW')}
|
||||||
|
aria-label="Close panel"
|
||||||
|
className="hover:text-gray-500 transition ease-in-out duration-150 flex items-center focus:outline-none"
|
||||||
|
>
|
||||||
|
<ChevronLeft className="h-6 w-6" />
|
||||||
|
<span className="ml-2 text-accent-7 text-xs hover:text-gray-500">
|
||||||
|
Back
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<UserNav />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div className="px-4 sm:px-6 flex-1">
|
||||||
|
<h2 className="pt-1 pb-8 text-2xl font-semibold tracking-wide cursor-pointer inline-block">
|
||||||
|
Shipping
|
||||||
|
</h2>
|
||||||
|
<div>
|
||||||
|
<div className="flex flex-row my-3 items-center">
|
||||||
|
<input className={s.radio} type="radio" />
|
||||||
|
<span className="ml-3 text-sm">Same as billing address</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row my-3 items-center">
|
||||||
|
<input className={s.radio} type="radio" />
|
||||||
|
<span className="ml-3 text-sm">
|
||||||
|
Use a different shipping address
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<hr className="border-accent-3 my-6" />
|
||||||
|
<div className="grid gap-3 grid-flow-row grid-cols-12">
|
||||||
|
<div className={cn(s.fieldset, 'col-span-6')}>
|
||||||
|
<label className={s.label}>First Name</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className={cn(s.fieldset, 'col-span-6')}>
|
||||||
|
<label className={s.label}>Last Name</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Company (Optional)</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Street and House Number</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Apartment, Suite, Etc. (Optional)</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className="grid gap-3 grid-flow-row grid-cols-12">
|
||||||
|
<div className={cn(s.fieldset, 'col-span-6')}>
|
||||||
|
<label className={s.label}>Postal Code</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
<div className={cn(s.fieldset, 'col-span-6')}>
|
||||||
|
<label className={s.label}>City</label>
|
||||||
|
<input className={s.input} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={s.fieldset}>
|
||||||
|
<label className={s.label}>Country/Region</label>
|
||||||
|
<select className={s.select}>
|
||||||
|
<option>Hong Kong</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-10 sticky z-20 bottom-0 w-full right-0 left-0 p-6">
|
||||||
|
<Button href="/checkout" Component="a" width="100%" variant="ghost">
|
||||||
|
Continue
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PaymentMethodView
|
1
components/checkout/ShippingView/index.ts
Normal file
1
components/checkout/ShippingView/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './ShippingView'
|
@ -1,9 +1,7 @@
|
|||||||
.root {
|
.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;
|
@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 {
|
@screen md {
|
||||||
.root {
|
|
||||||
@apply flex text-left;
|
@apply flex text-left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ const Footer: FC<Props> = ({ className, pages }) => {
|
|||||||
return (
|
return (
|
||||||
<footer className={rootClassName}>
|
<footer className={rootClassName}>
|
||||||
<Container>
|
<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">
|
<div className="col-span-1 lg:col-span-2">
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
<a className="flex flex-initial items-center font-bold md:mr-24">
|
<a className="flex flex-initial items-center font-bold md:mr-24">
|
||||||
@ -39,15 +39,29 @@ const Footer: FC<Props> = ({ className, pages }) => {
|
|||||||
<ul className="flex flex-initial flex-col md:flex-1">
|
<ul className="flex flex-initial flex-col md:flex-1">
|
||||||
<li className="py-3 md:py-0 md:pb-4">
|
<li className="py-3 md:py-0 md:pb-4">
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
<a className="text-primary hover:text-accents-6 transition ease-in-out duration-150">
|
<a className="text-primary hover:text-accent-6 transition ease-in-out duration-150">
|
||||||
Home
|
Home
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
<li className="py-3 md:py-0 md:pb-4">
|
||||||
|
<Link href="/">
|
||||||
|
<a className="text-primary hover:text-accent-6 transition ease-in-out duration-150">
|
||||||
|
Careers
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li className="py-3 md:py-0 md:pb-4">
|
||||||
|
<Link href="/blog">
|
||||||
|
<a className="text-primary hover:text-accent-6 transition ease-in-out duration-150">
|
||||||
|
Blog
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
{sitePages.map((page) => (
|
{sitePages.map((page) => (
|
||||||
<li key={page.url} className="py-3 md:py-0 md:pb-4">
|
<li key={page.url} className="py-3 md:py-0 md:pb-4">
|
||||||
<Link href={page.url!}>
|
<Link href={page.url!}>
|
||||||
<a className="text-primary hover:text-accents-6 transition ease-in-out duration-150">
|
<a className="text-primary hover:text-accent-6 transition ease-in-out duration-150">
|
||||||
{page.name}
|
{page.name}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
@ -60,7 +74,7 @@ const Footer: FC<Props> = ({ className, pages }) => {
|
|||||||
{legalPages.map((page) => (
|
{legalPages.map((page) => (
|
||||||
<li key={page.url} className="py-3 md:py-0 md:pb-4">
|
<li key={page.url} className="py-3 md:py-0 md:pb-4">
|
||||||
<Link href={page.url!}>
|
<Link href={page.url!}>
|
||||||
<a className="text-primary hover:text-accents-6 transition ease-in-out duration-150">
|
<a className="text-primary hover:text-accent-6 transition ease-in-out duration-150">
|
||||||
{page.name}
|
{page.name}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -28,7 +28,7 @@ const HomeAllProductsGrid: FC<Props> = ({
|
|||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
{categories.map((cat: any) => (
|
{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)}>
|
<Link href={getCategoryPath(cat.path)}>
|
||||||
<a>{cat.name}</a>
|
<a>{cat.name}</a>
|
||||||
</Link>
|
</Link>
|
||||||
@ -42,7 +42,7 @@ const HomeAllProductsGrid: FC<Props> = ({
|
|||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
{brands.flatMap(({ node }: any) => (
|
{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)}>
|
<Link href={getDesignerPath(node.path)}>
|
||||||
<a>{node.name}</a>
|
<a>{node.name}</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:hover {
|
.button:hover {
|
||||||
@apply border-accents-4 shadow-sm;
|
@apply border-accent-4 shadow-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:focus {
|
.button:focus {
|
||||||
@ -16,16 +16,14 @@
|
|||||||
|
|
||||||
.dropdownMenu {
|
.dropdownMenu {
|
||||||
@apply fixed right-0 top-12 mt-2 origin-top-right outline-none bg-primary z-40 w-full h-full;
|
@apply fixed right-0 top-12 mt-2 origin-top-right outline-none bg-primary z-40 w-full h-full;
|
||||||
}
|
|
||||||
|
|
||||||
@screen lg {
|
@screen lg {
|
||||||
.dropdownMenu {
|
@apply absolute border border-accent-1 shadow-lg w-56 h-auto;
|
||||||
@apply absolute border border-accents-1 shadow-lg w-56 h-auto;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@screen md {
|
|
||||||
.closeButton {
|
.closeButton {
|
||||||
|
@screen md {
|
||||||
@apply hidden;
|
@apply hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,7 +34,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.item:hover {
|
.item:hover {
|
||||||
@apply bg-accents-1;
|
@apply bg-accent-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
@ -8,6 +8,9 @@ import { Navbar, Footer } from '@components/common'
|
|||||||
import { useAcceptCookies } from '@lib/hooks/useAcceptCookies'
|
import { useAcceptCookies } from '@lib/hooks/useAcceptCookies'
|
||||||
import { Sidebar, Button, Modal, LoadingDots } from '@components/ui'
|
import { Sidebar, Button, Modal, LoadingDots } from '@components/ui'
|
||||||
import CartSidebarView from '@components/cart/CartSidebarView'
|
import CartSidebarView from '@components/cart/CartSidebarView'
|
||||||
|
import CheckoutSidebarView from '@components/checkout/CheckoutSidebarView'
|
||||||
|
import PaymentMethodView from '@components/checkout/PaymentMethodView'
|
||||||
|
import ShippingView from '@components/checkout/ShippingView'
|
||||||
|
|
||||||
import LoginView from '@components/auth/LoginView'
|
import LoginView from '@components/auth/LoginView'
|
||||||
import { CommerceProvider } from '@framework'
|
import { CommerceProvider } from '@framework'
|
||||||
@ -55,6 +58,7 @@ const Layout: FC<Props> = ({
|
|||||||
closeSidebar,
|
closeSidebar,
|
||||||
closeModal,
|
closeModal,
|
||||||
modalView,
|
modalView,
|
||||||
|
sidebarView,
|
||||||
} = useUI()
|
} = useUI()
|
||||||
const { acceptedCookies, onAcceptCookies } = useAcceptCookies()
|
const { acceptedCookies, onAcceptCookies } = useAcceptCookies()
|
||||||
const { locale = 'en-US' } = useRouter()
|
const { locale = 'en-US' } = useRouter()
|
||||||
@ -72,7 +76,10 @@ const Layout: FC<Props> = ({
|
|||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Sidebar open={displaySidebar} onClose={closeSidebar}>
|
<Sidebar open={displaySidebar} onClose={closeSidebar}>
|
||||||
<CartSidebarView />
|
{sidebarView === 'CART_VIEW' && <CartSidebarView />}
|
||||||
|
{sidebarView === 'CHECKOUT_VIEW' && <CheckoutSidebarView />}
|
||||||
|
{sidebarView === 'PAYMENT_VIEW' && <PaymentMethodView />}
|
||||||
|
{sidebarView === 'SHIPPING_VIEW' && <ShippingView />}
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|
||||||
<FeatureBar
|
<FeatureBar
|
||||||
|
@ -3,15 +3,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
.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 text-primary leading-6 font-medium transition ease-in-out duration-75 cursor-pointer text-accent-6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link:hover {
|
.link:hover {
|
||||||
@apply text-accents-9;
|
@apply text-accent-9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link:focus {
|
.link:focus {
|
||||||
@apply outline-none text-accents-8;
|
@apply outline-none text-accent-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
|
@ -19,7 +19,7 @@ const Searchbar: FC<Props> = ({ className, id = 'search' }) => {
|
|||||||
() => (
|
() => (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'relative text-sm bg-accents-1 text-base w-full transition-colors duration-150',
|
'relative text-sm bg-accent-1 text-base w-full transition-colors duration-150',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
.dropdownMenu {
|
.dropdownMenu {
|
||||||
@apply fixed right-0 mt-2 origin-top-right outline-none bg-primary z-40 w-full h-full;
|
@apply fixed right-0 mt-2 origin-top-right outline-none bg-primary z-40 w-full h-full;
|
||||||
}
|
|
||||||
|
|
||||||
@screen lg {
|
@screen lg {
|
||||||
.dropdownMenu {
|
@apply absolute top-10 border border-accent-1 shadow-lg w-56 h-auto;
|
||||||
@apply absolute top-10 border border-accents-1 shadow-lg w-56 h-auto;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,11 +12,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.link:hover {
|
.link:hover {
|
||||||
@apply bg-accents-1;
|
@apply bg-accent-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link.active {
|
.link.active {
|
||||||
@apply font-bold bg-accents-2;
|
@apply font-bold bg-accent-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.off {
|
.off {
|
||||||
|
@ -109,7 +109,7 @@ const DropdownMenu: FC<DropdownMenuProps> = ({ open = false }) => {
|
|||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<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()}
|
onClick={() => logout()}
|
||||||
>
|
>
|
||||||
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;
|
@apply mr-6 cursor-pointer relative transition ease-in-out duration-100 flex items-center outline-none text-primary;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@apply text-accents-6 transition scale-110 duration-100;
|
@apply text-accent-6 transition scale-110 duration-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
@ -24,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bagCount {
|
.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-left: 2.5px;
|
||||||
padding-right: 2.5px;
|
padding-right: 2.5px;
|
||||||
min-width: 1.25rem;
|
min-width: 1.25rem;
|
||||||
|
20
components/icons/ChevronLeft.tsx
Normal file
20
components/icons/ChevronLeft.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const ChevronUp = ({ ...props }) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
fill="none"
|
||||||
|
shapeRendering="geometricPrecision"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path d="M15 18l-6-6 6-6" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChevronUp
|
20
components/icons/ChevronRight.tsx
Normal file
20
components/icons/ChevronRight.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const ChevronUp = ({ ...props }) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
fill="none"
|
||||||
|
shapeRendering="geometricPrecision"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path d="M9 18l6-6-6-6" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChevronUp
|
@ -10,6 +10,7 @@ const CreditCard = ({ ...props }) => {
|
|||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
fill="none"
|
fill="none"
|
||||||
shapeRendering="geometricPrecision"
|
shapeRendering="geometricPrecision"
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
<rect x="1" y="4" width="22" height="16" rx="2" ry="2" />
|
<rect x="1" y="4" width="22" height="16" rx="2" ry="2" />
|
||||||
<path d="M1 10h22" />
|
<path d="M1 10h22" />
|
||||||
|
@ -9,10 +9,12 @@ export { default as Check } from './Check'
|
|||||||
export { default as Sun } from './Sun'
|
export { default as Sun } from './Sun'
|
||||||
export { default as Moon } from './Moon'
|
export { default as Moon } from './Moon'
|
||||||
export { default as Github } from './Github'
|
export { default as Github } from './Github'
|
||||||
export { default as DoubleChevron } from './DoubleChevron'
|
|
||||||
export { default as RightArrow } from './RightArrow'
|
export { default as RightArrow } from './RightArrow'
|
||||||
export { default as Info } from './Info'
|
export { default as Info } from './Info'
|
||||||
export { default as ChevronUp } from './ChevronUp'
|
|
||||||
export { default as Vercel } from './Vercel'
|
export { default as Vercel } from './Vercel'
|
||||||
export { default as MapPin } from './MapPin'
|
export { default as MapPin } from './MapPin'
|
||||||
export { default as CreditCard } from './CreditCard'
|
export { default as CreditCard } from './CreditCard'
|
||||||
|
export { default as ChevronUp } from './ChevronUp'
|
||||||
|
export { default as ChevronLeft } from './ChevronLeft'
|
||||||
|
export { default as ChevronRight } from './ChevronRight'
|
||||||
|
export { default as DoubleChevron } from './DoubleChevron'
|
||||||
|
@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
.simple {
|
.simple {
|
||||||
& .squareBg {
|
& .squareBg {
|
||||||
@apply bg-accents-0 !important;
|
@apply bg-accent-0 !important;
|
||||||
background-image: url('/bg-products.svg');
|
background-image: url('/bg-products.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,6 @@
|
|||||||
|
|
||||||
.active {
|
.active {
|
||||||
&.size {
|
&.size {
|
||||||
@apply border-accents-9 border-2;
|
@apply border-accent-9 border-2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
.root {
|
.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-secondary text-accent-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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root:hover {
|
.root:hover {
|
||||||
@apply bg-accents-0 text-primary border border-secondary;
|
@apply bg-accent-0 text-primary border border-secondary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root:focus {
|
.root:focus {
|
||||||
@ -15,16 +18,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.loading {
|
.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 {
|
.slim {
|
||||||
@apply py-2 transform-none normal-case;
|
@apply py-2 transform-none normal-case;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ghost {
|
||||||
|
@apply border border-accent-3 bg-accent-0 text-accent-9 text-sm;
|
||||||
|
}
|
||||||
|
|
||||||
.disabled,
|
.disabled,
|
||||||
.disabled:hover {
|
.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);
|
filter: grayscale(1);
|
||||||
-webkit-transform: translateZ(0);
|
-webkit-transform: translateZ(0);
|
||||||
-webkit-perspective: 1000;
|
-webkit-perspective: 1000;
|
||||||
|
@ -12,7 +12,7 @@ import { LoadingDots } from '@components/ui'
|
|||||||
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
href?: string
|
href?: string
|
||||||
className?: string
|
className?: string
|
||||||
variant?: 'flat' | 'slim'
|
variant?: 'flat' | 'slim' | 'ghost'
|
||||||
active?: boolean
|
active?: boolean
|
||||||
type?: 'submit' | 'reset' | 'button'
|
type?: 'submit' | 'reset' | 'button'
|
||||||
Component?: string | JSXElementConstructor<any>
|
Component?: string | JSXElementConstructor<any>
|
||||||
@ -39,6 +39,7 @@ const Button: React.FC<ButtonProps> = forwardRef((props, buttonRef) => {
|
|||||||
const rootClassName = cn(
|
const rootClassName = cn(
|
||||||
s.root,
|
s.root,
|
||||||
{
|
{
|
||||||
|
[s.ghost]: variant === 'ghost',
|
||||||
[s.slim]: variant === 'slim',
|
[s.slim]: variant === 'slim',
|
||||||
[s.loading]: loading,
|
[s.loading]: loading,
|
||||||
[s.disabled]: disabled,
|
[s.disabled]: disabled,
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
@apply grid grid-cols-1 gap-0;
|
@apply grid grid-cols-1 gap-0;
|
||||||
min-height: var(--row-height);
|
min-height: var(--row-height);
|
||||||
|
|
||||||
|
@screen lg {
|
||||||
|
@apply grid-cols-3 grid-rows-2;
|
||||||
|
}
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
@apply row-span-1 bg-transparent box-border overflow-hidden;
|
@apply row-span-1 bg-transparent box-border overflow-hidden;
|
||||||
height: 500px;
|
height: 500px;
|
||||||
@ -15,17 +19,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@screen lg {
|
|
||||||
.root {
|
|
||||||
@apply grid-cols-3 grid-rows-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.root & > * {
|
|
||||||
@apply col-span-1;
|
|
||||||
height: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.default {
|
.default {
|
||||||
& > * {
|
& > * {
|
||||||
@apply bg-transparent;
|
@apply bg-transparent;
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
.root {
|
.root {
|
||||||
@apply mx-auto grid grid-cols-1 py-32 gap-4;
|
@apply mx-auto grid grid-cols-1 py-32 gap-4;
|
||||||
}
|
|
||||||
|
|
||||||
@screen md {
|
@screen md {
|
||||||
.root {
|
|
||||||
@apply grid-cols-2;
|
@apply grid-cols-2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ const Hero: FC<Props> = ({ headline, description }) => {
|
|||||||
<p className="mt-5 text-xl leading-7 text-accent-2 text-white">
|
<p className="mt-5 text-xl leading-7 text-accent-2 text-white">
|
||||||
{description}
|
{description}
|
||||||
</p>
|
</p>
|
||||||
<Link href="/">
|
<Link href="/blog">
|
||||||
<a className="text-white pt-3 font-bold hover:underline flex flex-row cursor-pointer w-max-content">
|
<a className="text-white pt-3 font-bold hover:underline flex flex-row cursor-pointer w-max-content">
|
||||||
Read it here
|
Read it here
|
||||||
<RightArrow width="20" heigh="20" className="ml-1" />
|
<RightArrow width="20" heigh="20" className="ml-1" />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.root {
|
.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 {
|
.root:focus {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@apply inline-flex text-center items-center leading-7;
|
@apply inline-flex text-center items-center leading-7;
|
||||||
|
|
||||||
& span {
|
& span {
|
||||||
@apply bg-accents-6 rounded-full h-2 w-2;
|
@apply bg-accent-6 rounded-full h-2 w-2;
|
||||||
animation-name: blink;
|
animation-name: blink;
|
||||||
animation-duration: 1.4s;
|
animation-duration: 1.4s;
|
||||||
animation-iteration-count: infinite;
|
animation-iteration-count: infinite;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
@apply bg-primary p-12 border border-accents-2 relative;
|
@apply bg-primary p-12 border border-accent-2 relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal:focus {
|
.modal:focus {
|
||||||
|
@ -40,7 +40,7 @@ const Sidebar: FC<Props> = ({ children, open = false, onClose }) => {
|
|||||||
/>
|
/>
|
||||||
<section className="absolute inset-y-0 right-0 pl-10 max-w-full flex sm:pl-16 outline-none">
|
<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 md:w-screen md:max-w-md">
|
||||||
<div className="h-full flex flex-col text-base bg-accents-1 shadow-xl overflow-y-auto">
|
<div className="h-full flex flex-col text-base bg-accent-0 shadow-xl overflow-y-auto">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
@apply block;
|
@apply block;
|
||||||
background-image: linear-gradient(
|
background-image: linear-gradient(
|
||||||
270deg,
|
270deg,
|
||||||
var(--accents-1),
|
var(--accent-1),
|
||||||
var(--accents-2),
|
var(--accent-2),
|
||||||
var(--accents-2),
|
var(--accent-2),
|
||||||
var(--accents-1)
|
var(--accent-1)
|
||||||
);
|
);
|
||||||
background-size: 400% 100%;
|
background-size: 400% 100%;
|
||||||
animation: loading 8s ease-in-out infinite;
|
animation: loading 8s ease-in-out infinite;
|
||||||
@ -28,10 +28,10 @@
|
|||||||
z-index: 100;
|
z-index: 100;
|
||||||
background-image: linear-gradient(
|
background-image: linear-gradient(
|
||||||
270deg,
|
270deg,
|
||||||
var(--accents-1),
|
var(--accent-1),
|
||||||
var(--accents-2),
|
var(--accent-2),
|
||||||
var(--accents-2),
|
var(--accent-2),
|
||||||
var(--accents-1)
|
var(--accent-1)
|
||||||
);
|
);
|
||||||
background-size: 400% 100%;
|
background-size: 400% 100%;
|
||||||
animation: loading 8s ease-in-out infinite;
|
animation: loading 8s ease-in-out infinite;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.body {
|
.body {
|
||||||
@apply text-lg leading-7 font-medium max-w-6xl mx-auto;
|
@apply text-base leading-7 max-w-6xl mx-auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
@ -11,5 +11,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sectionHeading {
|
.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 font-semibold leading-7 tracking-wider uppercase border-b border-accent-2 mb-3;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ export interface State {
|
|||||||
displayModal: boolean
|
displayModal: boolean
|
||||||
displayToast: boolean
|
displayToast: boolean
|
||||||
modalView: string
|
modalView: string
|
||||||
|
sidebarView: string
|
||||||
toastText: string
|
toastText: string
|
||||||
userAvatar: string
|
userAvatar: string
|
||||||
}
|
}
|
||||||
@ -16,6 +17,7 @@ const initialState = {
|
|||||||
displayDropdown: false,
|
displayDropdown: false,
|
||||||
displayModal: false,
|
displayModal: false,
|
||||||
modalView: 'LOGIN_VIEW',
|
modalView: 'LOGIN_VIEW',
|
||||||
|
sidebarView: 'CART_VIEW',
|
||||||
displayToast: false,
|
displayToast: false,
|
||||||
toastText: '',
|
toastText: '',
|
||||||
userAvatar: '',
|
userAvatar: '',
|
||||||
@ -54,6 +56,10 @@ type Action =
|
|||||||
type: 'SET_MODAL_VIEW'
|
type: 'SET_MODAL_VIEW'
|
||||||
view: MODAL_VIEWS
|
view: MODAL_VIEWS
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'SET_SIDEBAR_VIEW'
|
||||||
|
view: SIDEBAR_VIEWS
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: 'SET_USER_AVATAR'
|
type: 'SET_USER_AVATAR'
|
||||||
value: string
|
value: string
|
||||||
@ -65,6 +71,9 @@ type MODAL_VIEWS =
|
|||||||
| 'FORGOT_VIEW'
|
| 'FORGOT_VIEW'
|
||||||
| 'NEW_SHIPPING_ADDRESS'
|
| 'NEW_SHIPPING_ADDRESS'
|
||||||
| 'NEW_PAYMENT_METHOD'
|
| 'NEW_PAYMENT_METHOD'
|
||||||
|
|
||||||
|
type SIDEBAR_VIEWS = 'CART_VIEW' | 'CHECKOUT_VIEW' | 'PAYMENT_METHOD_VIEW'
|
||||||
|
|
||||||
type ToastText = string
|
type ToastText = string
|
||||||
|
|
||||||
export const UIContext = React.createContext<State | any>(initialState)
|
export const UIContext = React.createContext<State | any>(initialState)
|
||||||
@ -128,6 +137,12 @@ function uiReducer(state: State, action: Action) {
|
|||||||
modalView: action.view,
|
modalView: action.view,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case 'SET_SIDEBAR_VIEW': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
sidebarView: action.view,
|
||||||
|
}
|
||||||
|
}
|
||||||
case 'SET_TOAST_TEXT': {
|
case 'SET_TOAST_TEXT': {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@ -170,6 +185,9 @@ export const UIProvider: FC = (props) => {
|
|||||||
const setModalView = (view: MODAL_VIEWS) =>
|
const setModalView = (view: MODAL_VIEWS) =>
|
||||||
dispatch({ type: 'SET_MODAL_VIEW', view })
|
dispatch({ type: 'SET_MODAL_VIEW', view })
|
||||||
|
|
||||||
|
const setSidebarView = (view: SIDEBAR_VIEWS) =>
|
||||||
|
dispatch({ type: 'SET_SIDEBAR_VIEW', view })
|
||||||
|
|
||||||
const value = useMemo(
|
const value = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
...state,
|
...state,
|
||||||
@ -182,6 +200,7 @@ export const UIProvider: FC = (props) => {
|
|||||||
openModal,
|
openModal,
|
||||||
closeModal,
|
closeModal,
|
||||||
setModalView,
|
setModalView,
|
||||||
|
setSidebarView,
|
||||||
openToast,
|
openToast,
|
||||||
closeToast,
|
closeToast,
|
||||||
setUserAvatar,
|
setUserAvatar,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.root {
|
.root {
|
||||||
@apply grid grid-cols-12 w-full gap-6 px-3 py-6 border-b border-accents-2 transition duration-100 ease-in-out;
|
@apply grid grid-cols-12 w-full gap-6 px-3 py-6 border-b border-accent-2 transition duration-100 ease-in-out;
|
||||||
|
|
||||||
&:nth-child(3n + 1) {
|
&:nth-child(3n + 1) {
|
||||||
& .productBg {
|
& .productBg {
|
||||||
|
@ -9,6 +9,7 @@ const fetchGraphqlApi: GraphQLFetcher = async (
|
|||||||
{ variables } = {},
|
{ variables } = {},
|
||||||
fetchOptions
|
fetchOptions
|
||||||
) => {
|
) => {
|
||||||
|
try {
|
||||||
const res = await fetch(API_URL, {
|
const res = await fetch(API_URL, {
|
||||||
...fetchOptions,
|
...fetchOptions,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -30,5 +31,15 @@ const fetchGraphqlApi: GraphQLFetcher = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
return { data, res }
|
return { data, res }
|
||||||
|
} catch (err) {
|
||||||
|
throw getError(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
message: `${err} \n Most likely related to an unexpected output. e.g the store might be protected with password or not available.`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
500
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export default fetchGraphqlApi
|
export default fetchGraphqlApi
|
||||||
|
@ -10,15 +10,11 @@ export const handler: SWRHook<Customer | null> = {
|
|||||||
query: getCustomerQuery,
|
query: getCustomerQuery,
|
||||||
},
|
},
|
||||||
async fetcher({ options, fetch }) {
|
async fetcher({ options, fetch }) {
|
||||||
const customerAccessToken = getCustomerToken()
|
const data = await fetch<any | null>({
|
||||||
if (customerAccessToken) {
|
|
||||||
const data = await fetch({
|
|
||||||
...options,
|
...options,
|
||||||
variables: { customerAccessToken: getCustomerToken() },
|
variables: { customerAccessToken: getCustomerToken() },
|
||||||
})
|
})
|
||||||
return data.customer
|
return data.customer ?? null
|
||||||
}
|
|
||||||
return null
|
|
||||||
},
|
},
|
||||||
useHook: ({ useData }) => (input) => {
|
useHook: ({ useData }) => (input) => {
|
||||||
return useData({
|
return useData({
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
import { Product } from '@commerce/types'
|
||||||
import { getConfig, ShopifyConfig } from '../api'
|
import { getConfig, ShopifyConfig } from '../api'
|
||||||
|
import fetchAllProducts from '../api/utils/fetch-all-products'
|
||||||
import { ProductEdge } from '../schema'
|
import { ProductEdge } from '../schema'
|
||||||
import getAllProductsPathsQuery from '../utils/queries/get-all-products-paths-query'
|
import getAllProductsPathsQuery from '../utils/queries/get-all-products-paths-query'
|
||||||
|
|
||||||
@ -19,22 +21,21 @@ const getAllProductPaths = async (options?: {
|
|||||||
config?: ShopifyConfig
|
config?: ShopifyConfig
|
||||||
preview?: boolean
|
preview?: boolean
|
||||||
}): Promise<ReturnType> => {
|
}): Promise<ReturnType> => {
|
||||||
let { config, variables = { first: 100, sortKey: 'BEST_SELLING' } } =
|
let { config, variables = { first: 250 } } = options ?? {}
|
||||||
options ?? {}
|
|
||||||
config = getConfig(config)
|
config = getConfig(config)
|
||||||
|
|
||||||
const { data } = await config.fetch(getAllProductsPathsQuery, {
|
const products = await fetchAllProducts({
|
||||||
|
config,
|
||||||
|
query: getAllProductsPathsQuery,
|
||||||
variables,
|
variables,
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
products: data.products?.edges?.map(
|
products: products?.map(({ node: { handle } }: ProductEdge) => ({
|
||||||
({ node: { handle } }: ProductEdge) => ({
|
|
||||||
node: {
|
node: {
|
||||||
path: `/${handle}`,
|
path: `/${handle}`,
|
||||||
},
|
},
|
||||||
})
|
})),
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,9 +27,10 @@ const getAllProducts = async (options: {
|
|||||||
{ variables }
|
{ variables }
|
||||||
)
|
)
|
||||||
|
|
||||||
const products = data.products?.edges?.map(({ node: p }: ProductEdge) =>
|
const products =
|
||||||
|
data.products?.edges?.map(({ node: p }: ProductEdge) =>
|
||||||
normalizeProduct(p)
|
normalizeProduct(p)
|
||||||
)
|
) ?? []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
products,
|
products,
|
||||||
|
@ -21,6 +21,7 @@ const getProduct = async (options: {
|
|||||||
const { data }: GraphQLFetcherResult = await config.fetch(getProductQuery, {
|
const { data }: GraphQLFetcherResult = await config.fetch(getProductQuery, {
|
||||||
variables,
|
variables,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { productByHandle } = data
|
const { productByHandle } = data
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { FetcherError } from '@commerce/utils/errors'
|
import { FetcherError } from '@commerce/utils/errors'
|
||||||
|
|
||||||
export function getError(errors: any[], status: number) {
|
export function getError(errors: any[] | null, status: number) {
|
||||||
errors = errors ?? [{ message: 'Failed to fetch Shopify API' }]
|
errors = errors ?? [{ message: 'Failed to fetch Shopify API' }]
|
||||||
return new FetcherError({ errors, status })
|
return new FetcherError({ errors, status })
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ const normalizeProductVariants = ({ edges }: ProductVariantConnection) => {
|
|||||||
name,
|
name,
|
||||||
values: [value],
|
values: [value],
|
||||||
})
|
})
|
||||||
|
|
||||||
return options
|
return options
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
@ -154,12 +155,6 @@ function normalizeLineItem({
|
|||||||
discounts: [],
|
discounts: [],
|
||||||
options:
|
options:
|
||||||
// By default Shopify adds a default variant with default names, we're removing it. https://community.shopify.com/c/Shopify-APIs-SDKs/Adding-new-product-variant-is-automatically-adding-quot-Default/td-p/358095
|
// By default Shopify adds a default variant with default names, we're removing it. https://community.shopify.com/c/Shopify-APIs-SDKs/Adding-new-product-variant-is-automatically-adding-quot-Default/td-p/358095
|
||||||
variant?.title == 'Default Title'
|
variant?.title == 'Default Title' ? [] : variant?.selectedOptions,
|
||||||
? []
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
value: variant?.title,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,10 @@ export const checkoutDetailsFragment = `
|
|||||||
id
|
id
|
||||||
sku
|
sku
|
||||||
title
|
title
|
||||||
|
selectedOptions {
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
image {
|
image {
|
||||||
originalSrc
|
originalSrc
|
||||||
altText
|
altText
|
||||||
|
@ -48,7 +48,7 @@ export default function Cart() {
|
|||||||
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
||||||
Your cart is empty
|
Your cart is empty
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-accents-6 px-10 text-center pt-2">
|
<p className="text-accent-6 px-10 text-center pt-2">
|
||||||
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -75,7 +75,7 @@ export default function Cart() {
|
|||||||
<div className="px-4 sm:px-6 flex-1">
|
<div className="px-4 sm:px-6 flex-1">
|
||||||
<Text variant="pageHeading">My Cart</Text>
|
<Text variant="pageHeading">My Cart</Text>
|
||||||
<Text variant="sectionHeading">Review your Order</Text>
|
<Text variant="sectionHeading">Review your Order</Text>
|
||||||
<ul className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accents-2 border-b border-accents-2">
|
<ul className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accent-2 border-b border-accent-2">
|
||||||
{data!.lineItems.map((item) => (
|
{data!.lineItems.map((item) => (
|
||||||
<CartItem
|
<CartItem
|
||||||
key={item.id}
|
key={item.id}
|
||||||
@ -93,7 +93,7 @@ export default function Cart() {
|
|||||||
{[1, 2, 3, 4, 5, 6].map((x) => (
|
{[1, 2, 3, 4, 5, 6].map((x) => (
|
||||||
<div
|
<div
|
||||||
key={x}
|
key={x}
|
||||||
className="border border-accents-3 w-full h-24 bg-accents-2 bg-opacity-50 transform cursor-pointer hover:scale-110 duration-75"
|
className="border border-accent-3 w-full h-24 bg-accent-2 bg-opacity-50 transform cursor-pointer hover:scale-110 duration-75"
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -107,7 +107,7 @@ export default function Cart() {
|
|||||||
<>
|
<>
|
||||||
{/* Shipping Address */}
|
{/* Shipping Address */}
|
||||||
{/* Only available with customCheckout set to true - Meaning that the provider does offer checkout functionality. */}
|
{/* Only available with customCheckout set to true - Meaning that the provider does offer checkout functionality. */}
|
||||||
<div className="rounded-md border border-accents-2 px-6 py-6 mb-4 text-center flex items-center justify-center cursor-pointer hover:border-accents-4">
|
<div className="rounded-md border border-accent-2 px-6 py-6 mb-4 text-center flex items-center justify-center cursor-pointer hover:border-accent-4">
|
||||||
<div className="mr-5">
|
<div className="mr-5">
|
||||||
<MapPin />
|
<MapPin />
|
||||||
</div>
|
</div>
|
||||||
@ -121,7 +121,7 @@ export default function Cart() {
|
|||||||
</div>
|
</div>
|
||||||
{/* Payment Method */}
|
{/* Payment Method */}
|
||||||
{/* Only available with customCheckout set to true - Meaning that the provider does offer checkout functionality. */}
|
{/* Only available with customCheckout set to true - Meaning that the provider does offer checkout functionality. */}
|
||||||
<div className="rounded-md border border-accents-2 px-6 py-6 mb-4 text-center flex items-center justify-center cursor-pointer hover:border-accents-4">
|
<div className="rounded-md border border-accent-2 px-6 py-6 mb-4 text-center flex items-center justify-center cursor-pointer hover:border-accent-4">
|
||||||
<div className="mr-5">
|
<div className="mr-5">
|
||||||
<CreditCard />
|
<CreditCard />
|
||||||
</div>
|
</div>
|
||||||
@ -132,7 +132,7 @@ export default function Cart() {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="border-t border-accents-2">
|
<div className="border-t border-accent-2">
|
||||||
<ul className="py-3">
|
<ul className="py-3">
|
||||||
<li className="flex justify-between py-1">
|
<li className="flex justify-between py-1">
|
||||||
<span>Subtotal</span>
|
<span>Subtotal</span>
|
||||||
@ -147,7 +147,7 @@ export default function Cart() {
|
|||||||
<span className="font-bold tracking-wide">FREE</span>
|
<span className="font-bold tracking-wide">FREE</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className="flex justify-between border-t border-accents-2 py-3 font-bold mb-10">
|
<div className="flex justify-between border-t border-accent-2 py-3 font-bold mb-10">
|
||||||
<span>Total</span>
|
<span>Total</span>
|
||||||
<span>{total}</span>
|
<span>{total}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,7 +27,7 @@ export default function Orders() {
|
|||||||
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
||||||
No orders found
|
No orders found
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-accents-6 px-10 text-center pt-2">
|
<p className="text-accent-6 px-10 text-center pt-2">
|
||||||
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -48,7 +48,7 @@ export default function Wishlist() {
|
|||||||
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
||||||
Your wishlist is empty
|
Your wishlist is empty
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-accents-6 px-10 text-center pt-2">
|
<p className="text-accent-6 px-10 text-center pt-2">
|
||||||
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,16 +27,16 @@ module.exports = {
|
|||||||
hover: 'var(--hover)',
|
hover: 'var(--hover)',
|
||||||
'hover-1': 'var(--hover-1)',
|
'hover-1': 'var(--hover-1)',
|
||||||
'hover-2': 'var(--hover-2)',
|
'hover-2': 'var(--hover-2)',
|
||||||
'accents-0': 'var(--accents-0)',
|
'accent-0': 'var(--accent-0)',
|
||||||
'accents-1': 'var(--accents-1)',
|
'accent-1': 'var(--accent-1)',
|
||||||
'accents-2': 'var(--accents-2)',
|
'accent-2': 'var(--accent-2)',
|
||||||
'accents-3': 'var(--accents-3)',
|
'accent-3': 'var(--accent-3)',
|
||||||
'accents-4': 'var(--accents-4)',
|
'accent-4': 'var(--accent-4)',
|
||||||
'accents-5': 'var(--accents-5)',
|
'accent-5': 'var(--accent-5)',
|
||||||
'accents-6': 'var(--accents-6)',
|
'accent-6': 'var(--accent-6)',
|
||||||
'accents-7': 'var(--accents-7)',
|
'accent-7': 'var(--accent-7)',
|
||||||
'accents-8': 'var(--accents-8)',
|
'accent-8': 'var(--accent-8)',
|
||||||
'accents-9': 'var(--accents-9)',
|
'accent-9': 'var(--accent-9)',
|
||||||
violet: 'var(--violet)',
|
violet: 'var(--violet)',
|
||||||
'violet-light': 'var(--violet-light)',
|
'violet-light': 'var(--violet-light)',
|
||||||
pink: 'var(--pink)',
|
pink: 'var(--pink)',
|
||||||
@ -51,7 +51,7 @@ module.exports = {
|
|||||||
secondary: 'var(--text-secondary)',
|
secondary: 'var(--text-secondary)',
|
||||||
},
|
},
|
||||||
boxShadow: {
|
boxShadow: {
|
||||||
'outline-normal': '0 0 0 2px var(--accents-2)',
|
'outline-normal': '0 0 0 2px var(--accent-2)',
|
||||||
magical:
|
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',
|
'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',
|
||||||
},
|
},
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
"@components/*": ["components/*"],
|
"@components/*": ["components/*"],
|
||||||
"@commerce": ["framework/commerce"],
|
"@commerce": ["framework/commerce"],
|
||||||
"@commerce/*": ["framework/commerce/*"],
|
"@commerce/*": ["framework/commerce/*"],
|
||||||
"@framework": ["framework/bigcommerce"],
|
"@framework": ["framework/shopify"],
|
||||||
"@framework/*": ["framework/bigcommerce/*"]
|
"@framework/*": ["framework/shopify/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
|
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user