PM_Console/frontend/src/components/Sidebar.jsx

99 خطوط
4.9 KiB
JavaScript

import { NavLink } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
import { LayoutDashboard, FolderKanban, CheckSquare, Kanban, Inbox, Timer, Users, Calendar, Paperclip, TrendingUp, Building2, Shield, Settings, PanelRightClose, PanelRightOpen, X } from 'lucide-react';
const iconSize = 18;
const menuItems = [
{ path: '/', label: 'داشبورد', icon: LayoutDashboard },
{ path: '/projects', label: 'پروژه‌ها', icon: FolderKanban },
{ path: '/tasks', label: 'تسک‌ها', icon: CheckSquare },
{ path: '/kanban', label: 'برد کاری', icon: Kanban },
{ path: '/backlog', label: 'بک‌لاگ', icon: Inbox },
{ path: '/sprints', label: 'اسپرینت‌ها', icon: Timer },
{ path: '/team', label: 'اعضای تیم', icon: Users },
{ path: '/meetings', label: 'جلسات', icon: Calendar },
{ path: '/files', label: 'فایل‌ها', icon: Paperclip },
{ path: '/reports', label: 'گزارش‌ها', icon: TrendingUp },
{ path: '/organization', label: 'ساختار سازمانی', icon: Building2 },
{ path: '/roles', label: 'نقش‌ها و دسترسی‌ها', icon: Shield },
{ path: '/settings', label: 'تنظیمات', icon: Settings },
];
export default function Sidebar({ collapsed, onToggle, mobileOpen = false, onMobileClose }) {
const { user } = useAuth();
return (
<aside id="main-navigation-drawer" className={`app-sidebar ${mobileOpen ? 'mobile-open' : ''}`} aria-label="منوی اصلی" style={{
width: collapsed ? '72px' : 'var(--sidebar-width)',
height: '100vh',
position: 'fixed',
right: 0,
top: 0,
background: 'var(--surface)',
borderLeft: '1px solid var(--gray-200)',
display: 'flex',
flexDirection: 'column',
zIndex: 100,
transition: 'width 0.2s ease, transform 0.2s ease',
overflow: 'hidden',
}}>
<div style={{ padding: collapsed ? '0.875rem 0.75rem' : '1rem 1rem 1rem 1.25rem', display: 'flex', alignItems: 'center', gap: '0.75rem', borderBottom: '1px solid var(--gray-100)', justifyContent: collapsed ? 'center' : 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', minWidth: 0 }}>
<img className="sidebar-brand-mark" src="/brand/project-mark.png" alt="" />
{!collapsed && <span style={{ fontWeight: 700, fontSize: '1rem', color: 'var(--gray-900)', whiteSpace: 'nowrap' }}>مدیریت پروژه</span>}
</div>
<button
type="button"
onClick={onToggle}
className="sidebar-collapse-toggle"
title={collapsed ? 'باز کردن منو' : 'بستن منو'}
style={{
width: 34,
height: 34,
borderRadius: 'var(--radius-sm)',
background: collapsed ? 'var(--surface-active)' : 'var(--gray-100)',
border: '1px solid var(--gray-200)',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
color: 'var(--gray-700)',
cursor: 'pointer',
boxShadow: 'var(--shadow)',
transition: 'var(--transition)',
flexShrink: 0,
}}
>
{collapsed ? <PanelRightOpen size={18} /> : <PanelRightClose size={18} />}
</button>
<button type="button" className="sidebar-mobile-close" onClick={onMobileClose} aria-label="بستن منوی اصلی">
<X size={20} />
</button>
</div>
<nav style={{ flex: 1, overflowY: 'auto', padding: '0.75rem 0' }}>
{menuItems.map((item) => (
<NavLink key={item.path} to={item.path} end={item.path === '/'} onClick={onMobileClose} style={({ isActive }) => ({
display: 'flex', alignItems: 'center', gap: '0.75rem',
padding: collapsed ? '0.75rem 1.5rem' : '0.625rem 1.25rem',
margin: '0 0.5rem',
borderRadius: 'var(--radius-sm)',
fontSize: '0.875rem',
fontWeight: isActive ? 600 : 400,
color: isActive ? 'var(--primary)' : 'var(--gray-600)',
background: isActive ? 'var(--surface-active)' : 'transparent',
justifyContent: collapsed ? 'center' : 'flex-start',
whiteSpace: 'nowrap',
transition: 'all 0.15s ease',
})}>
<item.icon size={iconSize} />
{!collapsed && item.label}
</NavLink>
))}
</nav>
<div style={{ padding: '0.75rem 1.25rem', borderTop: '1px solid var(--gray-100)', display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
{user?.avatar_url ? <img className="avatar avatar-sm avatar-img" src={user.avatar_url} alt={user?.name || 'avatar'} /> : <div className="avatar avatar-sm">{user?.name?.[0] || '?'}</div>}
{!collapsed && <div style={{ fontSize: '0.8125rem', color: 'var(--gray-600)', overflow: 'hidden', textOverflow: 'ellipsis' }}>{user?.name}</div>}
</div>
</aside>
);
}