Files
TtrpgPlayerPublisher/src/renderer/router.mjs
T
Ivan Fontosh f20c7e2f63 Turn Publisher into multi-page app with license manager v1.1.0.
Hash router with publish, licenses, generate, stats, and settings pages backed by license server admin API.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 00:21:22 +08:00

74 lines
1.7 KiB
JavaScript

/** @typedef {{ path: string; title: string; render: (root: HTMLElement) => void | (() => void) }} Route */
/** @type {Route[]} */
const routes = [];
/** @type {(() => void) | null} */
let cleanup = null;
/** @param {Route} route */
export function registerRoute(route) {
routes.push(route);
}
/** @param {string} hashPath */
export function navigate(hashPath) {
const path = hashPath.startsWith('#') ? hashPath : `#${hashPath}`;
if (location.hash !== path) {
location.hash = path;
} else {
renderCurrent();
}
}
function currentPath() {
const hash = location.hash.replace(/^#/, '') || '/publish';
return hash.startsWith('/') ? hash : `/${hash}`;
}
function findRoute() {
const path = currentPath();
return routes.find((r) => r.path === path) ?? routes.find((r) => r.path === '/publish');
}
function updateNav() {
const path = currentPath();
document.querySelectorAll('.nav a').forEach((a) => {
const href = a.getAttribute('href') ?? '';
a.classList.toggle('active', href === `#${path}`);
});
}
function renderCurrent() {
const route = findRoute();
const root = document.getElementById('page-root');
if (!root || !route) return;
if (cleanup) {
cleanup();
cleanup = null;
}
root.innerHTML = '';
document.title = `${route.title} — TTRPG Player Publisher`;
updateNav();
const result = route.render(root);
if (typeof result === 'function') {
cleanup = result;
}
}
export function startRouter() {
window.addEventListener('hashchange', renderCurrent);
if (!location.hash) {
location.hash = '#/publish';
} else {
renderCurrent();
}
}
export function getCurrentPath() {
return currentPath();
}