|
|
|
|
|
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); |
|
|
}; |
|
|
}, []); |
|
|
|
|
|
|
|
|
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; |
|
|
|