{ "name": "showcase-card", "type": "registry:ui", "dependencies": [ "framer-motion" ], "registryDependencies": [], "description": "A premium showcase card component with 3D tilt effect, parallax image, micro-interactions, and multiple variants. Perfect for portfolios, agency sites, and product showcases.", "files": [ { "path": "components/ui/showcase-card.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { motion, useMotionValue, useSpring, useTransform } from \"framer-motion\"\nimport { cn } from \"@/lib/utils\"\n\ninterface ShowcaseCardProps {\n /** Top tagline text */\n tagline?: string\n /** Main heading text */\n heading: string\n /** Description text below heading */\n description?: string\n /** Image URL for the hero section */\n imageUrl: string\n /** Alt text for the image */\n imageAlt?: string\n /** CTA button text */\n ctaText?: string\n /** CTA button click handler */\n onCtaClick?: () => void\n /** Brand name or logo text */\n brandName?: string\n /** Array of service tags */\n services?: string[]\n /** Custom class name */\n className?: string\n /** Enable 3D tilt effect on hover */\n enableTilt?: boolean\n /** Maximum tilt angle in degrees */\n maxTilt?: number\n /** Enable parallax effect on image */\n enableParallax?: boolean\n}\n\nfunction ShowcaseCard({\n tagline,\n heading,\n description,\n imageUrl,\n imageAlt = \"Showcase image\",\n ctaText,\n onCtaClick,\n brandName,\n services = [],\n className,\n enableTilt = true,\n maxTilt = 8,\n enableParallax = true,\n}: ShowcaseCardProps) {\n const cardRef = React.useRef(null)\n const [isHovered, setIsHovered] = React.useState(false)\n\n // Mouse position for tilt effect\n const mouseX = useMotionValue(0)\n const mouseY = useMotionValue(0)\n\n // Smooth spring animation for tilt\n const springConfig = { damping: 25, stiffness: 150 }\n const rotateX = useSpring(useTransform(mouseY, [-0.5, 0.5], [maxTilt, -maxTilt]), springConfig)\n const rotateY = useSpring(useTransform(mouseX, [-0.5, 0.5], [-maxTilt, maxTilt]), springConfig)\n\n // Parallax transform for image\n const parallaxX = useSpring(useTransform(mouseX, [-0.5, 0.5], [-15, 15]), springConfig)\n const parallaxY = useSpring(useTransform(mouseY, [-0.5, 0.5], [-15, 15]), springConfig)\n\n // Glow effect position\n const glowX = useSpring(useTransform(mouseX, [-0.5, 0.5], [0, 100]), springConfig)\n const glowY = useSpring(useTransform(mouseY, [-0.5, 0.5], [0, 100]), springConfig)\n\n const handleMouseMove = React.useCallback(\n (e: React.MouseEvent) => {\n if (!cardRef.current || !enableTilt) return\n\n const rect = cardRef.current.getBoundingClientRect()\n const x = (e.clientX - rect.left) / rect.width - 0.5\n const y = (e.clientY - rect.top) / rect.height - 0.5\n\n mouseX.set(x)\n mouseY.set(y)\n },\n [mouseX, mouseY, enableTilt]\n )\n\n const handleMouseEnter = () => {\n setIsHovered(true)\n }\n\n const handleMouseLeave = () => {\n setIsHovered(false)\n mouseX.set(0)\n mouseY.set(0)\n }\n\n return (\n \n {/* Subtle glow overlay on hover */}\n \n\n {/* Image Section */}\n
\n {/* Tagline */}\n {tagline && (\n \n \n {tagline}\n \n \n )}\n\n {/* Hero Image with Parallax */}\n \n \n \n\n {/* Gradient overlay for text readability */}\n
\n
\n\n {/* Content Section */}\n
\n {/* Heading */}\n \n {heading}\n \n\n {/* Description */}\n {description && (\n \n {description}\n \n )}\n\n {/* CTA Button */}\n {ctaText && (\n \n {/* Button hover shine effect */}\n \n {ctaText}\n \n )}\n
\n\n {/* Footer Section */}\n {(brandName || services.length > 0) && (\n \n
\n {/* Brand Name */}\n {brandName && (\n \n {brandName}\n \n )}\n\n {/* Services */}\n {services.length > 0 && (\n
\n {services.map((service, index) => (\n \n \n {service}\n \n {index < services.length - 1 && (\n \n ✦\n \n )}\n \n ))}\n
\n )}\n
\n \n )}\n\n {/* Border glow effect */}\n \n \n )\n}\n\n// Compact variant for grids\ninterface ShowcaseCardCompactProps {\n heading: string\n description?: string\n imageUrl: string\n imageAlt?: string\n className?: string\n onClick?: () => void\n}\n\nfunction ShowcaseCardCompact({\n heading,\n description,\n imageUrl,\n imageAlt = \"Showcase image\",\n className,\n onClick,\n}: ShowcaseCardCompactProps) {\n const [isHovered, setIsHovered] = React.useState(false)\n\n return (\n setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n whileHover={{ scale: 1.02, y: -4 }}\n whileTap={{ scale: 0.98 }}\n transition={{ duration: 0.3 }}\n >\n {/* Image */}\n
\n \n
\n
\n\n {/* Content */}\n
\n

{heading}

\n {description && (\n

{description}

\n )}\n
\n\n {/* Hover indicator */}\n \n \n \n \n \n \n \n )\n}\n\n// Horizontal variant for featured sections\ninterface ShowcaseCardHorizontalProps extends Omit {\n imagePosition?: \"left\" | \"right\"\n}\n\nfunction ShowcaseCardHorizontal({\n tagline,\n heading,\n description,\n imageUrl,\n imageAlt = \"Showcase image\",\n ctaText,\n onCtaClick,\n brandName,\n services = [],\n className,\n imagePosition = \"left\",\n enableParallax = true,\n}: ShowcaseCardHorizontalProps) {\n const [isHovered, setIsHovered] = React.useState(false)\n\n return (\n setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n initial={{ opacity: 0, y: 40 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.6 }}\n whileHover={{ scale: 1.01 }}\n >\n {/* Image Section */}\n
\n {tagline && (\n
\n {tagline}\n
\n )}\n\n \n
\n
\n\n {/* Content Section */}\n
\n \n {heading}\n \n\n {description && (\n \n {description}\n \n )}\n\n {ctaText && (\n \n {ctaText}\n \n )}\n\n {(brandName || services.length > 0) && (\n
\n {brandName && (\n {brandName}\n )}\n {services.length > 0 && (\n
\n {services.map((service, index) => (\n \n {service}\n {index < services.length - 1 && (\n \n )}\n \n ))}\n
\n )}\n
\n )}\n
\n \n )\n}\n\n// Grid container for showcase cards\ninterface ShowcaseGridProps {\n children: React.ReactNode\n columns?: 1 | 2 | 3 | 4\n gap?: \"sm\" | \"md\" | \"lg\"\n className?: string\n}\n\nfunction ShowcaseGrid({\n children,\n columns = 3,\n gap = \"md\",\n className,\n}: ShowcaseGridProps) {\n const gapClasses = {\n sm: \"gap-4\",\n md: \"gap-6\",\n lg: \"gap-8\",\n }\n\n const columnClasses = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-1 sm:grid-cols-2\",\n 3: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\",\n 4: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\",\n }\n\n return (\n
\n {children}\n
\n )\n}\n\nexport {\n ShowcaseCard,\n ShowcaseCardCompact,\n ShowcaseCardHorizontal,\n ShowcaseGrid,\n type ShowcaseCardProps,\n type ShowcaseCardCompactProps,\n type ShowcaseCardHorizontalProps,\n type ShowcaseGridProps,\n}\n", "type": "registry:ui" } ] }