Update app.js

This commit is contained in:
Mark Randall Havens △ The Empathic Technologist ⟁ Doctor Who 42 2025-11-08 12:32:47 -06:00 committed by GitHub
parent 8db7aa84d1
commit bafd4f29af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,5 +1,5 @@
/* ============================================================ /* ============================================================
Self-Organizing Static Site Framework v2.3.2 Self-Organizing Static Site Framework v2.3.3
============================================================ */ ============================================================ */
let INDEX, CURRENT_PATH = null, PATH_TO_EL = new Map(); let INDEX, CURRENT_PATH = null, PATH_TO_EL = new Map();
@ -17,12 +17,30 @@ const sidebar = document.querySelector(".sidebar");
const navToggle = document.getElementById("navToggle"); const navToggle = document.getElementById("navToggle");
const overlay = document.querySelector(".overlay"); const overlay = document.querySelector(".overlay");
/* --- Navigation toggle --- */ /* ------------------------------------------------------------
Utility: ensure external libs are ready before running
------------------------------------------------------------- */
async function ensureLibsReady() {
let tries = 0;
while ((!window.marked || !window.DOMPurify) && tries < 40) {
await new Promise(r => setTimeout(r, 100));
tries++;
}
if (!window.marked) console.warn("⚠️ marked.js not detected — markdown will show as plain text.");
if (!window.DOMPurify) console.warn("⚠️ DOMPurify not detected — HTML not sanitized.");
}
/* ------------------------------------------------------------
Sidebar toggle and overlay
------------------------------------------------------------- */
navToggle.addEventListener("click", () => sidebar.classList.toggle("open")); navToggle.addEventListener("click", () => sidebar.classList.toggle("open"));
overlay.addEventListener("click", () => sidebar.classList.remove("open")); overlay.addEventListener("click", () => sidebar.classList.remove("open"));
/* --- Index load --- */ /* ------------------------------------------------------------
Load and render index.json
------------------------------------------------------------- */
async function loadIndex() { async function loadIndex() {
await ensureLibsReady();
const res = await fetch("/index.json", { cache: "no-store" }); const res = await fetch("/index.json", { cache: "no-store" });
INDEX = await res.json(); INDEX = await res.json();
populateFilters(); populateFilters();
@ -49,7 +67,9 @@ function populateFilters() {
} }
} }
/* --- Tree build --- */ /* ------------------------------------------------------------
Build directory tree
------------------------------------------------------------- */
function rebuildTree() { function rebuildTree() {
treeEl.innerHTML = ""; treeEl.innerHTML = "";
PATH_TO_EL.clear(); PATH_TO_EL.clear();
@ -111,7 +131,9 @@ function renderNode(n) {
function iconForExt(ext){return ext===".md"?"📝":"🧩";} function iconForExt(ext){return ext===".md"?"📝":"🧩";}
function fmtDate(ms){return new Date(ms).toISOString().slice(0,10);} function fmtDate(ms){return new Date(ms).toISOString().slice(0,10);}
/* --- Path openers --- */ /* ------------------------------------------------------------
Path navigation
------------------------------------------------------------- */
function findDir(p){ function findDir(p){
p=p.replace(/\/$/,''); p=p.replace(/\/$/,'');
function search(n){ function search(n){
@ -145,7 +167,9 @@ async function openPath(path){
if(window.innerWidth<900) sidebar.classList.remove("open"); if(window.innerWidth<900) sidebar.classList.remove("open");
} }
/* --- Markdown renderer (v2.3.2 fix) --- */ /* ------------------------------------------------------------
Markdown rendering (stable version)
------------------------------------------------------------- */
async function renderMarkdown(path){ async function renderMarkdown(path){
mdView.innerHTML="<p style='color:var(--muted);font-style:italic;'>Loading…</p>"; mdView.innerHTML="<p style='color:var(--muted);font-style:italic;'>Loading…</p>";
htmlView.style.display="none"; htmlView.style.display="none";
@ -164,6 +188,7 @@ async function renderMarkdown(path){
requestAnimationFrame(()=>{ requestAnimationFrame(()=>{
mdView.innerHTML=safe; mdView.innerHTML=safe;
mdView.scrollTop=0; // reset scroll to top
mdView.classList.add("fade-in"); mdView.classList.add("fade-in");
mdView.style.display="block"; mdView.style.display="block";
}); });
@ -174,14 +199,18 @@ async function renderMarkdown(path){
} }
} }
/* --- HTML viewer --- */ /* ------------------------------------------------------------
HTML rendering
------------------------------------------------------------- */
function renderHTML(path){ function renderHTML(path){
htmlView.src="/"+path; htmlView.src="/"+path;
htmlView.style.display="block"; htmlView.style.display="block";
mdView.style.display="none"; mdView.style.display="none";
} }
/* --- Active / Pager --- */ /* ------------------------------------------------------------
Active state + pager
------------------------------------------------------------- */
function setActive(path){ function setActive(path){
document.querySelectorAll(".file.active").forEach(el=>el.classList.remove("active")); document.querySelectorAll(".file.active").forEach(el=>el.classList.remove("active"));
const el=PATH_TO_EL.get(path); const el=PATH_TO_EL.get(path);
@ -212,7 +241,9 @@ function updatePager(){
nextBtn.onclick=()=>i<list.length-1&&openPath(list[i+1].path); nextBtn.onclick=()=>i<list.length-1&&openPath(list[i+1].path);
} }
/* --- Search / Filter / Sort --- */ /* ------------------------------------------------------------
Search / filter / sort
------------------------------------------------------------- */
let searchTimer; let searchTimer;
searchBox.addEventListener("input",()=>{ searchBox.addEventListener("input",()=>{
clearTimeout(searchTimer); clearTimeout(searchTimer);
@ -221,7 +252,9 @@ searchBox.addEventListener("input",()=>{
sortSel.addEventListener("change",rebuildTree); sortSel.addEventListener("change",rebuildTree);
filterSel.addEventListener("change",rebuildTree); filterSel.addEventListener("change",rebuildTree);
/* --- Internal link interception --- */ /* ------------------------------------------------------------
Internal link interception
------------------------------------------------------------- */
document.body.addEventListener("click",e=>{ document.body.addEventListener("click",e=>{
const a=e.target.closest("a[href]"); const a=e.target.closest("a[href]");
if(!a) return; if(!a) return;