CoreControl/components/Sidebar.tsx

188 lines
6.4 KiB
TypeScript
Raw Normal View History

2025-05-17 19:33:52 +02:00
"use client"
import type React from "react"
2025-05-17 19:51:32 +02:00
import Breadcrumbs from "./Breadcrumbs"
2025-05-17 19:33:52 +02:00
import { useState } from "react"
import Link from "next/link"
import {
Home,
Globe,
Server,
Layout,
Clock,
PenToolIcon as Tool,
Settings,
LogOut,
ChevronDown,
Menu,
} from "lucide-react"
import packageJson from "@/package.json"
import Image from "next/image"
import Cookies from "js-cookie"
import { useRouter } from "next/navigation"
interface SidebarProps {
children: React.ReactNode
username: string
fullName: string
2025-05-17 19:51:32 +02:00
breadcrumbPath?: string[]
2025-05-17 19:33:52 +02:00
}
2025-05-17 19:51:32 +02:00
export default function Sidebar({ children, username, fullName, breadcrumbPath }: SidebarProps) {
2025-05-17 19:33:52 +02:00
const router = useRouter()
const [isProfileOpen, setIsProfileOpen] = useState(false)
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
const initials = useState(() => {
const nameToUse = fullName || username
return nameToUse
.split(" ")
.filter((part) => part.length > 0)
.map((part) => part[0])
.join("")
.toUpperCase()
.substring(0, 2)
})[0]
const logout = () => {
Cookies.remove("token")
router.push("/")
}
return (
<div className="flex flex-col md:flex-row min-h-screen w-full bg-base-100">
{/* Mobile menu button */}
<div className="md:hidden flex items-center p-4 bg-base-200 border-b">
<button onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)} className="btn btn-square btn-ghost">
<Menu size={24} />
</button>
<span className="ml-2 text-xl font-bold">CoreControl</span>
</div>
{/* Sidebar */}
<aside
className={`
bg-base-200 text-base-content md:flex md:flex-col
${isMobileMenuOpen ? "block" : "hidden"} md:block
w-full md:w-72 md:h-screen md:sticky md:top-0 md:left-0
relative
`}
>
{/* Top section with logo and title */}
<div className="hidden md:block">
<div className="p-4">
<div className="flex items-center gap-3">
<Image src="/logo.png" alt="Logo" width={60} height={60} className="rounded-lg" />
<div>
<h2 className="text-xl font-bold">CoreControl</h2>
<p className="text-sm opacity-70">v{packageJson.version}</p>
</div>
</div>
</div>
</div>
{/* Navigation menu - scrollable if needed */}
<div className="overflow-y-auto" style={{ height: "calc(100vh - 160px)" }}>
<ul className="menu menu-md p-4 w-full">
<li className="w-full">
<Link href="/dashboard" className="flex items-center w-full justify-start px-3 py-2">
<Home size={18} />
<span>Home</span>
</Link>
</li>
<li className="menu-title mt-4">
<span>Resources</span>
</li>
<li className="w-full">
<Link href="/dashboard/sites" className="flex items-center w-full justify-start px-3 py-2">
<Globe size={18} />
<span>Sites</span>
</Link>
</li>
<li className="w-full">
<Link href="/dashboard/servers" className="flex items-center w-full justify-start px-3 py-2">
<Server size={18} />
<span>Servers</span>
</Link>
</li>
<li className="w-full">
<Link href="/dashboard/applications" className="flex items-center w-full justify-start px-3 py-2">
<Layout size={18} />
<span>Applications</span>
</Link>
</li>
<li className="w-full">
<Link href="/dashboard/uptime" className="flex items-center w-full justify-start px-3 py-2">
<Clock size={18} />
<span>Uptime Pages</span>
</Link>
</li>
<li className="menu-title mt-4">
<span>System</span>
</li>
<li className="w-full">
<Link href="/dashboard/maintenance" className="flex items-center w-full justify-start px-3 py-2">
<Tool size={18} />
<span>Maintenance</span>
</Link>
</li>
<li className="w-full">
<Link href="/dashboard/settings" className="flex items-center w-full justify-start px-3 py-2">
<Settings size={18} />
<span>Settings</span>
</Link>
</li>
</ul>
</div>
{/* User profile fixed at bottom */}
<div className="p-4 border-t border-base-300 absolute bottom-0 left-0 w-full bg-base-200">
<div className="relative">
<button
onClick={() => setIsProfileOpen(!isProfileOpen)}
className="flex items-center gap-3 w-full p-2 rounded-lg hover:bg-base-300 transition-colors"
>
<div className="flex items-center justify-center w-10 h-10 rounded-full bg-primary text-primary-content">
<span className="inline-flex items-center justify-center" style={{ lineHeight: 1 }}>
{initials}
</span>
</div>
<div className="flex-1 text-left">
<p className="font-medium">{username}</p>
<p className="text-sm opacity-70">{fullName}</p>
</div>
<ChevronDown size={16} className={`transition-transform ${isProfileOpen ? "rotate-180" : ""}`} />
</button>
{isProfileOpen && (
<div className="absolute bottom-full mb-2 left-0 w-full bg-base-100 rounded-lg shadow-lg border border-base-300 overflow-hidden">
<ul className="menu p-0 w-full">
<li className="w-full">
<button
onClick={() => logout()}
className="flex items-center text-error w-full rounded-none px-4 py-3 justify-start"
>
<LogOut size={16} />
<span>Logout</span>
</button>
</li>
</ul>
</div>
)}
</div>
</div>
</aside>
{/* Main content */}
2025-05-17 19:51:32 +02:00
<main className="flex-1 overflow-auto">
<Breadcrumbs breadcrumbPath={breadcrumbPath} />
{children}
</main>
2025-05-17 19:33:52 +02:00
</div>
)
}