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:
@@ -0,0 +1,108 @@
|
||||
"use client";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { motion, useTransform, useScroll, useSpring } from "motion/react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export const TracingBeam = ({
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const { scrollYProgress } = useScroll({
|
||||
target: ref,
|
||||
offset: ["start start", "end start"],
|
||||
});
|
||||
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const [svgHeight, setSvgHeight] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (contentRef.current) {
|
||||
setSvgHeight(contentRef.current.offsetHeight);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const y1 = useSpring(useTransform(scrollYProgress, [0, 0.8], [50, svgHeight]), {
|
||||
stiffness: 500,
|
||||
damping: 90,
|
||||
});
|
||||
const y2 = useSpring(useTransform(scrollYProgress, [0, 1], [50, svgHeight - 200]), {
|
||||
stiffness: 500,
|
||||
damping: 90,
|
||||
});
|
||||
|
||||
return (
|
||||
<motion.div ref={ref} className={cn("relative mx-auto h-full w-full max-w-4xl", className)}>
|
||||
<div className="absolute top-3 -left-4 md:-left-20">
|
||||
<motion.div
|
||||
transition={{
|
||||
duration: 0.2,
|
||||
delay: 0.5,
|
||||
}}
|
||||
animate={{
|
||||
boxShadow: scrollYProgress.get() > 0 ? "none" : "rgba(0, 0, 0, 0.24) 0px 3px 8px",
|
||||
}}
|
||||
className="border-netural-200 ml-[27px] flex h-4 w-4 items-center justify-center rounded-full border shadow-sm"
|
||||
>
|
||||
<motion.div
|
||||
transition={{
|
||||
duration: 0.2,
|
||||
delay: 0.5,
|
||||
}}
|
||||
animate={{
|
||||
backgroundColor: scrollYProgress.get() > 0 ? "white" : "#10b981",
|
||||
borderColor: scrollYProgress.get() > 0 ? "white" : "#059669",
|
||||
}}
|
||||
className="h-2 w-2 rounded-full border border-neutral-300 bg-white"
|
||||
/>
|
||||
</motion.div>
|
||||
<svg
|
||||
viewBox={`0 0 20 ${svgHeight}`}
|
||||
width="20"
|
||||
height={svgHeight} // Set the SVG height
|
||||
className="ml-4 block"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<motion.path
|
||||
d={`M 1 0V -36 l 18 24 V ${svgHeight * 0.8} l -18 24V ${svgHeight}`}
|
||||
fill="none"
|
||||
stroke="#9091A0"
|
||||
strokeOpacity="0.16"
|
||||
transition={{
|
||||
duration: 10,
|
||||
}}
|
||||
></motion.path>
|
||||
<motion.path
|
||||
d={`M 1 0V -36 l 18 24 V ${svgHeight * 0.8} l -18 24V ${svgHeight}`}
|
||||
fill="none"
|
||||
stroke="url(#gradient)"
|
||||
strokeWidth="1.25"
|
||||
className="motion-reduce:hidden"
|
||||
transition={{
|
||||
duration: 10,
|
||||
}}
|
||||
></motion.path>
|
||||
<defs>
|
||||
<motion.linearGradient
|
||||
id="gradient"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="0"
|
||||
y1={y1} // set y1 for gradient
|
||||
y2={y2} // set y2 for gradient
|
||||
>
|
||||
<stop stopColor="#18CCFC" stopOpacity="0"></stop>
|
||||
<stop stopColor="#18CCFC"></stop>
|
||||
<stop offset="0.325" stopColor="#6344F5"></stop>
|
||||
<stop offset="1" stopColor="#AE48FF" stopOpacity="0"></stop>
|
||||
</motion.linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div ref={contentRef}>{children}</div>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user