Inital Commit

This commit is contained in:
Alex Emmet 2026-04-21 21:35:28 +02:00
commit a309e824be
29 changed files with 2856 additions and 0 deletions

115
website/md-render.js Normal file
View file

@ -0,0 +1,115 @@
// Basic Markdown renderer
function renderMarkdown(md) {
let html = md
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/^### (.*$)/gim, "<h3>$1</h3>")
.replace(/^## (.*$)/gim, "<h2>$1</h2>")
.replace(/^# (.*$)/gim, "<h1>$1</h1>")
.replace(/\*\*\*(.*?)\*\*\*/g, "<strong><em>$1</em></strong>")
.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
.replace(/\*(.*?)\*/g, "<em>$1</em>")
.replace(/___(.*?)___/g, "<strong><em>$1</em></strong>")
.replace(/__(.*?)__/g, "<strong>$1</strong>")
.replace(/_(.*?)_/g, "<em>$1</em>")
.replace(/```([\s\S]*?)```/g, "<pre><code>$1</code></pre>")
.replace(/`([^`]+)`/g, "<code>$1</code>")
.replace(/^> (.*$)/gim, "<blockquote>$1</blockquote>")
.replace(/^\s*-\s+(.*$)/gim, "<li>$1</li>")
.replace(/^\s*\d+\.\s+(.*$)/gim, "<li>$1</li>")
.replace(
/\[([^\]]+)\]\(([^)]+)\)/g,
'<a href="$2" target="_blank" rel="noopener">$1</a>',
)
.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1">')
.replace(/^---$/gim, "<hr>")
.replace(/\n/g, "<br>");
html = html.replace(/(<li>.*?<\/li>(?:<br><li>.*?<\/li>)*)/gs, (match) => {
const clean = match.replace(/<br>/g, "");
return `<ul>${clean}</ul>`;
});
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 =
'<p style="color:#d48a8a;">Failed to load post content.</p>';
}
}
document.addEventListener("DOMContentLoaded", () => {
loadPostContent();
});