// Minimal dependency-free hash router. Hash routing survives a reload and works on // a file:// origin (Capacitor native packaging), where there is no server to honour // deep paths. The route is a reactive rune so screens re-render on navigation. The pure // hash->Route parsing lives in routeparse.ts (unit-tested without a DOM). import { parse, type Route, type RouteName } from './routeparse'; export type { Route, RouteName }; export const router = $state<{ route: Route }>({ route: parse(typeof location !== 'undefined' ? location.hash : ''), }); if (typeof window !== 'undefined') { window.addEventListener('hashchange', () => { router.route = parse(location.hash); }); } /** navigate switches the hash route (and forces a re-parse if it is unchanged). The route rune is * updated synchronously — not left to the asynchronous `hashchange` — so a caller that renders off * the route in the same tick (notably bootstrap flipping `app.ready` right after `navigate('/login')`) * never sees `router.route` lag the hash for a frame, which would briefly render the previous route * (the empty-hash lobby) under the new screen. The later `hashchange` re-parses to the same value. */ export function navigate(path: string): void { const target = '#' + path; router.route = parse(target); if (location.hash !== target) { location.hash = path; } }