mirror of
https://github.com/vercel/commerce.git
synced 2025-07-23 04:36:49 +00:00
Ported more functionality
This commit is contained in:
@@ -1,117 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import {
|
||||
CarouselItemProps as ItemProps,
|
||||
CarouselProps as Props,
|
||||
} from 'components/ui/carousel/carousel'
|
||||
import dynamic from 'next/dynamic'
|
||||
const Carousel = dynamic<Props>(() =>
|
||||
import('components/ui/carousel/carousel').then((mod) => mod.Carousel)
|
||||
)
|
||||
const CarouselItem = dynamic<ItemProps>(() =>
|
||||
import('components/ui/carousel/carousel').then((mod) => mod.CarouselItem)
|
||||
)
|
||||
const Card = dynamic(() => import('components/ui/card'))
|
||||
|
||||
import Text from 'components/ui/text'
|
||||
|
||||
interface BlurbSectionProps {
|
||||
blurbs: any
|
||||
title: string
|
||||
mobileLayout: string
|
||||
desktopLayout: string
|
||||
imageFormat: 'square' | 'portrait' | 'landscape'
|
||||
}
|
||||
|
||||
const BlurbSection = ({
|
||||
title,
|
||||
mobileLayout,
|
||||
desktopLayout,
|
||||
blurbs,
|
||||
imageFormat,
|
||||
}: BlurbSectionProps) => {
|
||||
const gridLayout =
|
||||
desktopLayout === '2-column'
|
||||
? 'lg:grid-cols-2'
|
||||
: desktopLayout === '3-column'
|
||||
? 'lg:grid-cols-3'
|
||||
: 'lg:grid-cols-4'
|
||||
|
||||
const sliderLayout =
|
||||
desktopLayout === '2-column' ? 2 : desktopLayout === '3-column' ? 3 : 4
|
||||
|
||||
return (
|
||||
<div>
|
||||
{title ? (
|
||||
<Text
|
||||
className="mb-4 px-4 lg:px-8 lg:mb-6 2xl:px-16 2xl:mb-8"
|
||||
variant="sectionHeading"
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
) : (
|
||||
<Text
|
||||
className="italic mb-4 px-4 lg:px-8 lg:mb-6 2xl:px-16 2xl:mb-8"
|
||||
variant="sectionHeading"
|
||||
>
|
||||
No title provided yet
|
||||
</Text>
|
||||
)}
|
||||
<div
|
||||
className={`px-4 grid ${gridLayout} gap-x-4 gap-y-8 ${
|
||||
mobileLayout === 'stacked' ? 'lg:hidden' : 'hidden'
|
||||
} lg:px-8 2xl:!px-16`}
|
||||
>
|
||||
{blurbs.map((blurb: object | any, index: number) => {
|
||||
return (
|
||||
<div key={index}>
|
||||
<Card
|
||||
title={blurb?.title}
|
||||
link={blurb?.link}
|
||||
image={blurb?.image}
|
||||
text={blurb?.text}
|
||||
imageFormat={blurb?.imageFormat}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`${
|
||||
mobileLayout === 'stacked' ? 'hidden lg:block' : 'block'
|
||||
}`}
|
||||
>
|
||||
{blurbs && (
|
||||
<Carousel
|
||||
gliderClasses={'px-4 lg:px-8 2xl:px-16'}
|
||||
gliderItemWrapperClasses={'space-x-2 lg:space-x-4'}
|
||||
hasDots={true}
|
||||
slidesToShow={2.2}
|
||||
responsive={{
|
||||
breakpoint: 1024,
|
||||
settings: {
|
||||
slidesToShow:
|
||||
sliderLayout <= 4 ? sliderLayout + 0.5 : sliderLayout,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{blurbs.map((blurb: any, index: number) => (
|
||||
<CarouselItem key={`${index}`}>
|
||||
<Card
|
||||
title={blurb?.title}
|
||||
link={blurb?.link}
|
||||
image={blurb?.image}
|
||||
text={blurb.text}
|
||||
imageFormat={imageFormat}
|
||||
/>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</Carousel>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BlurbSection
|
@@ -1,2 +0,0 @@
|
||||
export { default } from './blurb-section';
|
||||
|
@@ -1,62 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import 'glider-js/glider.min.css'
|
||||
import { ArrowLeft, ArrowRight } from 'lucide-react'
|
||||
import React from 'react'
|
||||
import Glider from 'react-glider'
|
||||
|
||||
export interface CarouselItemProps {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export const CarouselItem: React.FC<CarouselItemProps> = ({
|
||||
children,
|
||||
}: CarouselItemProps) => {
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
export interface CarouselProps {
|
||||
children: JSX.Element | JSX.Element[] | any
|
||||
gliderClasses?: string
|
||||
hasArrows?: boolean
|
||||
hasDots?: boolean
|
||||
gliderItemWrapperClasses?: string
|
||||
slidesToShow?: number
|
||||
slidesToScroll?: number
|
||||
responsive?: any
|
||||
}
|
||||
|
||||
export const Carousel: React.FC<CarouselProps> = ({
|
||||
children,
|
||||
gliderClasses,
|
||||
hasArrows = true,
|
||||
hasDots = true,
|
||||
gliderItemWrapperClasses,
|
||||
slidesToShow = 1,
|
||||
slidesToScroll = 1,
|
||||
responsive,
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<Glider
|
||||
className={`flex !w-full relative ${gliderClasses}`}
|
||||
draggable
|
||||
slidesToShow={slidesToShow}
|
||||
scrollLock
|
||||
slidesToScroll={slidesToScroll}
|
||||
hasArrows={hasArrows}
|
||||
hasDots={hasDots}
|
||||
iconLeft={<ArrowLeft className="stroke-current" />}
|
||||
iconRight={<ArrowRight className="stroke-current" />}
|
||||
responsive={[responsive]}
|
||||
skipTrack
|
||||
>
|
||||
<div className={`flex ${gliderItemWrapperClasses} `}>
|
||||
{React.Children.map(children, (child) => {
|
||||
return React.cloneElement(child)
|
||||
})}
|
||||
</div>
|
||||
</Glider>
|
||||
</div>
|
||||
)
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { Info } from 'lucide-react'
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
import Hero from 'components/ui/hero'
|
||||
const Slider = dynamic(() => import('components/ui/slider'))
|
||||
const BlurbSection = dynamic(() => import('components/ui/blurb-section'))
|
||||
const FilteredProductList = dynamic(
|
||||
() => import('components/ui/filtered-product-list')
|
||||
)
|
||||
|
||||
interface getContentComponentProps {
|
||||
_type: string
|
||||
_key: number
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
const getContentComponent = ({
|
||||
_type,
|
||||
_key,
|
||||
disabled,
|
||||
...rest
|
||||
}: getContentComponentProps) => {
|
||||
let Component: any
|
||||
|
||||
switch (_type) {
|
||||
case 'hero':
|
||||
Component = Hero
|
||||
break
|
||||
case 'slider':
|
||||
Component = Slider
|
||||
break
|
||||
case 'filteredProductList':
|
||||
Component = FilteredProductList
|
||||
break
|
||||
case 'blurbSection':
|
||||
if (disabled !== true) {
|
||||
Component = BlurbSection
|
||||
} else {
|
||||
return
|
||||
}
|
||||
break
|
||||
default:
|
||||
return (
|
||||
<div
|
||||
className={`px-4 lg:px-8 2xl:px-16 ${
|
||||
process.env.NODE_ENV === 'production' ? 'hidden' : ''
|
||||
}`}
|
||||
key={`index-${_key}`}
|
||||
>
|
||||
<span className="inline-flex items-center bg-red font-bold p-2 text-sm">
|
||||
<Info className="mr-1" />
|
||||
{`No matching component (Type: ${_type})`}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return Component ? (
|
||||
<Component key={`index-${_key}`} {...rest} />
|
||||
) : (
|
||||
<div key={`index-${_key}`}>Something else</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface dynamicContentManagerProps {
|
||||
content: [] | any
|
||||
}
|
||||
|
||||
const DynamicContentManager = ({ content }: dynamicContentManagerProps) => {
|
||||
return (
|
||||
<div className="dynamic-content overflow-x-hidden">
|
||||
{content?.map(getContentComponent)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DynamicContentManager
|
@@ -1,2 +0,0 @@
|
||||
export { default } from './dynamic-content-manager';
|
||||
|
@@ -1,35 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import Text from 'components/ui/text'
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
const ProductCard = dynamic(() => import('components/ui/product-card'))
|
||||
|
||||
interface SliderProps {
|
||||
products: any
|
||||
title: string
|
||||
itemsToShow: number
|
||||
}
|
||||
|
||||
const FilteredProductList = ({ title, products, itemsToShow }: SliderProps) => {
|
||||
return (
|
||||
<div className="px-4 lg:px-8 2xl:px-16">
|
||||
{title ? (
|
||||
<Text className="mb-4 lg:mb-6 2xl:mb-8" variant="sectionHeading">
|
||||
{title}
|
||||
</Text>
|
||||
) : (
|
||||
<Text className="italic mb-4 lg:mb-6 2xl:mb-8" variant="sectionHeading">
|
||||
No title provided yet
|
||||
</Text>
|
||||
)}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{products.slice(0, itemsToShow).map((product: any, index: number) => (
|
||||
<ProductCard key={`${product.id}-${index}`} product={product} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FilteredProductList
|
@@ -1,2 +0,0 @@
|
||||
export { default } from './filtered-product-list';
|
||||
|
@@ -1,82 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
const SanityImage = dynamic(() => import('components/ui/sanity-image'))
|
||||
const Link = dynamic(() => import('components/ui/link'))
|
||||
const Text = dynamic(() => import('components/ui/text'))
|
||||
|
||||
interface HeroProps {
|
||||
variant: string
|
||||
text?: string
|
||||
label?: string
|
||||
title: string
|
||||
image: object | any
|
||||
desktopImage: object | any
|
||||
link: {
|
||||
title: string
|
||||
reference: {
|
||||
title: string
|
||||
slug: {
|
||||
current: string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type HeroSize = keyof typeof heroSize
|
||||
|
||||
const heroSize = {
|
||||
fullScreen: 'aspect-[3/4] lg:aspect-auto lg:h-[calc(100vh-4rem)]',
|
||||
halfScreen: 'aspect-square max-h-[60vh] lg:aspect-auto lg:min-h-[60vh]',
|
||||
}
|
||||
|
||||
const Hero = ({ variant, title, text, label, image, link }: HeroProps) => {
|
||||
const heroClass = heroSize[variant as HeroSize] || heroSize.fullScreen
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative w-screen ${heroClass} flex flex-col justify-end relative text-high-contrast`}
|
||||
>
|
||||
{image && (
|
||||
<SanityImage
|
||||
image={image}
|
||||
alt={image.alt}
|
||||
priority={true}
|
||||
width={1200}
|
||||
height={600}
|
||||
className="absolute inset-0 h-full w-full object-cover z-10"
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col items-start text-high-contrast absolute max-w-sm z-40 left-4 bottom-5 lg:max-w-xl lg:bottom-8 lg:left-8 2xl:left-16 2xl:bottom-16">
|
||||
{label && (
|
||||
<Text className="mb-1 lg:mb-2" variant="label">
|
||||
{label}
|
||||
</Text>
|
||||
)}
|
||||
{title ? (
|
||||
<Text variant="heading">{title}</Text>
|
||||
) : (
|
||||
<Text variant="heading" className="italic">
|
||||
No title provided yet
|
||||
</Text>
|
||||
)}
|
||||
{text && (
|
||||
<Text className="mt-4" variant="paragraph">
|
||||
{label}
|
||||
</Text>
|
||||
)}
|
||||
{link?.reference && (
|
||||
<Link
|
||||
className="inline-flex transition bg-high-contrast text-white text-base py-4 px-10 mt-6 hover:bg-low-contrast lg:mt-8"
|
||||
href={link.reference.slug.current}
|
||||
>
|
||||
{link?.title ? link.title : link.reference.title}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Hero
|
@@ -1,2 +0,0 @@
|
||||
export { default } from './hero';
|
||||
|
@@ -27,7 +27,7 @@ const ProductCard: FC<Props> = ({
|
||||
}) => {
|
||||
|
||||
const rootClassName = cn(
|
||||
'w-full group relative overflow-hidden transition-transform ease-linear',
|
||||
'w-full group relative overflow-hidden',
|
||||
className
|
||||
)
|
||||
|
||||
@@ -39,7 +39,7 @@ const ProductCard: FC<Props> = ({
|
||||
locale={product.locale}
|
||||
>
|
||||
{variant === 'default' && (
|
||||
<div className={'flex flex-col justify-center w-full h-full'}>
|
||||
<div className={'flex flex-col relative justify-center w-full h-full'}>
|
||||
|
||||
<WishlistButton
|
||||
className={'top-4 right-4 z-10 absolute'}
|
||||
@@ -48,13 +48,11 @@ const ProductCard: FC<Props> = ({
|
||||
product?.variants ? (product.variants[0] as any) : null
|
||||
}
|
||||
/>
|
||||
<div className="w-full h-full aspect-square overflow-hidden relative">
|
||||
<div className="w-full h-full overflow-hidden relative">
|
||||
{product?.images && (
|
||||
<SanityImage
|
||||
image={product?.images[0]}
|
||||
alt={product.title || 'Product Image'}
|
||||
width={400}
|
||||
height={400}
|
||||
sizes="(max-width: 1024px) 50vw, 20vw"
|
||||
/>
|
||||
)}
|
||||
|
@@ -1,2 +0,0 @@
|
||||
export { default } from './product-tag';
|
||||
|
@@ -1,48 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { cn } from 'lib/utils'
|
||||
import dynamic from 'next/dynamic'
|
||||
const Text = dynamic(() => import('components/ui/text'))
|
||||
|
||||
interface ProductTagProps {
|
||||
className?: string
|
||||
name: string
|
||||
price: string
|
||||
variant?: 'productView' | 'cardView'
|
||||
}
|
||||
|
||||
const ProductTag: React.FC<ProductTagProps> = ({
|
||||
name,
|
||||
price,
|
||||
className = '',
|
||||
variant = 'cardView',
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={cn('text-high-contrast flex items-start flex-col', className)}
|
||||
>
|
||||
<Text
|
||||
className={
|
||||
variant === 'cardView'
|
||||
? ''
|
||||
: '!text-[32px] !leading-[32px] !font-normal'
|
||||
}
|
||||
variant={variant === 'cardView' ? 'listChildHeading' : 'pageHeading'}
|
||||
>
|
||||
{name}
|
||||
</Text>
|
||||
<Text
|
||||
className={
|
||||
variant === 'cardView'
|
||||
? '!text-sm !font-semibold !leading-tight lg:!text-base'
|
||||
: '!font-bold !text-[32px] !leading-[32px]'
|
||||
}
|
||||
variant="paragraph"
|
||||
>
|
||||
{price}
|
||||
</Text>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProductTag
|
@@ -1 +0,0 @@
|
||||
export { default } from './Slider'
|
@@ -1,74 +0,0 @@
|
||||
import {
|
||||
CarouselItemProps as ItemProps,
|
||||
CarouselProps as Props,
|
||||
} from 'components/ui/carousel/carousel'
|
||||
import Text from 'components/ui/text'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useEffect, useState } from 'react'
|
||||
const Carousel = dynamic<Props>(() =>
|
||||
import('components/ui/carousel/carousel').then((mod) => mod.Carousel)
|
||||
)
|
||||
const CarouselItem = dynamic<ItemProps>(() =>
|
||||
import('components/ui/carousel/carousel').then((mod) => mod.CarouselItem)
|
||||
)
|
||||
const ProductCard = dynamic(() => import('components/ui/product-card'))
|
||||
const CategoryCard = dynamic(() => import('components/ui/category-card'))
|
||||
|
||||
interface SliderProps {
|
||||
products: [] | any
|
||||
title: string
|
||||
categories: [] | any
|
||||
sliderType: String
|
||||
}
|
||||
|
||||
const Slider = ({ products, categories, title, sliderType }: SliderProps) => {
|
||||
const [items, setItems] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
if (sliderType === 'products') setItems(products)
|
||||
else if (sliderType === 'categories') setItems(categories)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
{title ? (
|
||||
<Text
|
||||
className="mb-4 px-4 lg:px-8 lg:mb-6 2xl:px-16 2xl:mb-8"
|
||||
variant="sectionHeading"
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
) : (
|
||||
<Text
|
||||
className="italic mb-4 px-4 lg:px-8 lg:mb-6 2xl:px-16 2xl:mb-8"
|
||||
variant="sectionHeading"
|
||||
>
|
||||
No title provided yet
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{items && (
|
||||
<Carousel
|
||||
gliderClasses={'px-4 lg:px-8 2xl:px-16'}
|
||||
gliderItemWrapperClasses={'space-x-2 lg:space-x-4'}
|
||||
slidesToShow={2.2}
|
||||
responsive={{
|
||||
breakpoint: 1024,
|
||||
settings: {
|
||||
slidesToShow: 4.5
|
||||
},
|
||||
}}
|
||||
>
|
||||
{items.map((item: any, index: number) => (
|
||||
<CarouselItem key={`${sliderType}-${index}`}>
|
||||
{sliderType === 'products' && <ProductCard product={item} />}
|
||||
{sliderType === 'categories' && <CategoryCard category={item} />}
|
||||
</CarouselItem>
|
||||
))}
|
||||
</Carousel>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Slider
|
Reference in New Issue
Block a user