'use client';
import { motion, type HTMLMotionProps, type Variants } from 'framer-motion';
import { useRef, useState, type ReactNode, type MouseEvent } from 'react';
import { cn } from '@/lib/utils';
const cardVariants: Variants = {
hidden: {
opacity: 0,
y: 30,
scale: 0.95,
},
visible: {
opacity: 1,
y: 0,
scale: 1,
transition: {
duration: 0.6,
ease: [0.16, 1, 0.3, 1],
},
},
};
interface InkCardProps extends HTMLMotionProps<'div'> {
children: ReactNode;
className?: string;
hoverScale?: number;
hoverRotate?: number;
inkColor?: string;
showInkOnHover?: boolean;
}
export function InkCard({
children,
className = '',
hoverScale = 1.02,
hoverRotate = 0,
inkColor = 'rgba(196, 30, 58, 0.05)',
showInkOnHover = true,
...props
}: InkCardProps) {
const cardRef = useRef(null);
const [inkPosition, setInkPosition] = useState({ x: 50, y: 50 });
const [isHovered, setIsHovered] = useState(false);
const handleMouseMove = (e: MouseEvent) => {
if (!cardRef.current) return;
const rect = cardRef.current.getBoundingClientRect();
const x = ((e.clientX - rect.left) / rect.width) * 100;
const y = ((e.clientY - rect.top) / rect.height) * 100;
setInkPosition({ x, y });
};
return (
setIsHovered(true)}
onHoverEnd={() => setIsHovered(false)}
onMouseMove={handleMouseMove}
transition={{
type: 'spring',
stiffness: 300,
damping: 20,
}}
className={cn(
'relative overflow-hidden bg-white border border-[#E5E5E5] rounded-xl transition-shadow duration-300',
'hover:shadow-[0_12px_24px_rgba(28,28,28,0.08)]',
className
)}
{...props}
>
{showInkOnHover && (
)}
{children}
);
}
interface GeometricCardProps extends HTMLMotionProps<'div'> {
children: ReactNode;
className?: string;
cornerColor?: string;
}
export function GeometricCard({
children,
className = '',
cornerColor = '#C41E3A',
...props
}: GeometricCardProps) {
return (
{children}
);
}
interface FlipCardProps {
front: ReactNode;
back: ReactNode;
className?: string;
frontClassName?: string;
backClassName?: string;
}
export function FlipCard({
front,
back,
className = '',
frontClassName = '',
backClassName = '',
}: FlipCardProps) {
const [isFlipped, setIsFlipped] = useState(false);
return (
setIsFlipped(!isFlipped)}
style={{ perspective: 1000 }}
>
{front}
{back}
);
}
interface TiltCardProps extends HTMLMotionProps<'div'> {
children: ReactNode;
className?: string;
maxTilt?: number;
scale?: number;
}
export function TiltCard({
children,
className = '',
maxTilt = 10,
scale = 1.02,
...props
}: TiltCardProps) {
const cardRef = useRef(null);
const [rotateX, setRotateX] = useState(0);
const [rotateY, setRotateY] = useState(0);
const handleMouseMove = (e: MouseEvent) => {
if (!cardRef.current) return;
const rect = cardRef.current.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const mouseX = e.clientX - centerX;
const mouseY = e.clientY - centerY;
const rotateXValue = (mouseY / (rect.height / 2)) * -maxTilt;
const rotateYValue = (mouseX / (rect.width / 2)) * maxTilt;
setRotateX(rotateXValue);
setRotateY(rotateYValue);
};
const handleMouseLeave = () => {
setRotateX(0);
setRotateY(0);
};
return (
{children}
);
}
interface GlowCardProps extends HTMLMotionProps<'div'> {
children: ReactNode;
className?: string;
glowColor?: string;
}
export function GlowCard({
children,
className = '',
glowColor = 'rgba(196, 30, 58, 0.15)',
...props
}: GlowCardProps) {
const cardRef = useRef(null);
const [glowPosition, setGlowPosition] = useState({ x: 50, y: 50 });
const handleMouseMove = (e: MouseEvent) => {
if (!cardRef.current) return;
const rect = cardRef.current.getBoundingClientRect();
const x = ((e.clientX - rect.left) / rect.width) * 100;
const y = ((e.clientY - rect.top) / rect.height) * 100;
setGlowPosition({ x, y });
};
return (
{children}
);
}
interface ExpandCardProps extends HTMLMotionProps<'div'> {
children: ReactNode;
className?: string;
expandedContent?: ReactNode;
}
export function ExpandCard({
children,
className = '',
expandedContent,
...props
}: ExpandCardProps) {
const [isExpanded, setIsExpanded] = useState(false);
return (
setIsExpanded(!isExpanded)}
transition={{ type: 'spring', stiffness: 300, damping: 20 }}
className={cn(
'relative overflow-hidden bg-white border border-[#E5E5E5] rounded-xl cursor-pointer',
'transition-shadow duration-300',
'hover:shadow-[0_12px_24px_rgba(28,28,28,0.08)]',
className
)}
{...props}
>
{children}
{expandedContent && (
{expandedContent}
)}
);
}