// main.js — client router + markdown renderer // Routes: // #/ -> index // #/post/:id -> render that post const state = { posts: [], bySlug: new Map() }; function $(sel) { return document.querySelector(sel); } window.addEventListener("hashchange", router); document.addEventListener("DOMContentLoaded", init); async function init() { try { const res = await fetch("posts/posts.json", { cache: "no-cache" }); if (!res.ok) throw new Error("Could not load posts index."); state.posts = await res.json(); state.bySlug = new Map(state.posts.map(p => [p.slug, p])); // render index initially, or route if hash present router(); } catch (err) { const container = $("#posts"); if (container) container.innerHTML = `

⚠️ ${err.message}

`; } } function router() { const hash = location.hash.replace(/^#/, ""); const parts = hash.split("/").filter(Boolean); if (parts[0] === "post" && parts[1]) { renderPost(parts[1]); } else { renderIndex(); } } function renderIndex() { const postsContainer = $("#posts"); if (!postsContainer) return; postsContainer.innerHTML = ""; state.posts.forEach(post => { const article = document.createElement("article"); article.innerHTML = `

${post.title}

${new Date(post.date).toLocaleDateString()}

${post.excerpt}

`; article.addEventListener("click", () => { location.hash = `/post/${post.slug}`; }); postsContainer.appendChild(article); }); } async function renderPost(slug) { const main = document.querySelector("main"); const meta = state.bySlug.get(slug); if (!meta) { main.innerHTML = `

⚠️ Post not found.

`; return; } try { const res = await fetch(`posts/${meta.file}`, { cache: "no-cache" }); if (!res.ok) throw new Error("Post file missing."); const md = await res.text(); const html = marked.parse(md); main.innerHTML = `
← Back to Archive
${html}
`; $("#back").addEventListener("click", () => (location.hash = "/")); } catch (err) { main.innerHTML = `

⚠️ ${err.message}

`; } }