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();
|