diff --git a/api/data/navigation.json b/api/data/navigation.json index f1f95bb..05c6b54 100644 --- a/api/data/navigation.json +++ b/api/data/navigation.json @@ -83,7 +83,7 @@ }, { "label": "RECON", - "url": "/depot/recon" + "url": "/recon" } ] }, diff --git a/css/contraband.css b/css/contraband.css index a37ea5f..fd94b0c 100644 --- a/css/contraband.css +++ b/css/contraband.css @@ -595,16 +595,34 @@ /* ─── Subcategory Group Headings (Awesomelist) ─────────── */ .crt-subcat-group { - margin-bottom: 1.5rem; + margin-bottom: 0.5rem; } .crt-subcat-heading { font-family: 'Orbitron', monospace; font-size: 0.75rem; color: rgba(255, 170, 0, 0.8); letter-spacing: 2px; - padding: 0.6rem 0; + padding: 0.6rem 0.8rem; border-bottom: 1px solid rgba(255, 170, 0, 0.15); - margin-bottom: 0.5rem; + margin-bottom: 0; + cursor: pointer; + user-select: none; + transition: background 0.2s, color 0.2s; +} +.crt-subcat-heading:hover { + background: rgba(255, 170, 0, 0.06); + color: rgba(255, 170, 0, 1); +} +.crt-subcat-heading.expanded { + background: rgba(255, 170, 0, 0.08); + border-bottom-color: rgba(255, 170, 0, 0.3); +} +.crt-subcat-arrow { + display: inline-block; + width: 1rem; + font-size: 0.7rem; + color: rgba(255, 170, 0, 0.6); + transition: transform 0.2s; } .crt-subcat-count { font-family: 'JetBrains Mono', monospace; @@ -612,3 +630,8 @@ color: #666; margin-left: 0.5rem; } +.crt-subcat-entries { + padding-left: 0.5rem; + border-left: 1px solid rgba(255, 170, 0, 0.1); + margin-left: 0.4rem; +} diff --git a/js/awesomelist.js b/js/awesomelist.js index f0e89d9..6ee7ff0 100644 --- a/js/awesomelist.js +++ b/js/awesomelist.js @@ -87,6 +87,7 @@ // ─── Render: Sector Detail ─────────────────────────── function renderSector(sec) { state.view = 'detail'; + state.currentSector = sec; let html = ''; // Back button @@ -203,7 +204,9 @@ // ─── Event Bindings: Index ─────────────────────────── function bindIndexEvents() { document.querySelectorAll('.crt-card').forEach(card => { - card.addEventListener('click', () => { + card.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); loadSector(card.dataset.slug); }); }); @@ -232,13 +235,18 @@ // ─── Event Bindings: Detail ────────────────────────── function bindDetailEvents(sec) { // Back button - document.getElementById('crtBack').addEventListener('click', () => { + document.getElementById('crtBack').addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); loadIndex(); }); // List card clicks — show all subcategories and entries for that source list document.querySelectorAll('.crt-sub-card').forEach(card => { - card.addEventListener('click', () => { + card.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + const idx = parseInt(card.dataset.listIdx); const lst = sec.lists[idx]; const panel = document.getElementById('crtSubDetail'); @@ -262,9 +270,10 @@ notesEl.innerHTML = ''; notesEl.style.display = 'none'; - // Build entries grouped by subcategory + // Build entries grouped by subcategory with collapsible headings let eh = ''; - for (const sub of lst.subcategories) { + for (let si = 0; si < lst.subcategories.length; si++) { + const sub = lst.subcategories[si]; if (sub.entries.length === 0) continue; // Strip the source prefix from subcategory name if it starts with list name let subName = sub.name; @@ -274,13 +283,35 @@ } if (subName === lst.name) subName = 'General'; - eh += `
`; - eh += `
${esc(subName)} ${sub.entries.length}
`; + eh += `
`; + eh += `
${esc(subName)} ${sub.entries.length}
`; + eh += ``; + eh += `
`; } entriesEl.innerHTML = eh; + // Bind subcategory toggle clicks + entriesEl.querySelectorAll('.crt-subcat-heading').forEach(heading => { + heading.addEventListener('click', (ev) => { + ev.preventDefault(); + ev.stopPropagation(); + const toggleIdx = heading.dataset.subcatToggle; + const body = entriesEl.querySelector(`[data-subcat-body="${toggleIdx}"]`); + const arrow = heading.querySelector('.crt-subcat-arrow'); + if (body.style.display === 'none') { + body.style.display = ''; + if (arrow) arrow.textContent = '▾'; + heading.classList.add('expanded'); + } else { + body.style.display = 'none'; + if (arrow) arrow.textContent = '▸'; + heading.classList.remove('expanded'); + } + }); + }); + panel.style.display = ''; panel.scrollIntoView({ behavior: 'smooth', block: 'start' }); }); @@ -320,7 +351,7 @@ try { const data = await api(`/${slug}`); renderSector(data); - history.pushState({ view: 'detail', slug }, '', `/recon?sector=${slug}`); + history.pushState({ view: 'detail', slug: slug }, '', `/recon?sector=${slug}`); window.scrollTo({ top: 0, behavior: 'smooth' }); } catch (e) { root.innerHTML = `
SECTOR NOT FOUND // ${esc(e.message)}
`;