|
|
| 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; |
|
|