import { useState, useEffect, useCallback, useMemo } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { FiMenu, FiX, FiExternalLink, FiArrowUpRight } from 'react-icons/fi'; import { HiSparkles } from 'react-icons/hi'; export default function Navbar() { const [isOpen, setIsOpen] = useState(false); const [scrolled, setScrolled] = useState(false); // Memoized menu items for better performance const menuItems = useMemo( () => [ { label: 'Features', href: '#features' }, { label: 'Converters', href: '#converters' }, { label: 'Social Media', href: '#social-media' }, { label: 'About', href: '#about' }, ], [], ); // Optimized scroll handler with throttling const handleScroll = useCallback(() => { const scrollTop = window.scrollY; setScrolled(scrollTop > 20); }, []); useEffect(() => { let ticking = false; const throttledScroll = () => { if (!ticking) { requestAnimationFrame(() => { handleScroll(); ticking = false; }); ticking = true; } }; window.addEventListener('scroll', throttledScroll, { passive: true }); return () => window.removeEventListener('scroll', throttledScroll); }, [handleScroll]); // Close mobile menu when clicking outside useEffect(() => { const handleClickOutside = event => { if (isOpen && !event.target.closest('nav')) { setIsOpen(false); } }; document.addEventListener('click', handleClickOutside); return () => document.removeEventListener('click', handleClickOutside); }, [isOpen]); // Enhanced smooth scroll with easing function const easeInOutCubic = (t) => { return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; }; const smoothScrollTo = useCallback((targetPosition, duration = 1200) => { const startPosition = window.pageYOffset; const distance = targetPosition - startPosition; let startTime = null; const animation = (currentTime) => { if (startTime === null) startTime = currentTime; const timeElapsed = currentTime - startTime; const progress = Math.min(timeElapsed / duration, 1); const ease = easeInOutCubic(progress); window.scrollTo(0, startPosition + distance * ease); if (timeElapsed < duration) { requestAnimationFrame(animation); } }; requestAnimationFrame(animation); }, []); // Smooth scroll handler with improved offset calculation and animation const handleSmoothScroll = useCallback( href => { if (href.startsWith('#')) { const element = document.querySelector(href); if (element) { const offset = 80; // Account for fixed navbar height const elementPosition = element.getBoundingClientRect().top; const offsetPosition = elementPosition + window.pageYOffset - offset; smoothScrollTo(offsetPosition, 1200); // 1.2 second duration setIsOpen(false); } } }, [smoothScrollTo, setIsOpen], ); // Enhanced scroll to top with animation const scrollToTop = useCallback(() => { smoothScrollTo(0, 1000); // 1 second duration for scroll to top }, [smoothScrollTo]); return (
{/* Logo */}
LumaKit
{/* Desktop Menu */}
{menuItems.map((item, index) => ( handleSmoothScroll(item.href)} className="text-[var(--foreground-secondary)] hover:text-[var(--foreground)] transition-colors duration-300 text-sm font-medium relative group" whileHover={{ y: -1 }} transition={{ duration: 0.2 }} > {item.label} ))} handleSmoothScroll("#features")} rel="noopener noreferrer" className="group relative flex items-center space-x-2 bg-[var(--accent)] hover:bg-[var(--accent-hover)] text-[var(--background)] px-4 py-2 rounded-xl transition-all duration-300 text-sm font-medium shadow-lg hover:shadow-xl overflow-hidden" whileHover={{ scale: 1.02, y: -1 }} whileTap={{ scale: 0.98 }} transition={{ duration: 0.2 }} >
Try LumaKit
{/* Mobile Menu Button */} setIsOpen(!isOpen)} whileTap={{ scale: 0.95 }} aria-label="Toggle menu" > {isOpen ? : }
{/* Mobile Menu */} {isOpen && (
{menuItems.map((item, index) => ( handleSmoothScroll(item.href)} className="block w-full text-left text-[var(--foreground-secondary)] hover:text-[var(--foreground)] transition-colors duration-300 text-base font-medium py-2 px-3 rounded-lg hover:bg-[var(--background-tertiary)]" initial={{ opacity: 0, x: -20 }} animate={{ opacity: 1, x: 0 }} transition={{ delay: index * 0.1, duration: 0.3 }} > {item.label} ))} setIsOpen(false)} initial={{ opacity: 0, x: -20 }} animate={{ opacity: 1, x: 0 }} transition={{ delay: 0.4, duration: 0.3 }} >
Try LumaKit
)}
); }