✨ Update bottom navigation with raised scanner button
- Change Dashboard to Home in navigation - Add raised purple scanner button in center - Implement new nav layout: Home | Cards | Scanner | Collections | More - Scanner button features elevated design with purple gradient - Add proper active/inactive states for all nav items - Remove unused navigationItems array to fix linting warning - Perfect spacing with justify-around layout
This commit is contained in:
parent
0a03f0ed14
commit
708c68fb07
1 changed files with 100 additions and 92 deletions
|
|
@ -3,13 +3,6 @@ import { Link, useLocation, useNavigate } from 'react-router-dom';
|
||||||
import { useAuth } from '../contexts/AuthContext';
|
import { useAuth } from '../contexts/AuthContext';
|
||||||
import { useTheme } from '../contexts/ThemeContext';
|
import { useTheme } from '../contexts/ThemeContext';
|
||||||
|
|
||||||
interface NavigationItem {
|
|
||||||
name: string;
|
|
||||||
href: string;
|
|
||||||
icon: React.ReactNode;
|
|
||||||
activeIcon?: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MobileNavbar: React.FC = () => {
|
const MobileNavbar: React.FC = () => {
|
||||||
const { user, logout, isAdmin } = useAuth();
|
const { user, logout, isAdmin } = useAuth();
|
||||||
const { toggleTheme, effectiveTheme } = useTheme();
|
const { toggleTheme, effectiveTheme } = useTheme();
|
||||||
|
|
@ -17,70 +10,6 @@ const MobileNavbar: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [showUserMenu, setShowUserMenu] = useState(false);
|
const [showUserMenu, setShowUserMenu] = useState(false);
|
||||||
|
|
||||||
const navigationItems: NavigationItem[] = [
|
|
||||||
{
|
|
||||||
name: 'Dashboard',
|
|
||||||
href: '/dashboard',
|
|
||||||
icon: (
|
|
||||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
activeIcon: (
|
|
||||||
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Cards',
|
|
||||||
href: '/cards',
|
|
||||||
icon: (
|
|
||||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
activeIcon: (
|
|
||||||
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Scanner',
|
|
||||||
href: '/scanner',
|
|
||||||
icon: (
|
|
||||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" />
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 13a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
activeIcon: (
|
|
||||||
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path fillRule="evenodd" d="M1.5 6a2.25 2.25 0 012.25-2.25h1.386c.17 0 .318.114.362.278l.558 2.047c.25.895 1.03 1.425 1.944 1.425H19.5a2.25 2.25 0 012.25 2.25v6.75a2.25 2.25 0 01-2.25 2.25H4.5A2.25 2.25 0 012.25 18V9.75a2.25 2.25 0 012.25-2.25H1.5V6zM12 15a3 3 0 100-6 3 3 0 000 6z" clipRule="evenodd" />
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Collections',
|
|
||||||
href: '/collections',
|
|
||||||
icon: (
|
|
||||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'More',
|
|
||||||
href: '/menu',
|
|
||||||
icon: (
|
|
||||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
|
||||||
</svg>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
logout();
|
logout();
|
||||||
setShowUserMenu(false);
|
setShowUserMenu(false);
|
||||||
|
|
@ -143,27 +72,106 @@ const MobileNavbar: React.FC = () => {
|
||||||
|
|
||||||
{/* Bottom Navigation */}
|
{/* Bottom Navigation */}
|
||||||
<nav className="fixed bottom-0 left-0 right-0 z-50 bg-white dark:bg-surface-900 border-t border-surface-200 dark:border-surface-700 safe-area-inset-bottom">
|
<nav className="fixed bottom-0 left-0 right-0 z-50 bg-white dark:bg-surface-900 border-t border-surface-200 dark:border-surface-700 safe-area-inset-bottom">
|
||||||
<div className="grid grid-cols-5 px-2 py-2">
|
<div className="relative flex items-end justify-around px-4 py-2">
|
||||||
{navigationItems.map((item) => (
|
{/* Home */}
|
||||||
<Link
|
<Link
|
||||||
key={item.name}
|
to="/dashboard"
|
||||||
to={item.href === '/menu' ? '#' : item.href}
|
|
||||||
onClick={item.href === '/menu' ? (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setShowUserMenu(true);
|
|
||||||
} : undefined}
|
|
||||||
className={`flex flex-col items-center justify-center p-2 rounded-xl transition-all duration-200 ${
|
className={`flex flex-col items-center justify-center p-2 rounded-xl transition-all duration-200 ${
|
||||||
isActive(item.href) && item.href !== '/menu'
|
isActive('/dashboard')
|
||||||
? 'text-primary-600 dark:text-primary-400 bg-primary-50 dark:bg-primary-900/30'
|
? 'text-primary-600 dark:text-primary-400'
|
||||||
: 'text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-white hover:bg-surface-100 dark:hover:bg-surface-800'
|
: 'text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-white'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="mb-1">
|
<div className="mb-1">
|
||||||
{isActive(item.href) && item.activeIcon ? item.activeIcon : item.icon}
|
{isActive('/dashboard') ? (
|
||||||
|
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<span className="text-xs font-medium">{item.name}</span>
|
<span className="text-xs font-medium">Home</span>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
|
||||||
|
{/* Cards */}
|
||||||
|
<Link
|
||||||
|
to="/cards"
|
||||||
|
className={`flex flex-col items-center justify-center p-2 rounded-xl transition-all duration-200 ${
|
||||||
|
isActive('/cards')
|
||||||
|
? 'text-primary-600 dark:text-primary-400'
|
||||||
|
: 'text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-white'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="mb-1">
|
||||||
|
{isActive('/cards') ? (
|
||||||
|
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-medium">Cards</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Scanner - Special Raised Button */}
|
||||||
|
<Link
|
||||||
|
to="/scanner"
|
||||||
|
className="relative flex flex-col items-center justify-center -mt-6 mb-2"
|
||||||
|
>
|
||||||
|
<div className={`w-14 h-14 rounded-full shadow-lg transition-all duration-200 flex items-center justify-center ${
|
||||||
|
isActive('/scanner')
|
||||||
|
? 'bg-gradient-to-r from-primary-600 to-accent-600 shadow-primary-500/25 shadow-xl'
|
||||||
|
: 'bg-gradient-to-r from-primary-500 to-accent-500 hover:from-primary-600 hover:to-accent-600 shadow-primary-500/20 hover:shadow-xl'
|
||||||
|
}`}>
|
||||||
|
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" />
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 13a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-medium text-primary-600 dark:text-primary-400 mt-1">Scanner</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Collections */}
|
||||||
|
<Link
|
||||||
|
to="/collections"
|
||||||
|
className={`flex flex-col items-center justify-center p-2 rounded-xl transition-all duration-200 ${
|
||||||
|
isActive('/collections')
|
||||||
|
? 'text-primary-600 dark:text-primary-400'
|
||||||
|
: 'text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-white'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="mb-1">
|
||||||
|
{isActive('/collections') ? (
|
||||||
|
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path d="M7 4V2a1 1 0 011-1h8a1 1 0 011 1v2h3a1 1 0 110 2h-1v10a2 2 0 01-2 2H7a2 2 0 01-2-2V6H4a1 1 0 010-2h3zM9 4h6V3H9v1zm8 2H7v10h10V6z"/>
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-medium">Collections</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* More */}
|
||||||
|
<button
|
||||||
|
onClick={() => setShowUserMenu(true)}
|
||||||
|
className="flex flex-col items-center justify-center p-2 rounded-xl transition-all duration-200 text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-white"
|
||||||
|
>
|
||||||
|
<div className="mb-1">
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs font-medium">More</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue