{
  "name": "images-badge",
  "type": "registry:ui",
  "files": [
    {
      "path": "components/ui/images-badge.tsx",
      "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion } from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface ImagesBadgeProps {\n  text: string;\n  images: string[];\n  className?: string;\n  /** Optional link URL */\n  href?: string;\n  /** Link target attribute (e.g., \"_blank\" for new tab) */\n  target?: string;\n  /** Folder dimensions { width, height } in pixels */\n  folderSize?: { width: number; height: number };\n  /** Image dimensions when teased (peeking) { width, height } in pixels */\n  teaserImageSize?: { width: number; height: number };\n  /** Image dimensions when hovered { width, height } in pixels */\n  hoverImageSize?: { width: number; height: number };\n  /** How far images translate up on hover in pixels */\n  hoverTranslateY?: number;\n  /** How far images spread horizontally on hover in pixels */\n  hoverSpread?: number;\n  /** Rotation angle for fanned images on hover in degrees */\n  hoverRotation?: number;\n}\n\nexport function ImagesBadge({\n  text,\n  images,\n  className,\n  href,\n  target,\n  folderSize = { width: 32, height: 24 },\n  teaserImageSize = { width: 20, height: 14 },\n  hoverImageSize = { width: 48, height: 32 },\n  hoverTranslateY = -35,\n  hoverSpread = 20,\n  hoverRotation = 15,\n}: ImagesBadgeProps) {\n  const [isHovered, setIsHovered] = useState(false);\n\n  // Limit to max 3 images\n  const displayImages = images.slice(0, 3);\n\n  // Calculate folder tab dimensions proportionally\n  const tabWidth = folderSize.width * 0.375;\n  const tabHeight = folderSize.height * 0.25;\n\n  const Component = href ? \"a\" : \"div\";\n\n  return (\n    <Component\n      href={href}\n      target={target}\n      rel={target === \"_blank\" ? \"noopener noreferrer\" : undefined}\n      className={cn(\n        \"inline-flex cursor-pointer items-center gap-2 perspective-[1000px] transform-3d\",\n        className,\n      )}\n      onMouseEnter={() => setIsHovered(true)}\n      onMouseLeave={() => setIsHovered(false)}\n    >\n      {/* Folder Container */}\n      <motion.div\n        className=\"relative\"\n        style={{\n          width: folderSize.width,\n          height: folderSize.height,\n          transformStyle: \"preserve-3d\",\n        }}\n      >\n        {/* Folder Back */}\n        <div className=\"absolute inset-0 rounded-[4px] bg-gradient-to-b from-amber-400 to-amber-500 shadow-sm dark:from-amber-500 dark:to-amber-600\">\n          {/* Folder Tab */}\n          <div\n            className=\"absolute left-0.5 rounded-t-[2px] bg-gradient-to-b from-amber-300 to-amber-400 dark:from-amber-400 dark:to-amber-500\"\n            style={{\n              top: -tabHeight * 0.65,\n              width: tabWidth,\n              height: tabHeight,\n            }}\n          />\n        </div>\n\n        {/* Images that pop out */}\n        {displayImages.map((image, index) => {\n          const totalImages = displayImages.length;\n\n          // Calculate rotation based on index\n          const baseRotation =\n            totalImages === 1\n              ? 0\n              : totalImages === 2\n                ? (index - 0.5) * hoverRotation\n                : (index - 1) * hoverRotation;\n\n          // Hover positions - fan out\n          const hoverY = hoverTranslateY - (totalImages - 1 - index) * 3;\n          const hoverX =\n            totalImages === 1\n              ? 0\n              : totalImages === 2\n                ? (index - 0.5) * hoverSpread\n                : (index - 1) * hoverSpread;\n\n          // Teaser positions - slight peek from folder\n          const teaseY = -4 - (totalImages - 1 - index) * 1;\n          const teaseRotation =\n            totalImages === 1\n              ? 0\n              : totalImages === 2\n                ? (index - 0.5) * 3\n                : (index - 1) * 3;\n\n          return (\n            <motion.div\n              key={index}\n              className=\"absolute top-0.5 left-1/2 origin-bottom overflow-hidden rounded-[3px] bg-white shadow-sm ring-1 shadow-black/10 ring-black/10 dark:bg-neutral-800 dark:shadow-white/10 dark:ring-white/10\"\n              animate={{\n                x: `calc(-50% + ${isHovered ? hoverX : 0}px)`,\n                y: isHovered ? hoverY : teaseY,\n                rotate: isHovered ? baseRotation : teaseRotation,\n                width: isHovered ? hoverImageSize.width : teaserImageSize.width,\n                height: isHovered\n                  ? hoverImageSize.height\n                  : teaserImageSize.height,\n              }}\n              transition={{\n                type: \"spring\",\n                stiffness: 400,\n                damping: 25,\n                delay: index * 0.03,\n              }}\n              style={{\n                zIndex: 10 + index,\n              }}\n            >\n              <img\n                src={image}\n                alt={`Preview ${index + 1}`}\n                className=\"h-full w-full object-cover\"\n              />\n            </motion.div>\n          );\n        })}\n\n        {/* Folder Front (flattens on hover) */}\n        <motion.div\n          className=\"absolute inset-x-0 bottom-0 h-[85%] origin-bottom rounded-[4px] bg-gradient-to-b from-amber-300 to-amber-400 shadow-sm dark:from-amber-400 dark:to-amber-500\"\n          animate={{\n            rotateX: isHovered ? -45 : -25,\n            scaleY: isHovered ? 0.8 : 1,\n          }}\n          transition={{\n            type: \"spring\",\n            stiffness: 400,\n            damping: 25,\n          }}\n          style={{\n            transformStyle: \"preserve-3d\",\n            zIndex: 20,\n          }}\n        >\n          {/* Folder line detail */}\n          <div className=\"absolute top-1 right-1 left-1 h-px bg-amber-200/50 dark:bg-amber-300/50\" />\n        </motion.div>\n      </motion.div>\n\n      {/* Text */}\n      <span className=\"text-sm font-medium text-neutral-700 dark:text-neutral-200\">\n        {text}\n      </span>\n    </Component>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/ui/images-badge.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Images Badge"
}