Files
asepharyana bf75d9deef 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.
2026-09-20 19:10:43 +07:00

70 lines
2.0 KiB
TypeScript

"use client";
import React from "react";
import { motion } from "motion/react";
import { cn } from "@/lib/utils";
export const BoxesCore = ({ className, ...rest }: { className?: string }) => {
const rows = new Array(150).fill(1);
const cols = new Array(100).fill(1);
const colors = [
"#93c5fd",
"#f9a8d4",
"#86efac",
"#fde047",
"#fca5a5",
"#d8b4fe",
"#93c5fd",
"#a5b4fc",
"#c4b5fd",
];
const getRandomColor = () => {
return colors[Math.floor(Math.random() * colors.length)];
};
return (
<div
style={{
transform: `translate(-40%,-60%) skewX(-48deg) skewY(14deg) scale(0.675) rotate(0deg) translateZ(0)`,
}}
className={cn(
"absolute -top-1/4 left-1/4 z-0 flex h-full w-full -translate-x-1/2 -translate-y-1/2 p-4",
className
)}
{...rest}
>
{rows.map((_, i) => (
<motion.div key={`row` + i} className="relative h-8 w-16 border-l border-slate-700">
{cols.map((_, j) => (
<motion.div
whileHover={{
backgroundColor: `${getRandomColor()}`,
transition: { duration: 0 },
}}
animate={{
transition: { duration: 2 },
}}
key={`col` + j}
className="relative h-8 w-16 border-t border-r border-slate-700"
>
{j % 2 === 0 && i % 2 === 0 ? (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="1.5"
stroke="currentColor"
className="pointer-events-none absolute -top-[14px] -left-[22px] h-6 w-10 stroke-[1px] text-slate-700"
>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 6v12m6-6H6" />
</svg>
) : null}
</motion.div>
))}
</motion.div>
))}
</div>
);
};
export const Boxes = React.memo(BoxesCore);