SpartanNest Works
Cart 0

Course system / 02

Choose your assembly pathway

Filter by practical focus, compare learning depth, save a course to Fallows, or add it to your cart for a structured checkout review.

Open Fallows
`; footer.innerHTML=``; initTheme(); initMobileMenu(); initLoginModal(); updateCartCount(); initCookieBanner(); } function initTheme(){ const btn=document.getElementById('theme-toggle'); const saved=localStorage.getItem('spartanNestTheme'); if(saved==='light'){ document.documentElement.classList.add('light'); document.body.classList.remove('bg-slate-950'); document.body.classList.add('bg-slate-100','text-slate-900'); } btn.addEventListener('click',()=>{ if(document.documentElement.classList.contains('light')){ document.documentElement.classList.remove('light'); document.body.classList.remove('bg-slate-100','text-slate-900'); document.body.classList.add('bg-slate-950','text-slate-100'); localStorage.setItem('spartanNestTheme','dark'); }else{ document.documentElement.classList.add('light'); document.body.classList.remove('bg-slate-950','text-slate-100'); document.body.classList.add('bg-slate-100','text-slate-900'); localStorage.setItem('spartanNestTheme','light'); } }); } function initMobileMenu(){ const openBtn=document.getElementById('mobile-menu-open'); const menu=document.getElementById('mobile-menu'); openBtn.addEventListener('click',()=>{menu.classList.toggle('hidden');}); } function initLoginModal(){ const loginBtn=document.getElementById('login-open'); const regBtn=document.getElementById('register-open'); const modalHTML=``; document.body.insertAdjacentHTML('beforeend',modalHTML); const modal=document.getElementById('login-modal'); loginBtn.onclick=()=>modal.classList.remove('hidden'); regBtn.onclick=()=>modal.classList.remove('hidden'); modal.querySelector('#close-login').onclick=()=>modal.classList.add('hidden'); modal.onclick=e=>{if(e.target===modal)modal.classList.add('hidden');}; const form=modal.querySelector('#login-form'); form.onsubmit=function(e){e.preventDefault();modal.classList.add('hidden');alert('Signed in successfully.');}; } function updateCartCount(){ const countEl=document.getElementById('cart-count'); let cart=JSON.parse(localStorage.getItem('spartanNestCart')||'{}'); let total=0; for(let k in cart)total+=cart[k].quantity; countEl.textContent=total; } function initCookieBanner(){ const banner=document.getElementById('cookie-banner'); const accept=document.getElementById('cookie-accept'); if(!localStorage.getItem('spartanNestCookies'))banner.classList.remove('hidden'); accept.onclick=function(){localStorage.setItem('spartanNestCookies','accepted');banner.classList.add('hidden');}; } async function fetchCourses(){ const status=document.getElementById('catalog-status'); status.textContent='Loading catalog...'; try{ const res=await fetch('./catalog.json'); courses=await res.json(); filteredCourses=[...courses]; status.textContent=''; buildFilters(); renderGrid(); renderPagination(); const params=new URLSearchParams(window.location.search); if(params.has('item'))openModalById(params.get('item')); }catch(e){ status.textContent='Unable to load catalog data.'; } } function buildFilters(){ const catSelect=document.getElementById('category'); const cats=[...new Set(courses.map(c=>c.category))].sort(); catSelect.innerHTML=''; cats.forEach(c=>{const o=document.createElement('option');o.value=c;o.textContent=c;catSelect.appendChild(o);}); document.getElementById('search').oninput=applyFilters; catSelect.onchange=applyFilters; document.getElementById('sort').onchange=applyFilters; } function applyFilters(){ const q=document.getElementById('search').value.toLowerCase(); const cat=document.getElementById('category').value; const sort=document.getElementById('sort').value; filteredCourses=courses.filter(c=>{ const matchQ=!q||c.title.toLowerCase().includes(q)||c.summary.toLowerCase().includes(q); const matchCat=!cat||c.category===cat; return matchQ&&matchCat; }); if(sort==='price-low')filteredCourses.sort((a,b)=>a.price-b.price); else if(sort==='price-high')filteredCourses.sort((a,b)=>b.price-a.price); currentPage=1; renderGrid(); renderPagination(); } function renderGrid(){ const grid=document.getElementById('product-grid'); grid.innerHTML=''; const start=(currentPage-1)*perPage; const pageItems=filteredCourses.slice(start,start+perPage); if(pageItems.length===0){ grid.innerHTML='

No courses match your filters.

'; return; } pageItems.forEach(course=>{ const favs=JSON.parse(localStorage.getItem('spartanNestFavorites')||'[]'); const isFav=favs.includes(course.id); const card=document.createElement('div'); card.className='rounded-2xl border border-slate-800 bg-slate-900 p-6 flex flex-col'; card.innerHTML=`
${course.level} • ${course.duration}

${course.title}

${course.summary}

${course.format} • ${course.currency}${course.price}
Learn more
`; grid.appendChild(card); const favBtn=card.querySelector('[data-fav]'); favBtn.onclick=function(){ let favArray=JSON.parse(localStorage.getItem('spartanNestFavorites')||'[]'); if(favArray.includes(course.id)){ favArray=favArray.filter(x=>x!==course.id); favBtn.textContent='☆'; }else{ favArray.push(course.id); favBtn.textContent='★'; } localStorage.setItem('spartanNestFavorites',JSON.stringify(favArray)); } card.querySelector('[data-cart]').onclick=function(){ let cart=JSON.parse(localStorage.getItem('spartanNestCart')||'{}'); if(!cart[course.id])cart[course.id]={quantity:1,title:course.title}; else cart[course.id].quantity++; localStorage.setItem('spartanNestCart',JSON.stringify(cart)); updateCartCount(); } }); } function renderPagination(){ const nav=document.getElementById('pagination'); nav.innerHTML=''; const totalPages=Math.ceil(filteredCourses.length/perPage); for(let i=1;i<=totalPages;i++){ const link=document.createElement('a'); link.href='javascript:void(0)'; link.textContent=i; link.className='px-4 py-2 rounded-xl border border-slate-700 text-sm '+(i===currentPage?'bg-indigo-600 text-white':'hover:border-violet-400'); link.onclick=function(){currentPage=i;renderGrid();renderPagination();}; nav.appendChild(link); } } function openModalById(id){ const course=courses.find(c=>c.id===id); if(!course)return; const modal=document.getElementById('detail-modal'); document.getElementById('detail-title').textContent=course.title; document.getElementById('detail-description').textContent=course.description; const modUl=document.getElementById('detail-modules'); modUl.innerHTML=''; course.modules.forEach(m=>{const li=document.createElement('li');li.textContent='• '+m;modUl.appendChild(li);}); const outUl=document.getElementById('detail-outcomes'); outUl.innerHTML=''; course.outcomes.forEach(o=>{const li=document.createElement('li');li.textContent='• '+o;outUl.appendChild(li);}); modal.classList.remove('hidden'); document.getElementById('close-modal').onclick=()=>modal.classList.add('hidden'); modal.onclick=e=>{if(e.target===modal)modal.classList.add('hidden');}; document.onkeydown=function(ev){if(ev.key==='Escape')modal.classList.add('hidden');}; } function initDetailFromUrl(){ const params=new URLSearchParams(window.location.search); if(params.has('item')){ setTimeout(()=>openModalById(params.get('item')),300); } } function initAll(){ loadHeaderFooter(); document.getElementById('detail-modal').classList.add('hidden'); fetchCourses(); initDetailFromUrl(); } initAll();