${escapeHTML(post.title)}
${date}
${authorHtml}${html}
const SITE_URL = 'https://thefoldwithin.earth'; const state = { posts: [], bySlug: new Map(), bySection: new Map(), byTag: new Map(), bySeries: new Map(), byProgram: new Map(), allTags: new Set(), allSections: ['empathic-technologist', 'recursive-coherence', 'fold-within-earth', 'neutralizing-narcissism', 'simply-we', 'mirrormire'], sectionTitles: { 'empathic-technologist': 'The Empathic Technologist', 'recursive-coherence': 'Recursive Coherence Theory', 'fold-within-earth': 'The Fold Within Earth', 'neutralizing-narcissism': 'Neutralizing Narcissism', 'simply-we': 'Simply WE', 'mirrormire': 'Mirrormire' }, programTitles: { 'neutralizing-narcissism': 'Neutralizing Narcissism', 'open-source-justice': 'Open Source Justice', 'coparent': 'COPARENT' }, pages: [] }; const $ = s => document.querySelector(s); const $$ = s => document.querySelectorAll(s); window.addEventListener('hashchange', () => { $('nav ul').classList.remove('open'); $('.hamburger').setAttribute('aria-expanded', 'false'); router(); }); document.addEventListener('DOMContentLoaded', init); async function init() { try { const res = await fetch('index.json'); if (!res.ok) throw new Error('Could not load index.'); state.posts = await res.json(); state.posts.sort((a, b) => b.date.localeCompare(a.date)); state.bySlug = new Map(state.posts.map(p => [p.slug, p])); state.allSections.forEach(s => { state.bySection.set(s, state.posts.filter(p => p.section === s)); }); state.posts.forEach(p => { p.tags.forEach(t => { state.allTags.add(t); if (!state.byTag.has(t)) state.byTag.set(t, []); state.byTag.get(t).push(p); }); if (p.series) { if (!state.bySeries.has(p.series)) state.bySeries.set(p.series, []); state.bySeries.get(p.series).push(p); } p.programs.forEach(pr => { if (!state.byProgram.has(pr)) state.byProgram.set(pr, []); state.byProgram.get(pr).push(p); }); }); const pagesRes = await fetch('pages.json'); if (pagesRes.ok) state.pages = await pagesRes.json(); renderNav(); renderFooter(); setupSearchForm(); setupHamburger(); router(); } catch (e) { $('#main').innerHTML = `
⚠️ ${e.message}
`; } } function setupHamburger() { const hamburger = $('.hamburger'); hamburger.addEventListener('click', () => { const ul = $('nav ul'); const isOpen = ul.classList.toggle('open'); hamburger.setAttribute('aria-expanded', isOpen); }); } function renderNav() { $('#sections-list').innerHTML = state.allSections.map(s => `Email: info@thefoldwithin.earth
© ${new Date().getFullYear()} The Fold Within Earth
`; } function setupSearchForm() { $('#search-form').addEventListener('submit', e => { e.preventDefault(); const q = $('#search-input').value.trim(); if (q) { sessionStorage.setItem('lastSearch', q); location.hash = `/search?q=${encodeURIComponent(q)}`; } }); } function router() { const main = $('#main'); main.style.opacity = 0; const {parts, params} = getQueryParams(); document.title = 'The Fold Within Earth'; if (parts.length === 0) { renderHome(); } else if (parts[0] === 'section' && parts[1]) { renderArchive('section', parts[1], params); } else if (parts[0] === 'tag' && parts[1]) { renderArchive('tag', parts[1], params); } else if (parts[0] === 'post' && parts[1]) { renderPost(parts[1]); } else if (parts[0] === 'search') { let q = params.get('q') || sessionStorage.getItem('lastSearch') || ''; $('#search-input').value = q; renderSearch(q, params); } else if (parts[0] === 'about') { renderAbout(); } else if (parts[0] === 'mud') { renderMud(); } else if (parts[0] === 'start') { renderStart(); } else if (parts[0] === 'programs') { renderProgramsHome(); } else if (parts[0] === 'program' && parts[1]) { renderProgramArchive(parts[1], params); } else { render404(); } setTimeout(() => { main.style.opacity = 1; window.scrollTo(0, 0); main.focus(); }, 0); } function renderHome() { const latestAll = state.posts.slice(0, 10).map(renderCard).join(''); const bySection = state.allSections.map(s => { const secPosts = state.bySection.get(s) ? state.bySection.get(s).slice(0, 3) : []; const list = secPosts.map(p => `No posts found for ${escapeHTML(title)}.
`; return; } let sorted = postList.slice().sort((a, b) => sort === 'desc' ? b.date.localeCompare(a.date) : a.date.localeCompare(b.date)); let filtered = activeTags.length ? sorted.filter(p => activeTags.some(t => p.tags.includes(t))) : sorted; const perPage = 10; const totalPages = Math.ceil(filtered.length / perPage); const start = (page - 1) * perPage; const end = start + perPage; const cards = filtered.slice(start, end).map(renderCard).join(''); const availableTags = [...new Set(postList.flatMap(p => p.tags))]; $('#main').innerHTML = `⚠️ Post not found.
`; return; } try { const res = await fetch(`content/${post.file}`); if (!res.ok) throw new Error('Post file missing.'); let md = await res.text(); md = md.replace(/^---[\s\S]*?---/, '').trim(); const html = sanitizeMarkdown(md); const date = formatDate(post.date); const sectionPill = renderPill('section', state.sectionTitles[post.section] || post.section); const tagPills = post.tags.map(t => renderPill('tag', t)).join(''); const programPills = post.programs.map(pr => renderPill('program', state.programTitles[pr] || pr)).join(''); const reading = `${post.readingTime} min read`; const authorHtml = post.author ? `` : ''; const share = ``; const secPosts = state.bySection.get(post.section) || []; const idx = secPosts.findIndex(p => p.slug === slug); const prev = idx < secPosts.length - 1 ? secPosts[idx + 1] : null; const next = idx > 0 ? secPosts[idx - 1] : null; const navPost = ``; let navSeries = ''; if (post.series) { const seriesPosts = (state.bySeries.get(post.series) || []).sort((a, b) => a.date.localeCompare(b.date)); const sIdx = seriesPosts.findIndex(p => p.slug === slug); const prevSeries = sIdx > 0 ? seriesPosts[sIdx - 1] : null; const nextSeries = sIdx < seriesPosts.length - 1 ? seriesPosts[sIdx + 1] : null; navSeries = ``; } const related = state.posts.filter(p => p.slug !== slug && p.tags.some(t => post.tags.includes(t))) .sort((a, b) => { const sharedA = a.tags.filter(t => post.tags.includes(t)).length; const sharedB = b.tags.filter(t => post.tags.includes(t)).length; return sharedB - sharedA; }).slice(0, 3); const relatedHtml = related.length ? `${date}
${authorHtml}⚠️ ${e.message}
`; } } async function renderSearch(q, params) { if (!q) { $('#main').innerHTML = `Enter a search query above.
`; return; } if (!window.Fuse) { const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/fuse.js@7.0.0'; document.body.appendChild(script); await new Promise(resolve => script.onload = resolve); } const fuse = new Fuse(state.posts, {keys: ['title', 'excerpt', 'tags', 'section'], threshold: 0.3, includeMatches: true}); const results = fuse.search(q).map(r => ({item: r.item, matches: r.matches})); const title = `Search Results for "${escapeHTML(q)}" (${results.length} found)`; $('#main').innerHTML = `We’re building a canonical front door for a multi-track body of work:
MUD portal coming soon.
Start page not found.
`; return; } try { const res = await fetch(`content/${page.file}`); const md = (await res.text()).replace(/^---[\s\S]*?---/,'').trim(); $('#main').innerHTML = `⚠️ ${e.message}
`; } } function renderProgramsHome() { const cards = Object.entries(state.programTitles).map(([k, v]) => `Program
Explore all posts and guidance for ${escapeHTML(v)}.
No posts found for Program: ${escapeHTML(title)}.
`; return; } const cards = list.map(renderCard).join(''); $('#main').innerHTML = `⚠️ Page not found.
`; } function addCardListeners() { $('#main').addEventListener('click', e => { const article = e.target.closest('article[data-slug]'); if (article) { location.hash = `/post/${article.dataset.slug}`; } }); $('#main').addEventListener('keydown', e => { const article = e.target.closest('article[data-slug]'); if (article && e.key === 'Enter') { location.hash = `/post/${article.dataset.slug}`; } }); } function renderBreadcrumbs(pathParts) { let crumbs = `Home`; let currentPath = ''; pathParts.forEach((part, i) => { currentPath += `/${part}`; let label = part.charAt(0).toUpperCase() + part.slice(1); if (state.sectionTitles[part]) label = state.sectionTitles[part]; if (state.programTitles[part]) label = state.programTitles[part]; crumbs += ` › ${escapeHTML(label)}`; }); return ``; } function escapeHTML(str) { const div = document.createElement('div'); div.textContent = str; return div.innerHTML; }