163 lines
4.2 KiB
TypeScript
163 lines
4.2 KiB
TypeScript
import * as React from "react"
|
|
import { ChevronRight } from "lucide-react"
|
|
import Link from "next/link"
|
|
|
|
import { SearchForm } from "@/components/search-form"
|
|
import { VersionSwitcher } from "@/components/version-switcher"
|
|
import {
|
|
Collapsible,
|
|
CollapsibleContent,
|
|
CollapsibleTrigger,
|
|
} from "@/components/ui/collapsible"
|
|
import {
|
|
Sidebar,
|
|
SidebarContent,
|
|
SidebarGroup,
|
|
SidebarGroupContent,
|
|
SidebarGroupLabel,
|
|
SidebarHeader,
|
|
SidebarMenu,
|
|
SidebarMenuButton,
|
|
SidebarMenuItem,
|
|
SidebarRail,
|
|
} from "@/components/ui/sidebar"
|
|
import { useLayoutStore } from '@/stores/useLayoutStore';
|
|
// Define the interface for menu data
|
|
interface MenuItem {
|
|
title: string
|
|
url: string
|
|
isActive?: boolean
|
|
}
|
|
|
|
interface NavMainItem {
|
|
title: string
|
|
url: string
|
|
icon?: string
|
|
items: MenuItem[]
|
|
}
|
|
|
|
interface SidebarData {
|
|
navMain: NavMainItem[]
|
|
versions?: string[]
|
|
}
|
|
|
|
// Default data - used when no external data is provided
|
|
const defaultData: SidebarData = {
|
|
versions: ["1.0.0", "2.0.0"],
|
|
navMain: [
|
|
{
|
|
title: "Getting Started",
|
|
url: "#",
|
|
items: [
|
|
{
|
|
title: "Installation",
|
|
url: "#",
|
|
},
|
|
{
|
|
title: "Project Structure",
|
|
url: "#",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: "Building Your Application",
|
|
url: "#",
|
|
items: [
|
|
{
|
|
title: "Routing",
|
|
url: "#",
|
|
},
|
|
{
|
|
title: "Data Fetching",
|
|
url: "#",
|
|
isActive: true,
|
|
},
|
|
{
|
|
title: "Rendering",
|
|
url: "#",
|
|
},
|
|
{
|
|
title: "Caching",
|
|
url: "#",
|
|
},
|
|
{
|
|
title: "Styling",
|
|
url: "#",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: "API Reference",
|
|
url: "#",
|
|
items: [
|
|
{
|
|
title: "Components",
|
|
url: "#",
|
|
},
|
|
{
|
|
title: "File Conventions",
|
|
url: "#",
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}
|
|
|
|
export interface AppSidebarProps extends React.ComponentProps<typeof Sidebar> {
|
|
data?: SidebarData
|
|
}
|
|
|
|
export function AppSidebar({ data, ...props }: AppSidebarProps) {
|
|
// Use external data if provided, otherwise use default data
|
|
const sidebarData = data || defaultData
|
|
const { navigatorHeight } = useLayoutStore();
|
|
return (
|
|
<Sidebar {...props} style = {{top: navigatorHeight + 'px'}}>
|
|
<SidebarContent className="gap-0" >
|
|
{/* We create a collapsible SidebarGroup for each parent. */}
|
|
{sidebarData.navMain.map((item) => (
|
|
<Collapsible
|
|
key={item.title}
|
|
title={item.title}
|
|
defaultOpen
|
|
className="group/collapsible"
|
|
>
|
|
<SidebarGroup>
|
|
<SidebarGroupLabel
|
|
asChild
|
|
className="group/label text-sm text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
|
|
>
|
|
<CollapsibleTrigger>
|
|
<div className="flex items-center">
|
|
{item.icon && <span className="mr-2">{item.icon}</span>}
|
|
{item.title}
|
|
<ChevronRight className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-90" />
|
|
</div>
|
|
</CollapsibleTrigger>
|
|
</SidebarGroupLabel>
|
|
<CollapsibleContent>
|
|
<SidebarGroupContent>
|
|
<SidebarMenu>
|
|
{item.items.map((subItem) => (
|
|
<SidebarMenuItem key={subItem.title}>
|
|
<SidebarMenuButton asChild isActive={subItem.isActive}>
|
|
{subItem.url.startsWith('#') ? (
|
|
<a href={subItem.url}>{subItem.title}</a>
|
|
) : (
|
|
<Link href={subItem.url}>{subItem.title}</Link>
|
|
)}
|
|
</SidebarMenuButton>
|
|
</SidebarMenuItem>
|
|
))}
|
|
</SidebarMenu>
|
|
</SidebarGroupContent>
|
|
</CollapsibleContent>
|
|
</SidebarGroup>
|
|
</Collapsible>
|
|
))}
|
|
</SidebarContent>
|
|
<SidebarRail />
|
|
</Sidebar>
|
|
)
|
|
}
|