feat(nav): add responsive mobile dropdown menu with avatar and counters
- Hide desktop items on small screens, add Menu/X toggle - Include Matches badge, History, Profile, and Logout - Keep real-time pending matches counter
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useAuth } from '../../contexts/AuthContext';
|
||||
import { Video, LogOut, User, History, Users } from 'lucide-react';
|
||||
import { Video, LogOut, User, History, Users, Menu, X } from 'lucide-react';
|
||||
import Avatar from '../common/Avatar';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { matchesAPI } from '../../services/api';
|
||||
@@ -10,6 +10,7 @@ const Navbar = () => {
|
||||
const { user, logout } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const [pendingMatchesCount, setPendingMatchesCount] = useState(0);
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
|
||||
const handleLogout = () => {
|
||||
logout();
|
||||
@@ -68,8 +69,8 @@ const Navbar = () => {
|
||||
<span className="text-xl font-bold text-gray-900">spotlight.cam</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
{/* Desktop menu */}
|
||||
<div className="hidden md:flex items-center space-x-4">
|
||||
<Link
|
||||
to="/matches"
|
||||
className="flex items-center space-x-1 px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-primary-600 hover:bg-gray-100 relative"
|
||||
@@ -112,8 +113,70 @@ const Navbar = () => {
|
||||
<span>Logout</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile menu button */}
|
||||
<div className="flex md:hidden items-center">
|
||||
<button
|
||||
onClick={() => setMenuOpen((o) => !o)}
|
||||
aria-label="Open menu"
|
||||
className="p-2 rounded-md text-gray-700 hover:bg-gray-100"
|
||||
>
|
||||
{menuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile dropdown */}
|
||||
{menuOpen && (
|
||||
<div className="md:hidden border-t bg-white shadow-sm">
|
||||
<div className="px-4 py-3 flex items-center space-x-3">
|
||||
<Avatar src={user?.avatar} username={user.username} size={32} />
|
||||
<div className="flex-1">
|
||||
<p className="text-sm font-medium text-gray-900">{user.username}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-2 pb-2 space-y-1">
|
||||
<Link
|
||||
to="/matches"
|
||||
onClick={() => setMenuOpen(false)}
|
||||
className="flex items-center justify-between px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-100"
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
<Users className="w-4 h-4" /> Matches
|
||||
</span>
|
||||
{pendingMatchesCount > 0 && (
|
||||
<span className="ml-2 bg-red-500 text-white text-xs rounded-full h-5 px-2 flex items-center justify-center font-semibold">
|
||||
{pendingMatchesCount}
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
<Link
|
||||
to="/history"
|
||||
onClick={() => setMenuOpen(false)}
|
||||
className="flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-100"
|
||||
>
|
||||
<History className="w-4 h-4" /> History
|
||||
</Link>
|
||||
<Link
|
||||
to="/profile"
|
||||
onClick={() => setMenuOpen(false)}
|
||||
className="flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-100"
|
||||
>
|
||||
<User className="w-4 h-4" /> Profile
|
||||
</Link>
|
||||
<button
|
||||
onClick={() => {
|
||||
setMenuOpen(false);
|
||||
handleLogout();
|
||||
}}
|
||||
className="w-full flex items-center gap-2 px-3 py-2 rounded-md text-sm font-medium text-red-600 hover:bg-red-50"
|
||||
>
|
||||
<LogOut className="w-4 h-4" /> Logout
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user