Card
A card component
Made by lucasNew-Reels Instagram Creator
Craft YourImaginary Escape
The leading AI art generation and image editing tool with 3.5B+ creations
import ParticlesBackground from "@/components/targetblank/backgrounds/particles";
import {
Card,
CardDescription,
CardFooter,
CardGradient,
CardHeader,
CardIndicator,
CardTitle,
} from "@/components/targetblank/components/card";
export const CardDemo = () => {
return (
<Card
image={
"https://preview.redd.it/nature-vibes-v0-vhl86w7e60jc1.jpg?width=1080&crop=smart&auto=webp&s=b1553f868c8d46408ac0f2a860f19f8c14793bf4"
}
>
<CardGradient />
<CardIndicator className="z-[1]">
<div className="flex gap-2 justify-start items-center p-1 w-fit">
<div className="bg-lime-400 rounded-full shadow-sm size-1.5 shadow-lime-300" />
<span className="text-[9px] text-gray-600 leading-none">
New-Reels Instagram Creator
</span>
</div>
</CardIndicator>
<CardHeader className="z-[1]">
<CardTitle>
<div className="flex flex-col gap-1">
<span className="text-lime-900">Craft Your</span>
<span className="italic font-light text-gray-800">
Imaginary Escape
</span>
</div>
</CardTitle>
<CardDescription>
<span className="text-sm text-lime-800">
The leading AI art generation and image editing tool with 3.5B+
creations
</span>
</CardDescription>
</CardHeader>
<CardFooter
as="button"
className="px-4 py-2 w-full tracking-tight bg-[#bee227] rounded-lg"
>
<ParticlesBackground count={10} />
<span className="z-10 w-full text-center">Generated Image</span>
</CardFooter>
</Card>
);
};
Installation
Install the following dependencies:
Copy and paste the following code into your project:
import { cn } from "@/lib/utils";
import { HTMLMotionProps, motion } from "motion/react";
import * as React from "react";
import { useRef, useState } from "react";
const DEFAULT_COMPONENT = "button";
type CardProps = HTMLMotionProps<"div"> & {
image: string;
};
function Card({ className, image, ...props }: CardProps) {
const cardRef = useRef<HTMLDivElement>(null);
const [pos, setPos] = useState({ x: 0, y: 0 });
const handleMouseMove = (e: React.MouseEvent) => {
const card = cardRef.current;
if (!card) return;
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left - rect.width / 2;
const y = e.clientY - rect.top - rect.height / 2;
const strength = 0.08;
setPos({ x: x * strength, y: y * strength });
};
const handleMouseLeave = () => {
setPos({ x: 0, y: 0 });
};
return (
<div
data-slot="card"
className="flex justify-center items-center p-2 rounded-3xl shadow-sm bg-white/20 backdrop-blur-xs"
>
<motion.div
ref={cardRef}
className={cn(
"relative w-[300px] bg-cover bg-center flex flex-col gap-4 p-6 rounded-2xl shadow-[inset_0px_0px_3px_0px_#FFFFFF]",
className,
)}
style={{
backgroundImage: `url(${image})`,
}}
animate={{ x: pos.x, y: pos.y }}
transition={{ type: "spring", stiffness: 400, damping: 40, mass: 1 }}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
{...props}
/>
</div>
);
}
function CardGradient({
className,
fromBlur = 40,
fromColor = "rgba(255, 255, 255, 0.5)",
fromOpacity = 40,
toBlur = 70,
toColor = "rgba(0, 0, 0, 0)",
toOpacity = 70,
...props
}: React.ComponentProps<"div"> & {
fromBlur?: number;
toBlur?: number;
fromColor?: string;
toColor?: string;
fromOpacity?: number;
toOpacity?: number;
}) {
return (
<div
className={cn(
"absolute inset-0 rounded-2xl backdrop-blur-xl pointer-events-none",
className,
)}
style={{
background: `linear-gradient(to bottom, ${fromColor} ${fromOpacity}%, ${toColor} ${toOpacity}%)`,
mask: `linear-gradient(to bottom, rgba(0, 0, 0, 1) ${fromBlur.toString()}%, rgba(0, 0, 0, 0) ${toBlur.toString()}%)`,
}}
{...props}
/>
);
}
function CardIndicator({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-indicator"
className={cn(
"rounded-full border border-gray-200 bg-white/30 backdrop-blur-xs w-fit",
className,
)}
{...props}
/>
);
}
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-header"
className={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-1 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
className,
)}
{...props}
/>
);
}
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-title"
className={cn("font-semibold leading-none", className)}
{...props}
/>
);
}
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-description"
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
);
}
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
className={cn("px-1", className)}
{...props}
/>
);
}
type CardFooterProps<T extends React.ElementType = typeof DEFAULT_COMPONENT> = {
as?: T;
radius?: number;
blur?: number;
childClassName?: string;
} & React.ComponentProps<T>;
function CardFooter<T extends React.ElementType = typeof DEFAULT_COMPONENT>({
as,
className,
...props
}: CardFooterProps<T>) {
const Comp = as || DEFAULT_COMPONENT;
return (
<motion.div
data-slot="card-footer"
className="flex overflow-hidden relative justify-center items-center p-1 mt-20 rounded-xl backdrop-blur-sm bg-white/20 shadow-[inset_0px_0px_2px_0px_#FFFFFF]"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
<Comp
className={cn(
"flex overflow-hidden relative z-10 items-center w-full h-full text-sm text-center text-gray-700 shadow-[inset_0px_0px_2px_0px_#FFFFFF]",
className,
)}
{...props}
>
{props.children}
</Comp>
</motion.div>
);
}
export {
Card,
CardContent,
CardDescription,
CardFooter,
CardGradient,
CardHeader,
CardIndicator,
CardTitle,
};
Update the import paths to match your project setup.
Usage
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
</CardHeader>
<CardContent>
<p>Card Content</p>
</CardContent>
<CardFooter>
<p>Card Footer</p>
</CardFooter>
</Card>
Props
Prop | Type | Default |
---|---|---|
className? | string | - |
fromBlur? | number | 40 |
fromColor? | string | rgba(255, 255, 255, 0.5) |
fromOpacity? | number | 40 |
toBlur? | number | 70 |
toColor? | string | rgba(0, 0, 0, 0) |
toOpacity? | number | 70 |
Credits
- Credits to Blurr for the step bar component.