Files
neptune-front/src/components/ui/hero-parallax.tsx
Mathis 442bebd022 Add various UI components including ToggleGroup and RadioGroup
This commit introduces multiple new UI components for the project. The added components include ToggleGroup, RadioGroup, Pagination, ToastBox, Textarea, Breadcrumb, Skeleton, Collapsible, Checkbox, Calendar, Accordion, Sonner, and CopyButton. These components enhance the flexibility and functionality of the UI, providing essential elements for better user interaction.
2024-11-08 12:20:27 +01:00

137 lines
3.3 KiB
TypeScript

"use client";
import {
type MotionValue,
motion,
useScroll,
useSpring,
useTransform,
} from "framer-motion";
import Image from "next/image";
import Link from "next/link";
import React from "react";
interface HeroParallaxProps {
products: product[];
children?: React.ReactNode;
}
interface product {
title: string;
link: string;
thumbnail: string;
}
export const HeroParallax = ({ products, children }: HeroParallaxProps) => {
const firstRow = products.slice(0, 5);
const secondRow = products.slice(5, 10);
const thirdRow = products.slice(10, 15);
const ref = React.useRef(null);
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start start", "end start"],
});
const springConfig = { stiffness: 300, damping: 30, bounce: 100 };
const translateX = useSpring(
useTransform(scrollYProgress, [0, 1], [0, 1000]),
springConfig,
);
const translateXReverse = useSpring(
useTransform(scrollYProgress, [0, 1], [0, -1000]),
springConfig,
);
const rotateX = useSpring(
useTransform(scrollYProgress, [0, 0.2], [15, 0]),
springConfig,
);
const opacity = useSpring(
useTransform(scrollYProgress, [0, 0.2], [0.2, 1]),
springConfig,
);
const rotateZ = useSpring(
useTransform(scrollYProgress, [0, 0.2], [20, 0]),
springConfig,
);
const translateY = useSpring(
useTransform(scrollYProgress, [0, 0.2], [-700, 500]),
springConfig,
);
return (
<div
ref={ref}
className="h-[300vh] py-40 overflow-hidden antialiased relative flex flex-col self-auto [perspective:1000px] [transform-style:preserve-3d]"
>
{children}
<motion.div
style={{
rotateX,
rotateZ,
translateY,
opacity,
}}
className=""
>
<motion.div className="flex flex-row-reverse space-x-reverse space-x-20 mb-20">
{firstRow.map((product) => (
<ProductCard product={product} translate={translateX} key={product.title} />
))}
</motion.div>
<motion.div className="flex flex-row mb-20 space-x-20 ">
{secondRow.map((product) => (
<ProductCard
product={product}
translate={translateXReverse}
key={product.title}
/>
))}
</motion.div>
<motion.div className="flex flex-row-reverse space-x-reverse space-x-20">
{thirdRow.map((product) => (
<ProductCard product={product} translate={translateX} key={product.title} />
))}
</motion.div>
</motion.div>
</div>
);
};
export const ProductCard = ({
product,
translate,
}: {
product: {
title: string;
link: string;
thumbnail: string;
};
translate: MotionValue<number>;
}) => {
return (
<motion.div
style={{
x: translate,
}}
whileHover={{
y: -20,
}}
key={product.title}
className="group/product h-96 w-[30rem] relative flex-shrink-0"
>
<Link href={product.link} className="block group-hover/product:shadow-2xl ">
<Image
src={product.thumbnail}
height="600"
width="600"
className="object-cover object-left-top absolute h-full w-full rounded inset-0"
alt={product.title}
/>
</Link>
<div className="absolute inset-0 h-full w-full opacity-0 group-hover/product:opacity-80 bg-black pointer-events-none"></div>
<h2 className="absolute bottom-4 left-4 opacity-0 group-hover/product:opacity-100 text-white">
{product.title}
</h2>
</motion.div>
);
};