// Basic Markdown renderer
function renderMarkdown(md) {
let html = md
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/^### (.*$)/gim, "
$1
")
.replace(/^## (.*$)/gim, "$1
")
.replace(/^# (.*$)/gim, "$1
")
.replace(/\*\*\*(.*?)\*\*\*/g, "$1")
.replace(/\*\*(.*?)\*\*/g, "$1")
.replace(/\*(.*?)\*/g, "$1")
.replace(/___(.*?)___/g, "$1")
.replace(/__(.*?)__/g, "$1")
.replace(/_(.*?)_/g, "$1")
.replace(/```([\s\S]*?)```/g, "$1
")
.replace(/`([^`]+)`/g, "$1")
.replace(/^> (.*$)/gim, "$1
")
.replace(/^\s*-\s+(.*$)/gim, "$1")
.replace(/^\s*\d+\.\s+(.*$)/gim, "$1")
.replace(
/\[([^\]]+)\]\(([^)]+)\)/g,
'$1',
)
.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '
')
.replace(/^---$/gim, "
")
.replace(/\n/g, "
");
html = html.replace(/(.*?<\/li>(?:
.*?<\/li>)*)/gs, (match) => {
const clean = match.replace(/
/g, "");
return ``;
});
return html;
}
// Parallax for post hero
function initPostParallax() {
const hero = document.getElementById("post-hero");
if (!hero) return;
function update() {
const rect = hero.getBoundingClientRect();
const yPos = -(rect.top * 0.4);
hero.style.backgroundPositionY = `${yPos}px`;
}
window.addEventListener("scroll", update, { passive: true });
update();
}
// Load post hero image from posts.json head_img, fallback to random backdrop
async function loadPostHero(filename) {
try {
// Try to find the post metadata
const response = await fetch("/api/posts.json");
const posts = await response.json();
const post = posts.find((p) => p.file === filename);
const hero = document.getElementById("post-hero");
if (!hero) return;
if (post && post.head_img) {
hero.style.backgroundImage = `url('/assets/${post.head_img}')`;
} else {
// Fallback to random backdrop
const bdResponse = await fetch("/api/backdrops.json");
const backdrops = await response.json();
const random = backdrops[Math.floor(Math.random() * backdrops.length)];
hero.style.backgroundImage = `url('/assets/${random.name}.png')`;
}
initPostParallax();
} catch (err) {
console.error("Failed to load post hero:", err);
}
}
// Load post content
async function loadPostContent() {
const pathParts = window.location.pathname.split("/");
const filename = pathParts[pathParts.length - 1];
if (!filename) return;
loadPostHero(filename);
try {
const response = await fetch(`/api/post/${filename}`);
const md = await response.text();
let contentMd = md;
const titleMatch = md.match(/^#\s+(.+)$/m);
if (titleMatch) {
document.title = `${titleMatch[1]} - Anarchy Phase`;
const titleEl = document.getElementById("post-title");
if (titleEl) titleEl.textContent = titleMatch[1];
contentMd = md.replace(/^#\s+.+$/m, "").trim();
}
const container = document.getElementById("post-body");
if (container) {
container.innerHTML = renderMarkdown(contentMd);
}
} catch (err) {
console.error("Failed to load post:", err);
const container = document.getElementById("post-body");
if (container)
container.innerHTML =
'Failed to load post content.
';
}
}
document.addEventListener("DOMContentLoaded", () => {
loadPostContent();
});