feat: refactor AppSidebar to support nested tool menus with collapsible items

- Enhanced the AppSidebar component to recursively render tools with potential submenus.
- Introduced a buildFullPath function for dynamic routing based on tool hierarchy.
- Utilized the Collapsible component for better organization of tools with children.
- Maintained existing footer and header structure for consistency.
This commit is contained in:
typist
2025-10-29 05:45:09 +08:00
parent e9cf714da9
commit 3f7c81e892

View File

@@ -1,32 +1,89 @@
import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarMenuButton, SidebarMenuItem } from "@/components/ui/sidebar"; import type { ReactNode } from "react";
import { tools } from "@/components/tool"; import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarMenuButton, SidebarMenuItem, SidebarMenu, SidebarMenuSub, SidebarMenuSubItem, SidebarMenuSubButton } from "@/components/ui/sidebar";
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@/components/ui/collapsible";
import { tools, type Tool } from "@/components/tool";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { ModeToggle } from "@/components/theme/toggle"; import { ModeToggle } from "@/components/theme/toggle";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { ChevronRight } from "lucide-react";
export const AppSidebar = () => ( export const AppSidebar = () => {
// 递归构建完整路径
const buildFullPath = (pathSegments: string[]): string => {
return `/tool/${pathSegments.join("/")}`;
};
// 递归渲染菜单项
const renderMenuItem = (tool: Tool, parentPaths: string[] = []): ReactNode => {
const currentPaths = [...parentPaths, tool.path];
if (tool.children) {
// 有子菜单的项目
return (
<Collapsible
key={tool.name}
defaultOpen={false}
className="group/collapsible"
>
<SidebarMenuItem>
<CollapsibleTrigger asChild>
<SidebarMenuButton tooltip={tool.description}>
{tool.icon}
<span>{tool.name}</span>
<ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
</SidebarMenuButton>
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
{tool.children.map((child) => (
<SidebarMenuSubItem key={child.name}>
{child.children ? (
renderMenuItem(child, currentPaths)
) : (
<SidebarMenuSubButton asChild>
<Link
to={buildFullPath([...currentPaths, child.path])}
title={child.description}
>
{child.icon}
<span>{child.name}</span>
</Link>
</SidebarMenuSubButton>
)}
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenuItem>
</Collapsible>
);
}
// 没有子菜单的项目
return (
<SidebarMenuItem key={tool.name}>
<SidebarMenuButton asChild tooltip={tool.description}>
<Link to={buildFullPath(currentPaths)}>
{tool.icon}
<span>{tool.name}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
);
};
return (
<Sidebar> <Sidebar>
<SidebarHeader className="text-2xl font-bold flex justify-center items-center"> <SidebarHeader className="text-2xl font-bold flex justify-center items-center">
Lite Kit Lite Kit
</SidebarHeader> </SidebarHeader>
<SidebarContent> <SidebarContent>
<SidebarGroup> <SidebarGroup>
<SidebarGroupLabel> <SidebarGroupLabel>Tools</SidebarGroupLabel>
Tools
</SidebarGroupLabel>
<SidebarGroupContent> <SidebarGroupContent>
{ <SidebarMenu>
tools.map((tool) => ( {tools.map((tool) => renderMenuItem(tool))}
<SidebarMenuItem key={tool.name}> </SidebarMenu>
<SidebarMenuButton asChild>
<Link to={`/tool/${tool.path}`} title={tool.description}>
{tool.icon}
{tool.name}
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))
}
</SidebarGroupContent> </SidebarGroupContent>
</SidebarGroup> </SidebarGroup>
</SidebarContent> </SidebarContent>
@@ -37,4 +94,5 @@ export const AppSidebar = () => (
<ModeToggle /> <ModeToggle />
</SidebarFooter> </SidebarFooter>
</Sidebar> </Sidebar>
) );
};