world-game/src/router/index.js

98 lines
2.4 KiB
JavaScript
Raw Normal View History

import { slides } from "@state/slides.svelte";
import { site } from "@state/site.svelte";
import { locale } from "@state/locale.svelte";
let siteInitialized = false;
function normalizePath(path) {
return path === "/" ? "/home" : path;
}
async function loadSlide(path) {
const idx = slides.getIndexByPath(path);
if (idx !== -1) {
const slide = slides.all[idx];
if (slide.loaded || slide.loading) return;
slides.setLoading(path, true);
}
try {
const response = await fetch(`${path}.json`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
if (!siteInitialized && data.site) {
site.set(data.site);
locale.initialize(data.site.language, data.site.languages);
slides.init(data.site.navigation);
siteInitialized = true;
}
slides.setData(path, data);
} catch (error) {
console.error(`[router] Failed to load slide ${path}:`, error);
slides.setLoading(path, false);
}
}
function loadAllSlidesInBackground(exceptPath) {
slides.all
.filter((s) => s.path !== exceptPath)
.forEach((s) => loadSlide(s.path));
}
export function slideTo(path, { skipHistory = false } = {}) {
path = normalizePath(path);
if (!skipHistory) {
history.pushState({}, "", path === "/home" ? "/" : path);
}
const idx = slides.getIndexByPath(path);
if (idx !== -1 && slides.all[idx].title) {
document.title = `${slides.all[idx].title} — World Game`;
}
slides.slideTo(path);
if (idx !== -1 && !slides.all[idx].loaded) {
loadSlide(path);
}
}
export async function initRouter() {
const initialPath = normalizePath(window.location.pathname);
await loadSlide(initialPath);
const idx = slides.getIndexByPath(initialPath);
if (idx !== -1) {
slides.setActiveIndex(idx);
}
loadAllSlidesInBackground(initialPath);
window.addEventListener("popstate", () => {
const path = normalizePath(window.location.pathname);
slideTo(path, { skipHistory: true });
});
document.addEventListener("click", (e) => {
const link = e.target.closest("a");
if (!link) return;
const url = new URL(link.href, window.location.origin);
if (
url.origin === window.location.origin &&
!link.target &&
!link.hasAttribute("download")
) {
e.preventDefault();
slideTo(url.pathname);
}
});
}
// Keep navigateTo as alias so existing views don't break
export const navigateTo = slideTo;