thefoldwithin-earth/main.js

102 lines
2.6 KiB
JavaScript
Raw Normal View History

2025-10-16 19:45:05 -05:00
// main.js — client router + markdown renderer for The Fold Within
2025-10-16 17:25:32 -05:00
2025-10-16 18:24:10 -05:00
const state = {
posts: [],
2025-10-16 19:45:05 -05:00
bySlug: new Map(),
2025-10-16 18:24:10 -05:00
};
2025-10-16 17:52:19 -05:00
2025-10-16 19:45:05 -05:00
function $(sel) {
return document.querySelector(sel);
}
2025-10-16 18:24:10 -05:00
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();
2025-10-16 19:45:05 -05:00
state.bySlug = new Map(state.posts.map((p) => [p.slug, p]));
2025-10-16 18:24:10 -05:00
router();
} catch (err) {
2025-10-16 19:45:05 -05:00
$("#posts").innerHTML = `<p class="error">⚠️ ${err.message}</p>`;
2025-10-16 18:24:10 -05:00
}
}
function router() {
const hash = location.hash.replace(/^#/, "");
const parts = hash.split("/").filter(Boolean);
if (parts[0] === "post" && parts[1]) {
renderPost(parts[1]);
} else {
renderIndex();
}
}
2025-10-16 17:25:32 -05:00
2025-10-16 18:24:10 -05:00
function renderIndex() {
const postsContainer = $("#posts");
if (!postsContainer) return;
2025-10-16 19:45:05 -05:00
// Clear any loading message
2025-10-16 18:24:10 -05:00
postsContainer.innerHTML = "";
2025-10-16 17:25:32 -05:00
2025-10-16 19:45:05 -05:00
if (!state.posts.length) {
postsContainer.innerHTML = `<p class="error">⚠️ No posts found.</p>`;
return;
}
state.posts.forEach((post) => {
2025-10-16 17:39:09 -05:00
const article = document.createElement("article");
article.innerHTML = `
<div class="thumb"></div>
<h3>${post.title}</h3>
2025-10-16 18:24:10 -05:00
<p class="date">${new Date(post.date).toLocaleDateString()}</p>
2025-10-16 17:39:09 -05:00
<p>${post.excerpt}</p>
`;
2025-10-16 19:45:05 -05:00
article.addEventListener(
"click",
() => (location.hash = `/post/${post.slug}`)
);
2025-10-16 17:39:09 -05:00
postsContainer.appendChild(article);
});
2025-10-16 18:24:10 -05:00
}
async function renderPost(slug) {
const main = document.querySelector("main");
const meta = state.bySlug.get(slug);
if (!meta) {
main.innerHTML = `<p class="error">⚠️ Post not found.</p>`;
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();
2025-10-16 19:45:05 -05:00
// remove front-matter before rendering
const clean = md.replace(/^---[\s\S]*?---/, "").trim();
const html = marked.parse(clean);
const date = new Date(meta.date).toLocaleDateString();
2025-10-16 18:24:10 -05:00
main.innerHTML = `
<section class="post">
<a href="#/" id="back"> Back to Archive</a>
2025-10-16 19:45:05 -05:00
<div class="markdown">
<h1>${meta.title}</h1>
<p class="date">${date}</p>
<hr/>
${html}
</div>
2025-10-16 18:24:10 -05:00
</section>
`;
2025-10-16 17:39:09 -05:00
2025-10-16 18:24:10 -05:00
$("#back").addEventListener("click", () => (location.hash = "/"));
} catch (err) {
main.innerHTML = `<p class="error">⚠️ ${err.message}</p>`;
2025-10-16 17:25:32 -05:00
}
2025-10-16 18:24:10 -05:00
}