123 lines
4.0 KiB
TypeScript
123 lines
4.0 KiB
TypeScript
import { NavLink } from 'react-router-dom';
|
|
import {
|
|
Home, Briefcase, FlaskConical, Target, TrendingUp,
|
|
SlidersHorizontal, Star, Bell, Settings,
|
|
} from 'lucide-react';
|
|
import { useAppContext } from '../../context/AppContext';
|
|
import { getPlansRoute } from '../../views/tradePlansRoutes';
|
|
|
|
const NAV = [
|
|
{ to: '/', icon: Home, label: 'Home', end: true },
|
|
{ to: '/portfolio', icon: Briefcase, label: 'Portfolio', end: false },
|
|
{ to: '/research', icon: FlaskConical, label: 'Research', end: false },
|
|
{ to: getPlansRoute(), icon: Target, label: 'Plans', end: false },
|
|
{ to: '/markets', icon: TrendingUp, label: 'Markets', end: false },
|
|
{ to: '/screener', icon: SlidersHorizontal, label: 'Screener', end: false },
|
|
{ to: '/watchlist', icon: Star, label: 'Watchlist', end: false },
|
|
{ to: '/alerts', icon: Bell, label: 'Alerts', end: false },
|
|
{ to: '/settings', icon: Settings, label: 'Settings', end: false },
|
|
];
|
|
|
|
export function Sidebar() {
|
|
const { user, handleSignOut } = useAppContext();
|
|
const initials = user?.email
|
|
? user.email.slice(0, 2).toUpperCase()
|
|
: 'US';
|
|
|
|
return (
|
|
<aside className="trading-sidebar">
|
|
{/* Logo */}
|
|
<div className="trading-sidebar-logo" style={{
|
|
width: 40,
|
|
height: 40,
|
|
borderRadius: 10,
|
|
background: 'linear-gradient(135deg, var(--accent), color-mix(in oklab, var(--accent) 70%, var(--bl-info-strong) 30%))',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginBottom: 24,
|
|
flexShrink: 0,
|
|
boxShadow: '0 2px 8px color-mix(in oklab, var(--accent) 35%, transparent 65%)',
|
|
cursor: 'pointer',
|
|
fontSize: 20,
|
|
}}>
|
|
📈
|
|
</div>
|
|
|
|
{/* Nav items */}
|
|
<nav className="trading-sidebar-nav">
|
|
{NAV.map(({ to, icon: Icon, label, end }) => (
|
|
<NavLink
|
|
key={to}
|
|
to={to}
|
|
end={end}
|
|
className="trading-sidebar-link"
|
|
style={({ isActive }) => ({
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
padding: '10px 0 8px',
|
|
gap: 3,
|
|
borderLeft: isActive ? '3px solid var(--accent)' : '3px solid transparent',
|
|
color: isActive ? 'var(--accent)' : 'var(--muted-foreground)',
|
|
textDecoration: 'none',
|
|
background: isActive ? 'var(--sidebar-active)' : 'transparent',
|
|
transition: 'all 0.15s',
|
|
})}
|
|
>
|
|
{({ isActive }) => (
|
|
<>
|
|
<Icon size={20} strokeWidth={isActive ? 2.2 : 1.8} />
|
|
<span style={{
|
|
fontSize: 10,
|
|
fontWeight: isActive ? 700 : 500,
|
|
letterSpacing: '0.01em',
|
|
lineHeight: 1,
|
|
}}>
|
|
{label}
|
|
</span>
|
|
</>
|
|
)}
|
|
</NavLink>
|
|
))}
|
|
</nav>
|
|
|
|
{/* User avatar */}
|
|
<div
|
|
className="trading-sidebar-avatar"
|
|
title={`${user?.email ?? ''} — click to sign out`}
|
|
onClick={handleSignOut}
|
|
style={{
|
|
width: 36,
|
|
height: 36,
|
|
borderRadius: '50%',
|
|
background: 'var(--accent)',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
color: 'var(--primary-foreground)',
|
|
fontSize: 12,
|
|
fontWeight: 700,
|
|
cursor: 'pointer',
|
|
position: 'relative',
|
|
userSelect: 'none',
|
|
flexShrink: 0,
|
|
}}
|
|
>
|
|
{initials}
|
|
<span style={{
|
|
position: 'absolute',
|
|
bottom: 1,
|
|
right: 1,
|
|
width: 9,
|
|
height: 9,
|
|
borderRadius: '50%',
|
|
background: 'var(--bl-success)',
|
|
border: '2px solid var(--card)',
|
|
}} />
|
|
</div>
|
|
</aside>
|
|
);
|
|
}
|