diff --git a/api/save_settings.php b/api/save_settings.php index 9340e8e..36d9eb0 100644 --- a/api/save_settings.php +++ b/api/save_settings.php @@ -57,6 +57,22 @@ if ($action === 'upload_bg_image') { } else { echo json_encode(['success' => false, 'error' => 'Invalid color format.']); } +} elseif ($action === 'update_setting') { + $key = $_POST['key'] ?? ''; + $value = $_POST['value'] ?? ''; + $allowedKeys = [ + 'p1_title_color', 'p1_title_size', 'p1_title_font', 'p1_title_text', + 'p2_text_color', 'p2_text_size', 'p2_text_font', 'p2_line1_text', 'p2_line2_text', + 'p2_hint_color', 'p2_hint_size', 'p2_hint_font', 'p2_hint_text', + 'image_radius' + ]; + if (in_array($key, $allowedKeys)) { + $stmt = db()->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = ?"); + $stmt->execute([$value, $key]); + echo json_encode(['success' => true]); + } else { + echo json_encode(['success' => false, 'error' => 'Invalid setting key.']); + } } elseif ($action === 'remove_bg_image') { $stmt = db()->prepare("UPDATE settings SET setting_value = '' WHERE setting_key = 'bg_image'"); $stmt->execute(); @@ -67,16 +83,8 @@ if ($action === 'upload_bg_image') { $stmt->execute([$lockValue]); echo json_encode(['success' => true, 'locked' => $lockValue === '1']); } elseif ($action === 'reset') { - $stmt = db()->prepare("UPDATE settings SET setting_value = 'assets/pasted-20260206-164030-456a591e.jpg' WHERE setting_key = 'valentine_image'"); - $stmt->execute(); - $stmt = db()->prepare("UPDATE settings SET setting_value = '0' WHERE setting_key = 'is_locked'"); - $stmt->execute(); - $stmt = db()->prepare("UPDATE settings SET setting_value = '#ffe4e6' WHERE setting_key = 'bg_color'"); - $stmt->execute(); - $stmt = db()->prepare("UPDATE settings SET setting_value = '' WHERE setting_key = 'bg_image'"); - $stmt->execute(); - $stmt = db()->prepare("UPDATE settings SET setting_value = '#ffccd5' WHERE setting_key = 'popup_color'"); - $stmt->execute(); + // Reset button positions and sizes is handled by reloading the page in the frontend. + // We no longer reset colors or text content here. echo json_encode(['success' => true]); } else { echo json_encode(['success' => false, 'error' => 'Invalid action.']); diff --git a/assets/css/custom.css b/assets/css/custom.css index 2694f50..15d5c76 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -7,6 +7,20 @@ --secondary-text: #636e72; --border-color: rgba(0,0,0,0.05); --font-family: 'Inter', system-ui, -apple-system, sans-serif; + + --p1-title-color: #e63946; + --p1-title-size: 1.75rem; + --p1-title-font: 'Inter'; + + --p2-text-color: #e63946; + --p2-text-size: 1.25rem; + --p2-text-font: 'Inter'; + + --p2-hint-color: #636e72; + --p2-hint-size: 0.85rem; + --p2-hint-font: 'Inter'; + + --image-radius: 12px; } body { @@ -71,10 +85,46 @@ body { display: flex; flex-direction: column; gap: 0.75rem; - width: 200px; + width: 250px; animation: slideDown 0.3s ease; } +.settings-tabs { + display: flex; + border-bottom: 1px solid #eee; + margin-bottom: 0.5rem; +} + +.tab-btn { + background: none !important; + border: none !important; + border-bottom: 2px solid transparent !important; + border-radius: 0 !important; + padding: 0.5rem !important; + width: auto !important; + height: auto !important; + font-size: 0.8rem !important; + font-weight: 600; + cursor: pointer; + color: var(--secondary-text) !important; + box-shadow: none !important; +} + +.tab-btn.active { + border-bottom-color: var(--primary-color) !important; + color: var(--primary-color) !important; +} + +.tab-content { + display: none; + flex-direction: column; + gap: 0.75rem; +} + +.tab-content.active { + display: flex; +} + @keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } @@ -92,7 +142,8 @@ body { color: var(--secondary-text); } -.settings-group input[type="color"] { +.settings-group input[type="color"], +.settings-group select { width: 100%; height: 30px; border: 1px solid var(--border-color); @@ -100,6 +151,10 @@ body { cursor: pointer; } +.settings-group input[type="range"] { + width: 100%; +} + .settings-group .btn-small { padding: 4px 8px; font-size: 0.7rem; @@ -121,12 +176,13 @@ body { position: relative; } -h1 { - font-size: 1.75rem; +h1.p1-title { + font-size: var(--p1-title-size); + font-family: var(--p1-title-font), var(--font-family); + color: var(--p1-title-color); font-weight: 700; margin-bottom: 1.5rem; letter-spacing: -0.5px; - color: var(--primary-color); } .image-preview-container { @@ -134,7 +190,7 @@ h1 { height: 250px; background-color: rgba(255, 255, 255, 0.5); border: 2px solid rgba(0,0,0,0.05); - border-radius: 12px; + border-radius: var(--image-radius); margin-bottom: 1.5rem; display: flex; justify-content: center; @@ -199,20 +255,28 @@ h1 { } .success-text { - font-size: 1.25rem; + font-size: var(--p2-text-size); + font-family: var(--p2-text-font), var(--font-family); + color: var(--p2-text-color); line-height: 1.6; - color: var(--primary-color); font-weight: 700; margin-bottom: 0.5rem; } .redirect-hint { margin-top: 2rem; - font-size: 0.85rem; - color: var(--secondary-text); + font-size: var(--p2-hint-size); + font-family: var(--p2-hint-font), var(--font-family); + color: var(--p2-hint-color); font-style: italic; } #image-input, #bg-image-input { display: none; +} + +hr { + border: none; + border-top: 1px solid #eee; + margin: 0.5rem 0; } \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js index fc15cca..bd8da88 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -11,6 +11,8 @@ document.addEventListener('DOMContentLoaded', () => { 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; @@ -22,6 +24,87 @@ document.addEventListener('DOMContentLoaded', () => { }); } + // 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 + if (input.type === 'range') { + if (key.includes('size')) value += 'rem'; + else if (key.includes('radius')) value += 'px'; + } + document.documentElement.style.setProperty(`--${key.replace(/_/g, '-')}`, 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) => { @@ -113,7 +196,7 @@ document.addEventListener('DOMContentLoaded', () => { // Reset Experience resetBtn.addEventListener('click', () => { - if (confirm('Reset everything to defaults?')) { + if (confirm('Reset experience to page 1? (Positions and sizes will be reset)')) { const formData = new FormData(); formData.append('action', 'reset'); @@ -134,7 +217,7 @@ document.addEventListener('DOMContentLoaded', () => { const dodgeThreshold = 100; // pixels document.addEventListener('mousemove', (e) => { - if (!noBtn || (successBox && successBox.style.display === 'block')) return; + if (!noBtn || (successBox && successBox.style.display === 'block') || (previewPage2Toggle && previewPage2Toggle.checked)) return; const rect = noBtn.getBoundingClientRect(); const btnCenterX = rect.left + rect.width / 2; @@ -206,4 +289,4 @@ document.addEventListener('DOMContentLoaded', () => { }, 15000); }); } -}); +}); \ No newline at end of file diff --git a/db/migrations/003_add_text_and_image_settings.sql b/db/migrations/003_add_text_and_image_settings.sql new file mode 100644 index 0000000..5bdc85b --- /dev/null +++ b/db/migrations/003_add_text_and_image_settings.sql @@ -0,0 +1,12 @@ +INSERT INTO settings (setting_key, setting_value) VALUES +('p1_title_color', '#e63946'), +('p1_title_size', '1.75rem'), +('p1_title_font', 'Inter'), +('p2_text_color', '#e63946'), +('p2_text_size', '1.25rem'), +('p2_text_font', 'Inter'), +('p2_hint_color', '#636e72'), +('p2_hint_size', '0.85rem'), +('p2_hint_font', 'Inter'), +('image_radius', '12px') +ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value); diff --git a/db/migrations/004_add_text_content_settings.sql b/db/migrations/004_add_text_content_settings.sql new file mode 100644 index 0000000..a4c89aa --- /dev/null +++ b/db/migrations/004_add_text_content_settings.sql @@ -0,0 +1,6 @@ +-- Add text content settings +INSERT IGNORE INTO settings (setting_key, setting_value) VALUES +('p1_title_text', 'Gvantsa, would you be my valentine?'), +('p2_line1_text', 'Congratulations, you are now Sam\'s Valentine! ❤️'), +('p2_line2_text', 'He is so incredibly lucky to have someone in his life who would click yes.'), +('p2_hint_text', 'Redirecting you to a special surprise in 15 seconds...'); diff --git a/index.php b/index.php index 3b39361..683ee9a 100644 --- a/index.php +++ b/index.php @@ -12,15 +12,36 @@ $isLocked = ($settings['is_locked'] ?? '0') === '1'; $bgColor = $settings['bg_color'] ?? '#ffe4e6'; $bgImage = $settings['bg_image'] ?? ''; $popupColor = $settings['popup_color'] ?? '#ffccd5'; + +// New settings +$p1TitleColor = $settings['p1_title_color'] ?? '#e63946'; +$p1TitleSize = $settings['p1_title_size'] ?? '1.75rem'; +$p1TitleFont = $settings['p1_title_font'] ?? 'Inter'; +$p1TitleText = $settings['p1_title_text'] ?? 'Gvantsa, would you be my valentine?'; + +$p2TextColor = $settings['p2_text_color'] ?? '#e63946'; +$p2TextSize = $settings['p2_text_size'] ?? '1.25rem'; +$p2TextFont = $settings['p2_text_font'] ?? 'Inter'; +$p2Line1Text = $settings['p2_line1_text'] ?? "Congratulations, you are now Sam's Valentine! ❤️"; +$p2Line2Text = $settings['p2_line2_text'] ?? 'He is so incredibly lucky to have someone in his life who would click yes.'; + +$p2HintColor = $settings['p2_hint_color'] ?? '#636e72'; +$p2HintSize = $settings['p2_hint_size'] ?? '0.85rem'; +$p2HintFont = $settings['p2_hint_font'] ?? 'Inter'; +$p2HintText = $settings['p2_hint_text'] ?? 'Redirecting you to a special surprise in 15 seconds...'; + +$imageRadius = $settings['image_radius'] ?? '12px'; + +$fonts = ['Inter', 'Arial', 'Verdana', 'Times New Roman', 'Georgia', 'Courier New', 'Brush Script MT', 'Comic Sans MS']; ?> - Gvantsa, would you be my valentine? + <?= htmlspecialchars($p1TitleText) ?> @@ -40,6 +61,20 @@ $popupColor = $settings['popup_color'] ?? '#ffccd5'; --bg-color: ; --popup-bg: ; --bg-image: ; + + --p1-title-color: ; + --p1-title-size: ; + --p1-title-font: ; + + --p2-text-color: ; + --p2-text-size: ; + --p2-text-font: ; + + --p2-hint-color: ; + --p2-hint-size: ; + --p2-hint-font: ; + + --image-radius: ; } @@ -63,28 +98,116 @@ $popupColor = $settings['popup_color'] ?? '#ffccd5';