{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "navbar-flow",
  "type": "registry:ui",
  "title": "Navbar Flow",
  "description": "Animated navbar component with flowing SVG connections and dropdown menus.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion", "lucide-react"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/navbar-flow.tsx",
      "content": "'use client';\nimport React, { useEffect, useState } from 'react';\nimport { motion, useAnimation } from 'motion/react';\nimport {\n  Menu as List,\n  X as Close,\n  ChevronDown as ArrowDown,\n  ChevronUp as ArrowUp,\n} from 'lucide-react';\n\ninterface NavLink {\n  text: string;\n  url?: string;\n  submenu?: React.ReactNode;\n}\n\ninterface NavbarFlowProps {\n  emblem?: React.ReactNode;\n  links?: NavLink[];\n  extraIcons?: React.ReactNode[];\n  styleName?: string;\n  rightComponent?: React.ReactNode;\n}\n\ninterface ListItemProps {\n  setSelected: (element: string | null) => void;\n  selected: string | null;\n  element: string;\n  children: React.ReactNode;\n}\n\ninterface HoverLinkProps {\n  url: string;\n  children: React.ReactNode;\n  onPress?: () => void;\n}\n\ninterface FeatureItemProps {\n  heading: string;\n  url: string;\n  info: string;\n  onPress?: () => void;\n}\n\nconst springTransition = {\n  type: 'spring' as const,\n  mass: 0.5,\n  damping: 11.5,\n  stiffness: 100,\n  restDelta: 0.001,\n  restSpeed: 0.001,\n};\n\nconst ListItem: React.FC<ListItemProps> = ({\n  setSelected,\n  selected,\n  element,\n  children,\n}) => {\n  return (\n    <div\n      className='relative'\n      onMouseEnter={() => setSelected(element)}\n      onMouseLeave={(e) => {\n        const dropdown = e.currentTarget.querySelector('.dropdown-content');\n        if (dropdown) {\n          const dropdownRect = dropdown.getBoundingClientRect();\n          if (e.clientY < dropdownRect.top - 20) {\n            setSelected(null);\n          }\n        }\n      }}\n    >\n      <motion.p\n        transition={{ duration: 0.3 }}\n        className='cursor-pointer text-gray-800 dark:text-gray-200 font-medium text-base lg:text-xl whitespace-nowrap hover:opacity-[0.9] hover:text-gray-900 dark:hover:text-white py-1'\n      >\n        {element}\n      </motion.p>\n      {selected !== null && (\n        <motion.div\n          initial={{ opacity: 0, scale: 0.85, y: 10 }}\n          animate={{ opacity: 1, scale: 1, y: 0 }}\n          transition={springTransition}\n        >\n          {selected === element && (\n            <div className='absolute top-[calc(100%+0.5rem)] left-1/2 transform -translate-x-1/2 z-50'>\n              <motion.div\n                transition={springTransition}\n                layoutId='selected'\n                className='dropdown-content bg-white dark:bg-black backdrop-blur-xs rounded-2xl overflow-hidden border border-gray-200 dark:border-gray-700 shadow-2xl'\n                style={{\n                  maxWidth: 'min(90vw, 400px)',\n                }}\n                onMouseEnter={() => setSelected(element)}\n                onMouseLeave={() => setSelected(null)}\n              >\n                <motion.div layout className='w-max h-full p-4 min-w-48'>\n                  {children}\n                </motion.div>\n              </motion.div>\n            </div>\n          )}\n        </motion.div>\n      )}\n    </div>\n  );\n};\n\nexport const HoverLink: React.FC<HoverLinkProps> = ({\n  url,\n  children,\n  onPress,\n}) => {\n  return (\n    <a\n      href={url}\n      onClick={onPress}\n      className='block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors'\n    >\n      {children}\n    </a>\n  );\n};\n\nexport const FeatureItem: React.FC<FeatureItemProps> = ({\n  heading,\n  url,\n  info,\n  onPress,\n}) => {\n  return (\n    <a\n      href={url}\n      onClick={onPress}\n      className='block p-3 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors'\n    >\n      <h4 className='font-medium text-gray-900 dark:text-white'>{heading}</h4>\n      <p className='text-sm text-gray-600 dark:text-gray-400 mt-1'>{info}</p>\n    </a>\n  );\n};\n\nconst NavbarFlow: React.FC<NavbarFlowProps> = ({\n  emblem,\n  links = [],\n  extraIcons = [],\n  styleName = '',\n  rightComponent,\n}) => {\n  const [sequenceDone, setSequenceDone] = useState(false);\n  const [mobileMenuVisible, setMobileMenuVisible] = useState(false);\n  const [mobileView, setMobileView] = useState(false);\n  const [selectedSubmenu, setSelectedSubmenu] = useState<string | null>(null);\n  const [openedSections, setOpenedSections] = useState<Record<string, boolean>>(\n    {},\n  );\n  const [isMounted, setIsMounted] = useState(true);\n\n  const navMotion = useAnimation();\n  const emblemMotion = useAnimation();\n  const switchMotion = useAnimation();\n  const svgMotion = useAnimation();\n\n  useEffect(() => {\n    const detectMobile = () => {\n      setMobileView(window.innerWidth < 768);\n    };\n\n    detectMobile();\n    window.addEventListener('resize', detectMobile);\n    return () => window.removeEventListener('resize', detectMobile);\n  }, []);\n\n  useEffect(() => {\n    if (!isMounted) return;\n\n    const runSequence = async () => {\n      if (mobileView) {\n        await Promise.all([\n          emblemMotion.start({\n            opacity: 1,\n            x: 0,\n            transition: { duration: 0.6, ease: 'easeOut' },\n          }),\n          navMotion.start({\n            opacity: 1,\n            transition: { duration: 0.6, ease: 'easeOut' },\n          }),\n          switchMotion.start({\n            opacity: 1,\n            x: 0,\n            transition: { duration: 0.6, ease: 'easeOut' },\n          }),\n        ]);\n      } else {\n        await navMotion.start({\n          width: 'auto',\n          padding: '10px 30px',\n          transition: { duration: 0.8, ease: 'easeOut' },\n        });\n\n        await svgMotion.start({\n          opacity: 1,\n          transition: { duration: 0.5 },\n        });\n\n        await Promise.all([\n          emblemMotion.start({\n            opacity: 1,\n            x: 0,\n            transition: { duration: 0.6, ease: 'easeOut' },\n          }),\n          switchMotion.start({\n            opacity: 1,\n            x: 0,\n            transition: { duration: 0.6, ease: 'easeOut' },\n          }),\n        ]);\n      }\n\n      setSequenceDone(true);\n    };\n\n    runSequence();\n  }, [navMotion, emblemMotion, switchMotion, svgMotion, mobileView, isMounted]);\n\n  const toggleMobileMenu = () => {\n    setMobileMenuVisible(!mobileMenuVisible);\n  };\n\n  const toggleSection = (text: string) => {\n    setOpenedSections((prev) => ({\n      ...prev,\n      [text]: !prev[text],\n    }));\n  };\n\n  const hideMobileMenu = () => {\n    setMobileMenuVisible(false);\n  };\n\n  const renderSubmenuItems = (submenu: React.ReactNode) => {\n    if (!React.isValidElement(submenu)) return null;\n\n    const submenuProps = submenu.props as { children?: React.ReactNode };\n    if (!submenuProps.children) return null;\n\n    return React.Children.map(submenuProps.children, (child, childIdx) => (\n      <div key={childIdx} onClick={hideMobileMenu}>\n        {child}\n      </div>\n    ));\n  };\n\n  return (\n    <div className={`sticky top-0 z-50 w-full ${styleName}`}>\n      <div className='hidden md:block'>\n        <div className='relative w-full max-w-7xl mx-auto h-24 flex items-center justify-between px-4 lg:px-10'>\n          <motion.div\n            initial={{ opacity: 0, x: -50 }}\n            animate={emblemMotion}\n            className='bg-gray-200/80 dark:bg-black/95 backdrop-blur-xs text-gray-800 dark:text-gray-200 px-4 lg:px-8 py-3 lg:py-4 rounded-full font-semibold text-lg lg:text-xl z-10 shrink-0'\n          >\n            {emblem}\n          </motion.div>\n\n          <motion.nav\n            initial={{\n              width: '120px',\n              padding: '8px 20px',\n            }}\n            animate={navMotion}\n            className='bg-gray-200/80 dark:bg-black/95 backdrop-blur-xs rounded-full flex items-center justify-center gap-6 lg:gap-12 z-10 shrink-0'\n            onMouseLeave={() => setSelectedSubmenu(null)}\n          >\n            {links.map((element) => (\n              <div key={element.text}>\n                {element.submenu ? (\n                  <ListItem\n                    setSelected={setSelectedSubmenu}\n                    selected={selectedSubmenu}\n                    element={element.text}\n                  >\n                    {element.submenu}\n                  </ListItem>\n                ) : (\n                  <motion.div\n                    initial={{ opacity: 0 }}\n                    animate={{ opacity: sequenceDone ? 1 : 0 }}\n                  >\n                    <a\n                      href={element.url || '#'}\n                      className='text-gray-800 dark:text-gray-200 font-medium text-base lg:text-xl whitespace-nowrap hover:text-gray-900 dark:hover:text-white transition-colors py-1'\n                    >\n                      {element.text}\n                    </a>\n                  </motion.div>\n                )}\n              </div>\n            ))}\n          </motion.nav>\n\n          <motion.div\n            initial={{ opacity: 0, x: 50 }}\n            animate={switchMotion}\n            className='bg-gray-200/80 dark:bg-black/95 backdrop-blur-xs rounded-full p-2 lg:p-3 z-10 shrink-0 flex items-center gap-2 lg:gap-3'\n          >\n            {extraIcons.map((icon, idx) => (\n              <div key={idx} className='flex items-center justify-center'>\n                {icon}\n              </div>\n            ))}\n\n            {rightComponent && (\n              <div className='flex items-center justify-center'>\n                {rightComponent}\n              </div>\n            )}\n          </motion.div>\n\n          <motion.svg\n            initial={{ opacity: 0 }}\n            animate={svgMotion}\n            className='absolute inset-0 w-full h-full z-0 pointer-events-none'\n            viewBox='0 0 1400 96'\n            preserveAspectRatio='none'\n          >\n            <defs>\n              <filter id='connectionBlur'>\n                <feGaussianBlur in='SourceGraphic' stdDeviation='3' />\n              </filter>\n              <linearGradient\n                id='blueGradient'\n                x1='0%'\n                y1='0%'\n                x2='100%'\n                y2='0%'\n              >\n                <stop offset='0%' stopColor='#3b82f6' stopOpacity='0' />\n                <stop offset='50%' stopColor='#3b82f6' stopOpacity='1' />\n                <stop offset='100%' stopColor='#3b82f6' stopOpacity='0' />\n              </linearGradient>\n              <linearGradient\n                id='cyanGradient'\n                x1='0%'\n                y1='0%'\n                x2='100%'\n                y2='0%'\n              >\n                <stop offset='0%' stopColor='#06b6d4' stopOpacity='0' />\n                <stop offset='50%' stopColor='#06b6d4' stopOpacity='1' />\n                <stop offset='100%' stopColor='#06b6d4' stopOpacity='0' />\n              </linearGradient>\n              <linearGradient\n                id='purpleGradient'\n                x1='0%'\n                y1='0%'\n                x2='100%'\n                y2='0%'\n              >\n                <stop offset='0%' stopColor='#8b5cf6' stopOpacity='0' />\n                <stop offset='50%' stopColor='#8b5cf6' stopOpacity='1' />\n                <stop offset='100%' stopColor='#8b5cf6' stopOpacity='0' />\n              </linearGradient>\n              <linearGradient\n                id='orangeGradient'\n                x1='0%'\n                y1='0%'\n                x2='100%'\n                y2='0%'\n              >\n                <stop offset='0%' stopColor='#f59e0b' stopOpacity='0' />\n                <stop offset='50%' stopColor='#f59e0b' stopOpacity='1' />\n                <stop offset='100%' stopColor='#f59e0b' stopOpacity='0' />\n              </linearGradient>\n              <linearGradient\n                id='redGradient'\n                x1='0%'\n                y1='0%'\n                x2='100%'\n                y2='0%'\n              >\n                <stop offset='0%' stopColor='#ef4444' stopOpacity='0' />\n                <stop offset='50%' stopColor='#ef4444' stopOpacity='1' />\n                <stop offset='100%' stopColor='#ef4444' stopOpacity='0' />\n              </linearGradient>\n              <linearGradient\n                id='greenGradient'\n                x1='0%'\n                y1='0%'\n                x2='100%'\n                y2='0%'\n              >\n                <stop offset='0%' stopColor='#10b981' stopOpacity='0' />\n                <stop offset='50%' stopColor='#10b981' stopOpacity='1' />\n                <stop offset='100%' stopColor='#10b981' stopOpacity='0' />\n              </linearGradient>\n            </defs>\n\n            <motion.path\n              d='M 700 48 Q 500 30, 300 40 Q 200 35, 120 48'\n              stroke='url(#blueGradient)'\n              strokeWidth='3'\n              fill='none'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.8 }}\n              transition={{ duration: 2, ease: 'easeOut', delay: 1.5 }}\n            />\n            <motion.path\n              d='M 700 48 Q 500 30, 300 40 Q 200 35, 120 48'\n              stroke='url(#blueGradient)'\n              strokeWidth='3'\n              fill='none'\n              transform='scale(-1,1) translate(-1400,0)'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.8 }}\n              transition={{ duration: 2, ease: 'easeOut', delay: 1.5 }}\n            />\n            <motion.path\n              d='M 700 44 Q 520 60, 320 50 Q 220 55, 130 44'\n              stroke='url(#cyanGradient)'\n              strokeWidth='2.5'\n              fill='none'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.7 }}\n              transition={{ duration: 2.2, ease: 'easeOut', delay: 1.7 }}\n            />\n            <motion.path\n              d='M 700 44 Q 520 60, 320 50 Q 220 55, 130 44'\n              stroke='url(#cyanGradient)'\n              strokeWidth='2.5'\n              fill='none'\n              transform='scale(-1,1) translate(-1400,0)'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.7 }}\n              transition={{ duration: 2.2, ease: 'easeOut', delay: 1.7 }}\n            />\n            <motion.path\n              d='M 700 52 Q 480 25, 280 45 Q 180 30, 110 52'\n              stroke='url(#purpleGradient)'\n              strokeWidth='2.5'\n              fill='none'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.6 }}\n              transition={{ duration: 1.8, ease: 'easeOut', delay: 1.9 }}\n            />\n            <motion.path\n              d='M 700 52 Q 480 25, 280 45 Q 180 30, 110 52'\n              stroke='url(#purpleGradient)'\n              strokeWidth='2.5'\n              fill='none'\n              transform='scale(-1,1) translate(-1400,0)'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.6 }}\n              transition={{ duration: 1.8, ease: 'easeOut', delay: 1.9 }}\n            />\n            <motion.path\n              d='M 700 48 Q 900 35, 1100 45 Q 1200 40, 1280 48'\n              stroke='url(#orangeGradient)'\n              strokeWidth='3'\n              fill='none'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.8 }}\n              transition={{ duration: 2, ease: 'easeOut', delay: 2.1 }}\n            />\n            <motion.path\n              d='M 700 48 Q 900 35, 1100 45 Q 1200 40, 1280 48'\n              stroke='url(#orangeGradient)'\n              strokeWidth='3'\n              fill='none'\n              transform='scale(-1,1) translate(-1400,0)'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.8 }}\n              transition={{ duration: 2, ease: 'easeOut', delay: 2.1 }}\n            />\n            <motion.path\n              d='M 700 44 Q 880 65, 1080 50 Q 1180 60, 1270 44'\n              stroke='url(#redGradient)'\n              strokeWidth='2.5'\n              fill='none'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.7 }}\n              transition={{ duration: 2.2, ease: 'easeOut', delay: 2.3 }}\n            />\n            <motion.path\n              d='M 700 44 Q 880 65, 1080 50 Q 1180 60, 1270 44'\n              stroke='url(#redGradient)'\n              strokeWidth='2.5'\n              fill='none'\n              transform='scale(-1,1) translate(-1400,0)'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.7 }}\n              transition={{ duration: 2.2, ease: 'easeOut', delay: 2.3 }}\n            />\n            <motion.path\n              d='M 700 52 Q 920 25, 1120 40 Q 1220 30, 1290 52'\n              stroke='url(#greenGradient)'\n              strokeWidth='2.5'\n              fill='none'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.6 }}\n              transition={{ duration: 1.8, ease: 'easeOut', delay: 2.5 }}\n            />\n            <motion.path\n              d='M 700 52 Q 920 25, 1120 40 Q 1220 30, 1290 52'\n              stroke='url(#greenGradient)'\n              strokeWidth='2.5'\n              fill='none'\n              transform='scale(-1,1) translate(-1400,0)'\n              initial={{ pathLength: 0, opacity: 0 }}\n              animate={{ pathLength: 1, opacity: 0.6 }}\n              transition={{ duration: 1.8, ease: 'easeOut', delay: 2.5 }}\n            />\n\n            <g filter='url(#connectionBlur)' opacity='0.3'>\n              <path\n                d='M 700 48 Q 500 30, 300 40 Q 200 35, 120 48'\n                stroke='#3b82f6'\n                strokeWidth='4'\n                fill='none'\n              />\n              <path\n                d='M 700 44 Q 520 60, 320 50 Q 220 55, 130 44'\n                stroke='#06b6d4'\n                strokeWidth='4'\n                fill='none'\n              />\n              <path\n                d='M 700 52 Q 480 25, 280 45 Q 180 30, 110 52'\n                stroke='#8b5cf6'\n                strokeWidth='4'\n                fill='none'\n              />\n              <path\n                d='M 700 48 Q 900 35, 1100 45 Q 1200 40, 1280 48'\n                stroke='#f59e0b'\n                strokeWidth='4'\n                fill='none'\n              />\n              <path\n                d='M 700 44 Q 880 65, 1080 50 Q 1180 60, 1270 44'\n                stroke='#ef4444'\n                strokeWidth='4'\n                fill='none'\n              />\n              <path\n                d='M 700 52 Q 920 25, 1120 40 Q 1220 30, 1290 52'\n                stroke='#10b981'\n                strokeWidth='4'\n                fill='none'\n              />\n            </g>\n          </motion.svg>\n        </div>\n      </div>\n\n      <div className='block md:hidden'>\n        <div className='top-0 z-50 w-full border-b border-gray-200/40 dark:border-gray-800/40 bg-gray-50/95 dark:bg-black/95 backdrop-blur-sm supports-backdrop-filter:bg-gray-50/60 dark:supports-backdrop-filter:bg-black/60 relative'>\n          <div className='container flex h-16 max-w-(--breakpoint-2xl) items-center px-4'>\n            <motion.div\n              initial={{ opacity: 0, x: -20 }}\n              animate={emblemMotion}\n              className='mr-4 shrink-0'\n            >\n              <div className='bg-gray-200/80 dark:bg-gray-800/80 backdrop-blur-xs text-gray-800 dark:text-gray-200 px-4 py-2 rounded-full font-semibold text-base'>\n                {emblem}\n              </div>\n            </motion.div>\n\n            <div className='flex flex-1 items-center justify-end space-x-2'>\n              <motion.div\n                initial={{ opacity: 0, x: 20 }}\n                animate={switchMotion}\n                className='flex items-center space-x-2'\n              >\n                {extraIcons.map((icon, idx) => (\n                  <div key={idx} className='flex items-center justify-center'>\n                    {icon}\n                  </div>\n                ))}\n\n                {rightComponent && (\n                  <div className='flex items-center justify-center'>\n                    {rightComponent}\n                  </div>\n                )}\n              </motion.div>\n\n              <button\n                onClick={toggleMobileMenu}\n                className='flex items-center justify-center w-9 h-9 text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white transition-colors'\n              >\n                {mobileMenuVisible ? (\n                  <Close className='h-5 w-5' />\n                ) : (\n                  <List className='h-5 w-5' />\n                )}\n                <span className='sr-only'>Toggle menu</span>\n              </button>\n            </div>\n          </div>\n\n          <motion.div\n            initial={{ opacity: 0, maxHeight: 0 }}\n            animate={{\n              opacity: mobileMenuVisible ? 1 : 0,\n              maxHeight: mobileMenuVisible ? '80vh' : 0,\n            }}\n            transition={{ duration: 0.3 }}\n            className='absolute left-0 right-0 top-full z-40 overflow-y-auto border-t border-gray-200/40 dark:border-gray-800/40 bg-gray-50/95 dark:bg-black/95 backdrop-blur-sm'\n          >\n            <div className='container py-4 px-4'>\n              <nav className='flex flex-col space-y-3'>\n                {links.map((element, idx) => (\n                  <div key={element.text} className='space-y-2'>\n                    {element.submenu ? (\n                      <>\n                        <button\n                          className='flex items-center justify-between w-full text-gray-800 dark:text-gray-200 font-medium text-base py-2 px-4 rounded-lg hover:bg-gray-200/50 dark:hover:bg-gray-800/50 transition-colors border-b border-gray-200 dark:border-gray-800'\n                          onClick={() => toggleSection(element.text)}\n                        >\n                          <span>{element.text}</span>\n                          <span>\n                            {openedSections[element.text] ? (\n                              <ArrowUp className='h-4 w-4' />\n                            ) : (\n                              <ArrowDown className='h-4 w-4' />\n                            )}\n                          </span>\n                        </button>\n\n                        {openedSections[element.text] && (\n                          <motion.div\n                            initial={{ opacity: 0, height: 0 }}\n                            animate={{ opacity: 1, height: 'auto' }}\n                            transition={{ duration: 0.2 }}\n                            className='pl-4 space-y-1 overflow-hidden'\n                          >\n                            {renderSubmenuItems(element.submenu)}\n                          </motion.div>\n                        )}\n                      </>\n                    ) : (\n                      <a\n                        href={element.url || '#'}\n                        onClick={hideMobileMenu}\n                        className='text-gray-800 dark:text-gray-200 font-medium text-base py-2 px-4 rounded-lg hover:bg-gray-200/50 dark:hover:bg-gray-800/50 transition-colors border-b border-gray-200 dark:border-gray-800 block'\n                      >\n                        {element.text}\n                      </a>\n                    )}\n                  </div>\n                ))}\n              </nav>\n            </div>\n          </motion.div>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default NavbarFlow;\n"
    }
  ]
}
