Added Tailwind CSS and tw-animate-css imports to globals.css. Introduced a custom dark variant and an extensive @theme inline block with CSS variables for colors, radii, and animations. Included keyframes for shimmer-slide, spin-around, gradient, shine, and background-position-spin to enable consistent theming and dynamic UI effects across the application.
97 lines
2.5 KiB
TypeScript
97 lines
2.5 KiB
TypeScript
import { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
import { ArrowRightIcon } from "@radix-ui/react-icons";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
interface BentoGridProps extends ComponentPropsWithoutRef<"div"> {
|
|
children: ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
interface BentoCardProps extends ComponentPropsWithoutRef<"div"> {
|
|
name: string;
|
|
className: string;
|
|
background: ReactNode;
|
|
Icon: React.ElementType;
|
|
description: string;
|
|
href: string;
|
|
cta: string;
|
|
}
|
|
|
|
const BentoGrid = ({ children, className, ...props }: BentoGridProps) => {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"grid w-full gap-6",
|
|
"grid-cols-1 md:grid-cols-3",
|
|
"auto-rows-[minmax(280px,auto)]",
|
|
className
|
|
)}
|
|
style={{
|
|
gridTemplateColumns: "1fr 2fr",
|
|
gridTemplateRows: "auto auto",
|
|
}}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const BentoCard = ({
|
|
name,
|
|
className,
|
|
background,
|
|
Icon,
|
|
description,
|
|
href,
|
|
cta,
|
|
...props
|
|
}: BentoCardProps) => (
|
|
<div
|
|
key={name}
|
|
className={cn(
|
|
"group relative flex flex-col justify-between overflow-hidden rounded-xl",
|
|
"transition-all duration-300 hover:scale-[1.02] hover:shadow-lg",
|
|
// light styles
|
|
"bg-background border border-border/50",
|
|
"shadow-sm hover:shadow-xl",
|
|
// dark styles
|
|
"dark:bg-background dark:border-border/50",
|
|
"dark:shadow-sm dark:hover:shadow-xl",
|
|
className
|
|
)}
|
|
{...props}
|
|
>
|
|
<div className="relative">{background}</div>
|
|
<div className="p-6 flex flex-col justify-between h-full">
|
|
<div className="flex flex-col gap-4">
|
|
<div className="flex items-center gap-3">
|
|
<div className="p-2 rounded-lg bg-primary/10">
|
|
<Icon className="h-6 w-6 text-primary" />
|
|
</div>
|
|
<h3 className="text-xl font-semibold text-foreground">{name}</h3>
|
|
</div>
|
|
<p className="text-muted-foreground leading-relaxed">{description}</p>
|
|
</div>
|
|
|
|
<div className="mt-6">
|
|
<Button
|
|
variant="outline"
|
|
asChild
|
|
size="sm"
|
|
className="w-full justify-between group-hover:bg-primary group-hover:text-primary-foreground transition-colors"
|
|
>
|
|
<a href={href}>
|
|
{cta}
|
|
<ArrowRightIcon className="h-4 w-4 transition-transform group-hover:translate-x-1" />
|
|
</a>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
export { BentoCard, BentoGrid };
|