/* ═══════════════════════════════════════════════════════
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 += `
`;
html += ``;
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 += ``;
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();
})();