Infernovox ParkCraft

Fallows

Your saved courses. Toggle compare mode to highlight differences in pricing, duration and difficulty.

Back to Catalog Go to Cart
`; } if (id === 'site-footer') { el.innerHTML = ` `; } } } function initHeaderInteractions() { setTimeout(() => { const htmlEl = document.documentElement; document.querySelectorAll('[data-action="toggle-theme"]').forEach(btn => { btn.addEventListener('click', () => { htmlEl.classList.toggle('dark'); const mode = htmlEl.classList.contains('dark') ? 'dark' : 'light'; localStorage.setItem('ivxpc-theme', mode); }); }); const mobileBtn = document.querySelector('[data-action="toggle-mobile-nav"]'); const mobileNav = document.querySelector('[data-el="mobile-nav"]'); if (mobileBtn && mobileNav) { mobileBtn.addEventListener('click', () => mobileNav.classList.toggle('hidden')); } document.querySelectorAll('[data-action="open-login"]').forEach(el => { el.addEventListener('click', () => { const modal = document.getElementById('loginModal'); if (modal) modal.classList.remove('hidden'); else alert('Login modal available on all pages.'); }); }); document.querySelectorAll('[data-action="open-register"]').forEach(el => { el.addEventListener('click', () => { const modal = document.getElementById('registerModal'); if (modal) modal.classList.remove('hidden'); else alert('Registration available on all pages.'); }); }); document.querySelectorAll('[data-action="close-modal"]').forEach(el => { el.addEventListener('click', () => { el.closest('.fixed').classList.add('hidden'); }); }); document.addEventListener('keydown', function(e) { if (e.key.toLowerCase() === 't' && document.activeElement.tagName === 'BODY') { htmlEl.classList.toggle('dark'); localStorage.setItem('ivxpx-theme', htmlEl.classList.contains('dark') ? 'dark' : 'light'); } }); }, 220); } let catalogCache = []; async function loadCatalog() { try { const res = await fetch('./catalog.json'); catalogCache = await res.json(); } catch(e) { catalogCache = [ {id:1,name:"Advanced Parallel Parking",level:"Intermediate",duration:"3 weeks",price:189,category:"Urban"}, {id:2,name:"Night Vision Maneuvering",level:"Advanced",duration:"4 weeks",price:245,category:"Night"}, {id:5,name:"Tight Space Precision",level:"Intermediate",duration:"2 weeks",price:149,category:"Urban"} ]; } } function getFallows() { try { return JSON.parse(localStorage.getItem('ivxpc-fallows') || '[]'); } catch { return []; } } function saveFallows(arr) { localStorage.setItem('ivxpc-fallows', JSON.stringify(arr)); } function getCart() { try { return JSON.parse(localStorage.getItem('ivxpc-cart') || '[]'); } catch { return []; } } function addToCart(id) { const cart = getCart(); if (!cart.includes(id)) { cart.push(id); localStorage.setItem('ivxpc-cart', JSON.stringify(cart)); } const btns = document.querySelectorAll(`[data-cart-id="${id}"]`); btns.forEach(b => { b.textContent = 'Added'; b.disabled = true; setTimeout(() => { if (b) b.textContent = 'Add to cart'; b.disabled = false; }, 1400); }); } function removeFromFallows(id) { let fallows = getFallows(); fallows = fallows.filter(i => i !== id); saveFallows(fallows); renderFallows(); } let compareMode = false; let comparedItems = []; function toggleCompareMode() { compareMode = !compareMode; const btn = document.getElementById('compareToggle'); if (compareMode) { btn.classList.add('!bg-violet-500', '!text-white'); btn.textContent = 'Exit compare'; } else { btn.classList.remove('!bg-violet-500', '!text-white'); btn.textContent = 'Compare mode'; comparedItems = []; document.getElementById('compareSection').classList.add('hidden'); } renderFallows(); } function toggleItemCompare(id) { const idx = comparedItems.indexOf(id); if (idx > -1) { comparedItems.splice(idx, 1); } else { if (comparedItems.length < 4) comparedItems.push(id); } updateCompareTable(); } function updateCompareTable() { const section = document.getElementById('compareSection'); const body = document.getElementById('compareBody'); body.innerHTML = ''; if (comparedItems.length < 2) { section.classList.add('hidden'); return; } section.classList.remove('hidden'); comparedItems.forEach(id => { const item = catalogCache.find(c => c.id === id); if (!item) return; const row = document.createElement('tr'); row.className = 'border-b border-violet-400/20'; row.innerHTML = ` ${item.name} ${item.level} ${item.duration} $${item.price}
`; body.appendChild(row); }); body.querySelectorAll('[data-add-cart]').forEach(el => { el.onclick = () => addToCart(parseInt(el.dataset.addCart)); }); body.querySelectorAll('[data-remove-fallow]').forEach(el => { el.onclick = () => { removeFromFallows(parseInt(el.dataset.removeFallow)); comparedItems = comparedItems.filter(i => i !== parseInt(el.dataset.removeFallow)); updateCompareTable(); }; }); } function renderFallows() { const container = document.getElementById('list'); const emptyEl = document.getElementById('empty'); container.innerHTML = ''; const fallows = getFallows(); if (!fallows.length) { emptyEl.classList.remove('hidden'); document.getElementById('compareSection').classList.add('hidden'); return; } emptyEl.classList.add('hidden'); const filtered = catalogCache.filter(item => fallows.includes(item.id)); filtered.forEach(item => { const isCompared = comparedItems.includes(item.id); const card = document.createElement('div'); card.className = `dd23l xk9h7 p2aql border border-violet-400/30 px-5 py-6 rounded-2xl flex flex-col`; card.innerHTML = `
${item.category}
${item.name}
Level: ${item.level}
Duration: ${item.duration}
$${item.price}
${compareMode ? ` ` : ''}
`; container.appendChild(card); card.querySelector(`[data-remove="${item.id}"]`).onclick = () => removeFromFallows(item.id); card.querySelector(`[data-cart-id="${item.id}"]`).onclick = () => addToCart(item.id); const compareBtn = card.querySelector(`[data-compare="${item.id}"]`); if (compareBtn) { compareBtn.onclick = () => { toggleItemCompare(item.id); renderFallows(); }; } }); } function initFallowsPage() { initTailwind(); document.getElementById('compareToggle').addEventListener('click', toggleCompareMode); document.getElementById('clearAll').addEventListener('click', () => { if (confirm('Clear your entire Fallows list?')) { localStorage.removeItem('ivxpc-fallows'); comparedItems = []; document.getElementById('compareSection').classList.add('hidden'); renderFallows(); } }); Promise.all([ loadCatalog(), injectPart('site-header', './header.html'), injectPart('site-footer', './footer.html') ]).then(() => { initHeaderInteractions(); const fallows = getFallows(); if (!fallows.length) { document.getElementById('empty').classList.remove('hidden'); } else { renderFallows(); } }); } window.onload = initFallowsPage;