Files
mr_decor/components/sections/feature/feature-carousel-grid.tsx

137 lines
5.0 KiB
TypeScript

"use client";
import { ArrowRight, ChevronDown } from "lucide-react";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";
import type { CarouselApi } from "@/components/ui/carousel";
import {
Carousel,
CarouselContent,
CarouselItem,
} from "@/components/ui/carousel";
const features = [
{
id: "feature-1",
title: "Feature 1",
description:
"Nam vitae molestie arcu. Quisque eu libero orci. Aliquam imperdiet magna nec massa consectetur, id interdum ante congue.",
href: "#",
image: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/placeholder-1.svg",
},
{
id: "feature-2",
title: "Feature 2",
description:
"Nam vitae molestie arcu. Quisque eu libero orci. Aliquam imperdiet magna nec massa consectetur, id interdum ante congue.",
href: "#",
image: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/placeholder-2.svg",
},
{
id: "feature-3",
title: "Feature 3",
description:
"Nam vitae molestie arcu. Quisque eu libero orci. Aliquam imperdiet magna nec massa consectetur, id interdum ante congue.",
href: "#",
image: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/placeholder-3.svg",
},
];
interface FeatureCarouselGridProps {
className?: string;
}
const FeatureCarouselGrid = ({ className }: FeatureCarouselGridProps) => {
const [selection, setSelection] = useState(0);
const [carouselApi, setCarouselApi] = useState<CarouselApi>();
useEffect(() => {
if (!carouselApi) {
return;
}
carouselApi.scrollTo(selection);
}, [carouselApi, selection]);
useEffect(() => {
if (!carouselApi) {
return;
}
const updateSelection = () => {
setSelection(carouselApi.selectedScrollSnap());
};
carouselApi.on("select", updateSelection);
return () => {
carouselApi.off("select", updateSelection);
};
}, [carouselApi]);
return (
<section className={cn("py-32", className)}>
<div className="container mx-auto">
<div className="flex flex-col gap-8 md:flex-row-reverse">
<div className="aspect-5/6 overflow-clip rounded-3xl bg-accent">
<Carousel
setApi={setCarouselApi}
className="h-full w-full [&>div]:h-full"
>
<CarouselContent className="mx-0 h-full w-full">
{features.map((feature) => (
<CarouselItem key={feature.id} className="px-0">
<img
src={feature.image}
alt={feature.title}
className="h-full w-full object-cover object-center"
/>
</CarouselItem>
))}
</CarouselContent>
</Carousel>
</div>
<div className="flex shrink-0 flex-col md:w-1/2 md:pr-8 lg:pr-24 lg:text-left 2xl:pr-32">
<h2 className="text-heading-2 mb-6 font-semibold text-pretty">
Features
</h2>
<p className="text-body mb-16 leading-relaxed text-muted-foreground">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Elig
doloremque mollitia fugiat omnis! Porro facilis quo animi
consequatur. Explicabo.
</p>
<ul className="space-y-2">
{features.map((feature, i) => (
<li
key={feature.id}
className="group relative w-full cursor-pointer px-6 py-3 transition data-open:bg-accent"
data-open={selection === i ? "true" : undefined}
onClick={() => setSelection(i)}
>
<div className="flex items-center justify-between gap-x-2">
<div className="text-body-sm font-semibold text-accent-foreground">
{feature.title}
</div>
<div className="flex size-8 items-center justify-center rounded-full bg-accent text-accent-foreground group-hover:bg-primary group-hover:text-primary-foreground group-data-open:bg-primary group-data-open:text-primary-foreground">
<ChevronDown className="size-4 shrink-0 transition-transform duration-200 group-data-open:rotate-180" />
</div>
</div>
<div className="text-body-sm hidden font-medium group-data-open:block">
<p className="my-4 text-muted-foreground lg:my-6">
{feature.description}
</p>
<a
href="#"
className="group/link text-body-sm flex items-center pb-3 text-accent-foreground"
>
Learn more{" "}
<ArrowRight className="ml-2 size-4 transition-transform group-hover/link:translate-x-1" />
</a>
</div>
</li>
))}
</ul>
</div>
</div>
</div>
</section>
);
};
export { FeatureCarouselGrid };