Files
utools/frontend/app/router.js
T
2026-04-27 11:45:33 +02:00

87 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { page as homePage } from './pages/home.js';
import { page as subnetPage } from './pages/subnet.js';
import { page as dnsPage } from './pages/dns.js';
import { page as whoisPage } from './pages/whois.js';
import { page as macPage } from './pages/mac.js';
import { page as asnPage } from './pages/asn.js';
const routes = {
'/': homePage,
'/subnet': subnetPage,
'/dns': dnsPage,
'/whois': whoisPage,
'/mac': macPage,
'/asn': asnPage,
};
const app = document.getElementById('app');
let currentCleanup = null;
function setActiveNav(path) {
document.querySelectorAll('nav a').forEach(a => {
try {
const p = new URL(a.href).pathname;
a.classList.toggle('active-link', p === path);
} catch {}
});
}
async function navigate(path, { push = true, search = '' } = {}) {
const route = routes[path] ?? routes['/'];
// ── leave animation ──────────────────────────────────────────
app.classList.add('page-leaving');
if (currentCleanup) { try { currentCleanup(); } catch {} currentCleanup = null; }
await new Promise(r => setTimeout(r, 200));
// ── swap content ─────────────────────────────────────────────
app.innerHTML = route.template();
document.title = route.title ? `${route.title} uTools` : 'uTools Network Suite';
setActiveNav(path);
const fullUrl = path + (search ? (search.startsWith('?') ? search : '?' + search) : '');
if (push) history.pushState({ path }, '', fullUrl);
// ── enter animation ──────────────────────────────────────────
app.classList.remove('page-leaving');
app.classList.add('page-entering');
setTimeout(() => app.classList.remove('page-entering'), 300);
// ── init page ────────────────────────────────────────────────
const cleanup = await route.init(search);
currentCleanup = typeof cleanup === 'function' ? cleanup : null;
}
// ── Intercept same-origin link clicks ───────────────────────────
document.addEventListener('click', e => {
const a = e.target.closest('a[href]');
if (!a) return;
let url;
try { url = new URL(a.href); } catch { return; }
if (url.origin !== location.origin) return;
if (!(url.pathname in routes)) return;
e.preventDefault();
navigate(url.pathname, { push: true, search: url.search });
});
window.addEventListener('popstate', () => {
navigate(location.pathname, { push: false, search: location.search });
});
// ── Expose for programmatic navigation ──────────────────────────
window._router = {
navigate(path, searchObj = {}) {
const s = new URLSearchParams(searchObj).toString();
navigate(path, { push: true, search: s ? '?' + s : '' });
}
};
// ── Fetch version once ───────────────────────────────────────────
fetch('/api/version')
.then(r => r.json())
.then(d => { const el = document.getElementById('commit-sha'); if (el) el.textContent = d.commitSha || 'unknown'; })
.catch(() => { const el = document.getElementById('commit-sha'); if (el) el.textContent = 'error'; });
// ── Initial render ───────────────────────────────────────────────
navigate(location.pathname, { push: false, search: location.search });