Spaces:
Running
Running
import React, { useState, useEffect, useRef } from 'react'; | |
import { Link, useNavigate } from 'react-router-dom'; | |
import { Search, Bell, User, Menu, X } from 'lucide-react'; | |
import { motion, AnimatePresence } from 'framer-motion'; | |
const Navbar = () => { | |
const [isScrolled, setIsScrolled] = useState(false); | |
const [isMenuOpen, setIsMenuOpen] = useState(false); | |
const [searchVisible, setSearchVisible] = useState(false); | |
const [searchTerm, setSearchTerm] = useState(''); | |
const searchInputRef = useRef<HTMLInputElement>(null); | |
const navigate = useNavigate(); | |
useEffect(() => { | |
const handleScroll = () => { | |
if (window.scrollY > 50) { | |
setIsScrolled(true); | |
} else { | |
setIsScrolled(false); | |
} | |
}; | |
window.addEventListener('scroll', handleScroll); | |
return () => { | |
window.removeEventListener('scroll', handleScroll); | |
}; | |
}, []); | |
// Focus the search input when it becomes visible | |
useEffect(() => { | |
if (searchVisible && searchInputRef.current) { | |
setTimeout(() => { | |
searchInputRef.current?.focus(); | |
}, 200); | |
} | |
}, [searchVisible]); | |
const toggleMenu = () => { | |
setIsMenuOpen(!isMenuOpen); | |
}; | |
const toggleSearch = () => { | |
setSearchVisible(!searchVisible); | |
}; | |
const handleSearchSubmit = (e: React.FormEvent) => { | |
e.preventDefault(); | |
if (searchTerm.trim()) { | |
navigate(`/search?q=${encodeURIComponent(searchTerm)}`); | |
setSearchVisible(false); | |
setSearchTerm(''); | |
} | |
}; | |
return ( | |
<nav | |
className={`fixed top-0 left-0 w-full z-50 transition-all duration-300 px-4 sm:px-6 ${ | |
isScrolled ? 'bg-theme-background-dark shadow-lg py-2' : 'bg-gradient-to-b from-black/80 to-transparent py-4' | |
}`} | |
> | |
<div className="flex items-center justify-between"> | |
{/* Logo */} | |
<Link to="/" className="flex items-center"> | |
<h1 className="text-theme-primary text-2xl sm:text-3xl font-bold">NEXORA</h1> | |
</Link> | |
{/* Desktop Nav Links */} | |
<div className="hidden md:flex items-center space-x-6"> | |
<Link to="/" className="text-white hover:text-theme-primary transition-colors">Home</Link> | |
<Link to="/movies" className="text-white hover:text-theme-primary transition-colors">Movies</Link> | |
<Link to="/tv-shows" className="text-white hover:text-theme-primary transition-colors">TV Shows</Link> | |
<Link to="/my-list" className="text-white hover:text-theme-primary transition-colors">My List</Link> | |
</div> | |
{/* Right side icons */} | |
<div className="flex items-center space-x-4"> | |
{/* Search bar with animation */} | |
<div className="relative flex items-center"> | |
<AnimatePresence> | |
{searchVisible ? ( | |
<motion.form | |
onSubmit={handleSearchSubmit} | |
className="flex items-center" | |
initial={{ width: 0, opacity: 0 }} | |
animate={{ width: 200, opacity: 1 }} | |
exit={{ width: 0, opacity: 0 }} | |
transition={{ duration: 0.2 }} | |
> | |
<input | |
ref={searchInputRef} | |
type="text" | |
placeholder="Titles, people, genres" | |
className="bg-theme-background-dark border border-theme-border rounded px-3 py-1 | |
focus:outline-none focus:border-theme-primary text-white w-full" | |
value={searchTerm} | |
onChange={(e) => setSearchTerm(e.target.value)} | |
/> | |
<button | |
type="button" | |
onClick={toggleSearch} | |
className="ml-2 text-white hover:text-theme-primary" | |
> | |
<X className="w-5 h-5" /> | |
</button> | |
</motion.form> | |
) : ( | |
<button | |
onClick={toggleSearch} | |
className="hover:text-theme-primary transition-colors" | |
> | |
<Search className="w-5 h-5" /> | |
</button> | |
)} | |
</AnimatePresence> | |
</div> | |
<button className="hover:text-theme-primary transition-colors hidden sm:block"> | |
<Bell className="w-5 h-5" /> | |
</button> | |
<Link to="/profile" className="hover:text-theme-primary transition-colors hidden sm:block"> | |
<User className="w-5 h-5" /> | |
</Link> | |
{/* Mobile menu button */} | |
<button onClick={toggleMenu} className="md:hidden hover:text-theme-primary"> | |
<Menu className="w-6 h-6" /> | |
</button> | |
</div> | |
</div> | |
{/* Mobile menu */} | |
<AnimatePresence> | |
{isMenuOpen && ( | |
<motion.div | |
className="md:hidden absolute top-full left-0 right-0 bg-theme-background-dark/95 border-t border-theme-border" | |
initial={{ opacity: 0, height: 0 }} | |
animate={{ opacity: 1, height: 'auto' }} | |
exit={{ opacity: 0, height: 0 }} | |
transition={{ duration: 0.3 }} | |
> | |
<div className="flex flex-col p-4 space-y-3"> | |
<Link to="/" className="text-white py-2 hover:text-theme-primary">Home</Link> | |
<Link to="/movies" className="text-white py-2 hover:text-theme-primary">Movies</Link> | |
<Link to="/tv-shows" className="text-white py-2 hover:text-theme-primary">TV Shows</Link> | |
<Link to="/my-list" className="text-white py-2 hover:text-theme-primary">My List</Link> | |
<Link to="/profile" className="text-white py-2 hover:text-theme-primary">Profile</Link> | |
</div> | |
</motion.div> | |
)} | |
</AnimatePresence> | |
</nav> | |
); | |
}; | |
export default Navbar; | |