{
  "name": "sticky-scroll-reveal",
  "type": "registry:ui",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/sticky-scroll-reveal.tsx",
      "content": "\"use client\";\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { useMotionValueEvent, useScroll } from \"motion/react\";\nimport { motion } from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\n\nexport const StickyScroll = ({\n  content,\n  contentClassName,\n}: {\n  content: {\n    title: string;\n    description: string;\n    content?: React.ReactNode | any;\n  }[];\n  contentClassName?: string;\n}) => {\n  const [activeCard, setActiveCard] = React.useState(0);\n  const ref = useRef<any>(null);\n  const { scrollYProgress } = useScroll({\n    // uncomment line 22 and comment line 23 if you DONT want the overflow container and want to have it change on the entire page scroll\n    // target: ref\n    container: ref,\n    offset: [\"start start\", \"end start\"],\n  });\n  const cardLength = content.length;\n\n  useMotionValueEvent(scrollYProgress, \"change\", (latest) => {\n    const cardsBreakpoints = content.map((_, index) => index / cardLength);\n    const closestBreakpointIndex = cardsBreakpoints.reduce(\n      (acc, breakpoint, index) => {\n        const distance = Math.abs(latest - breakpoint);\n        if (distance < Math.abs(latest - cardsBreakpoints[acc])) {\n          return index;\n        }\n        return acc;\n      },\n      0,\n    );\n    setActiveCard(closestBreakpointIndex);\n  });\n\n  const backgroundColors = [\n    \"#0f172a\", // slate-900\n    \"#000000\", // black\n    \"#171717\", // neutral-900\n  ];\n  const linearGradients = [\n    \"linear-gradient(to bottom right, #06b6d4, #10b981)\", // cyan-500 to emerald-500\n    \"linear-gradient(to bottom right, #ec4899, #6366f1)\", // pink-500 to indigo-500\n    \"linear-gradient(to bottom right, #f97316, #eab308)\", // orange-500 to yellow-500\n  ];\n\n  const [backgroundGradient, setBackgroundGradient] = useState(\n    linearGradients[0],\n  );\n\n  useEffect(() => {\n    setBackgroundGradient(linearGradients[activeCard % linearGradients.length]);\n  }, [activeCard]);\n\n  return (\n    <motion.div\n      animate={{\n        backgroundColor: backgroundColors[activeCard % backgroundColors.length],\n      }}\n      className=\"relative flex h-[30rem] justify-center space-x-10 overflow-y-auto rounded-md p-10\"\n      ref={ref}\n    >\n      <div className=\"div relative flex items-start px-4\">\n        <div className=\"max-w-2xl\">\n          {content.map((item, index) => (\n            <div key={item.title + index} className=\"my-20\">\n              <motion.h2\n                initial={{\n                  opacity: 0,\n                }}\n                animate={{\n                  opacity: activeCard === index ? 1 : 0.3,\n                }}\n                className=\"text-2xl font-bold text-slate-100\"\n              >\n                {item.title}\n              </motion.h2>\n              <motion.p\n                initial={{\n                  opacity: 0,\n                }}\n                animate={{\n                  opacity: activeCard === index ? 1 : 0.3,\n                }}\n                className=\"text-kg mt-10 max-w-sm text-slate-300\"\n              >\n                {item.description}\n              </motion.p>\n            </div>\n          ))}\n          <div className=\"h-40\" />\n        </div>\n      </div>\n      <div\n        style={{ background: backgroundGradient }}\n        className={cn(\n          \"sticky top-10 hidden h-60 w-80 overflow-hidden rounded-md bg-white lg:block\",\n          contentClassName,\n        )}\n      >\n        {content[activeCard].content ?? null}\n      </div>\n    </motion.div>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/ui/sticky-scroll-reveal.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Sticky Scroll Reveal"
}