ProxMenux/web/components/DocSidebar.tsx

205 lines
7.5 KiB
TypeScript
Raw Normal View History

2025-02-13 23:04:40 +01:00
"use client"
import Link from "next/link"
import { usePathname } from "next/navigation"
2025-02-17 17:23:56 +01:00
import { useState, useEffect } from "react"
import { ChevronDown, ChevronRight, Menu, X } from "lucide-react"
2025-02-13 23:04:40 +01:00
2025-02-16 16:49:04 +01:00
interface SubMenuItem {
title: string
href: string
}
interface MenuItem {
title: string
href?: string
submenu?: SubMenuItem[]
}
2025-04-17 17:45:23 +02:00
export const sidebarItems: MenuItem[] = [
2025-02-13 23:04:40 +01:00
{ title: "Introduction", href: "/docs/introduction" },
{ title: "Installation", href: "/docs/installation" },
2025-02-25 20:40:47 +01:00
{
title: "Post-Install Script",
submenu: [
{ title: "Overview", href: "/docs/post-install" },
{ title: "Basic Settings", href: "/docs/post-install/basic-settings" },
{ title: "System", href: "/docs/post-install/system" },
{ title: "Virtualization", href: "/docs/post-install/virtualization" },
{ title: "Network", href: "/docs/post-install/network" },
{ title: "Storage", href: "/docs/post-install/storage" },
{ title: "Security", href: "/docs/post-install/security" },
{ title: "Customization", href: "/docs/post-install/customization" },
{ title: "Monitoring", href: "/docs/post-install/monitoring" },
{ title: "Performance", href: "/docs/post-install/performance" },
{ title: "Optional", href: "/docs/post-install/optional" },
2025-05-04 21:37:33 +02:00
],
},
{
title: "Help and Info",
submenu: [
{ title: "Overview", href: "/docs/help-info" },
{ title: "Useful System Commands", href: "/docs/help-info/system-commands" },
{ title: "VM and CT Management", href: "/docs/help-info/vm-ct-commands" },
{ title: "Storage and Disks", href: "/docs/help-info/storage-commands" },
{ title: "Network Commands", href: "/docs/help-info/network-commands" },
{ title: "Updates and Packages", href: "/docs/help-info/update-commands" },
{ title: "GPU Passthrough", href: "/docs/help-info/gpu-commands" },
{ title: "ZFS Management", href: "/docs/help-info/zfs-commands" },
{ title: "Backup and Restore", href: "/docs/help-info/backup-commands" },
{ title: "System CLI Tools", href: "/docs/help-info/tools-commands" },
2025-02-25 20:40:47 +01:00
],
},
2025-02-16 16:49:04 +01:00
{
2025-02-17 17:12:58 +01:00
title: "GPUs and Coral",
2025-02-16 16:49:04 +01:00
submenu: [
{ title: "HW iGPU acceleration to an LXC", href: "/docs/hardware/igpu-acceleration-lxc" },
{ title: "Coral TPU to an LXC", href: "/docs/hardware/coral-tpu-lxc" },
{ title: "Install Coral TPU on the Host", href: "/docs/hardware/install-coral-tpu-host" },
],
},
2025-03-23 19:07:02 +01:00
{
title: "Create VM",
submenu: [
2025-05-18 18:12:23 +02:00
{ title: "Overview", href: "/docs/create-vm" },
{ title: "System NAS", href: "/docs/create-vm/system-nas" },
2025-03-23 19:12:02 +01:00
{ title: "Synology VM", href: "/docs/create-vm/synology" },
2025-05-18 18:12:23 +02:00
{ title: "Others System NAS", href: "/docs/create-vm/system-nas/system-nas-others" },
{ title: "System Windows", href: "/docs/create-vm/system-windows" },
{ title: "UUP Dump ISO Creator", href: "/docs/utils/UUp-Dump-ISO-Creator" },
{ title: "System Linux", href: "/docs/create-vm/system-linux" },
2025-03-23 19:07:02 +01:00
],
},
2025-02-16 16:49:04 +01:00
{
2025-02-17 17:12:58 +01:00
title: "Storage",
2025-02-16 16:49:04 +01:00
submenu: [
{ title: "Disk Passthrough to a VM", href: "/docs/storage/disk-passthrough-vm" },
2025-04-15 20:04:45 +02:00
{ title: "Disk Passthrough to a CT", href: "/docs/storage/disk-passthrough-ct" },
2025-02-16 16:49:04 +01:00
{ title: "Import Disk Image to a VM", href: "/docs/storage/import-disk-image-vm" },
],
},
2025-02-16 17:18:47 +01:00
{
title: "Network",
submenu: [
{ title: "Repair Network", href: "/docs/network/repair-network" },
{ title: "Verify Network", href: "/docs/network/verify-network" },
{ title: "Show IP Information", href: "/docs/network/show-ip-information" },
],
},
{
title: "Settings ProxMenux",
submenu: [
{ title: "Change Language", href: "/docs/settings/change-language" },
{ title: "Show Version Information", href: "/docs/settings/show-version-information" },
{ title: "Uninstall ProxMenux", href: "/docs/settings/uninstall-proxmenux" },
],
},
2025-03-07 17:07:21 +01:00
{
title: "About",
submenu: [
{ title: "Code of Conduct", href: "/docs/about/code-of-conduct" },
2025-03-23 19:07:02 +01:00
{ title: "FAQ", href: "/docs/about/faq" },
{ title: "Contributors", href: "/docs/about/contributors" },
2025-03-07 17:07:21 +01:00
],
},
{ title: "External Repositories", href: "/docs/external-repositories" },
2025-02-13 23:04:40 +01:00
]
export default function DocSidebar() {
const pathname = usePathname()
2025-02-16 16:49:04 +01:00
const [openSections, setOpenSections] = useState<{ [key: string]: boolean }>({})
2025-02-17 17:23:56 +01:00
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
2025-02-16 16:49:04 +01:00
const toggleSection = (title: string) => {
setOpenSections((prev) => ({ ...prev, [title]: !prev[title] }))
}
2025-02-17 17:23:56 +01:00
const toggleMobileMenu = () => {
setIsMobileMenuOpen(!isMobileMenuOpen)
}
useEffect(() => {
const handleResize = () => {
2025-02-18 12:16:57 +01:00
if (window.innerWidth >= 768) {
2025-02-17 17:23:56 +01:00
setIsMobileMenuOpen(false)
}
}
window.addEventListener("resize", handleResize)
return () => window.removeEventListener("resize", handleResize)
}, [])
2025-02-16 16:49:04 +01:00
const renderMenuItem = (item: MenuItem) => {
if (item.submenu) {
const isOpen = openSections[item.title] || false
return (
<li key={item.title} className="mb-2">
<button
onClick={() => toggleSection(item.title)}
className="flex items-center justify-between w-full text-left p-2 rounded hover:bg-gray-200"
>
<span>{item.title}</span>
{isOpen ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
</button>
{isOpen && (
<ul className="ml-4 mt-2 space-y-2">
{item.submenu.map((subItem) => (
<li key={subItem.href}>
<Link
href={subItem.href}
className={`block p-2 rounded ${
pathname === subItem.href
? "bg-blue-500 text-white"
: "text-gray-700 hover:bg-gray-200 hover:text-gray-900"
}`}
2025-02-17 17:23:56 +01:00
onClick={() => setIsMobileMenuOpen(false)}
2025-02-16 16:49:04 +01:00
>
{subItem.title}
</Link>
</li>
))}
</ul>
)}
</li>
)
} else {
return (
<li key={item.href}>
<Link
href={item.href!}
className={`block p-2 rounded ${
pathname === item.href ? "bg-blue-500 text-white" : "text-gray-700 hover:bg-gray-200 hover:text-gray-900"
}`}
2025-02-17 17:23:56 +01:00
onClick={() => setIsMobileMenuOpen(false)}
2025-02-16 16:49:04 +01:00
>
{item.title}
</Link>
</li>
)
}
}
2025-02-13 23:04:40 +01:00
2025-02-18 13:04:41 +01:00
return (
<>
<div className="lg:hidden fixed top-16 left-0 right-0 z-50 bg-gray-100 border-b border-gray-200">
<button
className="w-full p-4 text-left flex items-center justify-between"
onClick={toggleMobileMenu}
aria-label="Toggle menu"
>
<span className="font-semibold">Documentation</span>
{isMobileMenuOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />}
</button>
</div>
<nav
2025-03-23 19:07:02 +01:00
className={`fixed lg:static top-[104px] left-0 w-full lg:w-72 h-[calc(100vh-104px)] lg:h-[calc(100vh-64px)] bg-gray-100 p-4 lg:p-6 pt-16 lg:pt-6 transform ${
2025-02-18 13:04:41 +01:00
isMobileMenuOpen ? "translate-y-0" : "-translate-y-full"
} lg:translate-y-0 transition-transform duration-300 ease-in-out overflow-y-auto z-30`}
2025-02-17 17:23:56 +01:00
>
2025-02-18 13:04:41 +01:00
<h2 className="text-lg font-semibold mb-4 text-gray-900 lg:mt-0 sr-only lg:not-sr-only">Documentation</h2>
<ul className="space-y-2">{sidebarItems.map(renderMenuItem)}</ul>
</nav>
</>
)
2025-02-18 11:59:05 +01:00
}