diff --git a/app/(admin)/_components/admin-layout-shell.tsx b/app/(admin)/_components/admin-layout-shell.tsx new file mode 100644 index 000000000..8dc2a86b3 --- /dev/null +++ b/app/(admin)/_components/admin-layout-shell.tsx @@ -0,0 +1,30 @@ +"use client"; + +import type { ComponentProps, ReactNode } from "react"; +import { usePathname } from "next/navigation"; +import { TopNavbar } from "@/components/top-navbar"; + +type AdminLayoutShellProps = ComponentProps & { + children: ReactNode; +}; + +function shouldHideSidebarChrome(pathname: string) { + return pathname === "/settings"; +} + +export function AdminLayoutShell({ + children, + ...topNavbarProps +}: AdminLayoutShellProps) { + const pathname = usePathname(); + const hideSidebarChrome = shouldHideSidebarChrome(pathname); + + return ( +
+ {hideSidebarChrome ? null : } +
+ {children} +
+
+ ); +} diff --git a/app/(admin)/layout.tsx b/app/(admin)/layout.tsx index fd960eca7..703e03359 100644 --- a/app/(admin)/layout.tsx +++ b/app/(admin)/layout.tsx @@ -1,6 +1,6 @@ import { auth } from "@/app/(auth)/auth"; -import { TopNavbar } from "@/components/top-navbar"; import { getSiteSettings, getNavLinks, getTutorialVideos } from "@/lib/db/queries"; +import { AdminLayoutShell } from "./_components/admin-layout-shell"; export default async function AdminLayout({ children, @@ -21,38 +21,37 @@ export default async function AdminLayout({ : null; return ( -
- ({ - id: link.id, - name: link.name, - url: link.url, - order: link.order, - toolboxGroup: link.toolboxGroup || 1, - }))} - toolbox1Name={siteSettings.toolbox1Name || "工具箱"} - toolbox1Enabled={siteSettings.toolbox1Enabled ?? true} - toolbox2Name={siteSettings.toolbox2Name || "工具箱2"} - toolbox2Enabled={siteSettings.toolbox2Enabled ?? false} - tutorialVideos={tutorialVideos.map(v => ({ - id: v.id, - title: v.title, - videoUrl: v.videoUrl, - coverUrl: v.coverUrl, - description: v.description, - order: v.order, - }))} - tutorialEnabled={siteSettings.tutorialEnabled ?? false} - rankingEnabled={siteSettings.rankingEnabled ?? true} - productPlanningEnabled={(siteSettings as any).productPlanningEnabled ?? true} - videoCanvasEnabled={(siteSettings as any).videoCanvasEnabled ?? true} - /> -
{children}
-
+ ({ + id: link.id, + name: link.name, + url: link.url, + order: link.order, + toolboxGroup: link.toolboxGroup || 1, + }))} + toolbox1Name={siteSettings.toolbox1Name || "工具箱"} + toolbox1Enabled={siteSettings.toolbox1Enabled ?? true} + toolbox2Name={siteSettings.toolbox2Name || "工具箱2"} + toolbox2Enabled={siteSettings.toolbox2Enabled ?? false} + tutorialVideos={tutorialVideos.map((v) => ({ + id: v.id, + title: v.title, + videoUrl: v.videoUrl, + coverUrl: v.coverUrl, + description: v.description, + order: v.order, + }))} + tutorialEnabled={siteSettings.tutorialEnabled ?? false} + rankingEnabled={siteSettings.rankingEnabled ?? true} + productPlanningEnabled={(siteSettings as any).productPlanningEnabled ?? true} + videoCanvasEnabled={(siteSettings as any).videoCanvasEnabled ?? true} + > + {children} + ); } diff --git a/app/(admin)/settings/_components/admin-settings-navigation.tsx b/app/(admin)/settings/_components/admin-settings-navigation.tsx index 5fc9010c0..acb571cbe 100644 --- a/app/(admin)/settings/_components/admin-settings-navigation.tsx +++ b/app/(admin)/settings/_components/admin-settings-navigation.tsx @@ -1,91 +1,272 @@ "use client"; import Link from "next/link"; -import { TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { ArrowLeft, ChevronDown } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectSeparator, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Separator } from "@/components/ui/separator"; import { ADMIN_SETTINGS_NAV_GROUPS } from "../_lib/settings-navigation"; +import type { AdminSettingsNavGroup, AdminSettingsNavItem } from "../_lib/types"; import { SettingStatusBadge } from "./setting-status-badge"; -export function AdminSettingsNavigation({ activeTab }: { activeTab: string }) { +function getActiveGroup(activeTab: string) { + return ADMIN_SETTINGS_NAV_GROUPS.find((group) => + group.items.some((item) => item.value === activeTab) + ); +} + +function getActiveItem(activeTab: string) { + return ADMIN_SETTINGS_NAV_GROUPS.flatMap((group) => group.items).find( + (item) => item.value === activeTab + ); +} + +function SettingsGroupDropdown({ + activeTab, + group, + onTabChange, +}: { + activeTab: string; + group: AdminSettingsNavGroup; + onTabChange: (value: string) => void; +}) { + const hasActiveTab = group.items.some((item) => item.value === activeTab); + return ( -
-
-
+ + + + + + {group.title} + + {group.items.map((item) => { + const Icon = item.icon; + const itemContent = ( + <> + +
+
{item.label}
+
+ {item.description} +
+
+ {item.value === activeTab ? ( + 当前 + ) : null} + + ); + + if (item.href) { + return ( + + {itemContent} + + ); + } + + return ( + onTabChange(item.value)} + > + {itemContent} + + ); + })} +
+
+ ); +} + +function SettingsQuickAction({ + activeTab, + item, + onTabChange, +}: { + activeTab: string; + item: AdminSettingsNavItem; + onTabChange: (value: string) => void; +}) { + const Icon = item.icon; + const className = + item.value === activeTab + ? "border-primary bg-primary text-primary-foreground hover:bg-primary/90" + : "border-border bg-background text-foreground hover:bg-accent hover:text-accent-foreground"; + + if (item.href) { + return ( + + ); + } + + return ( + + ); +} + +export function AdminSettingsNavigation({ + activeTab, + onTabChange, +}: { + activeTab: string; + onTabChange: (value: string) => void; +}) { + const activeGroup = getActiveGroup(activeTab); + const activeItem = getActiveItem(activeTab); + const ActiveIcon = activeItem?.icon; + + return ( +
+
+
Admin Console
-

- 系统设置中心 -

+
+

+ 系统设置中心 +

+ {activeGroup ? ( + {activeGroup.title} + ) : null} +

- 按后台人员的操作路径重新组织入口:先处理运营数据,再调整站点体验,最后管理模型与基础设施能力。 + 页面已改成横向工作区:顶部收拢分类入口,正文区域尽量留给配置表单和数据内容。

+
-
- {ADMIN_SETTINGS_NAV_GROUPS.map((group) => { - const hasActiveTab = group.items.some( - (item) => item.value === activeTab - ); - return ( -
-
-
-

{group.title}

-

- {group.description} -

-
- {hasActiveTab ? ( - 当前 - ) : null} -
- - {group.items.map((item) => { - const Icon = item.icon; - const triggerClassName = - "h-auto justify-start gap-2 rounded-md border border-transparent px-3 py-2 text-left data-[state=active]:border-border data-[state=active]:bg-muted/50"; - const content = ( - <> - - - - {item.label} - - - {item.description} - - - - ); - if (item.href) { - return ( - - {content} - - ); - } +
+
+ - return ( - - {content} - - ); - })} - -
- ); - })} +
+ {(activeGroup?.items ?? []).map((item) => ( + + ))} +
+
+ +
+ {ADMIN_SETTINGS_NAV_GROUPS.map((group) => ( + + ))} + + + +
+ {(activeGroup?.items ?? []).map((item) => ( + + ))} +
+
+ + {activeItem && ActiveIcon ? ( +
+
+ +
+
+
+

{activeItem.label}

+ {activeGroup ? ( + + {activeGroup.title} + + ) : null} +
+

+ {activeItem.description} +

+
+
+ ) : null}
); } diff --git a/app/(admin)/settings/admin-settings-client.tsx b/app/(admin)/settings/admin-settings-client.tsx index 38a2e25ff..ec7e1762e 100644 --- a/app/(admin)/settings/admin-settings-client.tsx +++ b/app/(admin)/settings/admin-settings-client.tsx @@ -126,7 +126,7 @@ import { } from "@/components/ui/select"; import { Separator } from "@/components/ui/separator"; import { Switch } from "@/components/ui/switch"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Tabs, TabsContent } from "@/components/ui/tabs"; import { Textarea } from "@/components/ui/textarea"; import { defaultAgentWorkflowUiConfig, @@ -7996,9 +7996,12 @@ export function AdminSettingsClient() { }, [expandedLocalAiSections]); return ( -
+
- + {/* 用户管理 */}