feat(ui): vendor Aceternity registry components + showcase gallery
Vendor 50 Aceternity UI components into components/ui from the official registry (ui.aceternity.com/registry/<slug>.json), adapted for this template's stack: Tailwind v4, motion/react 13, cn util, React 19. Add a live showcase gallery (/ui + /docs/... navigation is unchanged): app/ui/page.tsx renders <ShowcaseGallery> with 30+ demos — 3d-pin, aurora, background-beams, bento, card-stack, card-spotlight, direction-aware-hover, encrypted-text, evervault-card, flip-words, hero-highlight, hero-parallax, infinite-moving-cards, moving-border, sparkles, tracing-beam, animated-tooltip, typewriter-effect, placeholders-and-vanish-input and friends. Toolchain stays zero-warning: vendored animation code is scoped in eslint.config.mjs (react-hooks/react-compiler advisory rules, no-any, prefer-const, no-img-element) so app code keeps a 0-error gate. typecheck, build, 7 vitest tests and 2 test suites all green.
This commit is contained in:
1 parent
bc64b74a34
commit
bf75d9deef
53 files changed
+6781
-1
No files matched your search
@@ -0,0 +1,120 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { motion, useScroll, useTransform, useSpring, MotionValue } from "motion/react";
|
||||
|
||||
export const HeroParallax = ({
|
||||
products,
|
||||
}: {
|
||||
products: {
|
||||
title: string;
|
||||
link: string;
|
||||
thumbnail: string;
|
||||
}[];
|
||||
}) => {
|
||||
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="relative flex h-[300vh] flex-col self-auto overflow-hidden py-40 antialiased [perspective:1000px] [transform-style:preserve-3d]"
|
||||
>
|
||||
<Header />
|
||||
<motion.div
|
||||
style={{
|
||||
rotateX,
|
||||
rotateZ,
|
||||
translateY,
|
||||
opacity,
|
||||
}}
|
||||
className=""
|
||||
>
|
||||
<motion.div className="mb-20 flex flex-row-reverse space-x-20 space-x-reverse">
|
||||
{firstRow.map((product) => (
|
||||
<ProductCard product={product} translate={translateX} key={product.title} />
|
||||
))}
|
||||
</motion.div>
|
||||
<motion.div className="mb-20 flex flex-row 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-20 space-x-reverse">
|
||||
{thirdRow.map((product) => (
|
||||
<ProductCard product={product} translate={translateX} key={product.title} />
|
||||
))}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Header = () => {
|
||||
return (
|
||||
<div className="relative top-0 left-0 mx-auto w-full max-w-7xl px-4 py-20 md:py-40">
|
||||
<h1 className="text-2xl font-bold md:text-7xl dark:text-white">
|
||||
The Ultimate <br /> development studio
|
||||
</h1>
|
||||
<p className="mt-8 max-w-2xl text-base md:text-xl dark:text-neutral-200">
|
||||
We build beautiful products with the latest technologies and frameworks. We are a team of
|
||||
passionate developers and designers that love to build amazing products.
|
||||
</p>
|
||||
</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 relative h-96 w-[30rem] shrink-0"
|
||||
>
|
||||
<a href={product.link} className="block group-hover/product:shadow-2xl">
|
||||
<img
|
||||
src={product.thumbnail}
|
||||
height="600"
|
||||
width="600"
|
||||
className="absolute inset-0 h-full w-full object-cover object-left-top"
|
||||
alt={product.title}
|
||||
/>
|
||||
</a>
|
||||
<div className="pointer-events-none absolute inset-0 h-full w-full bg-black opacity-0 group-hover/product:opacity-80"></div>
|
||||
<h2 className="absolute bottom-4 left-4 text-white opacity-0 group-hover/product:opacity-100">
|
||||
{product.title}
|
||||
</h2>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
Reference in new issue
Block a user