|
|
import React, { useState, useEffect } from 'react';
|
|
|
import { useLocation, Link } from 'react-router-dom';
|
|
|
import {
|
|
|
LayoutDashboard,
|
|
|
TrendingUp,
|
|
|
BarChart3,
|
|
|
Bot,
|
|
|
Smile,
|
|
|
Activity,
|
|
|
DollarSign,
|
|
|
Newspaper,
|
|
|
Radio,
|
|
|
Monitor,
|
|
|
Settings,
|
|
|
HelpCircle,
|
|
|
ChevronLeft,
|
|
|
ChevronRight
|
|
|
} from 'lucide-react';
|
|
|
|
|
|
interface NavItem {
|
|
|
path: string;
|
|
|
label: string;
|
|
|
icon: React.ReactNode;
|
|
|
badge?: string;
|
|
|
section?: string;
|
|
|
}
|
|
|
|
|
|
const navItems: NavItem[] = [
|
|
|
|
|
|
{ path: '/', label: 'Dashboard', icon: <LayoutDashboard size={20} />, section: 'Main' },
|
|
|
{ path: '/market', label: 'Market', icon: <TrendingUp size={20} /> },
|
|
|
{ path: '/charts', label: 'Charts', icon: <BarChart3 size={20} /> },
|
|
|
|
|
|
|
|
|
{ path: '/ai-models', label: 'AI Models', icon: <Bot size={20} />, section: 'AI & Analysis' },
|
|
|
{ path: '/sentiment', label: 'Sentiment', icon: <Smile size={20} /> },
|
|
|
{ path: '/ai-analyst', label: 'AI Analyst', icon: <Activity size={20} /> },
|
|
|
{ path: '/technical-analysis', label: 'Technical', icon: <BarChart3 size={20} /> },
|
|
|
|
|
|
|
|
|
{ path: '/trading-assistant', label: 'Trading Assistant', icon: <DollarSign size={20} />, section: 'Trading' },
|
|
|
{ path: '/news', label: 'News', icon: <Newspaper size={20} /> },
|
|
|
|
|
|
|
|
|
{ path: '/providers', label: 'Providers', icon: <Radio size={20} />, section: 'System' },
|
|
|
{ path: '/system-monitor', label: 'System Monitor', icon: <Monitor size={20} />, badge: 'LIVE' },
|
|
|
{ path: '/settings', label: 'Settings', icon: <Settings size={20} /> },
|
|
|
{ path: '/help', label: 'Help', icon: <HelpCircle size={20} /> },
|
|
|
];
|
|
|
|
|
|
export const Sidebar: React.FC = () => {
|
|
|
const [collapsed, setCollapsed] = useState(false);
|
|
|
const location = useLocation();
|
|
|
|
|
|
useEffect(() => {
|
|
|
const savedState = localStorage.getItem('sidebar-collapsed');
|
|
|
if (savedState === 'true') {
|
|
|
setCollapsed(true);
|
|
|
}
|
|
|
}, []);
|
|
|
|
|
|
const toggleCollapse = () => {
|
|
|
const newState = !collapsed;
|
|
|
setCollapsed(newState);
|
|
|
localStorage.setItem('sidebar-collapsed', String(newState));
|
|
|
};
|
|
|
|
|
|
const isActive = (path: string) => {
|
|
|
if (path === '/' && location.pathname === '/') return true;
|
|
|
if (path !== '/' && location.pathname.startsWith(path)) return true;
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
let currentSection = '';
|
|
|
|
|
|
return (
|
|
|
<aside className={`sidebar ${collapsed ? 'collapsed' : ''}`} role="navigation" aria-label="Main navigation">
|
|
|
{/* Sidebar Header */}
|
|
|
<div className="sidebar-header">
|
|
|
<div className="sidebar-logo">
|
|
|
<span>C</span>
|
|
|
</div>
|
|
|
<div className="sidebar-brand">Crypto Monitor</div>
|
|
|
</div>
|
|
|
|
|
|
{/* Sidebar Navigation */}
|
|
|
<nav className="sidebar-nav">
|
|
|
{navItems.map((item) => {
|
|
|
const showSection = item.section && item.section !== currentSection;
|
|
|
if (item.section) currentSection = item.section;
|
|
|
|
|
|
return (
|
|
|
<React.Fragment key={item.path}>
|
|
|
{showSection && (
|
|
|
<div className="nav-section-header">{item.section}</div>
|
|
|
)}
|
|
|
<Link
|
|
|
to={item.path}
|
|
|
className={`nav-item ${isActive(item.path) ? 'active' : ''}`}
|
|
|
>
|
|
|
<span className="nav-item-icon">{item.icon}</span>
|
|
|
<span className="nav-item-label">{item.label}</span>
|
|
|
{item.badge && (
|
|
|
<span className="nav-item-badge">{item.badge}</span>
|
|
|
)}
|
|
|
</Link>
|
|
|
</React.Fragment>
|
|
|
);
|
|
|
})}
|
|
|
</nav>
|
|
|
|
|
|
{/* Sidebar Footer */}
|
|
|
<div className="sidebar-footer">
|
|
|
<button
|
|
|
className="sidebar-toggle"
|
|
|
onClick={toggleCollapse}
|
|
|
aria-label="Toggle sidebar"
|
|
|
>
|
|
|
<span className="sidebar-toggle-icon">
|
|
|
{collapsed ? <ChevronRight size={20} /> : <ChevronLeft size={20} />}
|
|
|
</span>
|
|
|
<span className="nav-item-label">Collapse</span>
|
|
|
</button>
|
|
|
</div>
|
|
|
</aside>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
export default Sidebar;
|
|
|
|