thefoldwithin-earth/public/app.js

105 lines
3.4 KiB
JavaScript
Raw Normal View History

2025-11-08 14:39:26 -06:00
const els = {
body: document.body,
2025-11-08 15:26:01 -06:00
menuBtn: document.getElementById("menuBtn"),
sectionSelect: document.getElementById("sectionSelect"),
sortSelect: document.getElementById("sortSelect"),
searchBox: document.getElementById("searchBox"),
postList: document.getElementById("postList"),
viewer: document.getElementById("viewer"),
content: document.getElementById("content")
2025-11-08 14:55:16 -06:00
};
2025-11-08 15:26:01 -06:00
let indexData = null;
let state = { section: "posts", sort: "newest", query: "", sidebarOpen: false };
2025-11-08 14:39:26 -06:00
async function init(){
2025-11-08 15:26:01 -06:00
indexData = await (await fetch("index.json")).json();
populateSections();
wireUI();
renderList();
handleHash();
window.addEventListener("hashchange", handleHash);
2025-11-08 14:55:16 -06:00
}
2025-11-08 15:26:01 -06:00
function populateSections(){
els.sectionSelect.innerHTML = "";
indexData.sections.forEach(s=>{
const opt = document.createElement("option");
opt.value = s; opt.textContent = s;
els.sectionSelect.appendChild(opt);
2025-11-08 14:39:26 -06:00
});
}
2025-11-08 14:17:27 -06:00
2025-11-08 15:26:01 -06:00
function wireUI(){
els.menuBtn.addEventListener("click", ()=>{
state.sidebarOpen = !state.sidebarOpen;
document.body.classList.toggle("sidebar-open", state.sidebarOpen);
2025-11-08 14:39:26 -06:00
});
2025-11-08 15:26:01 -06:00
els.sectionSelect.addEventListener("change", ()=>renderList());
els.sortSelect.addEventListener("change", ()=>renderList());
els.searchBox.addEventListener("input", ()=>renderList());
els.content.addEventListener("click", ()=>{
if (window.matchMedia("(max-width:1024px)").matches && document.body.classList.contains("sidebar-open")){
document.body.classList.remove("sidebar-open");
2025-11-08 14:39:26 -06:00
state.sidebarOpen = false;
2025-11-08 12:12:47 -06:00
}
2025-11-08 15:26:01 -06:00
});
2025-11-08 14:39:26 -06:00
}
2025-11-08 14:17:27 -06:00
2025-11-08 15:26:01 -06:00
function renderList(){
const section = els.sectionSelect.value;
const sort = els.sortSelect.value;
const query = els.searchBox.value.toLowerCase();
2025-11-08 12:59:27 -06:00
2025-11-08 15:26:01 -06:00
let posts = indexData.flat.filter(p=>p.path.startsWith(section));
if (query) posts = posts.filter(p=>p.title.toLowerCase().includes(query));
posts.sort((a,b)=> sort==="newest"? b.mtime-a.mtime : a.mtime-b.mtime);
2025-11-08 14:55:16 -06:00
2025-11-08 15:26:01 -06:00
els.postList.innerHTML = "";
for (const p of posts){
const li = document.createElement("li");
li.innerHTML = `<a href="#/${p.path}">${p.title}</a><br><small>${new Date(p.mtime).toISOString().split("T")[0]}</small>`;
els.postList.appendChild(li);
2025-11-08 14:17:27 -06:00
}
2025-11-08 15:26:01 -06:00
}
2025-11-08 13:06:29 -06:00
2025-11-08 15:26:01 -06:00
async function handleHash(){
const rel = location.hash.replace(/^#\//,"");
if (!rel) return renderDefault();
const file = indexData.flat.find(f=>f.path===rel);
if (!file) return;
file.ext===".md"? await renderMarkdown(file.path) : renderHTML(file.path);
2025-11-08 14:39:26 -06:00
}
2025-11-08 14:55:16 -06:00
async function renderMarkdown(rel){
2025-11-08 15:26:01 -06:00
const src = await fetch(rel).then(r=>r.text());
const html = marked.parse(src);
els.viewer.innerHTML = `<article>${html}</article>`;
2025-11-08 14:39:26 -06:00
}
2025-11-08 15:26:01 -06:00
function renderHTML(rel){
2025-11-08 14:39:26 -06:00
const iframe = document.createElement("iframe");
2025-11-08 14:55:16 -06:00
iframe.setAttribute("sandbox","allow-same-origin allow-scripts allow-forms");
2025-11-08 14:39:26 -06:00
iframe.loading = "eager";
2025-11-08 15:26:01 -06:00
iframe.src = "/" + rel;
2025-11-08 14:39:26 -06:00
els.viewer.innerHTML = "";
els.viewer.appendChild(iframe);
2025-11-08 14:55:16 -06:00
iframe.addEventListener("load", ()=>{
try{
2025-11-08 15:06:28 -06:00
const d = iframe.contentDocument || iframe.contentWindow.document;
const s = d.createElement("style");
s.textContent = `
2025-11-08 15:26:01 -06:00
html,body{margin:0;padding:0;background:transparent;color:#e6e3d7;font:16px/1.6 Inter,ui-sans-serif;}
main,article,section{max-width:720px;margin:auto;padding:2rem;}
2025-11-08 15:06:28 -06:00
`;
d.head.appendChild(s);
2025-11-08 14:55:16 -06:00
}catch{}
2025-11-08 14:39:26 -06:00
});
}
2025-11-08 15:26:01 -06:00
function renderDefault(){
const latest = [...indexData.flat].sort((a,b)=>b.mtime-a.mtime)[0];
if (latest) location.hash = "#/" + latest.path;
}
init();