CoreControl/components/app-sidebar.tsx

209 lines
6.9 KiB
TypeScript
Raw Normal View History

2025-04-18 00:07:21 +02:00
"use client"
import type * as React from "react"
2025-04-11 14:48:12 +02:00
import Image from "next/image"
2025-04-18 00:07:21 +02:00
import { usePathname } from "next/navigation"
import {
AppWindow,
Settings,
LayoutDashboardIcon,
Briefcase,
Server,
Network,
Activity,
LogOut,
ChevronDown,
} from "lucide-react"
2025-04-11 14:48:12 +02:00
import {
Sidebar,
SidebarContent,
SidebarGroup,
2025-04-18 00:07:21 +02:00
SidebarGroupContent,
SidebarGroupLabel,
2025-04-11 14:48:12 +02:00
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
SidebarRail,
2025-04-18 00:07:21 +02:00
SidebarFooter,
2025-04-11 14:48:12 +02:00
} from "@/components/ui/sidebar"
import { Button } from "@/components/ui/button"
import Link from "next/link"
2025-04-13 21:10:17 +02:00
import Cookies from "js-cookie"
import { useRouter } from "next/navigation"
import packageJson from "@/package.json"
2025-04-18 00:07:21 +02:00
import { cn } from "@/lib/utils"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"
2025-04-13 21:10:17 +02:00
interface NavItem {
title: string
icon?: React.ComponentType<any>
url: string
isActive?: boolean
items?: NavItem[]
}
2025-04-11 14:48:12 +02:00
2025-04-13 21:10:17 +02:00
const data: { navMain: NavItem[] } = {
2025-04-11 14:48:12 +02:00
navMain: [
{
2025-04-13 21:10:17 +02:00
title: "Dashboard",
icon: LayoutDashboardIcon,
2025-04-18 00:07:21 +02:00
url: "/dashboard",
2025-04-11 14:48:12 +02:00
},
{
2025-04-13 21:10:17 +02:00
title: "My Infrastructure",
url: "#",
icon: Briefcase,
items: [
{
title: "Servers",
icon: Server,
url: "/dashboard/servers",
},
{
title: "Applications",
icon: AppWindow,
url: "/dashboard/applications",
},
2025-04-15 12:17:14 +02:00
{
2025-04-15 12:20:03 +02:00
title: "Uptime",
2025-04-15 12:17:14 +02:00
icon: Activity,
2025-04-15 12:20:03 +02:00
url: "/dashboard/uptime",
2025-04-15 12:17:14 +02:00
},
2025-04-13 21:10:17 +02:00
{
title: "Network",
icon: Network,
url: "/dashboard/network",
2025-04-18 00:07:21 +02:00
},
2025-04-11 14:48:12 +02:00
],
2025-04-12 13:21:03 +02:00
},
{
title: "Settings",
icon: Settings,
2025-04-12 20:01:43 +02:00
url: "/dashboard/settings",
2025-04-11 14:48:12 +02:00
},
],
}
2025-04-13 21:10:17 +02:00
2025-04-11 14:48:12 +02:00
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
2025-04-13 21:10:17 +02:00
const router = useRouter()
2025-04-18 00:07:21 +02:00
const pathname = usePathname()
2025-04-13 21:10:17 +02:00
const logout = async () => {
2025-04-18 00:07:21 +02:00
Cookies.remove("token")
2025-04-13 21:10:17 +02:00
router.push("/")
}
2025-04-11 14:50:26 +02:00
2025-04-18 00:07:21 +02:00
// Check if a path is active (exact match or starts with path for parent items)
const isActive = (path: string) => {
if (path === "#") return false
return pathname === path || (path !== "/dashboard" && pathname?.startsWith(path))
}
// Check if any child item is active
const hasActiveChild = (items?: NavItem[]) => {
if (!items) return false
return items.some((item) => isActive(item.url))
}
2025-04-13 21:10:17 +02:00
return (
2025-04-11 14:48:12 +02:00
<Sidebar {...props}>
2025-04-18 00:07:21 +02:00
<SidebarHeader className="border-b border-sidebar-border/30 pb-2">
2025-04-11 14:48:12 +02:00
<SidebarMenu>
<SidebarMenuItem>
2025-04-18 00:07:21 +02:00
<SidebarMenuButton size="lg" asChild className="gap-3">
<a href="https://github.com/crocofied/corecontrol" target="_blank" rel="noreferrer noopener" className="transition-all hover:opacity-80">
2025-04-18 00:07:21 +02:00
<div className="flex items-center justify-center rounded-lg overflow-hidden bg-gradient-to-br from-teal-500 to-emerald-600 shadow-sm">
<Image src="/logo.png" width={48} height={48} alt="CoreControl Logo" className="object-cover" />
</div>
2025-04-11 14:48:12 +02:00
<div className="flex flex-col gap-0.5 leading-none">
2025-04-18 00:07:21 +02:00
<span className="font-semibold text-base">CoreControl</span>
<span className="text-xs text-sidebar-foreground/70">v{packageJson.version}</span>
2025-04-11 14:48:12 +02:00
</div>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
2025-04-18 00:07:21 +02:00
<SidebarContent className="flex flex-col h-full py-4">
2025-04-11 14:48:12 +02:00
<SidebarGroup className="flex-grow">
2025-04-18 00:07:21 +02:00
<SidebarGroupLabel className="text-xs font-medium text-sidebar-foreground/60 uppercase tracking-wider px-4 mb-2">
Main Navigation
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{data.navMain.map((item) =>
item.items?.length ? (
<Collapsible key={item.title} defaultOpen={hasActiveChild(item.items)} className="group/collapsible">
<SidebarMenuItem>
<CollapsibleTrigger asChild>
<SidebarMenuButton
className={cn(
"font-medium transition-all",
(hasActiveChild(item.items) || isActive(item.url)) &&
"text-sidebar-accent-foreground bg-sidebar-accent/50",
)}
2025-04-13 21:10:17 +02:00
>
2025-04-18 00:07:21 +02:00
{item.icon && <item.icon className="h-4 w-4" />}
<span>{item.title}</span>
<ChevronDown className="ml-auto h-4 w-4 transition-transform group-data-[state=open]/collapsible:rotate-180" />
</SidebarMenuButton>
</CollapsibleTrigger>
<CollapsibleContent>
<SidebarMenuSub>
{item.items.map((subItem) => (
<SidebarMenuSubItem key={subItem.title}>
<SidebarMenuSubButton asChild isActive={isActive(subItem.url)} className="transition-all">
<Link href={subItem.url} className="flex items-center">
{subItem.icon && <subItem.icon className="h-3.5 w-3.5 mr-2" />}
<span>{subItem.title}</span>
</Link>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</CollapsibleContent>
</SidebarMenuItem>
</Collapsible>
) : (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton
asChild
className={cn(
"font-medium transition-all",
isActive(item.url) && "text-sidebar-accent-foreground bg-sidebar-accent/50",
)}
>
<Link href={item.url}>
{item.icon && <item.icon className="h-4 w-4" />}
<span>{item.title}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
),
)}
</SidebarMenu>
</SidebarGroupContent>
2025-04-11 14:48:12 +02:00
</SidebarGroup>
2025-04-18 00:07:21 +02:00
<SidebarFooter className="border-t border-sidebar-border/30 pt-4 mt-auto">
<Button
variant="outline"
className="w-full justify-start text-destructive hover:text-destructive hover:bg-destructive/10 border-none shadow-none"
onClick={logout}
>
<LogOut className="h-4 w-4 mr-2" />
2025-04-11 14:48:12 +02:00
Logout
2025-04-13 21:10:17 +02:00
</Button>
2025-04-18 00:07:21 +02:00
</SidebarFooter>
2025-04-13 21:10:17 +02:00
</SidebarContent>
2025-04-11 14:48:12 +02:00
<SidebarRail />
</Sidebar>
)
2025-04-18 00:07:21 +02:00
}