OnCamera Collective

Sign in

Use a strong password. We never ask for one-time codes via DMs.

Create account

Theme

Your Fallows

These are saved locally on your device. You can remove items anytime.

Back to catalog Go to cart

Choose theme

Sign in

Use a strong password. We never store plain text passwords.

Create account

`; const footerHTML = ` `; document.querySelector('header').innerHTML = headerHTML; document.querySelector('footer').innerHTML = footerHTML; } function initTheme() { const savedTheme = localStorage.getItem('theme'); if (savedTheme === 'dark') document.documentElement.classList.add('dark'); else if (savedTheme === 'light') document.documentElement.classList.remove('dark'); } function initModalsAndNav() { const $ = (s) => document.querySelector(s); const $$ = (s) => document.querySelectorAll(s); // Theme buttons $$('#openTheme, #openThemeMobile').forEach(btn => btn?.addEventListener('click', () => $('#themeModal')?.showModal())); // Login / Register $$('#openLogin, #openLoginMobile').forEach(btn => btn?.addEventListener('click', () => $('#loginModal')?.showModal())); $$('#openRegister, #openRegisterMobile').forEach(btn => btn?.addEventListener('click', () => $('#registerModal')?.showModal())); // Close modals $$('[data-close-modal]').forEach(btn => { btn.addEventListener('click', (e) => { const target = e.currentTarget.getAttribute('data-close-modal'); if (target) document.querySelector(target)?.close(); }); }); // Mobile menu $('#mobileMenuBtn')?.addEventListener('click', () => { const menu = $('#mobileMenu'); if (menu) menu.classList.toggle('hidden'); }); // Theme selection $$('[data-theme]').forEach(btn => { btn.addEventListener('click', () => { const mode = btn.getAttribute('data-theme'); if (mode === 'dark') { document.documentElement.classList.add('dark'); localStorage.setItem('theme', 'dark'); } else { document.documentElement.classList.remove('dark'); localStorage.setItem('theme', 'light'); } $('#themeModal')?.close(); }); }); } async function loadFallows() { let catalog = []; try { const res = await fetch('./catalog.json'); catalog = await res.json(); } catch (e) { catalog = []; } const savedIds = JSON.parse(localStorage.getItem('fallows') || '[]'); const listEl = document.getElementById('favList'); const emptyEl = document.getElementById('emptyState'); listEl.innerHTML = ''; const fallows = catalog.filter(item => savedIds.includes(item.id)); if (fallows.length === 0) { emptyEl.classList.remove('hidden'); return; } emptyEl.classList.add('hidden'); fallows.forEach(course => { const li = document.createElement('li'); li.className = `xj9k2 p2aql border border-rose-200 dark:border-slate-700 rounded-3xl p-6 bg-white dark:bg-slate-800`; li.innerHTML = `
${course.category}

${course.title}

${course.short}

${course.level} • ${course.durationHours}h
$${course.priceUSD}
`; listEl.appendChild(li); }); // Remove handlers listEl.querySelectorAll('[data-remove]').forEach(btn => { btn.addEventListener('click', () => { const id = parseInt(btn.getAttribute('data-remove')); removeFallow(id); }); }); } function removeFallow(id) { let saved = JSON.parse(localStorage.getItem('fallows') || '[]'); saved = saved.filter(item => item !== id); localStorage.setItem('fallows', JSON.stringify(saved)); loadFallows(); } function initActions() { document.getElementById('clearAll').addEventListener('click', () => { if (confirm('Clear all fallows?')) { localStorage.setItem('fallows', '[]'); loadFallows(); } }); document.getElementById('exportIds').addEventListener('click', () => { const ids = JSON.parse(localStorage.getItem('fallows') || '[]'); const dataStr = JSON.stringify(ids, null, 2); const blob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'fallows-ids.json'; a.click(); URL.revokeObjectURL(url); }); } function initCookieBanner() { const banner = document.getElementById('cookieBanner'); if (!localStorage.getItem('cookieConsent')) { banner.classList.remove('hidden'); } document.getElementById('acceptCookies')?.addEventListener('click', () => { localStorage.setItem('cookieConsent', 'yes'); banner.classList.add('hidden'); }); } async function initialize() { initTailwind(); await injectHeaderFooter(); initTheme(); initModalsAndNav(); initActions(); await loadFallows(); initCookieBanner(); } window.onload = initialize;