Add monorepo structure for NexaVPN WireGuard control plane including: - .gitignore for node_modules, build artifacts, and environment files - README with project overview, monorepo layout, and quick start guide - Admin web UI with React, Vite, TypeScript, and nginx reverse proxy - API client with type definitions for users, devices, policies, gateways, and audit logs - Admin pages for dashboard, users, devices, policies, g
46 lines
1.1 KiB
TypeScript
46 lines
1.1 KiB
TypeScript
import { NavLink, Outlet } from "react-router-dom";
|
|
|
|
const items = [
|
|
["Dashboard", "/"],
|
|
["Users", "/users"],
|
|
["Devices", "/devices"],
|
|
["Policies", "/policies"],
|
|
["Gateways", "/gateways"],
|
|
["Audit", "/audit"],
|
|
["Settings", "/settings"]
|
|
];
|
|
|
|
export function Layout() {
|
|
return (
|
|
<div className="shell">
|
|
<aside className="sidebar">
|
|
<div>
|
|
<p className="eyebrow">NexaVPN</p>
|
|
<h1>Control Plane</h1>
|
|
</div>
|
|
<nav className="nav">
|
|
{items.map(([label, path]) => (
|
|
<NavLink
|
|
key={path}
|
|
to={path}
|
|
className={({ isActive }) => (isActive ? "nav-link active" : "nav-link")}
|
|
>
|
|
{label}
|
|
</NavLink>
|
|
))}
|
|
</nav>
|
|
</aside>
|
|
<main className="content">
|
|
<header className="topbar">
|
|
<div>
|
|
<p className="eyebrow">Enterprise WireGuard</p>
|
|
<h2>Self-hosted VPN management</h2>
|
|
</div>
|
|
<div className="pill">Secure by design</div>
|
|
</header>
|
|
<Outlet />
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|