forked from 0xWheatyz/SPARC
f64d1b745f
Combines GitCompareArrows icon import with Sun/Moon and ThemeContext imports.
119 lines
4.6 KiB
TypeScript
119 lines
4.6 KiB
TypeScript
import { Outlet, NavLink, useNavigate } from 'react-router-dom';
|
|
import { useAuth } from '../context/AuthContext';
|
|
import { useTheme } from '../context/ThemeContext';
|
|
import { Search, Layers, BarChart3, Info, Users, LogOut, GitCompareArrows, Sun, Moon } from 'lucide-react';
|
|
|
|
export function Layout() {
|
|
const { user, isAdmin, logout } = useAuth();
|
|
const { theme, toggleTheme } = useTheme();
|
|
const navigate = useNavigate();
|
|
|
|
const handleLogout = () => {
|
|
logout();
|
|
navigate('/login');
|
|
};
|
|
|
|
const navItems = [
|
|
{ to: '/analysis', icon: Search, label: 'Analysis' },
|
|
{ to: '/batch', icon: Layers, label: 'Batch' },
|
|
{ to: '/analytics', icon: BarChart3, label: 'Analytics' },
|
|
{ to: '/compare', icon: GitCompareArrows, label: 'Compare' },
|
|
{ to: '/about', icon: Info, label: 'About' },
|
|
];
|
|
|
|
if (isAdmin) {
|
|
navItems.push({ to: '/admin/users', icon: Users, label: 'Users' });
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gradient-to-br from-bg-dark to-slate-100 dark:to-indigo-950">
|
|
{/* Header */}
|
|
<header className="bg-bg-card/80 backdrop-blur-lg border-b border-primary/20">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="flex items-center justify-between h-16">
|
|
{/* Brand */}
|
|
<div className="flex items-center gap-3">
|
|
<span className="text-2xl">⚡</span>
|
|
<div>
|
|
<h1 className="text-xl font-bold bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
|
|
SPARC
|
|
</h1>
|
|
<span className="text-xs text-text-secondary uppercase tracking-wider">
|
|
Semiconductor Patent Analytics
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Navigation */}
|
|
<nav className="hidden md:flex items-center gap-1 bg-bg-card/60 rounded-xl p-1 border border-primary/15">
|
|
{navItems.map(({ to, icon: Icon, label }) => (
|
|
<NavLink
|
|
key={to}
|
|
to={to}
|
|
className={({ isActive }) =>
|
|
`flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-all ${
|
|
isActive
|
|
? 'bg-gradient-to-r from-primary to-primary-dark text-white'
|
|
: 'text-text-secondary hover:text-text-primary hover:bg-bg-card-hover'
|
|
}`
|
|
}
|
|
>
|
|
<Icon size={16} />
|
|
{label}
|
|
</NavLink>
|
|
))}
|
|
</nav>
|
|
|
|
{/* User menu */}
|
|
<div className="flex items-center gap-4">
|
|
<button
|
|
onClick={toggleTheme}
|
|
className="p-2 rounded-lg text-text-secondary hover:text-text-primary hover:bg-bg-card-hover transition-all"
|
|
aria-label={theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'}
|
|
>
|
|
{theme === 'dark' ? <Sun size={18} /> : <Moon size={18} />}
|
|
</button>
|
|
<div className="text-right hidden sm:block">
|
|
<div className="text-sm font-medium text-text-primary">{user?.email}</div>
|
|
<div className="text-xs text-text-secondary capitalize">{user?.role}</div>
|
|
</div>
|
|
<button
|
|
onClick={handleLogout}
|
|
className="flex items-center gap-2 px-3 py-2 rounded-lg text-text-secondary hover:text-error hover:bg-error/10 transition-all"
|
|
>
|
|
<LogOut size={18} />
|
|
<span className="hidden sm:inline">Logout</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
{/* Mobile Navigation */}
|
|
<nav className="md:hidden fixed bottom-0 left-0 right-0 bg-bg-card/95 backdrop-blur-lg border-t border-primary/20 z-50">
|
|
<div className="flex justify-around py-2">
|
|
{navItems.map(({ to, icon: Icon, label }) => (
|
|
<NavLink
|
|
key={to}
|
|
to={to}
|
|
className={({ isActive }) =>
|
|
`flex flex-col items-center gap-1 px-3 py-2 rounded-lg text-xs font-medium transition-all ${
|
|
isActive ? 'text-primary' : 'text-text-secondary'
|
|
}`
|
|
}
|
|
>
|
|
<Icon size={20} />
|
|
{label}
|
|
</NavLink>
|
|
))}
|
|
</div>
|
|
</nav>
|
|
|
|
{/* Main content */}
|
|
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 pb-24 md:pb-8">
|
|
<Outlet />
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|