Files
new-api-analytics/components/Sidebar.tsx

116 lines
5.3 KiB
TypeScript

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { motion } from "motion/react";
import { LayoutDashboard, Trophy, ScrollText, Users, Activity, Sun, Moon, Monitor, Languages } from "lucide-react";
import { useI18n } from "@/lib/i18n";
import { useTheme, type Theme } from "@/lib/theme";
export function Sidebar() {
const pathname = usePathname();
const { t, locale, setLocale } = useI18n();
const { theme, setTheme, isEmbedded } = useTheme();
const nav = [
{ href: "/", label: t("nav.overview"), icon: LayoutDashboard },
{ href: "/rankings", label: t("nav.rankings"), icon: Trophy },
{ href: "/aggregation", label: t("nav.aggregation"), icon: Users },
{ href: "/logs", label: t("nav.logs"), icon: ScrollText },
];
const themes: { value: Theme; icon: typeof Sun; label: string }[] = [
{ value: "light", icon: Sun, label: t("theme.light") },
{ value: "dark", icon: Moon, label: t("theme.dark") },
{ value: "system", icon: Monitor, label: t("theme.system") },
];
return (
<aside className="fixed left-0 top-0 z-30 flex h-screen w-[220px] flex-col glass !rounded-none !border-l-0 !border-t-0 !border-b-0">
{/* Logo */}
<div className="flex h-16 items-center gap-3 border-b border-t px-5" style={{ borderColor: "var(--surface-border)" }}>
<div className="flex h-8 w-8 items-center justify-center rounded-lg border" style={{ borderColor: "var(--surface-border)", background: "var(--btn-active-bg)" }}>
<Activity className="h-4 w-4 text-t-accent" style={{ color: "var(--accent)" }} />
</div>
<div>
<span className="text-sm font-semibold tracking-wide text-t-primary" style={{ color: "var(--text-primary)" }}>Neural</span>
<span className="text-sm font-light tracking-wide" style={{ color: "var(--accent)" }}>Pulse</span>
</div>
</div>
<nav className="flex-1 space-y-1 p-3 pt-4">
{nav.map((item) => {
const active = item.href === "/" ? pathname === "/" : pathname.startsWith(item.href);
const Icon = item.icon;
return (
<Link key={item.href} href={item.href}>
<motion.div
className="relative flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm transition-colors"
style={{ color: active ? "var(--text-accent)" : "var(--text-muted)" }}
whileHover={{ x: 2 }}
transition={{ type: "spring", stiffness: 400, damping: 30 }}
>
{active && (
<motion.div
layoutId="sidebar-active"
className="absolute inset-0 rounded-lg"
style={{ background: "var(--btn-active-bg)", border: "1px solid var(--surface-border)" }}
transition={{ type: "spring", stiffness: 350, damping: 30 }}
/>
)}
<Icon className="relative z-10 h-4 w-4" />
<span className="relative z-10 font-medium">{item.label}</span>
{active && (
<motion.div
className="absolute left-0 top-1/2 h-5 w-[2px] -translate-y-1/2 rounded-full"
style={{ background: "var(--accent)" }}
layoutId="sidebar-indicator"
transition={{ type: "spring", stiffness: 350, damping: 30 }}
/>
)}
</motion.div>
</Link>
);
})}
</nav>
{/* Controls */}
<div className="space-y-3 p-4 border-t" style={{ borderColor: "var(--surface-border)" }}>
{!isEmbedded && (
<div className="flex gap-1 rounded-lg p-0.5" style={{ background: "var(--row-hover)", border: "1px solid var(--surface-border)" }}>
{themes.map(({ value, icon: Icon }) => (
<button key={value} onClick={() => setTheme(value)}
className="flex-1 flex items-center justify-center rounded-md py-1.5 transition-colors"
style={{
background: theme === value ? "var(--btn-active-bg)" : "transparent",
color: theme === value ? "var(--text-accent)" : "var(--text-muted)",
border: theme === value ? "1px solid var(--surface-border)" : "1px solid transparent",
}}
title={themes.find(t => t.value === value)?.label}
>
<Icon className="h-3.5 w-3.5" />
</button>
))}
</div>
)}
{/* Language switcher */}
<button
onClick={() => setLocale(locale === "zh" ? "en" : "zh")}
className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-xs transition-colors"
style={{ color: "var(--text-muted)", background: "var(--row-hover)", border: "1px solid var(--surface-border)" }}
>
<Languages className="h-3.5 w-3.5" />
<span className="font-medium">{locale === "zh" ? "English" : "中文"}</span>
</button>
{/* Status */}
<div className="flex items-center gap-2">
<div className="h-2 w-2 rounded-full bg-emerald-400 shadow-[0_0_8px_rgba(52,211,153,0.5)]" />
<span className="text-xs" style={{ color: "var(--text-muted)" }}>{t("common.systemOnline")}</span>
</div>
</div>
</aside>
);
}