98 lines
3.9 KiB
JavaScript
98 lines
3.9 KiB
JavaScript
import { h, render, Link, hComp, ToastContainer, connect, requestUpdate, reactive } from '/static/hoover/index.js?v=4';
|
|
|
|
import DashboardPage from '/static/pages/dashboard.js?v=4';
|
|
import InterfacesPage from '/static/pages/interfaces.js?v=4';
|
|
import ZonesPage from '/static/pages/zones.js?v=4';
|
|
import RulesPage from '/static/pages/rules.js?v=4';
|
|
import NatPage from '/static/pages/nat.js?v=4';
|
|
import DhcpPage from '/static/pages/dhcp.js?v=4';
|
|
import ProxyPage from '/static/pages/proxy.js?v=4';
|
|
import CertsPage from '/static/pages/certs.js?v=4';
|
|
import WireguardPage from '/static/pages/wireguard.js?v=4';
|
|
import LogsPage from '/static/pages/logs.js?v=4';
|
|
import NotFoundPage from '/static/pages/notfound.js?v=4';
|
|
|
|
/* ── Navigation items ──────────────────────────────────────── */
|
|
const Nav = [
|
|
{ path: '/dashboard', label: 'Dashboard' },
|
|
{ path: '/interfaces', label: 'Interfaces' },
|
|
{ path: '/zones', label: 'Zones' },
|
|
{ path: '/rules', label: 'Rules' },
|
|
{ path: '/nat', label: 'NAT' },
|
|
{ path: '/dhcp', label: 'DHCP' },
|
|
{ path: '/proxy', label: 'Proxy' },
|
|
{ path: '/certs', label: 'Certs' },
|
|
{ path: '/wireguard', label: 'WireGuard' },
|
|
{ path: '/logs', label: 'Logs' },
|
|
];
|
|
|
|
/* ── Page map ──────────────────────────────────────────────── */
|
|
const Pages = {
|
|
dashboard: DashboardPage,
|
|
interfaces: InterfacesPage,
|
|
zones: ZonesPage,
|
|
rules: RulesPage,
|
|
nat: NatPage,
|
|
dhcp: DhcpPage,
|
|
proxy: ProxyPage,
|
|
certs: CertsPage,
|
|
wireguard: WireguardPage,
|
|
logs: LogsPage,
|
|
};
|
|
|
|
/* ── Router ────────────────────────────────────────────────── */
|
|
const router = {
|
|
state: reactive({ path: location.hash.slice(1) || '/dashboard' }),
|
|
component() {
|
|
const name = this.state.path.replace(/^\//, '');
|
|
const page = Pages[name] || NotFoundPage;
|
|
return hComp(page, this.state.path);
|
|
},
|
|
};
|
|
|
|
window.location.hash || (window.location.hash = router.state.path);
|
|
window.addEventListener('hashchange', () => {
|
|
router.state.path = location.hash.slice(1) || '/dashboard';
|
|
});
|
|
|
|
/* ── Sidebar render root ───────────────────────────────────── */
|
|
function Sidebar() {
|
|
const current = router.state.path;
|
|
return h('div', { class: 'sidebar' },
|
|
h('div', { class: 'logo' }, 'Vacuum Wall'),
|
|
h('nav', null,
|
|
Nav.map(item =>
|
|
Link({
|
|
path: item.path,
|
|
class: current === item.path ? 'active' : '',
|
|
children: [item.label],
|
|
}),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
/* ── Main content render root ──────────────────────────────── */
|
|
function MainContent() {
|
|
return [
|
|
router.component(),
|
|
ToastContainer(),
|
|
];
|
|
}
|
|
|
|
/* ── Init ──────────────────────────────────────────────────── */
|
|
export function initApp() {
|
|
const sidebarEl = document.getElementById('sidebar');
|
|
const mainEl = document.getElementById('main');
|
|
if (sidebarEl && mainEl) {
|
|
render(sidebarEl, Sidebar);
|
|
render(mainEl, MainContent);
|
|
}
|
|
// Defer connect() after the first render microtask settles to prevent
|
|
// the initial requestUpdate() from triggering a second commit while
|
|
// the vnode tree is still being finalized.
|
|
setTimeout(connect, 0);
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', initApp);
|