89 lines
3.3 KiB
JavaScript

import { useEffect, useRef } from "react";
import { Moon, Plus, RefreshCcw, Route, Search, Server, Sun } from "lucide-react";
import Button from "./ui/Button";
export default function Header({
query,
onQueryChange,
theme,
onToggleTheme,
onAddServer,
onAddService,
onRefresh,
loading,
searchEnabled = true,
}) {
const searchRef = useRef(null);
useEffect(() => {
function onKey(event) {
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
event.preventDefault();
searchRef.current?.focus();
}
}
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, []);
return (
<header className="sticky top-0 z-40 border-b border-line bg-bg">
<div className="mx-auto flex max-w-7xl flex-wrap items-center gap-3 px-4 py-3.5 sm:px-6 lg:px-8">
<div className="flex items-center gap-3">
<span className="flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-cyan-500 to-indigo-600 text-white shadow-lg shadow-cyan-500/30">
<Route size={20} />
</span>
<div className="leading-tight">
<p className="text-[11px] font-bold uppercase tracking-[0.18em] text-accent">MTC</p>
<h1 className="text-[15px] font-bold text-ink">Reverse Proxy Manager</h1>
</div>
</div>
{searchEnabled && (
<div className="order-last w-full sm:order-none sm:mx-auto sm:max-w-md sm:flex-1">
<div className="group relative">
<Search size={15} className="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-ink-muted" />
<input
ref={searchRef}
value={query}
onChange={(event) => onQueryChange(event.target.value)}
placeholder="Search servers, IPs, endpoints…"
className="input pl-9! pr-14!"
type="search"
/>
<kbd className="mono pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 rounded border border-line bg-surface-2 px-1.5 py-0.5 text-[10px] font-medium text-ink-muted">
Ctrl K
</kbd>
</div>
</div>
)}
<div className="flex items-center gap-2">
<button
aria-label="Toggle theme"
className="rounded-lg border border-line bg-surface-2 p-2 text-ink-soft transition hover:border-line-strong hover:text-ink"
onClick={onToggleTheme}
type="button"
>
{theme === "dark" ? <Sun size={16} /> : <Moon size={16} />}
</button>
<button
aria-label="Refresh"
className="rounded-lg border border-line bg-surface-2 p-2 text-ink-soft transition hover:border-line-strong hover:text-ink"
onClick={onRefresh}
type="button"
>
<RefreshCcw size={16} className={loading ? "animate-spin" : ""} />
</button>
<Button variant="secondary" icon={Plus} onClick={onAddService} className="hidden md:inline-flex">
Service
</Button>
<Button variant="primary" icon={Server} onClick={onAddServer}>
<span className="hidden sm:inline">Add </span>Server
</Button>
</div>
</div>
</header>
);
}