Welcome to Voxelant
This demonstration access panel does not submit credentials. Continue browsing the public learning resources.
Browse catalog
Cart
A considered learning plan.
Your cart is empty.
Browse catalog
Order review saved locally
This demonstration has no payment or server processing. Your displayed course selection remains in this browser.
`;
const footerHTML = ``;
function insertHeaderFooter() {
document.querySelector('header').innerHTML = headerHTML;
document.querySelector('footer').innerHTML = footerHTML;
}
function initThemeAndMobileAndAuth() {
const html = document.documentElement;
const saved = localStorage.getItem('voxelant-theme') || 'light';
if (saved === 'dark') {
html.classList.add('dark');
document.body.style.backgroundColor = '#0f172a';
} else {
document.body.style.backgroundColor = '#f8fafc';
}
const toggle = document.querySelector('[data-theme-toggle]');
if (toggle) toggle.addEventListener('click', () => {
const isDark = html.classList.contains('dark');
const next = isDark ? 'light' : 'dark';
if (next === 'dark') {
html.classList.add('dark');
document.body.style.backgroundColor = '#0f172a';
} else {
html.classList.remove('dark');
document.body.style.backgroundColor = '#f8fafc';
}
localStorage.setItem('voxelant-theme', next);
});
const mb = document.getElementById('mobile-menu-btn');
const nav = document.getElementById('site-navigation');
if (mb && nav) mb.addEventListener('click', () => {
const hidden = nav.classList.contains('hidden');
if (hidden) {
nav.classList.remove('hidden');
nav.classList.add('flex', 'flex-col', 'w-full', 'mt-4', 'md:hidden');
mb.setAttribute('aria-expanded', 'true');
mb.textContent = 'Close';
} else {
nav.classList.add('hidden');
nav.classList.remove('flex', 'flex-col', 'w-full', 'mt-4', 'md:hidden');
mb.setAttribute('aria-expanded', 'false');
mb.textContent = 'Menu';
}
});
const authModal = document.getElementById('auth-modal');
document.querySelectorAll('[data-open-auth]').forEach(btn => btn.addEventListener('click', () => {
authModal.removeAttribute('hidden');
}));
const closeBtn = document.querySelector('[data-close-modal]');
if (closeBtn) closeBtn.addEventListener('click', () => authModal.setAttribute('hidden', ''));
}
let catalog = [];
let cart = JSON.parse(localStorage.getItem('voxelant-cart') || '{}');
async function loadData() {
const res = await fetch('./catalog.json');
catalog = await res.json();
renderCart();
}
function saveCart() {
localStorage.setItem('voxelant-cart', JSON.stringify(cart));
}
function renderCart() {
const list = document.getElementById('cart-list');
const empty = document.getElementById('cart-empty');
const summary = document.getElementById('cart-summary');
list.innerHTML = '';
let total = 0;
let hasItems = false;
Object.keys(cart).forEach(id => {
const qty = cart[id];
const item = catalog.find(p => p.id === id);
if (!item || qty < 1) return;
hasItems = true;
const subtotal = item.price * qty;
total += subtotal;
const row = document.createElement('div');
row.className = 'p9k2l flex items-center justify-between border border-slate-200 bg-white px-6 py-5 rounded-xl';
row.innerHTML = `
${item.title}
${item.duration}
${qty}
$${subtotal}
`;
list.appendChild(row);
});
if (hasItems) {
empty.classList.add('hidden');
summary.classList.remove('hidden');
document.getElementById('cart-total').textContent = `Total: $${total}`;
} else {
empty.classList.remove('hidden');
summary.classList.add('hidden');
}
attachCartListeners();
}
function attachCartListeners() {
document.querySelectorAll('[data-inc]').forEach(btn => {
btn.onclick = () => {
const id = btn.getAttribute('data-inc');
cart[id] = (cart[id] || 0) + 1;
saveCart();
renderCart();
};
});
document.querySelectorAll('[data-dec]').forEach(btn => {
btn.onclick = () => {
const id = btn.getAttribute('data-dec');
if (cart[id] > 1) cart[id]--;
saveCart();
renderCart();
};
});
document.querySelectorAll('[data-remove]').forEach(btn => {
btn.onclick = () => {
const id = btn.getAttribute('data-remove');
delete cart[id];
saveCart();
renderCart();
};
});
}
function initCheckout() {
const modal = document.getElementById('checkout-modal');
const btn = document.getElementById('checkout-btn');
const close = document.getElementById('close-checkout');
if (btn) btn.onclick = () => modal.removeAttribute('hidden');
if (close) close.onclick = () => modal.setAttribute('hidden', '');
}
function initCookie() {
const b = document.getElementById('cookie-banner');
if (!b) return;
const key = 'voxelant-cookie-choice';
if (localStorage.getItem(key) === 'accepted') { b.style.display = 'none'; return; }
b.querySelector('[data-close-cookie]').onclick = () => {
localStorage.setItem(key, 'accepted');
b.style.display = 'none';
};
}
function boot() {
insertHeaderFooter();
initThemeAndMobileAndAuth();
initCheckout();
initCookie();
loadData();
}
boot();