{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "motion-navbar",
  "type": "registry:ui",
  "title": "Motion Navbar",
  "description": "modern react navbar with smooth animations, dropdown menus, and mobile-friendly design.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion", "lucide-react"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/motion-navbar.tsx",
      "content": "'use client';\n\nimport React, { useState, createContext, useContext } from 'react';\nimport { motion, AnimatePresence } from 'motion/react';\nimport { Menu, X, ChevronDown, LucideIcon } from 'lucide-react';\nimport { cn } from '@/lib/utils';\n\ninterface NavbarProps {\n  children: React.ReactNode;\n  className?: string;\n}\n\ninterface NavbarLogoProps {\n  className?: string;\n}\n\ninterface NavBodyProps {\n  children: React.ReactNode;\n  className?: string;\n}\n\ninterface NavItemsProps {\n  items: {\n    label: string;\n    href: string;\n  }[];\n  className?: string;\n  onItemClick?: () => void;\n}\ntype IconType = LucideIcon | React.ComponentType<React.SVGProps<SVGSVGElement>>;\ninterface NavDropdownProps {\n  label: string;\n  items: {\n    label: string;\n    href: string;\n    icon?: IconType;\n  }[];\n  className?: string;\n  index?: number;\n}\n\ninterface MobileNavProps {\n  children: React.ReactNode;\n  className?: string;\n  isOpen?: boolean;\n}\n\ninterface MobileNavHeaderProps {\n  children: React.ReactNode;\n  className?: string;\n}\n\ninterface MobileNavMenuProps {\n  children: React.ReactNode;\n  className?: string;\n  isOpen: boolean;\n  onClose: () => void;\n}\n\nconst MobileMenuContext = createContext<{\n  isMobileMenuOpen: boolean;\n  setIsMobileMenuOpen: (open: boolean) => void;\n}>({\n  isMobileMenuOpen: false,\n  setIsMobileMenuOpen: () => {},\n});\n\nexport const Navbar = ({ children, className }: NavbarProps) => {\n  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);\n\n  return (\n    <MobileMenuContext.Provider\n      value={{ isMobileMenuOpen, setIsMobileMenuOpen }}\n    >\n      <nav\n        className={cn(\n          'fixed top-0 left-0 right-0 z-50 px-4 md:px-6 py-4',\n          className,\n        )}\n      >\n        <motion.div\n          className={cn(\n            'flex items-center justify-between max-w-(--breakpoint-2xl) mx-auto',\n          )}\n          transition={{ duration: 0.3 }}\n        >\n          {children}\n        </motion.div>\n      </nav>\n    </MobileMenuContext.Provider>\n  );\n};\n\nexport const NavBody = ({ children, className }: NavBodyProps) => {\n  return (\n    <motion.div\n      className={cn(\n        'hidden md:flex bg-black dark:bg-white shadow-lg px-6 py-1',\n        className,\n      )}\n      initial={{ opacity: 0, x: 20 }}\n      animate={{ opacity: 1, x: 1 }}\n      transition={{ duration: 0.5, delay: 0.1 }}\n    >\n      <div className='flex items-center gap-1'>{children}</div>\n    </motion.div>\n  );\n};\n\nexport const NavDropdown = ({\n  label,\n  items,\n  className,\n  index = 0,\n}: NavDropdownProps) => {\n  const [isOpen, setIsOpen] = useState(false);\n\n  return (\n    <div\n      className='relative'\n      onMouseEnter={() => setIsOpen(true)}\n      onMouseLeave={() => setIsOpen(false)}\n    >\n      <motion.button\n        className={cn(\n          'relative px-4 py-2 text-sm font-medium text-white dark:text-black hover:bg-white hover:text-black dark:hover:bg-black dark:hover:text-white rounded-full flex items-center gap-1',\n          className,\n        )}\n        initial={{ opacity: 0, y: -10 }}\n        animate={{ opacity: 1, y: 0 }}\n        transition={{ duration: 0.3, delay: 0.1 * index }}\n      >\n        {label}\n        <ChevronDown\n          size={16}\n          className={`transition-transform ${isOpen ? 'rotate-180' : ''}`}\n        />\n      </motion.button>\n\n      <AnimatePresence>\n        {isOpen && (\n          <motion.div\n            className='absolute top-full left-0 mt-2 bg-black dark:bg-white rounded-xl shadow-2xl p-4 min-w-51.25'\n            initial={{ opacity: 0, y: -10 }}\n            animate={{ opacity: 1, y: 0 }}\n            exit={{ opacity: 0, y: -10 }}\n            transition={{ duration: 0.2 }}\n          >\n            {items.map((item) => {\n              const Icon = item.icon;\n              return (\n                <a\n                  key={item.label}\n                  href={item.href}\n                  className='flex items-center justify-between px-4 py-3 text-gray-200 dark:text-gray-800 hover:text-gray-800 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-900 rounded-lg transition-colors'\n                >\n                  <span className='font-medium text-sm'>{item.label}</span>\n                  {Icon && <Icon size={18} className='text-gray-400' />}\n                </a>\n              );\n            })}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n};\n\nexport const NavItems = ({ items, className, onItemClick }: NavItemsProps) => {\n  const [hoveredItem, setHoveredItem] = useState<string | null>(null);\n\n  return (\n    <>\n      {items.map((item, index) => (\n        <motion.a\n          key={item.label}\n          href={item.href}\n          onClick={onItemClick}\n          className={cn(\n            'relative px-4 py-2 text-sm font-medium text-white dark:text-black hover:bg-white hover:text-black dark:hover:bg-black dark:hover:text-white rounded-full ',\n            className,\n          )}\n          onMouseEnter={() => setHoveredItem(item.label)}\n          onMouseLeave={() => setHoveredItem(null)}\n          initial={{ opacity: 0, y: -10 }}\n          animate={{ opacity: 1, y: 0 }}\n          transition={{ duration: 0.3, delay: 0.1 * index }}\n        >\n          {hoveredItem === item.label && (\n            <motion.div\n              className='absolute inset-0 bg-gray-100 dark:bg-gray-900 rounded-full'\n              layoutId='navbar-hover'\n              transition={{ type: 'spring', stiffness: 400, damping: 30 }}\n            />\n          )}\n          <span className='relative z-10'>{item.label}</span>\n        </motion.a>\n      ))}\n    </>\n  );\n};\n\nexport const MobileNav = ({\n  children,\n  className,\n  isOpen = false,\n}: MobileNavProps) => {\n  const { isMobileMenuOpen } = useContext(MobileMenuContext);\n\n  return (\n    <motion.div\n      className={cn(\n        'md:hidden bg-black dark:bg-white shadow-lg z-20 fixed right-4',\n        className,\n      )}\n      animate={{\n        width: isMobileMenuOpen ? 'calc(100vw - 2rem)' : 'auto',\n        right: isMobileMenuOpen ? '1rem' : '4',\n      }}\n      transition={{ duration: 0.3 }}\n    >\n      {children}\n    </motion.div>\n  );\n};\n\nexport const MobileNavHeader = ({\n  children,\n  className,\n}: MobileNavHeaderProps) => {\n  const { isMobileMenuOpen } = useContext(MobileMenuContext);\n\n  return (\n    <div\n      className={cn(\n        'flex items-center',\n        isMobileMenuOpen ? 'w-full justify-end' : 'justify-end',\n        className,\n      )}\n    >\n      {children}\n    </div>\n  );\n};\n\nexport const MobileNavMenu = ({\n  children,\n  className,\n}: Omit<MobileNavMenuProps, 'isOpen' | 'onClose'>) => {\n  const { isMobileMenuOpen, setIsMobileMenuOpen } =\n    useContext(MobileMenuContext);\n\n  const onClose = () => setIsMobileMenuOpen(false);\n\n  return (\n    <>\n      <AnimatePresence>\n        {isMobileMenuOpen && (\n          <motion.div\n            className={cn(\n              'md:hidden fixed inset-x-4 top-16 bg-black dark:bg-white shadow-2xl overflow-hidden origin-top z-50',\n              className,\n            )}\n            initial={{ opacity: 0, scaleY: 0, height: 0 }}\n            animate={{\n              opacity: 1,\n              scaleY: 1,\n              height: 'auto',\n              transition: {\n                duration: 0.4,\n                ease: [0.4, 0.0, 0.2, 1],\n                opacity: { duration: 0.3 },\n                scaleY: { duration: 0.4 },\n              },\n            }}\n            exit={{\n              opacity: 0,\n              scaleY: 0,\n              height: 0,\n              transition: {\n                duration: 0.3,\n                ease: [0.4, 0.0, 0.2, 1],\n              },\n            }}\n          >\n            <div className='px-6 py-8'>{children}</div>\n          </motion.div>\n        )}\n      </AnimatePresence>\n\n      <AnimatePresence>\n        {isMobileMenuOpen && (\n          <motion.div\n            className='fixed inset-0 w-full z-40 md:hidden'\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            onClick={onClose}\n          />\n        )}\n      </AnimatePresence>\n    </>\n  );\n};\n\nexport const MobileNavToggle = ({\n  isOpen,\n  onClick,\n}: {\n  isOpen: boolean;\n  onClick: () => void;\n}) => {\n  const { isMobileMenuOpen, setIsMobileMenuOpen } =\n    useContext(MobileMenuContext);\n\n  const handleClick = () => {\n    setIsMobileMenuOpen(!isMobileMenuOpen);\n  };\n\n  return (\n    <motion.button\n      onClick={handleClick}\n      className='flex items-center gap-2 text-sm font-medium text-gray-300 dark:text-gray-700 px-4 py-2.5'\n    >\n      <AnimatePresence mode='wait'>\n        {isMobileMenuOpen ? (\n          <motion.div\n            key='close'\n            initial={{ opacity: 0, filter: 'blur(4px)', y: 10 }}\n            animate={{ opacity: 1, filter: 'blur(0px)', y: 0 }}\n            exit={{ opacity: 0, filter: 'blur(4px)', y: -10 }}\n            transition={{ duration: 0.1, ease: 'easeInOut' }}\n            className='flex items-center gap-2'\n          >\n            <X size={20} />\n            <span>Close</span>\n          </motion.div>\n        ) : (\n          <motion.div\n            key='menu'\n            initial={{ opacity: 0, filter: 'blur(4px)', y: 10 }}\n            animate={{ opacity: 1, filter: 'blur(0px)', y: 0 }}\n            exit={{ opacity: 0, filter: 'blur(4px)', y: -10 }}\n            transition={{ duration: 0.1, ease: 'easeInOut' }}\n            className='flex items-center gap-2'\n          >\n            <Menu size={20} />\n            <span>Menu</span>\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </motion.button>\n  );\n};\n\nexport const NavbarLogo = ({ className }: NavbarLogoProps) => {\n  const { isMobileMenuOpen } = useContext(MobileMenuContext);\n\n  return (\n    <motion.a\n      href='/'\n      className={cn('flex items-center h-10 gap-2 relative z-20', className)}\n      animate={{\n        opacity: isMobileMenuOpen ? 0 : 1,\n        x: isMobileMenuOpen ? -100 : 0,\n      }}\n      transition={{ duration: 0.3 }}\n    >\n      <img\n        src='/images/scrollxuilogo.svg'\n        alt='logo'\n        width={30}\n        height={30}\n        className='md:w-10 md:h-10'\n      />\n      <span\n        className={cn(\n          'text-xl md:text-xl font-semibold transition-colors duration-300',\n          className,\n        )}\n      >\n        ScrollX UI\n      </span>\n    </motion.a>\n  );\n};\n\nexport const NavbarButton = ({\n  href,\n  children,\n  className,\n  variant = 'primary',\n  onClick,\n}: {\n  href?: string;\n  children: React.ReactNode;\n  className?: string;\n  variant?: 'primary' | 'secondary';\n  onClick?: () => void;\n}) => {\n  const baseStyles =\n    'flex justify-center items-center w-full max-w-[280px] mx-auto px-4 py-2 text-sm font-medium rounded-full transition-colors';\n\n  const variantStyles = {\n    primary: 'text-white bg-orange-500 hover:bg-orange-600 font-semibold',\n    secondary:\n      'text-white dark:text-black hover:bg-white hover:text-black dark:hover:bg-black dark:hover:text-white',\n  };\n\n  return (\n    <motion.a\n      href={href}\n      onClick={onClick}\n      className={cn(baseStyles, variantStyles[variant], className)}\n      whileHover={{ scale: 1.05 }}\n      whileTap={{ scale: 0.95 }}\n    >\n      {children}\n    </motion.a>\n  );\n};\n\nexport const NavbarDivider = () => {\n  return <div className='w-px h-6 bg-gray-300 mx-2' />;\n};\n"
    },
    {
      "type": "registry:lib",
      "path": "lib/utils.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}"
    }
  ]
}
