add category section
This commit is contained in:
@@ -1,34 +1,151 @@
|
||||
"use client"
|
||||
|
||||
import { Card, CardContent } from "@/components/UI/card"
|
||||
import {Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious} from "@/components/UI/Carousel";
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/UI/Carousel"
|
||||
import { categories } from "@/data/mockCategories"
|
||||
import Image from "next/image"
|
||||
import {easeOut, motion} from "framer-motion"
|
||||
|
||||
type Props = {
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export function CarouselComponent() {
|
||||
const containerVariants = {
|
||||
hidden: {},
|
||||
show: {
|
||||
transition: {
|
||||
staggerChildren: 0.08,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const itemVariants = {
|
||||
hidden: {
|
||||
opacity: 0,
|
||||
y: 30,
|
||||
scale: 0.95,
|
||||
},
|
||||
show: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
transition: {
|
||||
duration: 0.4,
|
||||
ease: easeOut,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export function CarouselComponent({ title, description }: Props) {
|
||||
return (
|
||||
<Carousel
|
||||
dir={"rtl"}
|
||||
className="w-full"
|
||||
opts={{
|
||||
direction: "rtl",
|
||||
}}
|
||||
>
|
||||
<CarouselContent>
|
||||
{Array.from({ length: 150 }).map((_, index) => (
|
||||
<CarouselItem key={index} className="basis-1/3">
|
||||
<div className="p-1">
|
||||
<Card dir={"rtl"}>
|
||||
<CardContent className="flex aspect-square items-center justify-center p-6">
|
||||
hello
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious />
|
||||
<CarouselNext />
|
||||
</Carousel>
|
||||
<div className="relative w-full">
|
||||
|
||||
<Carousel dir="rtl" className="w-full" opts={{ direction: "rtl" }}>
|
||||
|
||||
{/* 🔥 Animated Header */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 40 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.6 }}
|
||||
className="flex items-center justify-between w-full h-full my-5"
|
||||
>
|
||||
<span className="flex items-center justify-center gap-x-2">
|
||||
<motion.div
|
||||
initial={{ height: 0 }}
|
||||
animate={{ height: 64 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="bg-primary-100 w-4 rounded-2xl rounded-tr-none"
|
||||
/>
|
||||
<div>
|
||||
<p className="text-lg font-semibold">{title}</p>
|
||||
<p className="text-muted-foreground">{description}</p>
|
||||
</div>
|
||||
</span>
|
||||
</motion.div>
|
||||
|
||||
{/* 🔥 Animated Carousel Items */}
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
>
|
||||
<CarouselContent>
|
||||
{categories.map((category) => (
|
||||
<CarouselItem
|
||||
key={category.id}
|
||||
className="
|
||||
md:basis-1/5
|
||||
lg:basis-1/7
|
||||
relative
|
||||
after:content-['']
|
||||
after:absolute
|
||||
after:top-1/2
|
||||
after:-translate-y-1/2
|
||||
after:left-2
|
||||
after:w-px
|
||||
after:h-[50%]
|
||||
after:bg-border
|
||||
last:after:hidden
|
||||
"
|
||||
>
|
||||
<motion.div variants={itemVariants} className="p-1">
|
||||
<motion.div
|
||||
whileHover={{
|
||||
scale: 1.05,
|
||||
y: -5,
|
||||
}}
|
||||
transition={{ type: "spring", stiffness: 300 }}
|
||||
>
|
||||
<Card dir="rtl" className="transition-shadow hover:shadow-xl cursor-pointer">
|
||||
<CardContent className="flex flex-col gap-3 h-30 items-center justify-center p-6">
|
||||
<motion.div
|
||||
whileHover={{ rotate: 5 }}
|
||||
transition={{ type: "spring", stiffness: 200 }}
|
||||
>
|
||||
<Image
|
||||
src={category.image}
|
||||
alt={category.title}
|
||||
width={80}
|
||||
height={80}
|
||||
className="rounded-full"
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
<p className="font-semibold text-text-muted">
|
||||
{category.title}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
</motion.div>
|
||||
|
||||
{/* 🔥 Animated Controls */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.5 }}
|
||||
className="absolute top-10 left-16 flex gap-2"
|
||||
>
|
||||
<motion.div whileTap={{ scale: 0.85 }}>
|
||||
<CarouselPrevious />
|
||||
</motion.div>
|
||||
<motion.div whileTap={{ scale: 0.85 }}>
|
||||
<CarouselNext />
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
</Carousel>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import {CarouselComponent} from "./CarouselComponent";
|
||||
import { CarouselComponent } from "./CarouselComponent"
|
||||
import { useTranslations } from "next-intl"
|
||||
|
||||
const Categories = () => {
|
||||
const t = useTranslations("Categories")
|
||||
|
||||
return (
|
||||
<>
|
||||
<CarouselComponent />
|
||||
</>
|
||||
<div className="container mx-auto my-16">
|
||||
<CarouselComponent
|
||||
title={t("title")}
|
||||
description={t("description")}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Categories;
|
||||
|
||||
export default Categories
|
||||
|
||||
@@ -7,7 +7,7 @@ import useEmblaCarousel, {
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/UI/button"
|
||||
import {ChevronIcon} from "@/assets";
|
||||
import {ArrowLeft, ArrowRight, ChevronIcon} from "@/assets";
|
||||
|
||||
type CarouselApi = UseEmblaCarouselType[1]
|
||||
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
|
||||
@@ -138,7 +138,7 @@ function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
ref={carouselRef}
|
||||
className="overflow-hidden"
|
||||
className="overflow-hidden border border-text-primary/10 p-1 rounded-2xl"
|
||||
data-slot="carousel-content"
|
||||
>
|
||||
<div
|
||||
@@ -185,7 +185,7 @@ function CarouselPrevious({
|
||||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"rounded-full absolute touch-manipulation",
|
||||
"rounded-xl p-5 absolute touch-manipulation bg-card border border-primary-300",
|
||||
orientation === "horizontal"
|
||||
? "top-1/2 -left-12 -translate-y-1/2"
|
||||
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
@@ -195,7 +195,7 @@ function CarouselPrevious({
|
||||
onClick={scrollPrev}
|
||||
{...props}
|
||||
>
|
||||
<ChevronIcon className="cn-rtl-flip" />
|
||||
<ArrowLeft className="text-text-primary" />
|
||||
<span className="sr-only">Previous slide</span>
|
||||
</Button>
|
||||
)
|
||||
@@ -215,7 +215,7 @@ function CarouselNext({
|
||||
variant={variant}
|
||||
size={size}
|
||||
className={cn(
|
||||
"rounded-full absolute touch-manipulation",
|
||||
"rounded-xl p-5 absolute touch-manipulation bg-card border-primary-300",
|
||||
orientation === "horizontal"
|
||||
? "top-1/2 -right-12 -translate-y-1/2"
|
||||
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
@@ -225,7 +225,7 @@ function CarouselNext({
|
||||
onClick={scrollNext}
|
||||
{...props}
|
||||
>
|
||||
<ChevronIcon className="cn-rtl-flip rotate-180" />
|
||||
<ArrowRight className="text-text-primary size-5" />
|
||||
<span className="sr-only">Next slide</span>
|
||||
</Button>
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ function Card({
|
||||
<div
|
||||
data-slot="card"
|
||||
data-size={size}
|
||||
className={cn("ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-xl py-4 text-sm ring-1 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl group/card flex flex-col", className)}
|
||||
className={cn("ring-foreground/10 text-card-foreground gap-4 overflow-hidden rounded-xl py-4 text-sm has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl group/card flex flex-col", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user