Feat: pages Article + navigation blog/article interne
All checks were successful
Deploy / Deploy to Production (push) Successful in 19s
All checks were successful
Deploy / Deploy to Production (push) Successful in 19s
- Router: findSlideIndex() avec fallback parent path (/blog/slug → /blog) pour sub-pages - article.json.php: réécriture — date, intro, cover, body (blocks→HTML), related articles (fallback siblings si vide) - Article.svelte: sous-composant — topbar date+retour, titre Terminal, intro, cover, body rich text (styles :global pour blocks Kirby), related articles grid, responsive - Blog.svelte: gère deux modes (liste + article) — intercepte les clics article via stopPropagation (avant le router), fetch article data, pushState pour URL, popstate pour back/forward, direct navigation /blog/slug sur mount Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3ab4b21e8c
commit
0505cc7b8e
4 changed files with 465 additions and 97 deletions
|
|
@ -8,16 +8,39 @@ 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) {
|
||||
const idx = slides.getIndexByPath(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(/\/[^/]+$/, "");
|
||||
idx = slides.getIndexByPath(parentPath);
|
||||
if (idx !== -1) slidePath = parentPath;
|
||||
}
|
||||
|
||||
if (idx !== -1) {
|
||||
const slide = slides.all[idx];
|
||||
if (slide.loaded || slide.loading) return;
|
||||
slides.setLoading(path, true);
|
||||
slides.setLoading(slidePath, true);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${path}.json`);
|
||||
// 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();
|
||||
|
||||
|
|
@ -28,10 +51,10 @@ async function loadSlide(path) {
|
|||
siteInitialized = true;
|
||||
}
|
||||
|
||||
slides.setData(path, data);
|
||||
slides.setData(slidePath, data);
|
||||
} catch (error) {
|
||||
console.error(`[router] Failed to load slide ${path}:`, error);
|
||||
slides.setLoading(path, false);
|
||||
console.error(`[router] Failed to load slide ${slidePath}:`, error);
|
||||
slides.setLoading(slidePath, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -48,15 +71,17 @@ export function slideTo(path, { skipHistory = false } = {}) {
|
|||
history.pushState({}, "", path === "/home" ? "/" : path);
|
||||
}
|
||||
|
||||
const idx = slides.getIndexByPath(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(path);
|
||||
slides.slideTo(slidePath);
|
||||
|
||||
if (idx !== -1 && !slides.all[idx].loaded) {
|
||||
loadSlide(path);
|
||||
loadSlide(slidePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,12 +90,14 @@ export async function initRouter() {
|
|||
|
||||
await loadSlide(initialPath);
|
||||
|
||||
const idx = slides.getIndexByPath(initialPath);
|
||||
const idx = findSlideIndex(initialPath);
|
||||
if (idx !== -1) {
|
||||
slides.setActiveIndex(idx);
|
||||
}
|
||||
|
||||
loadAllSlidesInBackground(initialPath);
|
||||
loadAllSlidesInBackground(
|
||||
idx !== -1 ? slides.all[idx].path : initialPath
|
||||
);
|
||||
|
||||
window.addEventListener("popstate", () => {
|
||||
const path = normalizePath(window.location.pathname);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue