document.addEventListener('DOMContentLoaded', () => { const noBtn = document.getElementById('no-btn'); const yesBtn = document.getElementById('yes-btn'); const proposalBox = document.getElementById('proposal-box'); const successBox = document.getElementById('success-message'); const lockBtn = document.getElementById('lock-btn'); const resetBtn = document.getElementById('reset-btn'); const settingsToggle = document.getElementById('settings-toggle'); const settingsPanel = document.getElementById('settings-panel'); const bgColorPicker = document.getElementById('bg-color-picker'); const popupColorPicker = document.getElementById('popup-color-picker'); const bgImageInput = document.getElementById('bg-image-input'); const removeBgBtn = document.getElementById('remove-bg-btn'); const imageRadiusPicker = document.getElementById('image-radius-picker'); const previewPage2Toggle = document.getElementById('preview-page2-toggle'); let yesScale = 1; let isLocked = typeof IS_LOCKED !== 'undefined' ? IS_LOCKED : false; // Audio Context for sounds const AudioCtx = window.AudioContext || window.webkitAudioContext; let audioCtx = null; function playSound(type) { if (!audioCtx) audioCtx = new AudioCtx(); const osc = audioCtx.createOscillator(); const gain = audioCtx.createGain(); osc.connect(gain); gain.connect(audioCtx.destination); const now = audioCtx.currentTime; if (type === 'happy') { // Happy sound: Arpeggio osc.type = 'sine'; osc.frequency.setValueAtTime(523.25, now); // C5 osc.frequency.exponentialRampToValueAtTime(880, now + 0.1); // A5 gain.gain.setValueAtTime(0.3, now); gain.gain.exponentialRampToValueAtTime(0.01, now + 0.3); osc.start(now); osc.stop(now + 0.3); } else { // Less happy sound: Low thud osc.type = 'triangle'; osc.frequency.setValueAtTime(150, now); osc.frequency.exponentialRampToValueAtTime(40, now + 0.2); gain.gain.setValueAtTime(0.3, now); gain.gain.exponentialRampToValueAtTime(0.01, now + 0.2); osc.start(now); osc.stop(now + 0.2); } } // Settings Toggle if (settingsToggle) { settingsToggle.addEventListener('click', () => { settingsPanel.style.display = settingsPanel.style.display === 'none' ? 'flex' : 'none'; }); } // Tabs logic const tabBtns = document.querySelectorAll('.tab-btn'); const tabContents = document.querySelectorAll('.tab-content'); tabBtns.forEach(btn => { btn.addEventListener('click', () => { const tab = btn.dataset.tab; tabBtns.forEach(b => b.classList.remove('active')); tabContents.forEach(c => c.classList.remove('active')); btn.classList.add('active'); document.getElementById(`tab-${tab}`).classList.add('active'); }); }); // Preview Page 2 Toggle if (previewPage2Toggle) { previewPage2Toggle.addEventListener('change', (e) => { if (e.target.checked) { proposalBox.style.display = 'none'; successBox.style.display = 'block'; } else { proposalBox.style.display = 'block'; successBox.style.display = 'none'; } }); } // Image Radius if (imageRadiusPicker) { imageRadiusPicker.addEventListener('input', (e) => { document.documentElement.style.setProperty('--image-radius', `${e.target.value}px`); }); imageRadiusPicker.addEventListener('change', (e) => { saveSetting('image_radius', `${e.target.value}px`); }); } // Generic Setting Inputs const settingInputs = document.querySelectorAll('.setting-input'); settingInputs.forEach(input => { const key = input.dataset.key; input.addEventListener('input', (e) => { let value = e.target.value; // Handle Text Updates if (key === 'p1_title_text') { document.querySelector('.p1-title').textContent = value; } else if (key === 'p2_line1_text') { document.querySelector('.p2-line1').textContent = value; } else if (key === 'p2_line2_text') { document.querySelector('.p2-line2').textContent = value; } else if (key === 'p2_hint_text') { document.querySelector('.redirect-hint').textContent = value; } // Handle CSS Variable Updates let cssKey = key.replace(/_/g, '-'); if (input.type === 'range') { if (key.includes('size')) value += 'rem'; else if (key.includes('radius')) value += 'px'; } document.documentElement.style.setProperty(`--${cssKey}`, value); }); input.addEventListener('change', (e) => { let value = e.target.value; if (input.type === 'range') { if (key.includes('size')) value += 'rem'; else if (key.includes('radius')) value += 'px'; } saveSetting(key, value); }); }); function saveSetting(key, value) { const formData = new FormData(); formData.append('action', 'update_setting'); formData.append('key', key); formData.append('value', value); return fetch('api/save_settings.php', { method: 'POST', body: formData }); } // Color Pickers if (bgColorPicker) { bgColorPicker.addEventListener('input', (e) => { document.documentElement.style.setProperty('--bg-color', e.target.value); }); bgColorPicker.addEventListener('change', (e) => { const formData = new FormData(); formData.append('action', 'update_bg_color'); formData.append('color', e.target.value); fetch('api/save_settings.php', { method: 'POST', body: formData }); }); } if (popupColorPicker) { popupColorPicker.addEventListener('input', (e) => { document.documentElement.style.setProperty('--popup-bg', e.target.value); }); popupColorPicker.addEventListener('change', (e) => { const formData = new FormData(); formData.append('action', 'update_popup_color'); formData.append('color', e.target.value); fetch('api/save_settings.php', { method: 'POST', body: formData }); }); } // Background Image Upload if (bgImageInput) { bgImageInput.addEventListener('change', function() { const file = this.files[0]; if (file) { const formData = new FormData(); formData.append('action', 'upload_bg_image'); formData.append('image', file); fetch('api/save_settings.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { document.documentElement.style.setProperty('--bg-image', `url('${data.path}?t=${new Date().getTime()}')`); location.reload(); // Reload to update the "Remove" button visibility } else { alert(data.error || 'Failed to upload background image'); } }) .catch(error => { console.error('Error:', error); alert('An error occurred during upload.'); }); } }); } if (removeBgBtn) { removeBgBtn.addEventListener('click', () => { const formData = new FormData(); formData.append('action', 'remove_bg_image'); fetch('api/save_settings.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { document.documentElement.style.setProperty('--bg-image', 'none'); location.reload(); } }); }); } // Lock/Unlock Toggle lockBtn.addEventListener('click', () => { const newLockedState = !isLocked; const formData = new FormData(); formData.append('action', 'toggle_lock'); formData.append('lock', newLockedState); fetch('api/save_settings.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { location.reload(); } }); }); // Reset Experience resetBtn.addEventListener('click', () => { if (confirm('Reset experience to page 1? (Positions and sizes will be reset)')) { const formData = new FormData(); formData.append('action', 'reset'); fetch('api/save_settings.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { location.reload(); } }); } }); // "No" Button Dodging Logic const dodgeThreshold = 100; // pixels document.addEventListener('mousemove', (e) => { if (!noBtn || (successBox && successBox.style.display === 'block') || (previewPage2Toggle && previewPage2Toggle.checked)) return; const rect = noBtn.getBoundingClientRect(); const btnCenterX = rect.left + rect.width / 2; const btnCenterY = rect.top + rect.height / 2; const distance = Math.hypot(e.clientX - btnCenterX, e.clientY - btnCenterY); if (distance < dodgeThreshold) { const angle = Math.atan2(e.clientY - btnCenterY, e.clientX - btnCenterX); const moveDist = dodgeThreshold - distance + 20; let newX = rect.left - Math.cos(angle) * moveDist; let newY = rect.top - Math.sin(angle) * moveDist; // Keep within viewport bounds const padding = 20; newX = Math.max(padding, Math.min(window.innerWidth - rect.width - padding, newX)); newY = Math.max(padding, Math.min(window.innerHeight - rect.height - padding, newY)); noBtn.style.position = 'fixed'; noBtn.style.left = `${newX}px`; noBtn.style.top = `${newY}px`; noBtn.style.margin = '0'; } }); // "No" Click Logic if (noBtn) { noBtn.addEventListener('click', (e) => { e.preventDefault(); playSound('sad'); yesScale += 0.15; yesBtn.style.transform = `scale(${yesScale})`; }); } // "Yes" Click Logic if (yesBtn) { yesBtn.addEventListener('click', () => { playSound('happy'); proposalBox.style.display = 'none'; successBox.style.display = 'block'; // Hide controls during celebration document.querySelector('.admin-controls').style.display = 'none'; // Confetti effect const duration = 15 * 1000; const animationEnd = Date.now() + duration; const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 }; function randomInRange(min, max) { return Math.random() * (max - min) + min; } const interval = setInterval(function() { const timeLeft = animationEnd - Date.now(); if (timeLeft <= 0) { return clearInterval(interval); } const particleCount = 50 * (timeLeft / duration); confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } })); confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } })); }, 250); // Redirect after 15s setTimeout(() => { window.location.href = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"; }, 15000); }); } });