Update app.js

This commit is contained in:
Mark Randall Havens △ The Empathic Technologist ⟁ Doctor Who 42 2025-11-08 15:48:53 -06:00 committed by GitHub
parent a43055f3b8
commit 42af773c98
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,6 +1,7 @@
const els = { const els = {
body: document.body, body: document.body,
menuBtn: document.getElementById("menuBtn"), menuBtn: document.getElementById("menuBtn"),
primaryNav: document.getElementById("primaryNav"),
sectionSelect: document.getElementById("sectionSelect"), sectionSelect: document.getElementById("sectionSelect"),
sortSelect: document.getElementById("sortSelect"), sortSelect: document.getElementById("sortSelect"),
searchBox: document.getElementById("searchBox"), searchBox: document.getElementById("searchBox"),
@ -10,6 +11,11 @@ const els = {
}; };
const staticPages = new Set(["about", "contact", "legal"]); const staticPages = new Set(["about", "contact", "legal"]);
const sectionIcons = { // Optional: Add icons per section (e.g., 'essays': '✍️')
essays: '✍️',
fieldnotes: '📓',
pinned: '📌'
};
let indexData = null; let indexData = null;
let sidebarOpen = false; let sidebarOpen = false;
@ -17,22 +23,34 @@ let sidebarOpen = false;
async function init() { async function init() {
try { try {
indexData = await (await fetch("index.json")).json(); indexData = await (await fetch("index.json")).json();
populateNav();
populateSections(); populateSections();
wireUI(); wireUI();
renderList(); renderList();
handleHash(); handleHash();
window.addEventListener("hashchange", handleHash); window.addEventListener("hashchange", handleHash);
} catch (e) { } catch (e) {
els.viewer.innerHTML = "<h1>Error Loading Index</h1><p>Failed to load site data. Please try refreshing.</p>"; els.viewer.innerHTML = "<h1>Error Loading Site</h1><p>Failed to load index data. Please refresh or check connection.</p>";
} }
} }
function populateNav() {
els.primaryNav.innerHTML = '<a href="#/">Home</a>';
staticPages.forEach(p => {
els.primaryNav.innerHTML += `<a href="#/${p}/">${p.charAt(0).toUpperCase() + p.slice(1)}</a>`;
});
indexData.sections.forEach(s => {
els.primaryNav.innerHTML += `<a href="#/${s}/">${s.charAt(0).toUpperCase() + s.slice(1)}</a>`;
});
}
function populateSections() { function populateSections() {
els.sectionSelect.innerHTML = ""; els.sectionSelect.innerHTML = "";
indexData.sections.forEach(s => { indexData.sections.forEach(s => {
const icon = sectionIcons[s] ? `${sectionIcons[s]} ` : '';
const opt = document.createElement("option"); const opt = document.createElement("option");
opt.value = s; opt.value = s;
opt.textContent = s; opt.textContent = `${icon}${s}`;
els.sectionSelect.appendChild(opt); els.sectionSelect.appendChild(opt);
}); });
} }
@ -72,54 +90,59 @@ function renderList() {
} }
async function handleHash() { async function handleHash() {
els.viewer.innerHTML = ""; // Clear viewer to avoid stale content els.viewer.innerHTML = "";
const rel = location.hash.replace(/^#\//, ""); const rel = location.hash.replace(/^#\//, "");
if (!rel) return renderDefault(); if (!rel) return renderDefault();
if (rel.endsWith('/')) { if (rel.endsWith('/')) {
const section = rel.replace(/\/$/, ''); const section = rel.replace(/\/$/, '');
if (staticPages.has(section)) { if (staticPages.has(section)) {
renderHTML(section + '/index.html'); renderIframe(`${section}/index.html`);
} else if (indexData.sections.includes(section)) { } else if (indexData.sections.includes(section)) {
els.sectionSelect.value = section; els.sectionSelect.value = section;
renderList(); renderList();
const sectionPosts = indexData.flat.filter(p => p.path.split('/')[0] === section); const sectionPosts = indexData.flat.filter(p => p.path.split('/')[0] === section);
if (sectionPosts.length === 0) { if (sectionPosts.length === 0) {
els.viewer.innerHTML = `<h1>${section.charAt(0).toUpperCase() + section.slice(1)}</h1><p>No posts in this section yet.</p>`; els.viewer.innerHTML = `<h1>${section.charAt(0).toUpperCase() + section.slice(1)}</h1><p>No content in this section yet. Check back soon!</p>`;
} else { } else {
const latest = sectionPosts.sort((a, b) => b.mtime - a.mtime)[0]; const latest = sectionPosts.sort((a, b) => b.mtime - a.mtime)[0];
location.hash = '#/' + latest.path; // Triggers hashchange to load location.hash = '#/' + latest.path;
} }
} else { } else {
els.viewer.innerHTML = '<h1>404 Not Found</h1>'; els.viewer.innerHTML = '<h1>404: Section Not Found</h1><p>The requested section does not exist.</p>';
} }
} else { } else {
const file = indexData.flat.find(f => f.path === rel); const file = indexData.flat.find(f => f.path === rel);
if (!file) { if (!file) {
els.viewer.innerHTML = '<h1>404 Not Found</h1>'; els.viewer.innerHTML = '<h1>404: File Not Found</h1><p>The requested file could not be located.</p>';
return; return;
} }
try { try {
file.ext === ".md" ? await renderMarkdown(file.path) : renderHTML(file.path); if (file.ext === ".md") {
await renderMarkdown(file.path);
} else {
renderIframe(file.path);
}
} catch (e) { } catch (e) {
els.viewer.innerHTML = '<h1>Error Loading Content</h1><p>Failed to load the file. Please try another.</p>'; els.viewer.innerHTML = '<h1>Error Loading Content</h1><p>Unable to load the file. It may be corrupted or inaccessible.</p>';
} }
} }
} }
async function renderMarkdown(rel) { async function renderMarkdown(rel) {
const src = await fetch(rel).then(r => { if (!r.ok) throw new Error(); return r.text(); }); const src = await fetch(rel).then(r => { if (!r.ok) throw new Error('Fetch failed'); return r.text(); });
const html = marked.parse(src); const html = marked.parse(src);
els.viewer.innerHTML = `<article>${html}</article>`; els.viewer.innerHTML = `<article>${html}</article>`;
} }
function renderHTML(rel) { function renderIframe(rel) {
const iframe = document.createElement("iframe"); const iframe = document.createElement("iframe");
iframe.setAttribute("sandbox", "allow-same-origin allow-scripts allow-forms"); iframe.setAttribute("sandbox", "allow-same-origin allow-scripts allow-forms");
iframe.loading = "eager"; iframe.loading = "eager";
iframe.src = "/" + rel; iframe.src = "/" + rel;
els.viewer.appendChild(iframe); els.viewer.appendChild(iframe);
iframe.addEventListener("load", () => { iframe.addEventListener("load", () => {
if (rel.endsWith('.pdf')) return;
try { try {
const d = iframe.contentDocument || iframe.contentWindow.document; const d = iframe.contentDocument || iframe.contentWindow.document;
const s = d.createElement("style"); const s = d.createElement("style");
@ -134,7 +157,11 @@ function renderHTML(rel) {
function renderDefault() { function renderDefault() {
const latest = [...indexData.flat].sort((a, b) => b.mtime - a.mtime)[0]; const latest = [...indexData.flat].sort((a, b) => b.mtime - a.mtime)[0];
if (latest) location.hash = "#/" + latest.path; if (latest) {
location.hash = "#/" + latest.path;
} else {
els.viewer.innerHTML = '<h1>Welcome</h1><p>No content yet. Add files to sections and redeploy!</p>';
}
} }
init(); init();