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.
137 lines
3.3 KiB
TypeScript
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>
|
|
);
|
|
};
|