sojorn/admin/src/components/Sidebar.tsx

94 lines
3.7 KiB
TypeScript

'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { useAuth } from '@/lib/auth';
import { cn } from '@/lib/utils';
import {
LayoutDashboard, Users, FileText, Shield, Scale, Flag,
Settings, Activity, LogOut, ChevronLeft, ChevronRight, Sliders, FolderTree, HardDrive, AtSign, Brain, ScrollText,
} from 'lucide-react';
import { useState } from 'react';
const navItems = [
{ href: '/', label: 'Dashboard', icon: LayoutDashboard },
{ href: '/users', label: 'Users', icon: Users },
{ href: '/posts', label: 'Posts', icon: FileText },
{ href: '/moderation', label: 'Moderation', icon: Shield },
{ href: '/appeals', label: 'Appeals', icon: Scale },
{ href: '/reports', label: 'Reports', icon: Flag },
{ href: '/algorithm', label: 'Algorithm', icon: Sliders },
{ href: '/categories', label: 'Categories', icon: FolderTree },
{ href: '/usernames', label: 'Usernames', icon: AtSign },
{ href: '/ai-moderation', label: 'AI Moderation', icon: Brain },
{ href: '/ai-audit-log', label: 'AI Audit Log', icon: ScrollText },
{ href: '/storage', label: 'Storage', icon: HardDrive },
{ href: '/system', label: 'System Health', icon: Activity },
{ href: '/settings', label: 'Settings', icon: Settings },
];
export default function Sidebar() {
const pathname = usePathname();
const { logout } = useAuth();
const [collapsed, setCollapsed] = useState(false);
return (
<aside
className={cn(
'fixed left-0 top-0 h-screen bg-white border-r border-warm-300 flex flex-col transition-all duration-300 z-30',
collapsed ? 'w-16' : 'w-60'
)}
>
{/* Logo */}
<div className="h-16 flex items-center px-4 border-b border-warm-300">
<div className="w-8 h-8 bg-brand-500 rounded-lg flex items-center justify-center flex-shrink-0">
<span className="text-white font-bold text-sm">S</span>
</div>
{!collapsed && <span className="ml-3 font-semibold text-gray-900">Sojorn Admin</span>}
</div>
{/* Navigation */}
<nav className="flex-1 py-4 overflow-y-auto">
{navItems.map((item) => {
const isActive = pathname === item.href || (item.href !== '/' && pathname.startsWith(item.href));
const Icon = item.icon;
return (
<Link
key={item.href}
href={item.href}
className={cn(
'flex items-center px-4 py-2.5 mx-2 rounded-lg text-sm font-medium transition-colors mb-0.5',
isActive
? 'bg-brand-50 text-brand-600'
: 'text-gray-600 hover:bg-warm-200 hover:text-gray-900'
)}
title={collapsed ? item.label : undefined}
>
<Icon className="w-5 h-5 flex-shrink-0" />
{!collapsed && <span className="ml-3">{item.label}</span>}
</Link>
);
})}
</nav>
{/* Footer */}
<div className="border-t border-warm-300 p-3">
<button
onClick={() => setCollapsed(!collapsed)}
className="flex items-center px-2 py-2 w-full rounded-lg text-sm text-gray-500 hover:bg-warm-200 transition-colors"
>
{collapsed ? <ChevronRight className="w-5 h-5" /> : <ChevronLeft className="w-5 h-5" />}
{!collapsed && <span className="ml-3">Collapse</span>}
</button>
<button
onClick={logout}
className="flex items-center px-2 py-2 w-full rounded-lg text-sm text-red-600 hover:bg-red-50 transition-colors mt-1"
>
<LogOut className="w-5 h-5 flex-shrink-0" />
{!collapsed && <span className="ml-3">Sign Out</span>}
</button>
</div>
</aside>
);
}