rebase www template

This commit is contained in:
2026-04-27 11:45:33 +02:00
parent 07bc5ffd9f
commit a42f1b87e9
27 changed files with 2574 additions and 4615 deletions
+86
View File
@@ -0,0 +1,86 @@
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 });