Files
AirCardIOS/web/src/pages/router.ts
T
ClaudeandClaude Opus 5.5 05a735993b feat(web): Projektgerüst, Router, Grundlayout
Vite + TypeScript ohne UI-Framework in web/, exakte Versionen, History-Router
(matchRoute, navigate, startRouter mit Cleanup, a[data-link], popstate),
Grundlayout mit Kopfzeile, Fußzeile und Platzhalterseiten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 07:23:01 +00:00

65 lines
2.0 KiB
TypeScript

export type RouteId = 'editor' | 'cards' | 'reset';
type Render = (route: RouteId, root: HTMLElement) => void | (() => void);
export function matchRoute(pathname: string): RouteId {
const path = pathname.replace(/\/+$/, '') || '/';
if (path === '/karten') return 'cards';
if (path === '/passwort-neu') return 'reset';
return 'editor';
}
// Beendet den laufenden Router (Seiten-Cleanup, Listener); null, solange keiner läuft.
let stopCurrent: (() => void) | null = null;
let renderCurrent: (() => void) | null = null;
export function navigate(path: string): void {
const url = new URL(path, location.href);
const target = url.pathname + url.search + url.hash;
if (target !== location.pathname + location.search + location.hash) {
history.pushState(null, '', target);
}
renderCurrent?.();
}
export function startRouter(render: Render): void {
stopCurrent?.();
const root = document.getElementById('app-root');
if (!root) throw new Error('#app-root fehlt');
let cleanup: void | (() => void);
const renderPage = () => {
cleanup?.();
cleanup = undefined;
cleanup = render(matchRoute(location.pathname), root);
};
const onClick = (event: MouseEvent) => {
if (event.defaultPrevented || event.button !== 0) return;
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
const anchor = (event.target as Element | null)?.closest<HTMLAnchorElement>('a[data-link]');
if (!anchor || (anchor.target && anchor.target !== '_self')) return;
const url = new URL(anchor.href, location.href);
if (url.origin !== location.origin) return;
event.preventDefault();
navigate(url.pathname + url.search + url.hash);
};
document.addEventListener('click', onClick);
window.addEventListener('popstate', renderPage);
renderCurrent = renderPage;
stopCurrent = () => {
document.removeEventListener('click', onClick);
window.removeEventListener('popstate', renderPage);
cleanup?.();
cleanup = undefined;
renderCurrent = null;
stopCurrent = null;
};
renderPage();
}