|
|
import React from 'react'; |
|
|
import { useTranslation } from 'react-i18next'; |
|
|
import { NavLink, useLocation } from 'react-router-dom'; |
|
|
import UserProfileMenu from '@/components/ui/UserProfileMenu'; |
|
|
|
|
|
interface SidebarProps { |
|
|
collapsed: boolean; |
|
|
} |
|
|
|
|
|
interface MenuItem { |
|
|
path: string; |
|
|
label: string; |
|
|
icon: React.ReactNode; |
|
|
} |
|
|
|
|
|
const Sidebar: React.FC<SidebarProps> = ({ collapsed }) => { |
|
|
const { t } = useTranslation(); |
|
|
const location = useLocation(); |
|
|
|
|
|
|
|
|
const appVersion = import.meta.env.PACKAGE_VERSION as string; |
|
|
|
|
|
|
|
|
const menuItems: MenuItem[] = [ |
|
|
{ |
|
|
path: '/', |
|
|
label: t('nav.dashboard'), |
|
|
icon: ( |
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> |
|
|
<path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z" /> |
|
|
<path d="M12 2.252A8.014 8.014 0 0117.748 8H12V2.252z" /> |
|
|
</svg> |
|
|
), |
|
|
}, |
|
|
{ |
|
|
path: '/servers', |
|
|
label: t('nav.servers'), |
|
|
icon: ( |
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> |
|
|
<path fillRule="evenodd" d="M2 5a2 2 0 012-2h12a2 2 0 012 2v2a2 2 0 01-2 2H4a2 2 0 01-2-2V5zm14 1a1 1 0 11-2 0 1 1 0 012 0zM2 13a2 2 0 012-2h12a2 2 0 012 2v2a2 2 0 01-2 2H4a2 2 0 01-2-2v-2zm14 1a1 1 0 11-2 0 1 1 0 012 0z" clipRule="evenodd" /> |
|
|
</svg> |
|
|
), |
|
|
}, |
|
|
{ |
|
|
path: '/groups', |
|
|
label: t('nav.groups'), |
|
|
icon: ( |
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> |
|
|
<path d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z" /> |
|
|
</svg> |
|
|
), |
|
|
}, |
|
|
{ |
|
|
path: '/market', |
|
|
label: t('nav.market'), |
|
|
icon: ( |
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> |
|
|
<path d="M3 1a1 1 0 000 2h1.22l.305 1.222a.997.997 0 00.01.042l1.358 5.43-.893.892C3.74 11.846 4.632 14 6.414 14H15a1 1 0 000-2H6.414l1-1H14a1 1 0 00.894-.553l3-6A1 1 0 0017 3H6.28l-.31-1.243A1 1 0 005 1H3zM16 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM6.5 18a1.5 1.5 0 100-3 1.5 1.5 0 000 3z" /> |
|
|
</svg> |
|
|
), |
|
|
}, |
|
|
{ |
|
|
path: '/logs', |
|
|
label: t('nav.logs'), |
|
|
icon: ( |
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"> |
|
|
<path fillRule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z" clipRule="evenodd" /> |
|
|
</svg> |
|
|
), |
|
|
}, |
|
|
]; |
|
|
|
|
|
return ( |
|
|
<aside |
|
|
className={`bg-white dark:bg-gray-800 shadow-sm transition-all duration-300 ease-in-out flex flex-col h-full relative ${ |
|
|
collapsed ? 'w-16' : 'w-64' |
|
|
}`} |
|
|
> |
|
|
{/* Scrollable navigation area */} |
|
|
<div className="overflow-y-auto flex-grow"> |
|
|
<nav className="p-3 space-y-1"> |
|
|
{menuItems.map((item) => ( |
|
|
<NavLink |
|
|
key={item.path} |
|
|
to={item.path} |
|
|
className={({ isActive }) => |
|
|
`flex items-center px-3 py-2 rounded-md transition-colors ${ |
|
|
isActive |
|
|
? 'bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200' |
|
|
: 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700' |
|
|
}` |
|
|
} |
|
|
end={item.path === '/'} |
|
|
> |
|
|
<span className="flex-shrink-0">{item.icon}</span> |
|
|
{!collapsed && <span className="ml-3">{item.label}</span>} |
|
|
</NavLink> |
|
|
))} |
|
|
</nav> |
|
|
</div> |
|
|
|
|
|
{/* User profile menu fixed at the bottom */} |
|
|
<div className="p-3 bg-white dark:bg-gray-800"> |
|
|
<UserProfileMenu collapsed={collapsed} version={appVersion} /> |
|
|
</div> |
|
|
</aside> |
|
|
); |
|
|
}; |
|
|
|
|
|
export default Sidebar; |