Sign in to 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
${x.modules.map(m => `- ${m}
`).join('')}
Practical outcomes
${x.outcomes.map(o => `- ${o}
`).join('')}
`;
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(); });
})();