💎 — tokens
🚀
No funnel selected

Create a new funnel or select one from the sidebar.

🖥 Live Preview
📄
Save your funnel to see a live preview
`; } function refreshPreview() { if (state.activeFunnelIdx === null) return; const f = activeFunnel(); if (!f || !f.pages?.length) return; const frame = document.getElementById('previewFrame'); const ph = document.getElementById('previewPlaceholder'); frame.srcdoc = buildPreviewHTML(f); frame.style.display = ''; ph.style.display = 'none'; } // ── EXPORT ──────────────────────────────────────────────────────────────────── function exportHTML() { const f = activeFunnel(); if (!f?.id) return; window.open(`/api/bookvaib-funnel-export/${f.id}?token_header=1`, '_blank'); // use fetch with auth header authHeaders().then(h => fetch(`/api/bookvaib-funnel-export/${f.id}`, { headers: h })) .then(r => { if (!r.ok) throw new Error('Export failed'); return r.blob(); }) .then(blob => { const url = URL.createObjectURL(blob); const filename = (f.name||'funnel').replace(/[^a-zA-Z0-9]/g,'-').toLowerCase()+'.html'; const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); saveProject({ name: filename, type: 'funnel-html-export', tool: 'Funnel Builder HTML Export', metadata: { funnelId: f.id }, state: { id: f.id, name: f.name, pages: f.pages, settings: f.settings }, blob, mimeType: blob.type || 'text/html', fileExt: 'html' }); }).catch(e=>alert('Export failed: '+e.message)); } function exportPDF() { const f = activeFunnel(); if (!f?.id) return; authHeaders().then(h => fetch(`/api/bookvaib-funnel-export/${f.id}`, { headers: h })) .then(r => { if (!r.ok) throw new Error('PDF export failed'); return r.blob(); }) .then(blob => { const url = URL.createObjectURL(blob); const w = window.open(url, '_blank'); setTimeout(()=>{ if(w) w.print(); }, 1200); saveProject({ name: (f.name || 'funnel') + '.pdf', type: 'funnel-pdf-export', tool: 'Funnel Builder PDF Export', metadata: { funnelId: f.id }, state: { id: f.id, name: f.name, pages: f.pages, settings: f.settings }, blob, mimeType: blob.type || 'application/pdf', fileExt: 'pdf' }); }).catch(e=>alert('PDF failed: '+e.message)); } // ── HELPERS ─────────────────────────────────────────────────────────────────── function activeFunnel() { return state.activeFunnelIdx !== null ? state.funnels[state.activeFunnelIdx] : null; } function markDirty() { state.dirty = true; const btn = document.getElementById('saveBtn'); if (btn) { btn.disabled = false; btn.textContent = 'Save*'; } } function openModal(id) { document.getElementById(id).classList.add('open'); } function closeModal(id) { document.getElementById(id).classList.remove('open'); } function openNewFunnelModal() { document.getElementById('newFunnelNameInput').value = ''; openModal('newFunnelOverlay'); } function openAiModal() { if (state.activeFunnelIdx === null) { alert('Please select or create a funnel first.'); return; } document.getElementById('aiMsg').style.display='none'; openModal('aiOverlay'); } function syncColor() { const hex = document.getElementById('settColorHex').value; document.getElementById('settColor').value = hex; markDirty(); } document.getElementById('settColor').addEventListener('input', e => { document.getElementById('settColorHex').value = e.target.value; markDirty(); }); function esc(s) { return String(s||'').replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); } // Close modals on overlay click document.querySelectorAll('.overlay').forEach(o => o.addEventListener('click', e => { if(e.target===o) o.classList.remove('open'); }));