{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "media-card",
  "type": "registry:ui",
  "title": "Media Card",
  "description": "An Interactive media cards with a fluid cursor and a polished, modern aesthetic.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion", "clsx", "tailwind-merge"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/media-card.tsx",
      "content": "'use client';\nimport React, { useEffect, useState, useRef } from 'react';\nimport {\n  motion,\n  AnimatePresence,\n  useMotionValue,\n  useSpring,\n} from 'motion/react';\nimport { cn } from '@/lib/utils';\n\ninterface MediaCardRootProps {\n  children: React.ReactNode;\n  className?: string;\n  dotClassName?: string;\n  marqueeClassName?: string;\n  springConfig?: {\n    stiffness?: number;\n    damping?: number;\n    mass?: number;\n  };\n  marqueeSpeed?: number;\n  marqueeDelay?: number;\n}\n\ninterface MediaCardItemProps {\n  src: string;\n  alt: string;\n  title: string;\n  type?: 'image' | 'video';\n  className?: string;\n}\n\ninterface CursorContextType {\n  setLabel: (label: string | null) => void;\n  containerRef: React.RefObject<HTMLDivElement | null>;\n}\n\nconst CursorContext = React.createContext<CursorContextType | null>(null);\n\nconst useCursor = () => {\n  const context = React.useContext(CursorContext);\n  if (!context) {\n    throw new Error('MediaCard components must be used within MediaCard root');\n  }\n  return context;\n};\n\nconst Cursor = ({\n  label,\n  containerRef,\n  dotClassName,\n  marqueeClassName,\n  springConfig = { stiffness: 300, damping: 30, mass: 0.5 },\n  marqueeSpeed = 10,\n  marqueeDelay = 0.5,\n}: {\n  label: string | null;\n  containerRef: React.RefObject<HTMLDivElement | null>;\n  dotClassName?: string;\n  marqueeClassName?: string;\n  springConfig?: { stiffness?: number; damping?: number; mass?: number };\n  marqueeSpeed?: number;\n  marqueeDelay?: number;\n}) => {\n  const rawX = useMotionValue(0);\n  const rawY = useMotionValue(0);\n  const [isInside, setIsInside] = useState(false);\n\n  const x = useSpring(rawX, springConfig);\n  const y = useSpring(rawY, springConfig);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    if (!container) return;\n\n    const move = (e: MouseEvent) => {\n      const rect = container.getBoundingClientRect();\n      const isWithinBounds =\n        e.clientX >= rect.left &&\n        e.clientX <= rect.right &&\n        e.clientY >= rect.top &&\n        e.clientY <= rect.bottom;\n\n      setIsInside(isWithinBounds);\n\n      if (isWithinBounds) {\n        rawX.set(e.clientX);\n        rawY.set(e.clientY);\n      }\n    };\n\n    window.addEventListener('mousemove', move);\n    return () => window.removeEventListener('mousemove', move);\n  }, [rawX, rawY, containerRef]);\n\n  if (!isInside) return null;\n\n  return (\n    <motion.div\n      className='fixed pointer-events-none z-10000'\n      style={{ left: x, top: y, x: '-50%', y: '-50%' }}\n    >\n      <AnimatePresence mode='wait'>\n        {label ? (\n          <motion.div\n            key='marquee'\n            initial={{\n              opacity: 0,\n              scale: 0.8,\n            }}\n            animate={{\n              opacity: 1,\n              scale: 1,\n            }}\n            exit={{\n              opacity: 0,\n              scale: 0.8,\n            }}\n            transition={{\n              duration: 0.3,\n              ease: [0.25, 0.1, 0.25, 1],\n            }}\n            className={cn(\n              'overflow-hidden backdrop-blur-md shadow-2xl flex items-center justify-center bg-white/95 rounded-full w-40 h-10',\n              marqueeClassName,\n            )}\n          >\n            <div className='relative w-full h-full flex items-center'>\n              <motion.div\n                className='absolute whitespace-nowrap text-sm font-bold tracking-widest flex'\n                initial={{ x: '0%' }}\n                animate={{ x: '-50%' }}\n                transition={{\n                  duration: marqueeSpeed,\n                  repeat: Infinity,\n                  ease: 'linear',\n                  delay: marqueeDelay,\n                }}\n              >\n                <span className='px-1'>{label}</span>\n                <span className='px-1'>{label}</span>\n              </motion.div>\n            </div>\n          </motion.div>\n        ) : (\n          <motion.div\n            key='dot'\n            initial={{\n              width: '8px',\n              height: '8px',\n              opacity: 1,\n            }}\n            animate={{\n              width: '8px',\n              height: '8px',\n              opacity: 1,\n            }}\n            exit={{\n              width: '8px',\n              height: '8px',\n              opacity: 1,\n            }}\n            transition={{ duration: 0.2 }}\n            className={cn('rounded-full bg-black', dotClassName)}\n          />\n        )}\n      </AnimatePresence>\n    </motion.div>\n  );\n};\n\nconst MediaCard = ({\n  children,\n  className,\n  dotClassName,\n  marqueeClassName,\n  springConfig,\n  marqueeSpeed,\n  marqueeDelay,\n}: MediaCardRootProps) => {\n  const [label, setLabel] = useState<string | null>(null);\n  const containerRef = useRef<HTMLDivElement | null>(null);\n\n  return (\n    <CursorContext.Provider value={{ setLabel, containerRef }}>\n      <Cursor\n        label={label}\n        containerRef={containerRef}\n        dotClassName={dotClassName}\n        marqueeClassName={marqueeClassName}\n        springConfig={springConfig}\n        marqueeSpeed={marqueeSpeed}\n        marqueeDelay={marqueeDelay}\n      />\n      <div ref={containerRef} className={cn('', className)}>\n        {children}\n      </div>\n    </CursorContext.Provider>\n  );\n};\n\nconst MediaCardItem = ({\n  src,\n  alt,\n  title,\n  type = 'image',\n  className,\n}: MediaCardItemProps) => {\n  const { setLabel } = useCursor();\n\n  return (\n    <div\n      onMouseEnter={() => setLabel(title)}\n      onMouseLeave={() => setLabel(null)}\n      className={cn('relative overflow-hidden rounded-3xl', className)}\n    >\n      {type === 'video' ? (\n        <video\n          src={src}\n          className='w-full h-full object-cover'\n          loop\n          muted\n          playsInline\n          autoPlay\n        />\n      ) : (\n        <img src={src} alt={alt} className='w-full h-full object-cover' />\n      )}\n    </div>\n  );\n};\n\nexport { MediaCard, MediaCardItem };\n"
    },
    {
      "type": "registry:lib",
      "path": "lib/utils.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}"
    }
  ]
}
