From 8b67b5d7d6a8bc3374e4107a8ee05be8eed74cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mark=20Randall=20Havens=20=E2=96=B3=20The=20Empathic=20Tec?= =?UTF-8?q?hnologist=20=E2=9F=81=20Doctor=20Who=2042?= Date: Sat, 8 Nov 2025 18:10:27 -0600 Subject: [PATCH] Update app.js --- public/app.js | 74 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/public/app.js b/public/app.js index 9266a68..070d741 100755 --- a/public/app.js +++ b/public/app.js @@ -35,18 +35,18 @@ async function init() { function populateNav() { els.primaryNav.innerHTML = 'Home'; - indexData.sections.forEach(s => { - els.primaryNav.innerHTML += `${s.name.charAt(0).toUpperCase() + s.name.slice(1)}`; + indexData.sections.filter(s => indexData.flat.some(f => f.path.split('/')[0] === s && f.isIndex)).forEach(s => { + els.primaryNav.innerHTML += `${s.charAt(0).toUpperCase() + s.slice(1)}`; }); } function populateSections() { els.sectionSelect.innerHTML = ''; - indexData.sections.filter(s => !s.isStatic).forEach(s => { // Only dynamic in drop-down - const icon = sectionIcons[s.name] ? `${sectionIcons[s.name]} ` : ''; + indexData.sections.forEach(s => { + const icon = sectionIcons[s] ? `${sectionIcons[s]} ` : ''; const opt = document.createElement("option"); - opt.value = s.name; - opt.textContent = `${icon}${s.name}`; + opt.value = s; + opt.textContent = `${icon}${s}`; els.sectionSelect.appendChild(opt); }); } @@ -58,7 +58,7 @@ function populateTags() { const opt = document.createElement("option"); opt.value = t; opt.textContent = `${icon}${t}`; - opt.title = `Filter by ${t}`; // Tooltip for elegance + opt.title = `Filter by ${t}`; els.tagSelect.appendChild(opt); }); } @@ -68,7 +68,12 @@ function wireUI() { sidebarOpen = !sidebarOpen; document.body.classList.toggle("sidebar-open", sidebarOpen); }); - [els.sectionSelect, els.tagSelect, els.sortSelect, els.searchMode, els.searchBox].forEach(el => el.addEventListener("change", renderList) || el.addEventListener("input", renderList)); + els.sectionSelect.addEventListener("change", () => { + renderList(); + if (els.sectionSelect.value !== "all") loadDefaultForSection(els.sectionSelect.value); + }); + [els.tagSelect, els.sortSelect, els.searchMode].forEach(el => el.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"); @@ -84,9 +89,9 @@ function renderList() { const mode = els.searchMode.value; const query = els.searchBox.value.toLowerCase(); - let posts = indexData.flat; + let posts = indexData.flat.filter(p => !p.isIndex); // Exclude index from lists if (section !== "all") posts = posts.filter(p => p.path.split('/')[0] === section); - if (tags.length > 0) posts = posts.filter(p => tags.every(t => p.tags.includes(t))); // AND for coherence + if (tags.length > 0) posts = posts.filter(p => tags.every(t => p.tags.includes(t))); if (query) { posts = posts.filter(p => { const searchText = mode === "content" ? (p.title + ' ' + p.excerpt).toLowerCase() : p.title.toLowerCase(); @@ -98,39 +103,54 @@ function renderList() { els.postList.innerHTML = posts.length ? "" : "
  • No matching posts found. Try adjusting filters.
  • "; for (const p of posts) { const li = document.createElement("li"); - const pin = p.pinned ? "★ " : ""; + const pin = p.isPinned ? "★ " : ""; li.innerHTML = `${pin}${p.title}
    ${new Date(p.mtime).toISOString().split("T")[0]}`; els.postList.appendChild(li); } } +function loadDefaultForSection(section) { + const posts = indexData.flat.filter(p => p.path.split('/')[0] === section && !p.isIndex); // Exclude index + if (!posts.length) { + els.viewer.innerHTML = `

    ${section.charAt(0).toUpperCase() + section.slice(1)}

    No content yet. Add files and redeploy!

    `; + return; + } + const pinned = posts.filter(p => p.isPinned).sort((a, b) => b.mtime - a.mtime)[0]; + const toLoad = pinned || posts.sort((a, b) => b.mtime - a.mtime)[0]; + location.hash = '#/' + toLoad.path; +} + async function handleHash() { - els.viewer.classList.remove("fade-in"); // Reset for animation + els.viewer.classList.remove("fade-in"); els.viewer.innerHTML = ""; - void els.viewer.offsetWidth; // Trigger reflow + void els.viewer.offsetWidth; els.viewer.classList.add("fade-in"); const rel = location.hash.replace(/^#\//, ""); if (!rel) return renderDefault(); if (rel.endsWith('/')) { - const sectionName = rel.replace(/\/$/, ''); - const section = indexData.sections.find(s => s.name === sectionName); - if (section) { - if (section.isStatic) { - renderIframe(`${sectionName}/index.html`); - } else { - els.sectionSelect.value = sectionName; - renderList(); - const sectionPosts = indexData.flat.filter(p => p.path.split('/')[0] === sectionName); - if (sectionPosts.length === 0) { - els.viewer.innerHTML = `

    ${sectionName.charAt(0).toUpperCase() + sectionName.slice(1)}

    No content yet. Add files and redeploy!

    `; + const section = rel.replace(/\/$/, ''); + if (!indexData.sections.includes(section)) { + els.viewer.innerHTML = '

    404: Section Not Found

    Try navigating from the menu.

    '; + return; + } + const indexFile = indexData.flat.find(f => f.path.split('/')[0] === section && f.isIndex); + if (indexFile) { + // Load index for top nav + try { + if (indexFile.ext === ".md") { + await renderMarkdown(indexFile.path); } else { - const latest = sectionPosts.sort((a, b) => b.mtime - a.mtime)[0]; - location.hash = '#/' + latest.path; + renderIframe(indexFile.path); } + } catch (e) { + els.viewer.innerHTML = '

    Error Loading Index

    Unable to load section index.

    '; } } else { - els.viewer.innerHTML = '

    404: Section Not Found

    Try navigating from the menu.

    '; + // Dynamic load for drop-down style + els.sectionSelect.value = section; + renderList(); + loadDefaultForSection(section); } } else { const file = indexData.flat.find(f => f.path === rel);