97 lines
3.8 KiB
TypeScript
97 lines
3.8 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import { clsx } from "clsx";
|
|
import { useAuth } from "@/components/AuthProvider";
|
|
|
|
interface NavItem {
|
|
href: string;
|
|
label: string;
|
|
icon: React.ReactNode;
|
|
}
|
|
|
|
function ServerIcon() {
|
|
return (
|
|
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function KeyIcon() {
|
|
return (
|
|
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 5.25a3 3 0 013 3m3 0a6 6 0 01-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1121.75 8.25z" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
const navItems: NavItem[] = [
|
|
{ href: "/servers", label: "Servers", icon: <ServerIcon /> },
|
|
{ href: "/keys", label: "SSH Keys", icon: <KeyIcon /> },
|
|
];
|
|
|
|
export function Sidebar() {
|
|
const pathname = usePathname();
|
|
const { user, authEnabled } = useAuth();
|
|
|
|
return (
|
|
<aside className="flex h-screen w-60 flex-col border-r border-border bg-surface">
|
|
<div className="flex h-16 items-center gap-3 border-b border-border px-5">
|
|
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-accent">
|
|
<svg className="h-4 w-4 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 5.25a3 3 0 013 3m3 0a6 6 0 01-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1121.75 8.25z" />
|
|
</svg>
|
|
</div>
|
|
<span className="text-base font-semibold text-text-primary">KeyManager</span>
|
|
</div>
|
|
|
|
<nav className="flex-1 overflow-y-auto px-3 py-4">
|
|
<ul className="space-y-1">
|
|
{navItems.map((item) => {
|
|
const isActive =
|
|
pathname === item.href || pathname.startsWith(item.href + "/");
|
|
return (
|
|
<li key={item.href}>
|
|
<Link
|
|
href={item.href}
|
|
className={clsx(
|
|
"flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors",
|
|
isActive
|
|
? "bg-accent/15 text-accent"
|
|
: "text-text-secondary hover:bg-surface-2 hover:text-text-primary"
|
|
)}
|
|
>
|
|
{item.icon}
|
|
{item.label}
|
|
</Link>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
</nav>
|
|
|
|
<div className="border-t border-border px-4 py-3">
|
|
{authEnabled && user && (
|
|
<div className="mb-3">
|
|
<p className="truncate text-sm font-medium text-text-primary">{user.name || user.email}</p>
|
|
<p className="truncate text-xs text-text-secondary">{user.email}</p>
|
|
</div>
|
|
)}
|
|
<div className="flex items-center justify-between">
|
|
<p className="text-xs text-text-secondary">KeyManager v1.0</p>
|
|
{authEnabled && user && (
|
|
<a
|
|
href="/auth/logout"
|
|
className="text-xs text-text-secondary transition-colors hover:text-danger"
|
|
>
|
|
Logout
|
|
</a>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
);
|
|
}
|