Spaces:
Sleeping
Sleeping
| 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; | |