File size: 4,210 Bytes
b190b45 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
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[] = [
// Main Section
{ 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} /> },
// AI & Analysis Section
{ 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} /> },
// Trading Section
{ path: '/trading-assistant', label: 'Trading Assistant', icon: <DollarSign size={20} />, section: 'Trading' },
{ path: '/news', label: 'News', icon: <Newspaper size={20} /> },
// System Section
{ 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;
|