-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
26 changed files
with
1,285 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { motion } from 'framer-motion'; | ||
|
||
interface FadeInProps { | ||
children: React.ReactNode; | ||
} | ||
|
||
export const FadeIn = ({ children }: FadeInProps) => { | ||
return ( | ||
<motion.div | ||
initial={{ opacity: 0 }} | ||
whileInView={{ opacity: 1 }} | ||
transition={{ duration: 1, ease: 'easeIn' }} | ||
> | ||
{children} | ||
</motion.div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { motion } from 'framer-motion'; | ||
import { Fragment } from 'react'; | ||
|
||
interface SlideInCharacters { | ||
text: string; | ||
} | ||
|
||
export const SlideInCharacters = ({ text }: SlideInCharacters) => { | ||
const characters = text.split(''); | ||
|
||
return ( | ||
<Fragment> | ||
{characters.map((character, index) => { | ||
if (character === ' ') { | ||
return ( | ||
<motion.span | ||
key={index} | ||
className="inline-block w-4" | ||
initial={{ x: 100, opacity: 0 }} | ||
whileInView={{ x: 0, opacity: 1 }} | ||
viewport={{ once: true }} | ||
transition={{ | ||
duration: 0.1, | ||
delay: 0.5 + index * 0.05, | ||
ease: 'easeOut', | ||
}} | ||
/> | ||
); | ||
} | ||
|
||
return ( | ||
<motion.span | ||
className="inline-block" | ||
initial={{ x: 100, opacity: 0 }} | ||
whileInView={{ x: 0, opacity: 1 }} | ||
transition={{ duration: 0.5, delay: 0.5 + index * 0.1 }} | ||
> | ||
{character} | ||
</motion.span> | ||
); | ||
})} | ||
</Fragment> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { useCart } from '@/context/cart-context'; | ||
import { Dialog, Transition } from '@headlessui/react'; | ||
import { useEffect, Fragment } from 'react'; | ||
import { CartSummary } from './cart-summary'; | ||
import { EmptyCart } from './empty-cart'; | ||
import { useLenis } from '@/context/lenis-context'; | ||
|
||
interface CartModalProps { | ||
isOpen: boolean; | ||
closeCart: () => void; | ||
} | ||
|
||
export const CartModal = ({ isOpen, closeCart }: CartModalProps) => { | ||
const lenis = useLenis(); | ||
const { totalCartItems } = useCart(); | ||
|
||
useEffect(() => { | ||
if (isOpen) { | ||
lenis?.stop(); | ||
} | ||
|
||
if (!isOpen) { | ||
lenis?.start(); | ||
} | ||
}, [isOpen]); | ||
|
||
return ( | ||
<Transition appear show={isOpen} as={Fragment}> | ||
<Dialog onClose={closeCart} className="relative z-50" as="div"> | ||
<Overlay /> | ||
<div className="fixed bottom-0 top-auto h-[500px] w-full lg:right-10 lg:bottom-auto lg:top-10 lg:max-w-sm"> | ||
<Transition.Child | ||
as={Fragment} | ||
enterTo="opacity-100" | ||
leaveFrom="opacity-100" | ||
enter="ease duration-500" | ||
leave="ease-in duration-300" | ||
leaveTo="opacity-0 lg:translate-x-10 lg:-translate-y-10 translate-y-10" | ||
enterFrom="opacity-0 lg:translate-x-10 lg:-translate-y-10 translate-y-10" | ||
> | ||
<Dialog.Panel className="h-full w-full rounded-t-2xl border border-white border-opacity-20 bg-noir p-4 lg:rounded-none"> | ||
{totalCartItems > 0 ? <CartSummary /> : <EmptyCart />} | ||
</Dialog.Panel> | ||
</Transition.Child> | ||
</div> | ||
</Dialog> | ||
</Transition> | ||
); | ||
}; | ||
|
||
const Overlay = () => { | ||
return ( | ||
<Transition.Child | ||
as={Fragment} | ||
leaveTo="opacity-0" | ||
enterTo="opacity-100" | ||
enterFrom="opacity-0" | ||
leaveFrom="opacity-100" | ||
leave="ease-in duration-300" | ||
enter="linear duration-500" | ||
> | ||
<div className="linear fixed inset-0 bg-white bg-opacity-20 backdrop-blur-sm transition-all duration-500" /> | ||
</Transition.Child> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import Link from 'next/link'; | ||
import { Minus, Plus, Crosshair, X } from 'react-feather'; | ||
import { useCart } from '@/context/cart-context'; | ||
import { LineItem } from '@medusajs/medusa'; | ||
import Image from 'next/image'; | ||
|
||
export const CartSummary = () => { | ||
const { cart } = useCart(); | ||
|
||
return ( | ||
<div className="flex h-full w-full flex-col gap-4"> | ||
<div className="track w-full border-b border-white border-opacity-20 pb-2 text-center font-alt-sans text-sm uppercase opacity-80"> | ||
<h3>Shopping Cart</h3> | ||
</div> | ||
|
||
<div className="scrollbar-hide flex grow flex-col gap-4 overflow-y-auto"> | ||
{cart?.items.map((item) => { | ||
return <CartItem key={item.id} item={item} />; | ||
})} | ||
</div> | ||
|
||
<div className="mt-auto w-full"> | ||
<div className="flex w-full items-center justify-between py-2 font-alt-sans text-sm uppercase"> | ||
<span>Total</span> | ||
<span>${((cart?.total || 0) / 100).toFixed(2)}</span> | ||
</div> | ||
<Link href="/checkout"> | ||
<a className="flex w-full items-center justify-center border border-white border-opacity-50 p-2 text-center text-xs uppercase duration-300 hover:border-monster-green-300 hover:text-monster-green-300"> | ||
<span>Continue To Checkout</span> | ||
</a> | ||
</Link> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
interface CartItemProps { | ||
item: LineItem; | ||
} | ||
|
||
const CartItem = ({ item }: CartItemProps) => { | ||
const { addItem, removeItem, updateItem } = useCart(); | ||
const itemQuantity = item.quantity; | ||
|
||
const handleRemoveItem = () => { | ||
removeItem(item.id); | ||
}; | ||
|
||
const decreaseQuantity = () => { | ||
if (itemQuantity > 1) { | ||
updateItem({ | ||
lineId: item.id, | ||
quantity: itemQuantity - 1, | ||
}); | ||
} else { | ||
removeItem(item.id); | ||
} | ||
}; | ||
|
||
const increaseQuantity = () => { | ||
updateItem({ | ||
lineId: item.id, | ||
quantity: itemQuantity + 1, | ||
}); | ||
}; | ||
|
||
return ( | ||
<div> | ||
<div className="flex items-center justify-between gap-4 font-alt-sans text-white text-opacity-90"> | ||
<div className="flex h-[80px] w-[80px] shrink-0 items-center justify-center border-white border-opacity-20 bg-white bg-opacity-10"> | ||
<Image src={item.thumbnail || ''} width={20} height={50} /> | ||
</div> | ||
|
||
<div className="flex grow flex-col gap-2 text-sm"> | ||
<div className="text-sm">{item.title}</div> | ||
<div className="flex items-center gap-4 text-xs"> | ||
<div>${(item.unit_price / 100).toFixed(2)}</div> | ||
|
||
<div className="flex divide-x divide-white divide-opacity-20 border border-white border-opacity-20"> | ||
<button | ||
onClick={decreaseQuantity} | ||
className="flex items-center justify-center p-1" | ||
> | ||
<Minus size={16} className="" /> | ||
</button> | ||
<div className="flex items-center justify-center p-1 px-2"> | ||
<span> {item.quantity}</span> | ||
</div> | ||
<button | ||
onClick={increaseQuantity} | ||
className="flex items-center justify-center p-1" | ||
> | ||
<Plus size={16} /> | ||
</button> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div> | ||
<button | ||
onClick={handleRemoveItem} | ||
className="text-xs uppercase underline hover:text-monster-green-300" | ||
> | ||
<span className="sr-only">Remove Item</span> | ||
<X size={24} strokeWidth={1} /> | ||
</button> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import Link from 'next/link'; | ||
|
||
export const EmptyCart = () => { | ||
return ( | ||
<div className="flex h-full w-full flex-col items-center justify-center gap-4 border border-white border-opacity-10"> | ||
<p className="text-lg uppercase">Your cart is empty 👀</p> | ||
<Link href="/shop"> | ||
<a className="border border-white border-opacity-70 py-2 px-4 text-center text-sm uppercase duration-300 hover:border-monster-green-300 hover:text-monster-green-300"> | ||
Explore the Shop | ||
</a> | ||
</Link> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { CartModal } from './cart-modal'; | ||
import { useCart } from '@/context/cart-context'; | ||
import { useState, useEffect, useRef, Fragment } from 'react'; | ||
|
||
export const CartButton = () => { | ||
const { totalCartItems } = useCart(); | ||
const [isOpen, setIsOpen] = useState(false); | ||
|
||
const openCart = () => setIsOpen(true); | ||
|
||
const closeCart = () => setIsOpen(false); | ||
|
||
return ( | ||
<Fragment> | ||
<button | ||
onClick={openCart} | ||
className={`font-alt-sans text-xs uppercase tracking-widest opacity-80 ${ | ||
isOpen && 'pointer-events-none' | ||
}`} | ||
> | ||
Cart [{totalCartItems}] | ||
</button> | ||
<CartModal isOpen={isOpen} closeCart={closeCart} /> | ||
</Fragment> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { ProductCard } from './product-card'; | ||
import { NavBar } from './nav-bar'; | ||
|
||
export { ProductCard, NavBar }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { ProductCollection } from '@medusajs/medusa'; | ||
import Link from 'next/link'; | ||
import { useRouter } from 'next/router'; | ||
|
||
interface NavBarProps { | ||
collections: ProductCollection[]; | ||
} | ||
|
||
export const NavBar = ({ collections }: NavBarProps) => { | ||
const router = useRouter(); | ||
|
||
const currentCollection = router.asPath.split('/')[3]; | ||
const isCollectionPage = router.asPath.includes('/collections/'); | ||
|
||
return ( | ||
<div className="md:scrollbar-hide overflow-scroll"> | ||
<div className="flex w-fit items-center divide-x divide-white divide-opacity-10 border border-white border-opacity-10 font-alt-sans text-sm uppercase"> | ||
<Link href="/shop"> | ||
<a | ||
className={`whitespace-nowrap px-4 py-1 ${ | ||
!isCollectionPage && 'bg-white bg-opacity-10' | ||
}`} | ||
> | ||
All | ||
</a> | ||
</Link> | ||
{collections.map((collection) => { | ||
return ( | ||
<Link | ||
href={`/shop/collections/${collection.handle}`} | ||
key={collection.id} | ||
> | ||
<a | ||
className={`whitespace-nowrap px-4 py-1 ${ | ||
currentCollection === collection.handle && | ||
'bg-white bg-opacity-10' | ||
}`} | ||
> | ||
{collection.title} | ||
</a> | ||
</Link> | ||
); | ||
})} | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import Image from 'next/image'; | ||
import Link from 'next/link'; | ||
import { Product as MedusaProduct } from '@medusajs/medusa'; | ||
import { formatPrice } from '@/utils/format-price'; | ||
|
||
interface ProductCardProps { | ||
product: MedusaProduct; | ||
} | ||
|
||
export const ProductCard = ({ product }: ProductCardProps) => { | ||
const { title, thumbnail, handle, variants } = product; | ||
const price = variants[0]?.prices[0]; | ||
|
||
return ( | ||
<Link href={`/shop/${handle}`} key={handle}> | ||
<a className="group flex items-center justify-center bg-lotion bg-opacity-5 p-4 pt-6 font-alt-sans"> | ||
<div className="flex flex-col gap-4"> | ||
<div className="flex items-center justify-center py-3"> | ||
<div className="pointer-events-none w-28 border-opacity-20 duration-500 ease-in-out group-hover:scale-105"> | ||
<Image src={thumbnail || ''} width={300} height={700} /> | ||
</div> | ||
</div> | ||
<div className="flex grow flex-col items-center gap-2 pt-3 text-center font-alt-sans text-sm duration-500 group-hover:text-monster-green-300 group-hover:opacity-100"> | ||
<div className="capitalize lg:text-lg">{title}</div> | ||
<div className="mt-auto w-fit border border-lotion border-opacity-10 bg-white bg-opacity-5 p-2 px-4 font-alt-sans text-xs backdrop-blur-md"> | ||
{formatPrice(price)} | ||
</div> | ||
</div> | ||
</div> | ||
</a> | ||
</Link> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
interface ContainerProps { | ||
children: React.ReactNode; | ||
className?: string; | ||
} | ||
|
||
export const Container = ({ children, className }: ContainerProps) => { | ||
return ( | ||
<div | ||
className={`mx-auto w-full max-w-screen-2xl px-4 xl:px-8 ${className}`} | ||
> | ||
{children} | ||
</div> | ||
); | ||
}; |
Oops, something went wrong.