77 lines
2.4 KiB
TypeScript
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>
|
|
);
|
|
}
|