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:
		| @@ -1,32 +1,89 @@ | ||||
| import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarMenuButton, SidebarMenuItem } from "@/components/ui/sidebar"; | ||||
| import { tools } from "@/components/tool"; | ||||
| import type { ReactNode } from "react"; | ||||
| 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 { ModeToggle } from "@/components/theme/toggle"; | ||||
| 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> | ||||
|       <SidebarHeader className="text-2xl font-bold flex justify-center items-center"> | ||||
|         Lite Kit | ||||
|       </SidebarHeader> | ||||
|       <SidebarContent> | ||||
|         <SidebarGroup> | ||||
|         <SidebarGroupLabel> | ||||
|           Tools | ||||
|         </SidebarGroupLabel> | ||||
|           <SidebarGroupLabel>Tools</SidebarGroupLabel> | ||||
|           <SidebarGroupContent> | ||||
|           { | ||||
|             tools.map((tool) => ( | ||||
|               <SidebarMenuItem key={tool.name}> | ||||
|                 <SidebarMenuButton asChild> | ||||
|                   <Link to={`/tool/${tool.path}`} title={tool.description}> | ||||
|                     {tool.icon} | ||||
|                     {tool.name} | ||||
|                   </Link> | ||||
|                 </SidebarMenuButton> | ||||
|               </SidebarMenuItem> | ||||
|             )) | ||||
|           } | ||||
|             <SidebarMenu> | ||||
|               {tools.map((tool) => renderMenuItem(tool))} | ||||
|             </SidebarMenu> | ||||
|           </SidebarGroupContent> | ||||
|         </SidebarGroup> | ||||
|       </SidebarContent> | ||||
| @@ -37,4 +94,5 @@ export const AppSidebar = () => ( | ||||
|         <ModeToggle /> | ||||
|       </SidebarFooter> | ||||
|     </Sidebar> | ||||
| ) | ||||
|   ); | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user
	 typist
					typist