Files
jiang13-bbs/frontend/app/admin/settings/SettingsShell.tsx

77 lines
2.4 KiB
TypeScript

"use client";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import { useRef, type KeyboardEvent, type ReactNode } from "react";
import { Globe } from "lucide-react";
import {
AdminPageHeader,
AdminSettingsPage,
AdminSettingsWork,
} from "@/components/admin";
const NAV: { href: string; label: string }[] = [
{ href: "/admin/settings/basic", label: "基本信息" },
{ href: "/admin/settings/access", label: "互动与安全" },
{ href: "/admin/settings/mail", label: "邮件服务" },
{ href: "/admin/settings/storage", label: "文件与存储" },
{ href: "/admin/settings/filter", label: "内容过滤" },
{ href: "/admin/settings/maintenance", label: "维护与诊断" },
];
export default function SettingsShell({ children }: { children: ReactNode }) {
const pathname = usePathname();
const router = useRouter();
const navRefs = useRef<(HTMLAnchorElement | null)[]>([]);
const onNavKeyDown = (e: KeyboardEvent<HTMLAnchorElement>, i: number) => {
if (
e.key !== "ArrowDown" &&
e.key !== "ArrowUp" &&
e.key !== "Home" &&
e.key !== "End" &&
e.key !== "ArrowRight" &&
e.key !== "ArrowLeft"
) {
return;
}
e.preventDefault();
let next = i;
if (e.key === "ArrowDown" || e.key === "ArrowRight") next = (i + 1) % NAV.length;
else if (e.key === "ArrowUp" || e.key === "ArrowLeft") next = (i + NAV.length - 1) % NAV.length;
else if (e.key === "Home") next = 0;
else next = NAV.length - 1;
navRefs.current[next]?.focus();
router.push(NAV[next].href);
};
const nav = (
<nav className="admin-settings-nav" aria-label="设置分类">
{NAV.map((item, i) => {
const isActive = pathname === item.href;
return (
<Link
key={item.href}
ref={(el) => {
navRefs.current[i] = el;
}}
href={item.href}
className="admin-settings-nav-link"
aria-current={isActive ? "page" : undefined}
onKeyDown={(e) => onNavKeyDown(e, i)}
>
{item.label}
</Link>
);
})}
</nav>
);
return (
<AdminSettingsPage>
<AdminPageHeader icon={Globe} title="站点设置" description="基本信息、互动安全与运营模块" />
<AdminSettingsWork nav={nav}>{children}</AdminSettingsWork>
</AdminSettingsPage>
);
}