8c12e1c73d
- Neue Seite /zfs: Pools-Tabelle mit aufklappbaren Zeilen, Tabs File Systems / Snapshots / Status, vdev-Baum im Status-Tab - /datasets und /snapshots gelöscht (Funktionalität konsolidiert) - Header bereinigt: ZFS-Link ersetzt Datasets/Snapshots, navLink-Hilfsfunktion reduziert Redundanz Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
101 lines
3.3 KiB
TypeScript
101 lines
3.3 KiB
TypeScript
"use client"
|
|
|
|
import Link from "next/link"
|
|
import { usePathname, useRouter } from "next/navigation"
|
|
import { Button } from "@/components/ui/button"
|
|
import { HardDrive, Menu, LogOut } from "lucide-react"
|
|
import { useState, useEffect } from "react"
|
|
import { api } from "@/lib/api"
|
|
|
|
export function Header() {
|
|
const pathname = usePathname()
|
|
const router = useRouter()
|
|
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
|
const [zfsAvailable, setZfsAvailable] = useState(false)
|
|
|
|
useEffect(() => {
|
|
const checkZfsAvailability = async () => {
|
|
const status = await api.getSystemStatus()
|
|
setZfsAvailable(status.zfs_available)
|
|
}
|
|
checkZfsAvailability()
|
|
}, [])
|
|
|
|
const handleLogout = async () => {
|
|
await api.logout()
|
|
router.push("/login")
|
|
}
|
|
|
|
const isActive = (path: string) => pathname === path
|
|
|
|
const navLink = (href: string, label: string, mobile = false) => (
|
|
<Link
|
|
href={href}
|
|
className={`${mobile ? "block " : ""}px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
isActive(href)
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
onClick={mobile ? () => setIsMenuOpen(false) : undefined}
|
|
>
|
|
{label}
|
|
</Link>
|
|
)
|
|
|
|
return (
|
|
<header className="sticky top-0 z-50 w-full border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="flex items-center justify-between h-16">
|
|
{/* Logo */}
|
|
<Link href="/" className="flex items-center gap-2 font-bold text-lg">
|
|
<HardDrive className="w-6 h-6" />
|
|
<span>ZMB Webui</span>
|
|
</Link>
|
|
|
|
{/* Desktop Navigation */}
|
|
<nav className="hidden md:flex items-center gap-1">
|
|
{navLink("/", "Dashboard")}
|
|
{zfsAvailable && navLink("/zfs", "ZFS")}
|
|
{navLink("/navigator", "Navigator")}
|
|
{navLink("/shares", "Shares")}
|
|
{navLink("/file-sharing", "File Sharing")}
|
|
{navLink("/identities", "Identities")}
|
|
{navLink("/logs", "Logs")}
|
|
{navLink("/services", "Services")}
|
|
</nav>
|
|
|
|
{/* Logout Button */}
|
|
<div className="flex items-center gap-2">
|
|
<Button variant="ghost" size="sm" onClick={handleLogout}>
|
|
<LogOut className="w-4 h-4 mr-2" />
|
|
<span className="hidden sm:inline">Logout</span>
|
|
</Button>
|
|
|
|
{/* Mobile Menu Button */}
|
|
<button
|
|
className="md:hidden p-2"
|
|
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
|
>
|
|
<Menu className="w-6 h-6" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile Navigation */}
|
|
{isMenuOpen && (
|
|
<nav className="md:hidden pb-4 space-y-1">
|
|
{navLink("/", "Dashboard", true)}
|
|
{zfsAvailable && navLink("/zfs", "ZFS", true)}
|
|
{navLink("/navigator", "Navigator", true)}
|
|
{navLink("/shares", "Shares", true)}
|
|
{navLink("/file-sharing", "File Sharing", true)}
|
|
{navLink("/identities", "Identities", true)}
|
|
{navLink("/logs", "Logs", true)}
|
|
{navLink("/services", "Services", true)}
|
|
</nav>
|
|
)}
|
|
</div>
|
|
</header>
|
|
)
|
|
}
|