/* ═══════════════════════════════════════════════════════ AWESOME LISTS // Propaganda Resource Controller ═══════════════════════════════════════════════════════ */ (function () { 'use strict'; const API = '/api/awesomelist'; const root = document.getElementById('awesomelistRoot'); if (!root) return; let state = { view: 'sectors', data: null, searchTimeout: null, activeListSlug: null, activeSubIdx: null }; // ─── Utilities ─────────────────────────────────────── function esc(s) { const d = document.createElement('div'); d.textContent = s || ''; return d.innerHTML; } function md(s) { if (!s) return ''; let h = esc(s); h = h.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); h = h.replace(/\*\*([^*]+)\*\*/g, '$1'); h = h.replace(/\*([^*]+)\*/g, '$1'); h = h.replace(/`([^`]+)`/g, '$1'); return h; } function fmt(n) { return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } async function api(endpoint) { const res = await fetch(API + endpoint); if (!res.ok) throw new Error(`API ${res.status}`); return res.json(); } // ─── Render: Sectors (Level 1) ─────────────────────── function renderSectors(data) { state.view = 'sectors'; state.data = data; let html = ''; // Stats bar html += `
DATABASE● ONLINE
TOTAL LISTS${fmt(data.total_lists)}
TOTAL ENTRIES${fmt(data.total_entries)}
SECTORS${data.total_sectors}
STATUS● DECLASSIFIED
`; // Search html += `
`; html += `
`; // Sector grid html += `
`; for (const sector of data.sectors) { html += `
${sector.icon}
${esc(sector.code)}
${esc(sector.name)}
${sector.list_count} LISTS ${fmt(sector.total_entries)} ENTRIES
`; } html += `
`; root.innerHTML = html; bindSectorEvents(); } // ─── Render: Lists in Sector (Level 2) ────────────── function renderSector(sector) { state.view = 'sector'; state.activeListSlug = null; let html = ''; html += `
◄ BACK TO SECTORS
`; html += `
${esc(sector.code)}
${sector.icon} ${esc(sector.name)}
${sector.list_count} LISTS ${fmt(sector.total_entries)} ENTRIES
`; // Filter search html += `
`; // List cards html += `
`; for (const lst of sector.lists) { html += `
${esc(lst.title)}
${esc(lst.description || '')}
${fmt(lst.entry_count)} entries ${lst.subcategory_count} sections ${lst.stars ? `⭐ ${esc(lst.stars)}` : ''}
`; } html += `
`; // Detail panel html += ``; root.innerHTML = html; bindListEvents(sector); } // ─── Render: Single List Detail (Level 3) ─────────── function renderListDetail(listData) { state.activeSubIdx = null; const panel = document.getElementById('alListDetail'); if (!panel) return; let html = `
`; html += `
${esc(listData.title)}
`; if (listData.description) { html += `
${md(listData.description)}
`; } if (listData.github_url) { html += `📂 ${esc(listData.github_url)}`; } // Subcategory cards if (listData.subcategories && listData.subcategories.length > 0) { html += `
`; for (let i = 0; i < listData.subcategories.length; i++) { const sub = listData.subcategories[i]; if (sub.entries.length === 0) continue; html += `
${esc(sub.name)}
${sub.entries.length} items
`; } html += `
`; html += ``; } html += `
`; panel.innerHTML = html; panel.style.display = 'block'; // Bind sub card clicks panel.querySelectorAll('.al-sub-card').forEach(card => { card.addEventListener('click', () => { const idx = parseInt(card.dataset.subIdx); if (state.activeSubIdx === idx) { state.activeSubIdx = null; card.classList.remove('active'); document.getElementById('alEntriesPanel').style.display = 'none'; return; } state.activeSubIdx = idx; panel.querySelectorAll('.al-sub-card').forEach(c => c.classList.remove('active')); card.classList.add('active'); renderEntries(listData.subcategories[idx]); }); }); panel.scrollIntoView({ behavior: 'smooth', block: 'start' }); } // ─── Render: Entries ───────────────────────────────── function renderEntries(sub) { const panel = document.getElementById('alEntriesPanel'); if (!panel) return; let html = `
`; html += `
${esc(sub.name)} — ${sub.entries.length} ITEMS
`; for (const entry of sub.entries) { html += `
`; html += ``; html += `
`; if (entry.url) { html += `
${esc(entry.name || entry.url)}`; } else { html += `
${md(entry.name || '')}`; } if (entry.stars) { html += `⭐ ${esc(entry.stars)}`; } html += `
`; if (entry.description) { html += `
${md(entry.description)}
`; } html += `
`; } html += `
`; panel.innerHTML = html; panel.style.display = 'block'; panel.scrollIntoView({ behavior: 'smooth', block: 'start' }); } // ─── Render: Search Results ────────────────────────── function renderSearchResults(data) { const container = document.getElementById('alSearchResults'); const countEl = document.getElementById('alSearchCount'); const grid = document.getElementById('alSectorGrid'); if (!data.results || data.results.length === 0) { container.innerHTML = data.query ? '
NO MATCHING RESULTS FOUND
' : ''; countEl.textContent = data.query ? '0 RESULTS' : ''; if (grid) grid.style.display = data.query ? 'none' : ''; return; } countEl.textContent = `${data.total} RESULTS`; if (grid) grid.style.display = 'none'; let html = ''; for (const r of data.results) { html += `
`; if (r.type === 'list') { html += `
${esc(r.sector_code)} // ${esc(r.sector_name)}
`; html += `
${esc(r.title)}`; if (r.stars) html += `⭐ ${esc(r.stars)}`; html += `
`; if (r.description) html += `
${md(r.description)}
`; html += `
${fmt(r.entry_count)} entries
`; } else { html += `
${esc(r.list_title)} / ${esc(r.subcategory)}
`; html += `
`; if (r.url) { html += `${esc(r.name || r.url)}`; } else { html += md(r.name); } if (r.stars) html += `⭐ ${esc(r.stars)}`; html += `
`; if (r.description) html += `
${md(r.description)}
`; } html += `
`; } container.innerHTML = html; } // ─── Event Bindings ────────────────────────────────── function bindSectorEvents() { document.querySelectorAll('.al-sector-card').forEach(card => { card.addEventListener('click', () => { const code = card.dataset.code; const sector = state.data.sectors.find(s => s.code === code); if (sector) { history.pushState({ view: 'sector', code }, '', `?sector=${code}`); renderSector(sector); } }); }); const searchInput = document.getElementById('alSearch'); if (searchInput) { searchInput.addEventListener('input', () => { clearTimeout(state.searchTimeout); const q = searchInput.value.trim(); if (q.length < 2) { document.getElementById('alSearchResults').innerHTML = ''; document.getElementById('alSearchCount').textContent = ''; const grid = document.getElementById('alSectorGrid'); if (grid) grid.style.display = ''; return; } state.searchTimeout = setTimeout(async () => { try { const data = await api(`/search?q=${encodeURIComponent(q)}`); renderSearchResults(data); } catch (e) { console.error(e); } }, 300); }); } } function bindListEvents(sector) { // Back button document.getElementById('alBackSectors').addEventListener('click', () => { history.pushState({ view: 'sectors' }, '', window.location.pathname); renderSectors(state.data); }); // List card clicks document.querySelectorAll('.al-list-card').forEach(card => { card.addEventListener('click', async () => { const slug = card.dataset.slug; if (state.activeListSlug === slug) { state.activeListSlug = null; card.classList.remove('active'); document.getElementById('alListDetail').style.display = 'none'; return; } state.activeListSlug = slug; document.querySelectorAll('.al-list-card').forEach(c => c.classList.remove('active')); card.classList.add('active'); const panel = document.getElementById('alListDetail'); panel.innerHTML = '
LOADING DOSSIER...
'; panel.style.display = 'block'; try { const listData = await api(`/list/${slug}`); renderListDetail(listData); } catch (e) { panel.innerHTML = '
FAILED TO LOAD DOSSIER
'; } }); }); // Filter const filterInput = document.getElementById('alSectorFilter'); if (filterInput) { filterInput.addEventListener('input', () => { const q = filterInput.value.trim().toLowerCase(); document.querySelectorAll('.al-list-card').forEach(card => { const title = card.querySelector('.al-list-title').textContent.toLowerCase(); const desc = card.querySelector('.al-list-desc').textContent.toLowerCase(); card.style.display = (!q || title.includes(q) || desc.includes(q)) ? '' : 'none'; }); }); } } // ─── History Navigation ────────────────────────────── window.addEventListener('popstate', (e) => { if (e.state && e.state.view === 'sector' && state.data) { const sector = state.data.sectors.find(s => s.code === e.state.code); if (sector) { renderSector(sector); return; } } if (state.data) renderSectors(state.data); }); // ─── Init ──────────────────────────────────────────── async function init() { root.innerHTML = '
ACCESSING PROPAGANDA DATABASE...
'; try { const data = await api(''); state.data = data; // Check URL params const params = new URLSearchParams(window.location.search); const sectorCode = params.get('sector'); if (sectorCode) { const sector = data.sectors.find(s => s.code.toLowerCase() === sectorCode.toLowerCase()); if (sector) { renderSector(sector); return; } } renderSectors(data); } catch (e) { root.innerHTML = '
FAILED TO ACCESS DATABASE — RETRY LATER
'; console.error(e); } } init(); })();