{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-animate-footer",
  "title": "Footer ",
  "description": "A minimal footer design inspired by Dia browser.",
  "dependencies": [
    "gsap"
  ],
  "files": [
    {
      "path": "registry/components/animate/footer/index.tsx",
      "content": "'use client';\n\nimport { useEffect, useMemo, useRef } from 'react';\nimport { gsap } from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\nimport { SplitText } from 'gsap/SplitText';\n\ngsap.registerPlugin(ScrollTrigger, SplitText);\n\ntype FooterColorProps = {\n  text?: string;\n  gradient?: string[];\n};\n\ntype FooterThemePreset = {\n  text: string;\n  gradient: string[];\n};\n\nexport const FOOTER_THEME_PRESETS = {\n  'dia-browser': {\n    text: '#3F3F46',\n    gradient: [\n      '#1D4ED8',\n      '#60A5FA',\n      '#E5E7EB',\n      '#fbbb0c',\n      '#f93b3b',\n      '#FB7185',\n      '#EC4899',\n      '#fb3af2',\n    ],\n  },\n  ocean: {\n    text: '#0F172A',\n    gradient: [\n      '#1E3A8A',\n      '#1D4ED8',\n      '#2563EB',\n      '#3B82F6',\n      '#60A5FA',\n      '#93C5FD',\n      '#BFDBFE',\n      '#E0F2FE',\n    ],\n  },\n  amber: {\n    text: '#451A03',\n    gradient: [\n      '#FEF3C7',\n      '#FCD34D',\n      '#F59E0B',\n      '#D97706',\n      '#B45309',\n      '#92400E',\n      '#78350F',\n      '#451A03',\n    ],\n  },\n  emerald: {\n    text: '#022C22',\n    gradient: [\n      '#D1FAE5',\n      '#6EE7B7',\n      '#34D399',\n      '#10B981',\n      '#059669',\n      '#047857',\n      '#065F46',\n      '#022C22',\n    ],\n  },\n  violet: {\n    text: '#2E1065',\n    gradient: [\n      '#F5F3FF',\n      '#DDD6FE',\n      '#C4B5FD',\n      '#A78BFA',\n      '#8B5CF6',\n      '#7C3AED',\n      '#6D28D9',\n      '#4C1D95',\n    ],\n  },\n  rose: {\n    text: '#4A044E',\n    gradient: [\n      '#FFE4E6',\n      '#FDA4AF',\n      '#FB7185',\n      '#F43F5E',\n      '#E11D48',\n      '#BE123C',\n      '#9F1239',\n      '#4A044E',\n    ],\n  },\n} satisfies Record<string, FooterThemePreset>;\n\nexport type FooterTheme = keyof typeof FOOTER_THEME_PRESETS;\n\ntype FooterProps = {\n  colors?: FooterColorProps;\n  theme?: FooterTheme;\n  copyrightText?: string;\n};\n\nconst DEFAULT_FOOTER_THEME: FooterTheme = 'dia-browser';\n\nconst currentYear = new Date().getFullYear();\n\nexport default function Footer({\n  colors,\n  theme = DEFAULT_FOOTER_THEME,\n  copyrightText,\n}: FooterProps) {\n  const rootRef = useRef<HTMLDivElement>(null);\n\n  const activeTheme = useMemo(\n    () =>\n      FOOTER_THEME_PRESETS[theme] ?? FOOTER_THEME_PRESETS[DEFAULT_FOOTER_THEME],\n    [theme],\n  );\n\n  const resolvedColors = useMemo(() => {\n    const gradient = Array.from({ length: 8 }, (_, index) => {\n      return (\n        colors?.gradient?.[index] ?? activeTheme.gradient[index] ?? '#9A3412'\n      );\n    });\n\n    return {\n      text: colors?.text ?? activeTheme.text,\n      gradient,\n    };\n  }, [activeTheme, colors]);\n\n  useEffect(() => {\n    const root = rootRef.current;\n    if (!root) {\n      return;\n    }\n\n    if (typeof gsap === 'undefined') {\n      console.error('GSAP is not loaded. Cannot proceed with animations.');\n      const elements = root.querySelectorAll<Element>(\n        '.svg-container, .main-title',\n      );\n      elements.forEach((el: Element) => {\n        (el as HTMLElement).style.opacity = '1';\n      });\n      return;\n    }\n\n    const ctx = gsap.context(() => {\n      const svg = root.querySelector('svg');\n      if (svg) {\n        for (let i = 0; i < 9; i++) {\n          const gradient = svg.getElementById?.(\n            `grad${i}`,\n          ) as SVGLinearGradientElement | null;\n          if (gradient) {\n            gradient\n              .querySelectorAll<SVGStopElement>('stop')\n              .forEach((stop: SVGStopElement, idx: number) => {\n                if (idx < resolvedColors.gradient.length) {\n                  stop.setAttribute('stop-color', resolvedColors.gradient[idx]);\n                } else if (\n                  resolvedColors.gradient[resolvedColors.gradient.length - 1]\n                ) {\n                  stop.setAttribute(\n                    'stop-color',\n                    resolvedColors.gradient[resolvedColors.gradient.length - 1],\n                  );\n                }\n              });\n          }\n        }\n      }\n\n      const animationSection = root.querySelector('.animation-section') ?? root;\n      const mainTitle = root.querySelector<Element>('.main-title');\n      const allSplitLines: gsap.TweenTarget[] = [];\n\n      if (mainTitle) {\n        const mainTitleSplit = new SplitText(mainTitle, { type: 'lines' });\n        gsap.set(mainTitleSplit.lines, {\n          opacity: 0,\n          y: 30,\n          filter: 'blur(8px)',\n        });\n        allSplitLines.push(...mainTitleSplit.lines);\n      }\n\n      gsap\n        .timeline({\n          scrollTrigger: {\n            trigger: animationSection,\n            start: 'top bottom',\n            end: 'bottom bottom',\n            scrub: 1,\n          },\n        })\n        .to('.svg-container', { autoAlpha: 1, duration: 0.01 }, 0)\n        .to('.main-title', { autoAlpha: 1, duration: 0.01 }, 0)\n        .to(\n          '.svg-container',\n          {\n            transform: 'scaleY(0.05) translateY(-30px)',\n            duration: 0.3,\n            ease: 'power2.out',\n          },\n          0,\n        )\n        .to(\n          '.svg-container',\n          {\n            transform: 'scaleY(1) translateY(0px)',\n            duration: 1.2,\n            ease: 'power2.out',\n          },\n          0.3,\n        )\n        .to(\n          allSplitLines,\n          {\n            duration: 0.8,\n            y: 0,\n            opacity: 1,\n            filter: 'blur(0px)',\n            stagger: 0.08,\n            ease: 'power2.out',\n          },\n          0.9,\n        );\n    }, root);\n\n    const handleResize = () => {\n      ScrollTrigger.refresh();\n    };\n\n    window.addEventListener('resize', handleResize);\n\n    return () => {\n      window.removeEventListener('resize', handleResize);\n      ctx.revert();\n    };\n  }, [resolvedColors]);\n\n  const footerCopy = copyrightText ?? `copyright © ${currentYear} — Sahil Rana`;\n\n  return (\n    <div ref={rootRef} className=\"overflow-x-hidden mt-[40vh]\">\n      <div className=\"scroll-space bg-background transition-colors duration-300\" />\n      <div className=\"animation-section relative h-screen bg-background transition-colors duration-300\">\n        <div className=\"footer-container pointer-events-none fixed inset-x-0 bottom-0 z-10 h-screen\">\n          <div className=\"svg-container pointer-events-none absolute inset-x-0 bottom-0 z-15 h-screen origin-bottom opacity-0 will-change-[transform,opacity,filter] transform-[scaleY(0.05)_translateY(100vh)]\">\n            <svg\n              className=\"spectrum-svg size-full\"\n              viewBox=\"0 0 1567 584\"\n              preserveAspectRatio=\"none\"\n              fill=\"none\"\n              xmlns=\"http://www.w3.org/2000/svg\"\n            >\n              <g clipPath=\"url(#clip)\" filter=\"url(#blur)\">\n                <path d=\"M1219 584H1393V184H1219V584Z\" fill=\"url(#grad0)\" />\n                <path d=\"M1045 584H1219V104H1045V584Z\" fill=\"url(#grad1)\" />\n                <path\n                  d=\"M348 584H174L174 184H348L348 584Z\"\n                  fill=\"url(#grad2)\"\n                />\n                <path\n                  d=\"M522 584H348L348 104H522L522 584Z\"\n                  fill=\"url(#grad3)\"\n                />\n                <path d=\"M697 584H522L522 54H697L697 584Z\" fill=\"url(#grad4)\" />\n                <path d=\"M870 584H1045V54H870V584Z\" fill=\"url(#grad5)\" />\n                <path d=\"M870 584H697L697 0H870L870 584Z\" fill=\"url(#grad6)\" />\n                <path\n                  d=\"M174 585H0.000183105L-3.75875e-06 295H174L174 585Z\"\n                  fill=\"url(#grad7)\"\n                />\n                <path d=\"M1393 584H1567V294H1393V584Z\" fill=\"url(#grad8)\" />\n              </g>\n              <defs>\n                <filter\n                  id=\"blur\"\n                  x=\"-30\"\n                  y=\"-30\"\n                  width=\"1627\"\n                  height=\"644\"\n                  filterUnits=\"userSpaceOnUse\"\n                  colorInterpolationFilters=\"sRGB\"\n                >\n                  <feFlood floodOpacity=\"0\" result=\"BackgroundImageFix\" />\n                  <feBlend\n                    mode=\"normal\"\n                    in=\"SourceGraphic\"\n                    in2=\"BackgroundImageFix\"\n                    result=\"shape\"\n                  />\n                  <feGaussianBlur\n                    stdDeviation=\"15\"\n                    result=\"effect1_foregroundBlur\"\n                  />\n                </filter>\n                {Array.from({ length: 9 }, (_, i) => {\n                  const coords: {\n                    x1: string;\n                    y1: string;\n                    x2: string;\n                    y2: string;\n                  } = {\n                    0: { x1: '1306', y1: '584', x2: '1306', y2: '184' },\n                    1: { x1: '1132', y1: '584', x2: '1132', y2: '104' },\n                    2: { x1: '261', y1: '584', x2: '261', y2: '184' },\n                    3: { x1: '435', y1: '584', x2: '435', y2: '104' },\n                    4: { x1: '609.501', y1: '584', x2: '609.501', y2: '54' },\n                    5: { x1: '957.5', y1: '584', x2: '957.5', y2: '54' },\n                    6: { x1: '783.501', y1: '584', x2: '783.501', y2: '0' },\n                    7: { x1: '87.0003', y1: '585', x2: '87.0003', y2: '295' },\n                    8: { x1: '1480', y1: '584', x2: '1480', y2: '294' },\n                  }[i] || { x1: '1306', y1: '584', x2: '1306', y2: '184' };\n\n                  return (\n                    <linearGradient\n                      key={`grad${i}`}\n                      id={`grad${i}`}\n                      x1={coords.x1}\n                      y1={coords.y1}\n                      x2={coords.x2}\n                      y2={coords.y2}\n                      gradientUnits=\"userSpaceOnUse\"\n                    >\n                      <stop stopColor={resolvedColors.gradient[0]} />\n                      <stop\n                        offset=\"0.182709\"\n                        stopColor={resolvedColors.gradient[1]}\n                      />\n                      <stop\n                        offset=\"0.283673\"\n                        stopColor={resolvedColors.gradient[2]}\n                      />\n                      <stop\n                        offset=\"0.413484\"\n                        stopColor={resolvedColors.gradient[3]}\n                      />\n                      <stop\n                        offset=\"0.586565\"\n                        stopColor={resolvedColors.gradient[4]}\n                      />\n                      <stop\n                        offset=\"0.682722\"\n                        stopColor={resolvedColors.gradient[5]}\n                      />\n                      <stop\n                        offset=\"0.802892\"\n                        stopColor={resolvedColors.gradient[6]}\n                      />\n                      <stop\n                        offset=\"1\"\n                        stopColor={resolvedColors.gradient[7]}\n                        stopOpacity=\"0\"\n                      />\n                    </linearGradient>\n                  );\n                })}\n                <clipPath id=\"clip\">\n                  <rect width=\"1567\" height=\"584\" fill=\"white\" />\n                </clipPath>\n              </defs>\n            </svg>\n          </div>\n          <div\n            className=\"main-title pointer-events-none absolute bottom-1/2 left-1/2 z-20 -translate-x-1/2 translate-y-1/2 bg-transparent text-center text-foreground leading-[1.4] opacity-0 transition-colors duration-300 font-serif\"\n            style={{ color: resolvedColors.text }}\n          >\n            {footerCopy}\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/odysseyui/footer.tsx"
    }
  ],
  "type": "registry:ui"
}