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; } /** * Trouve l'index de la slide correspondant au path. * Si le path exact n'existe pas, essaie le chemin parent * (ex: /blog/article-slug → /blog). */ function findSlideIndex(path) { let idx = slides.getIndexByPath(path); if (idx !== -1) return idx; const parentPath = path.replace(/\/[^/]+$/, ""); if (parentPath) return slides.getIndexByPath(parentPath); return -1; } async function loadSlide(path) { let slidePath = path; let idx = slides.getIndexByPath(slidePath); // Sub-page: resolve to parent slide (ex: /blog/slug → /blog) if (idx === -1) { const parentPath = path.replace(/\/[^/]+$/, ""); if (parentPath && parentPath !== path) { const parentIdx = slides.getIndexByPath(parentPath); if (parentIdx !== -1) { idx = parentIdx; slidePath = parentPath; } else if (!siteInitialized) { // Slides not yet initialized — assume sub-page, fetch parent to bootstrap slidePath = parentPath; } } } if (idx !== -1) { const slide = slides.all[idx]; if (slide.loaded || slide.loading) return; slides.setLoading(slidePath, true); } try { // Fetch the actual slide path (parent), not the sub-page const response = await fetch(`${slidePath}.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(slidePath, data); } catch (error) { console.error(`[router] Failed to load slide ${slidePath}:`, error); slides.setLoading(slidePath, 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 = findSlideIndex(path); const slidePath = idx !== -1 ? slides.all[idx].path : path; if (idx !== -1 && slides.all[idx].title) { document.title = `${slides.all[idx].title} — World Game`; } slides.slideTo(slidePath); if (idx !== -1 && !slides.all[idx].loaded) { loadSlide(slidePath); } } export async function initRouter() { const initialPath = normalizePath(window.location.pathname); await loadSlide(initialPath); const idx = findSlideIndex(initialPath); if (idx !== -1) { slides.setActiveIndex(idx); } loadAllSlidesInBackground( idx !== -1 ? slides.all[idx].path : 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;