Your Cart

Everything you need to keep your hands moving with calm intention.

`; // Footer HTML footerEl.innerHTML = ` `; // Attach header/footer logic setupHeaderInteractions(); setupCookieBanner(); } function setupHeaderInteractions() { const mobileBtn = document.getElementById('open-mobile'); const mobileMenu = document.getElementById('mobile-menu'); if (mobileBtn && mobileMenu) { mobileBtn.addEventListener('click', () => mobileMenu.classList.toggle('hidden')); } // Theme toggler const themeBtn = document.getElementById('open-theme'); if (themeBtn) { themeBtn.addEventListener('click', () => { const isDark = document.documentElement.classList.contains('dark'); window.__kn_applyTheme(isDark ? 'light' : 'dark'); }); } // Update cart counts updateNavCounts(); } function updateNavCounts() { const cart = JSON.parse(localStorage.getItem('knotnode_cart') || '[]'); const count = cart.reduce((sum, item) => sum + item.qty, 0); const navCount = document.getElementById('nav-cart-count'); const mCount = document.getElementById('m-cart-count'); if (navCount) navCount.textContent = count; if (mCount) mCount.textContent = count; } function setupCookieBanner() { const banner = document.getElementById('cookie-banner'); if (!banner) return; if (!localStorage.getItem('knotnode_cookies')) { setTimeout(() => banner.classList.remove('hidden'), 1800); } const accept = document.getElementById('cookie-accept'); const decline = document.getElementById('cookie-decline'); if (accept) accept.onclick = () => { localStorage.setItem('knotnode_cookies', 'accepted'); banner.classList.add('hidden'); }; if (decline) decline.onclick = () => { localStorage.setItem('knotnode_cookies', 'declined'); banner.classList.add('hidden'); }; } // CART LOGIC let catalogData = []; async function loadCatalog() { try { const res = await fetch('./catalog.json'); catalogData = await res.json(); } catch (e) { catalogData = []; } } function getCart() { return JSON.parse(localStorage.getItem('knotnode_cart') || '[]'); } function saveCart(cart) { localStorage.setItem('knotnode_cart', JSON.stringify(cart)); updateNavCounts(); } function updateQuantity(itemId, newQty) { let cart = getCart(); const item = cart.find(i => i.id === itemId); if (!item) return; if (newQty < 1) newQty = 1; item.qty = newQty; saveCart(cart); renderCart(); } function removeFromCart(itemId) { let cart = getCart(); cart = cart.filter(i => i.id !== itemId); saveCart(cart); renderCart(); } function calculateTotal(cart) { return cart.reduce((sum, item) => { const prod = catalogData.find(p => p.id === item.id); const price = prod ? prod.price : 0; return sum + (price * item.qty); }, 0); } function renderCart() { const list = document.getElementById('cart-list'); const summary = document.getElementById('summary'); const empty = document.getElementById('empty-state'); const cart = getCart(); list.innerHTML = ''; if (cart.length === 0) { empty.classList.remove('hidden'); summary.classList.add('hidden'); return; } else { empty.classList.add('hidden'); summary.classList.remove('hidden'); } cart.forEach(cartItem => { const product = catalogData.find(p => p.id === cartItem.id); if (!product) return; const itemTotal = (product.price * cartItem.qty).toFixed(2); const div = document.createElement('div'); div.className = `dd23l border border-rose-200 dark:border-slate-700 bg-white/70 dark:bg-slate-900/70 rounded-3xl p-6 flex flex-col sm:flex-row items-center gap-6`; div.innerHTML = `
🧵
${product.title}
${product.duration} · ${product.level}
$${(product.price * cartItem.qty).toFixed(2)}
${cartItem.qty}
`; list.appendChild(div); // Bind buttons const minusBtn = div.querySelector('[data-action="minus"]'); const plusBtn = div.querySelector('[data-action="plus"]'); const removeBtn = div.querySelector('[data-action="remove"]'); minusBtn.addEventListener('click', () => updateQuantity(cartItem.id, cartItem.qty - 1)); plusBtn.addEventListener('click', () => updateQuantity(cartItem.id, cartItem.qty + 1)); removeBtn.addEventListener('click', () => removeFromCart(cartItem.id)); }); const subtotalEl = document.getElementById('subtotal'); subtotalEl.textContent = '$' + calculateTotal(cart).toFixed(2); } function setupCheckout() { const checkoutBtn = document.getElementById('checkout-btn'); const modal = document.getElementById('checkout-modal'); const closeBtn = document.getElementById('close-checkout'); if (checkoutBtn) { checkoutBtn.addEventListener('click', () => { modal.style.display = 'flex'; const cart = getCart(); if (cart.length > 0) { localStorage.removeItem('knotnode_cart'); updateNavCounts(); } }); } if (closeBtn) { closeBtn.addEventListener('click', () => modal.style.display = 'none'); } modal.addEventListener('click', (e) => { if (e.target === modal) modal.style.display = 'none'; }); } async function initialize() { await injectHeaderFooter(); await loadCatalog(); renderCart(); setupCheckout(); // Make sure cart count is correct on load updateNavCounts(); } window.onload = initialize; })();