{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "fan-folder",
  "title": "Fan Folder",
  "description": "Cards fan out and spread behind the folder on hover.",
  "files": [
    {
      "path": "components/library/fan-folder.tsx",
      "content": "\"use client\"\n\nimport { motion } from \"motion/react\"\nimport { useId, useState } from \"react\"\n\nconst spring = { type: \"spring\" as const, stiffness: 500, damping: 45, mass: 1 }\n\nconst DEFAULT_SIZE = 80\nconst getScale = (size: number) => size / 121\n\n// ─── Color Themes ────────────────────────────────────────────────────────────\n\ntype ColorTheme = {\n    front: [string, string, string, string, string]\n    back: [string, string, string, string, string]\n    shadowIntensity: { highlight: number; shadow: number; drop: number }\n    borderHighlight: number\n}\n\nconst colorThemes = {\n    black: {\n        front: [\"#4A4A4A\", \"#2C2C2C\", \"#1A1A1A\", \"#0D0D0D\", \"#1F1F1F\"],\n        back: [\"#525252\", \"#3D3D3D\", \"#252525\", \"#181818\", \"#0E0E0E\"],\n        shadowIntensity: { highlight: 0.15, shadow: 0.4, drop: 0.5 },\n        borderHighlight: 0.18,\n    },\n    green: {\n        front: [\"#7A8B6F\", \"#657A58\", \"#566B4A\", \"#465A3C\", \"#526645\"],\n        back: [\"#5C6B50\", \"#4F5E44\", \"#435139\", \"#38452F\", \"#2E3926\"],\n        shadowIntensity: { highlight: 0.25, shadow: 0.25, drop: 0.35 },\n        borderHighlight: 0.3,\n    },\n    blue: {\n        front: [\"#6B8DB5\", \"#4A7099\", \"#3A5F85\", \"#2B4D6E\", \"#35587A\"],\n        back: [\"#4A6A8A\", \"#3D5A78\", \"#314B65\", \"#263D53\", \"#1E3244\"],\n        shadowIntensity: { highlight: 0.2, shadow: 0.3, drop: 0.4 },\n        borderHighlight: 0.25,\n    },\n    purple: {\n        front: [\"#8B7AAF\", \"#7460A0\", \"#604D8D\", \"#4D3B78\", \"#5A4585\"],\n        back: [\"#6B5A8A\", \"#5C4D78\", \"#4D4065\", \"#3E3353\", \"#322944\"],\n        shadowIntensity: { highlight: 0.2, shadow: 0.3, drop: 0.4 },\n        borderHighlight: 0.25,\n    },\n} satisfies Record<string, ColorTheme>\n\nexport type FanFolderColor = keyof typeof colorThemes\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nexport const FanFolder = ({\n    size = DEFAULT_SIZE,\n    color = \"black\",\n}: {\n    size?: number\n    color?: FanFolderColor\n}) => {\n    const [hovered, setHovered] = useState(false)\n    const s = getScale(size)\n    const svgHeight = Math.round(108 * s)\n    const bodyHeight = Math.round(78 * s)\n    const cardW = Math.round(44 * s)\n    const cardH = Math.round(52 * s)\n    const theme = colorThemes[color] ?? colorThemes.black\n\n    const cardVariants = {\n        hidden: { opacity: 0, y: 0, x: 0, rotate: 0, scale: 1, pointerEvents: \"none\" as const },\n        left: { opacity: 1, y: -38 * s, x: -28 * s, rotate: -15, scale: 1.25, pointerEvents: \"auto\" as const },\n        center: { opacity: 1, y: -47 * s, x: -4 * s, rotate: 6, scale: 1.25, pointerEvents: \"auto\" as const },\n        right: { opacity: 1, y: -34 * s, x: 20 * s, rotate: 23, scale: 1.25, pointerEvents: \"auto\" as const },\n    }\n\n    return (\n        <motion.div\n            className=\"relative cursor-pointer\"\n            style={{ width: size, height: svgHeight }}\n            onHoverStart={() => setHovered(true)}\n            onHoverEnd={() => setHovered(false)}\n            animate={hovered ? { y: 5 } : { y: 0 }}\n            transition={spring}\n        >\n            {/* Folder SVG background */}\n            <FolderSvg size={size} color={color} />\n\n            {/* 3 white cards - fan out on hover */}\n            <motion.div\n                className=\"bg-white absolute rounded-md z-3 shadow-[0_1px_8px_0_rgba(255,255,255,0.25)] top-[40%] left-1/3 origin-bottom\"\n                style={{ width: cardW, height: cardH }}\n                initial=\"hidden\"\n                animate={hovered ? \"left\" : \"hidden\"}\n                variants={cardVariants}\n                transition={spring}\n            />\n            <motion.div\n                className=\"bg-neutral-300 absolute rounded-md z-2 shadow-[0_1px_8px_0_rgba(255,255,255,0.25)] top-[40%] left-1/3 origin-bottom\"\n                style={{ width: cardW, height: cardH }}\n                initial=\"hidden\"\n                animate={hovered ? \"center\" : \"hidden\"}\n                variants={cardVariants}\n                transition={spring}\n            />\n            <motion.div\n                className=\"bg-neutral-400 absolute rounded-md z-1 shadow-[0_1px_8px_0_rgba(255,255,255,0.25)] top-[40%] left-1/3 origin-bottom\"\n                style={{ width: cardW, height: cardH }}\n                initial=\"hidden\"\n                animate={hovered ? \"right\" : \"hidden\"}\n                variants={cardVariants}\n                transition={spring}\n            />\n\n            {/* Folder body overlay */}\n            <div\n                className=\"absolute bottom-0 left-0 z-4\"\n                style={{\n                    width: size,\n                    height: bodyHeight,\n                    borderRadius: `${Math.round(12 * s)}px ${Math.round(12 * s)}px ${Math.round(10 * s)}px ${Math.round(10 * s)}px`,\n                    background: `linear-gradient(160deg, ${theme.front[0]} 0%, ${theme.front[1]} 20%, ${theme.front[2]} 50%, ${theme.front[3]} 80%, ${theme.front[4]} 100%)`,\n                    boxShadow: `inset 0 ${Math.round(2 * s)}px ${Math.round(3 * s)}px rgba(255,255,255,${theme.shadowIntensity.highlight}), inset 0 -${Math.round(2 * s)}px ${Math.round(4 * s)}px rgba(0,0,0,${theme.shadowIntensity.shadow}), 0 ${Math.round(2 * s)}px ${Math.round(8 * s)}px rgba(0,0,0,${theme.shadowIntensity.drop})`,\n                    borderTop: `${Math.max(1, Math.round(1 * s))}px solid rgba(255,255,255,${theme.borderHighlight})`,\n                    borderLeft: `${Math.max(1, Math.round(0.5 * s))}px solid rgba(255,255,255,${theme.borderHighlight * 0.5})`,\n                    borderRight: `${Math.max(1, Math.round(0.5 * s))}px solid rgba(0,0,0,${theme.borderHighlight * 0.25})`,\n                    borderBottom: `${Math.max(1, Math.round(1 * s))}px solid rgba(0,0,0,${theme.borderHighlight * 0.7})`,\n                }}\n            />\n        </motion.div>\n    )\n}\n\n// ─── SVG Back Panel ──────────────────────────────────────────────────────────\n\nconst FOLDER_PATH = \"M 0 15.319 C 0 6.858 7.179 0 16.035 0 L 34.354 0 C 39.172 0 43.878 1.382 47.864 3.968 L 60.431 12.117 C 64.416 14.703 69.122 16.085 73.94 16.085 L 104.697 16.085 C 113.527 16.085 120.696 22.905 120.733 31.341 L 121 92.617 C 121.037 101.103 113.847 108 104.964 108 L 16.035 108 C 7.179 108 0 101.142 0 92.681 Z\"\n\nexport const FolderSvg = ({\n    size = DEFAULT_SIZE,\n    color = \"black\",\n}: {\n    size?: number\n    color?: FanFolderColor\n}) => {\n    const s = getScale(size)\n    const uid = useId()\n    const theme = colorThemes[color] ?? colorThemes.black\n\n    const backId = `f1Back-${uid}`\n    const shineId = `f1Shine-${uid}`\n    const edgeId = `f1Edge-${uid}`\n    const vignetteId = `f1Vignette-${uid}`\n\n    return (\n        <svg xmlns=\"http://www.w3.org/2000/svg\" width={size} height={Math.round(108 * s)} viewBox=\"0 0 121 108\" fill=\"none\">\n            <defs>\n                <linearGradient id={backId} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n                    <stop offset=\"0%\" stopColor={theme.back[0]} />\n                    <stop offset=\"15%\" stopColor={theme.back[1]} />\n                    <stop offset=\"45%\" stopColor={theme.back[2]} />\n                    <stop offset=\"75%\" stopColor={theme.back[3]} />\n                    <stop offset=\"100%\" stopColor={theme.back[4]} />\n                </linearGradient>\n                <linearGradient id={shineId} x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0.6\">\n                    <stop offset=\"0%\" stopColor=\"rgba(255,255,255,0.14)\" />\n                    <stop offset=\"30%\" stopColor=\"rgba(255,255,255,0.04)\" />\n                    <stop offset=\"60%\" stopColor=\"rgba(255,255,255,0)\" />\n                    <stop offset=\"85%\" stopColor=\"rgba(255,255,255,0.06)\" />\n                    <stop offset=\"100%\" stopColor=\"rgba(0,0,0,0.2)\" />\n                </linearGradient>\n                <linearGradient id={edgeId} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n                    <stop offset=\"0%\" stopColor=\"rgba(255,255,255,0.22)\" />\n                    <stop offset=\"8%\" stopColor=\"rgba(255,255,255,0.05)\" />\n                    <stop offset=\"100%\" stopColor=\"rgba(0,0,0,0)\" />\n                </linearGradient>\n                <radialGradient id={vignetteId} cx=\"0.5\" cy=\"0.3\" r=\"0.7\">\n                    <stop offset=\"0%\" stopColor=\"rgba(255,255,255,0.05)\" />\n                    <stop offset=\"100%\" stopColor=\"rgba(0,0,0,0.18)\" />\n                </radialGradient>\n            </defs>\n            <path d={FOLDER_PATH} fill={`url(#${backId})`} />\n            <path d={FOLDER_PATH} fill={`url(#${shineId})`} />\n            <path d={FOLDER_PATH} fill={`url(#${edgeId})`} />\n            <path d={FOLDER_PATH} fill={`url(#${vignetteId})`} />\n            <path d={FOLDER_PATH} fill=\"none\" stroke=\"rgba(255,255,255,0.08)\" strokeWidth=\"0.5\" />\n        </svg>\n    )\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}