RadiantVector

Learning catalog

Build your own RadiantVector track.

Compare focused courses designed around real graphic design decisions, not disconnected tool demonstrations.

`; const footerHTML = ``; document.querySelector('header').innerHTML = headerHTML; document.querySelector('footer').innerHTML = footerHTML; let items = [], page = 1; const perPage = 6; const saved = () => JSON.parse(localStorage.getItem('rv-fallows') || '[]'); const cart = () => JSON.parse(localStorage.getItem('rv-cart') || '{}'); function render() { const q = document.querySelector('#search').value.toLowerCase(); const level = document.querySelector('#filter').value; const list = items.filter(x => (level === 'all' || x.level === level) && (x.title + x.summary + x.category).toLowerCase().includes(q)); const pages = Math.max(1, Math.ceil(list.length / perPage)); page = Math.min(page, pages); document.querySelector('#catalog-grid').innerHTML = list.slice((page - 1) * perPage, page * perPage).map(x => `

${x.category} · ${x.level}

${x.title}

${x.summary}

$${x.price.toFixed(2)} · ${x.duration}

`).join('') || '

No courses match this search.

'; document.querySelector('#pagination').innerHTML = Array.from({length: pages}, (_, i) => ``).join(''); } document.addEventListener('click', e => { const id = Number(e.target.dataset.fav || e.target.dataset.cart || e.target.dataset.detail); if (e.target.dataset.page) { page = Number(e.target.dataset.page); render(); } if (e.target.dataset.fav) { const a = saved(); if (!a.includes(id)) a.push(id); localStorage.setItem('rv-fallows', JSON.stringify(a)); } if (e.target.dataset.cart) { const c = cart(); c[id] = (c[id] || 0) + 1; localStorage.setItem('rv-cart', JSON.stringify(c)); } if (e.target.dataset.detail) { const x = items.find(i => i.id === id); document.querySelector('#detail-content').innerHTML = `

${x.category} · ${x.level}

${x.title}

${x.description}

Modules

Practical outcomes

`; document.querySelector('#detail-modal').classList.replace('hidden', 'flex'); } }); document.querySelector('#detail-close').addEventListener('click', () => document.querySelector('#detail-modal').classList.replace('flex', 'hidden')); document.querySelector('#search').addEventListener('input', () => { page = 1; render(); }); document.querySelector('#filter').addEventListener('change', () => { page = 1; render(); }); fetch('./catalog.json').then(r => r.json()).then(data => { items = data; render(); }).catch(() => { items = []; render(); }); })();