149 lines
4.3 KiB
TypeScript
149 lines
4.3 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { ArrowLeft } from "lucide-react";
|
|
import { useRouter } from "next/navigation";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select";
|
|
import { ADMIN_SETTINGS_NAV_ITEMS } from "../_lib/settings-navigation";
|
|
import type { AdminSettingsNavItem } from "../_lib/types";
|
|
|
|
function SettingsQuickAction({
|
|
activeTab,
|
|
item,
|
|
onTabChange,
|
|
stretched = false,
|
|
}: {
|
|
activeTab: string;
|
|
item: AdminSettingsNavItem;
|
|
onTabChange: (value: string) => void;
|
|
stretched?: boolean;
|
|
}) {
|
|
const Icon = item.icon;
|
|
const className =
|
|
item.value === activeTab
|
|
? "border-foreground/10 bg-foreground text-background shadow-sm hover:!bg-foreground/90 hover:!text-background dark:border-white/20 dark:bg-white dark:text-black dark:hover:!bg-white/90 dark:hover:!text-black"
|
|
: "border-transparent bg-transparent text-muted-foreground hover:!border-border/80 hover:!bg-zinc-100 hover:!text-foreground dark:hover:!bg-zinc-900/50";
|
|
const layoutClassName = stretched
|
|
? "h-8 w-full min-w-0 justify-center gap-1.5 rounded-md border px-2.5 text-xs"
|
|
: "h-8 shrink-0 gap-1.5 rounded-md border px-2.5 text-xs";
|
|
|
|
if (item.href) {
|
|
return (
|
|
<Button
|
|
asChild
|
|
className={`${layoutClassName} ${className}`}
|
|
size="sm"
|
|
variant="ghost"
|
|
>
|
|
<Link href={item.href}>
|
|
<Icon className="h-3.5 w-3.5" />
|
|
<span className={stretched ? "truncate" : ""}>{item.label}</span>
|
|
</Link>
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Button
|
|
className={`${layoutClassName} ${className}`}
|
|
onClick={() => onTabChange(item.value)}
|
|
size="sm"
|
|
variant="ghost"
|
|
>
|
|
<Icon className="h-3.5 w-3.5" />
|
|
<span className={stretched ? "truncate" : ""}>{item.label}</span>
|
|
</Button>
|
|
);
|
|
}
|
|
|
|
export function AdminSettingsNavigation({
|
|
activeTab,
|
|
onTabChange,
|
|
}: {
|
|
activeTab: string;
|
|
onTabChange: (value: string) => void;
|
|
}) {
|
|
const router = useRouter();
|
|
const activeItem = ADMIN_SETTINGS_NAV_ITEMS.find(
|
|
(item) => item.value === activeTab
|
|
);
|
|
const handleSelectChange = (value: string) => {
|
|
const nextItem = ADMIN_SETTINGS_NAV_ITEMS.find(
|
|
(item) => item.value === value
|
|
);
|
|
if (nextItem?.href) {
|
|
router.push(nextItem.href);
|
|
return;
|
|
}
|
|
onTabChange(value);
|
|
};
|
|
|
|
return (
|
|
<nav
|
|
aria-label="系统设置导航"
|
|
className="sticky top-2 z-30 rounded-lg border bg-background/95 p-2 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-background/85"
|
|
>
|
|
<div className="md:hidden">
|
|
<div className="flex items-center gap-2">
|
|
<Select onValueChange={handleSelectChange} value={activeTab}>
|
|
<SelectTrigger className="h-8 flex-1 border-border/70 bg-background shadow-none">
|
|
<SelectValue placeholder={activeItem?.label || "选择设置项"} />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{ADMIN_SETTINGS_NAV_ITEMS.map((item) => (
|
|
<SelectItem key={item.value} value={item.value}>
|
|
{item.label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
|
|
<Button
|
|
asChild
|
|
className="h-8 rounded-md border-border/70 px-2.5 text-xs"
|
|
size="sm"
|
|
variant="outline"
|
|
>
|
|
<Link href="/">
|
|
<ArrowLeft className="h-3.5 w-3.5" />
|
|
返回
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="hidden min-w-0 grid-cols-7 gap-1 md:grid xl:grid-cols-[repeat(13,minmax(78px,1fr))_auto]">
|
|
{ADMIN_SETTINGS_NAV_ITEMS.map((item) => (
|
|
<SettingsQuickAction
|
|
activeTab={activeTab}
|
|
item={item}
|
|
key={item.value}
|
|
onTabChange={onTabChange}
|
|
stretched
|
|
/>
|
|
))}
|
|
|
|
<Button
|
|
asChild
|
|
className="h-8 min-w-0 rounded-md border-border/70 px-2.5 text-xs"
|
|
size="sm"
|
|
variant="outline"
|
|
>
|
|
<Link href="/">
|
|
<ArrowLeft className="h-3.5 w-3.5" />
|
|
返回工作台
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
</nav>
|
|
);
|
|
}
|