94 lines
3.7 KiB
TypeScript
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>
|
|
);
|
|
}
|