Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
61 lines
1.8 KiB
TypeScript
61 lines
1.8 KiB
TypeScript
'use client';
|
|
|
|
import Link from 'next/link';
|
|
import { usePathname } from 'next/navigation';
|
|
import { cn } from '@/lib/cn';
|
|
|
|
interface NavItem {
|
|
label: string;
|
|
href: string;
|
|
icon: string;
|
|
}
|
|
|
|
const navItems: NavItem[] = [
|
|
{ label: 'Chat', href: '/chat', icon: '💬' },
|
|
{ label: 'Tasks', href: '/tasks', icon: '📋' },
|
|
{ label: 'Projects', href: '/projects', icon: '📁' },
|
|
{ label: 'Settings', href: '/settings', icon: '⚙️' },
|
|
{ label: 'Admin', href: '/admin', icon: '🛡️' },
|
|
];
|
|
|
|
export function Sidebar(): React.ReactElement {
|
|
const pathname = usePathname();
|
|
|
|
return (
|
|
<aside className="fixed left-0 top-0 z-30 flex h-screen w-sidebar flex-col border-r border-surface-border bg-surface-card">
|
|
<div className="flex h-14 items-center px-4">
|
|
<Link href="/" className="text-lg font-semibold text-text-primary">
|
|
Mosaic
|
|
</Link>
|
|
</div>
|
|
|
|
<nav className="flex-1 space-y-1 px-2 py-2">
|
|
{navItems.map((item) => {
|
|
const isActive = pathname === item.href || pathname.startsWith(`${item.href}/`);
|
|
return (
|
|
<Link
|
|
key={item.href}
|
|
href={item.href}
|
|
className={cn(
|
|
'flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors',
|
|
isActive
|
|
? 'bg-blue-600/20 text-blue-400'
|
|
: 'text-text-secondary hover:bg-surface-elevated hover:text-text-primary',
|
|
)}
|
|
>
|
|
<span className="text-base" aria-hidden="true">
|
|
{item.icon}
|
|
</span>
|
|
{item.label}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
|
|
<div className="border-t border-surface-border p-4">
|
|
<p className="text-xs text-text-muted">Mosaic Stack v0.0.4</p>
|
|
</div>
|
|
</aside>
|
|
);
|
|
}
|