{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "profilecard",
  "type": "registry:ui",
  "title": "Profile Card",
  "description": "A reusable profile card component displaying a user's image, name, bio, skills, and social links with interactive animations.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion", "lucide-react"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/profilecard.tsx",
      "content": "'use client';\nimport React, { useState, useRef } from 'react';\nimport Image from 'next/image';\nimport Link from 'next/link';\nimport { ArrowBigLeft, X } from 'lucide-react';\nimport {\n  motion,\n  useMotionValue,\n  useTransform,\n  useAnimation,\n  AnimatePresence,\n  useMotionTemplate,\n} from 'motion/react';\n\ninterface Skill {\n  name: string;\n  icon:\n    | string\n    | React.ComponentType<React.SVGProps<SVGSVGElement>>\n    | React.ReactElement;\n}\n\ninterface SocialLink {\n  name: string;\n  url: string;\n  icon:\n    | React.ComponentType<React.SVGProps<SVGSVGElement>>\n    | string\n    | React.ReactElement;\n}\n\ninterface ProfileCardProps {\n  img: string;\n  name: string;\n  bio: string;\n  skills: Skill[];\n  socialLinks?: SocialLink[];\n  position: string;\n  spotlight?: boolean;\n  spotlightColor?: string;\n}\n\nexport default function ProfileCard({\n  img,\n  name,\n  bio,\n  skills,\n  socialLinks = [],\n  position,\n  spotlight = false,\n  spotlightColor = '14, 165, 233',\n}: ProfileCardProps) {\n  const [isRevealed, setIsRevealed] = useState(false);\n  const [isImageShrunken, setIsImageShrunken] = useState(false);\n  const arrowControls = useAnimation();\n  const dragX = useMotionValue(0);\n  const dragThreshold = 50;\n  const isAnimating = useRef(false);\n\n  const mouseX = useMotionValue(0);\n  const mouseY = useMotionValue(0);\n  const spotlightX = useMotionValue(0);\n  const spotlightY = useMotionValue(0);\n  const backgroundImage = useMotionTemplate`radial-gradient(300px circle at ${spotlightX}px ${spotlightY}px, rgba(${spotlightColor}, 0.15), transparent)`;\n\n  const arrowRotation = useTransform(dragX, [0, dragThreshold], [-180, 145]);\n\n  const handleDragEnd = () => {\n    if (dragX.get() > dragThreshold && !isRevealed && !isAnimating.current) {\n      isAnimating.current = true;\n      arrowControls.start({ x: dragThreshold, transition: { duration: 0.2 } });\n      setIsImageShrunken(true);\n      setTimeout(() => {\n        setIsRevealed(true);\n        isAnimating.current = false;\n      }, 400);\n    } else if (dragX.get() <= dragThreshold && !isRevealed) {\n      arrowControls.start({\n        x: 0,\n        transition: { type: 'spring', stiffness: 500, damping: 30 },\n      });\n    } else if (isRevealed) {\n      arrowControls.start({\n        x: dragThreshold,\n        transition: { type: 'spring', stiffness: 500, damping: 30 },\n      });\n    }\n  };\n\n  const resetCard = () => {\n    if (isRevealed && !isAnimating.current) {\n      isAnimating.current = true;\n      x.set(0);\n      y.set(0);\n      arrowControls.start({ x: 0, transition: { duration: 0.3 } });\n      setIsRevealed(false);\n      setTimeout(() => {\n        setIsImageShrunken(false);\n        isAnimating.current = false;\n      }, 300);\n    }\n  };\n\n  const x = useMotionValue(0);\n  const y = useMotionValue(0);\n  const rotateDepth = 12;\n  const translateDepth = 15;\n\n  const rotateX = useTransform(\n    y,\n    [-0.5, 0.5],\n    [`-${rotateDepth}deg`, `${rotateDepth}deg`],\n  );\n  const rotateY = useTransform(\n    x,\n    [-0.5, 0.5],\n    [`${rotateDepth}deg`, `-${rotateDepth}deg`],\n  );\n  const translateX = useTransform(\n    x,\n    [-0.5, 0.5],\n    [`-${translateDepth}px`, `${translateDepth}px`],\n  );\n  const translateY = useTransform(\n    y,\n    [-0.5, 0.5],\n    [`${translateDepth}px`, `-${translateDepth}px`],\n  );\n\n  const cardRef = useRef<HTMLDivElement>(null);\n\n  const handleMouseMove = (e: React.MouseEvent) => {\n    if (!cardRef.current || !isRevealed || isAnimating.current) return;\n    const rect = cardRef.current.getBoundingClientRect();\n    const mouseXPos = e.clientX - rect.left;\n    const mouseYPos = e.clientY - rect.top;\n\n    const buffer = 10;\n    if (\n      mouseXPos < -buffer ||\n      mouseXPos > rect.width + buffer ||\n      mouseYPos < -buffer ||\n      mouseYPos > rect.height + buffer\n    )\n      return;\n\n    x.set(mouseXPos / rect.width - 0.5);\n    y.set(mouseYPos / rect.height - 0.5);\n\n    if (spotlight) {\n      mouseX.set(mouseXPos);\n      mouseY.set(mouseYPos);\n      spotlightX.set(mouseXPos);\n      spotlightY.set(mouseYPos);\n    }\n  };\n\n  const handleMouseLeave = () => {\n    if (isRevealed && !isAnimating.current) {\n      setTimeout(() => {\n        if (isRevealed && !isAnimating.current) {\n          x.set(0);\n          y.set(0);\n        }\n      }, 50);\n    }\n  };\n\n  const renderSkillIcon = (skill: Skill) => {\n    if (typeof skill.icon === 'string') {\n      if (skill.icon.startsWith('<svg')) {\n        return (\n          <div\n            dangerouslySetInnerHTML={{ __html: skill.icon }}\n            className='w-5 h-5 flex items-center justify-center'\n          />\n        );\n      } else {\n        return (\n          <Image src={skill.icon} alt={skill.name} width={20} height={20} />\n        );\n      }\n    }\n\n    if (React.isValidElement(skill.icon)) {\n      return React.cloneElement(skill.icon, {\n        className: 'w-5 h-5',\n      } as React.HTMLAttributes<HTMLElement>);\n    }\n\n    if (typeof skill.icon === 'function') {\n      const IconComponent = skill.icon;\n      return <IconComponent className='w-5 h-5' />;\n    }\n\n    return null;\n  };\n\n  return (\n    <div className='flex items-center justify-center'>\n      <motion.div\n        ref={cardRef}\n        className={`relative w-68 h-[21.2rem] rounded-[15px] overflow-hidden shadow-lg dark:shadow-[0_4px_10px_rgba(255,255,255,0.1)] bg-neutral-50 dark:bg-black ${\n          spotlight && isRevealed ? 'group' : ''\n        }`}\n        onMouseMove={handleMouseMove}\n        onMouseLeave={handleMouseLeave}\n        style={\n          isRevealed\n            ? {\n                rotateX,\n                rotateY,\n                translateX,\n                translateY,\n                transformStyle: 'preserve-3d',\n                transition: 'transform 0.1s ease-out',\n              }\n            : {}\n        }\n      >\n        {spotlight && isRevealed && (\n          <motion.div\n            className='pointer-events-none absolute -inset-px rounded-[15px] opacity-0 transition duration-300 group-hover:opacity-100'\n            style={{ backgroundImage }}\n          />\n        )}\n        <motion.div\n          initial={{ width: '100%', height: '100%' }}\n          animate={{\n            width: isImageShrunken ? '6rem' : '100%',\n            height: isImageShrunken ? '8rem' : '100%',\n            top: isImageShrunken ? '4.5rem' : 0,\n            left: isImageShrunken ? '1rem' : 0,\n            borderRadius: isImageShrunken ? '0.5rem' : '0px',\n          }}\n          transition={{ duration: 0.4, ease: 'easeInOut' }}\n          className='absolute overflow-hidden'\n        >\n          <Image src={img} alt={name} fill className='object-cover' />\n\n          <motion.div\n            className='absolute top-2 right-2 w-6.75 h-7.25 flex items-center justify-center bg-white rounded shadow-sm cursor-grab active:cursor-grabbing z-10'\n            drag={!isRevealed ? 'x' : false}\n            dragConstraints={{ left: 0, right: dragThreshold }}\n            dragElastic={0.1}\n            dragMomentum={false}\n            onDragEnd={handleDragEnd}\n            style={{ x: dragX }}\n            animate={arrowControls}\n            whileTap={!isRevealed ? { scale: 1.1 } : {}}\n          >\n            <motion.div style={{ rotate: arrowRotation }}>\n              <ArrowBigLeft className='w-4 h-4 text-black pointer-events-none' />\n            </motion.div>\n          </motion.div>\n        </motion.div>\n\n        <AnimatePresence>\n          {isRevealed && (\n            <motion.div\n              key='content'\n              className='absolute inset-0'\n              initial={{ opacity: 0 }}\n              animate={{ opacity: 1 }}\n              exit={{ opacity: 0 }}\n              transition={{ duration: 0.3 }}\n            >\n              <motion.div\n                className='absolute top-2 right-2 w-6 h-6 flex items-center justify-center dark:bg-white bg-black rounded-full cursor-pointer z-20'\n                onClick={resetCard}\n                whileHover={{ scale: 1.1 }}\n                whileTap={{ scale: 0.95 }}\n              >\n                <X\n                  className='w-4 h-4 text-white dark:text-black'\n                  strokeWidth={2}\n                />\n              </motion.div>\n\n              <div className='p-4'>\n                <h1 className='text-xl font-bold tracking-wider'>{name}</h1>\n                <p className='text-sm tracking-wider'>{position}</p>\n              </div>\n\n              <div className='absolute top-18 left-32'>\n                <h3 className='text-lg font-semibold mb-2'>Skills</h3>\n                <div className='flex flex-wrap gap-2'>\n                  {skills.map((skill, index) => (\n                    <div\n                      key={index}\n                      className={`bg-gray-300 dark:bg-gray-800 rounded-md p-1 flex items-center justify-center w-8 h-8 ${\n                        spotlight ? 'group relative overflow-hidden' : ''\n                      }`}\n                      title={skill.name}\n                      onMouseMove={\n                        spotlight\n                          ? (e) => {\n                              const rect =\n                                e.currentTarget.getBoundingClientRect();\n                              const x = e.clientX - rect.left;\n                              const y = e.clientY - rect.top;\n                              e.currentTarget.style.setProperty(\n                                '--spotlight-x',\n                                `${x}px`,\n                              );\n                              e.currentTarget.style.setProperty(\n                                '--spotlight-y',\n                                `${y}px`,\n                              );\n                            }\n                          : undefined\n                      }\n                    >\n                      {spotlight && (\n                        <div\n                          className='pointer-events-none absolute -inset-px rounded-md opacity-0 transition duration-300 group-hover:opacity-100'\n                          style={{\n                            background: `radial-gradient(100px circle at var(--spotlight-x, 50%) var(--spotlight-y, 50%), rgba(${spotlightColor}, 0.2), transparent)`,\n                          }}\n                        />\n                      )}\n                      <div className='relative z-10'>\n                        {renderSkillIcon(skill)}\n                      </div>\n                    </div>\n                  ))}\n                </div>\n              </div>\n\n              <div className='absolute top-52 left-0 px-4'>\n                <p className='text-sm'>{bio}</p>\n              </div>\n\n              <div className='absolute bottom-4 left-4 flex gap-4'>\n                {socialLinks.map((social, index) => {\n                  const renderIcon = () => {\n                    if (typeof social.icon === 'string') {\n                      return (\n                        <Image\n                          src={social.icon}\n                          alt={social.name}\n                          fill\n                          className='object-contain'\n                        />\n                      );\n                    } else if (React.isValidElement(social.icon)) {\n                      return React.cloneElement(social.icon, {\n                        className: 'w-5 h-5',\n                        width: 20,\n                        height: 20,\n                      } as React.HTMLAttributes<HTMLElement>);\n                    } else if (typeof social.icon === 'function') {\n                      const IconComponent = social.icon;\n                      return <IconComponent className='w-5 h-5' />;\n                    }\n                    return null;\n                  };\n\n                  return (\n                    <Link\n                      key={index}\n                      href={social.url}\n                      target='_blank'\n                      rel='noreferrer'\n                    >\n                      <div\n                        className={`w-5 h-5 relative flex items-center justify-center ${\n                          spotlight ? 'group overflow-hidden rounded' : ''\n                        }`}\n                        title={social.name}\n                        onMouseMove={\n                          spotlight\n                            ? (e) => {\n                                const rect =\n                                  e.currentTarget.getBoundingClientRect();\n                                const x = e.clientX - rect.left;\n                                const y = e.clientY - rect.top;\n                                e.currentTarget.style.setProperty(\n                                  '--spotlight-x',\n                                  `${x}px`,\n                                );\n                                e.currentTarget.style.setProperty(\n                                  '--spotlight-y',\n                                  `${y}px`,\n                                );\n                              }\n                            : undefined\n                        }\n                      >\n                        {spotlight && (\n                          <div\n                            className='pointer-events-none absolute -inset-px rounded opacity-0 transition duration-300 group-hover:opacity-100'\n                            style={{\n                              background: `radial-gradient(80px circle at var(--spotlight-x, 50%) var(--spotlight-y, 50%), rgba(${spotlightColor}, 0.2), transparent)`,\n                            }}\n                          />\n                        )}\n                        <div className='relative z-10'>{renderIcon()}</div>\n                      </div>\n                      <span className='sr-only'>{social.name}</span>\n                    </Link>\n                  );\n                })}\n              </div>\n            </motion.div>\n          )}\n        </AnimatePresence>\n\n        {!isRevealed && !isImageShrunken && (\n          <motion.div\n            className='absolute top-2.5 right-8.75 text-white text-xs opacity-80 bg-black bg-opacity-50 px-2 py-1 rounded'\n            initial={{ opacity: 0 }}\n            animate={{\n              opacity: [0, 0.8, 0],\n              transition: { repeat: Infinity, duration: 2, repeatDelay: 1 },\n            }}\n          >\n            Drag →\n          </motion.div>\n        )}\n      </motion.div>\n    </div>\n  );\n}\n"
    }
  ]
}
