| <!DOCTYPE html> |
| <html lang="ar" dir="rtl"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Be My Valentine 💖</title> |
| <style> |
| * { |
| margin: 0; |
| padding: 0; |
| box-sizing: border-box; |
| } |
| |
| body { |
| font-family: 'Arial', sans-serif; |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| min-height: 100vh; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| overflow: hidden; |
| position: relative; |
| } |
| |
| |
| body.custom-bg { |
| background-image: var(--bg-image); |
| background-size: cover; |
| background-position: center; |
| } |
| |
| body.custom-bg::before { |
| content: ''; |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| background: rgba(0, 0, 0, 0.3); |
| z-index: 0; |
| } |
| |
| .container { |
| text-align: center; |
| background: white; |
| padding: 50px; |
| border-radius: 30px; |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); |
| max-width: 600px; |
| position: relative; |
| z-index: 1; |
| } |
| |
| h1 { |
| font-size: 2.5em; |
| margin-bottom: 30px; |
| color: #ff1744; |
| text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1); |
| } |
| |
| .valentine-text { |
| color: #e91e63; |
| } |
| |
| |
| .characters-container { |
| display: flex; |
| justify-content: center; |
| align-items: flex-end; |
| gap: 20px; |
| margin: 30px 0; |
| min-height: 250px; |
| position: relative; |
| } |
| |
| .character { |
| position: relative; |
| animation: bounce 2s ease-in-out infinite; |
| } |
| |
| .character img { |
| width: 180px; |
| height: 180px; |
| object-fit: contain; |
| filter: drop-shadow(0 5px 15px rgba(0, 0, 0, 0.2)); |
| } |
| |
| |
| .stitch { |
| animation-delay: 0s; |
| } |
| |
| |
| .angela { |
| animation-delay: 1s; |
| } |
| |
| @keyframes bounce { |
| 0%, 100% { |
| transform: translateY(0) scale(1); |
| } |
| 50% { |
| transform: translateY(-20px) scale(1.05); |
| } |
| } |
| |
| |
| .heart-between { |
| position: absolute; |
| top: 30%; |
| left: 50%; |
| transform: translate(-50%, -50%); |
| font-size: 50px; |
| animation: pulse 1.5s ease-in-out infinite; |
| z-index: 10; |
| } |
| |
| @keyframes pulse { |
| 0%, 100% { |
| transform: translate(-50%, -50%) scale(1); |
| opacity: 1; |
| } |
| 50% { |
| transform: translate(-50%, -50%) scale(1.3); |
| opacity: 0.8; |
| } |
| } |
| |
| |
| .sticker { |
| position: absolute; |
| width: 100px; |
| height: 100px; |
| object-fit: contain; |
| animation: rotate-float 6s ease-in-out infinite; |
| z-index: 2; |
| } |
| |
| .sticker1 { |
| top: -30px; |
| right: -30px; |
| } |
| |
| .sticker2 { |
| bottom: -30px; |
| left: -30px; |
| animation-delay: 3s; |
| } |
| |
| @keyframes rotate-float { |
| 0%, 100% { |
| transform: rotate(0deg) translateY(0); |
| } |
| 25% { |
| transform: rotate(10deg) translateY(-10px); |
| } |
| 50% { |
| transform: rotate(-10deg) translateY(-5px); |
| } |
| 75% { |
| transform: rotate(5deg) translateY(-15px); |
| } |
| } |
| |
| .question { |
| font-size: 1.8em; |
| color: #f44336; |
| margin: 30px 0; |
| font-weight: bold; |
| } |
| |
| .buttons { |
| display: flex; |
| gap: 20px; |
| justify-content: center; |
| align-items: center; |
| margin-top: 30px; |
| flex-wrap: wrap; |
| position: relative; |
| min-height: 80px; |
| } |
| |
| .yes-button { |
| background: #ff1744; |
| color: white; |
| border: none; |
| padding: 20px 60px; |
| font-size: 2em; |
| border-radius: 15px; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| font-weight: bold; |
| box-shadow: 0 5px 15px rgba(255, 23, 68, 0.4); |
| } |
| |
| .yes-button:hover { |
| background: #d81b60; |
| transform: scale(1.1); |
| box-shadow: 0 8px 25px rgba(255, 23, 68, 0.6); |
| } |
| |
| .yes-button:active { |
| transform: scale(1.05); |
| } |
| |
| .no-button { |
| background: #9e9e9e; |
| color: white; |
| border: none; |
| padding: 8px 20px; |
| font-size: 0.9em; |
| border-radius: 10px; |
| cursor: pointer; |
| position: absolute; |
| transition: all 0.2s ease; |
| white-space: nowrap; |
| } |
| |
| .no-button:hover { |
| background: #757575; |
| } |
| |
| .hearts { |
| position: fixed; |
| top: -10%; |
| width: 100%; |
| height: 100%; |
| pointer-events: none; |
| z-index: 9999; |
| } |
| |
| .heart { |
| position: absolute; |
| font-size: 30px; |
| animation: fall linear infinite; |
| opacity: 0; |
| } |
| |
| @keyframes fall { |
| 0% { |
| opacity: 1; |
| top: -10%; |
| transform: translateX(0); |
| } |
| 100% { |
| opacity: 0; |
| top: 110%; |
| transform: translateX(50px); |
| } |
| } |
| |
| .success-message { |
| display: none; |
| position: fixed; |
| top: 50%; |
| left: 50%; |
| transform: translate(-50%, -50%) scale(0); |
| background: white; |
| padding: 60px; |
| border-radius: 30px; |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4); |
| z-index: 10000; |
| text-align: center; |
| transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); |
| } |
| |
| .success-message.show { |
| display: block; |
| transform: translate(-50%, -50%) scale(1); |
| } |
| |
| .success-message h2 { |
| font-size: 3em; |
| color: #ff1744; |
| margin-bottom: 20px; |
| } |
| |
| .success-message p { |
| font-size: 1.5em; |
| color: #666; |
| } |
| |
| .emoji { |
| font-size: 4em; |
| animation: spin-pulse 2s ease-in-out infinite; |
| } |
| |
| @keyframes spin-pulse { |
| 0%, 100% { |
| transform: scale(1) rotate(0deg); |
| } |
| 25% { |
| transform: scale(1.2) rotate(-10deg); |
| } |
| 75% { |
| transform: scale(1.2) rotate(10deg); |
| } |
| } |
| |
| |
| .sparkle { |
| position: absolute; |
| width: 5px; |
| height: 5px; |
| background: #ffd700; |
| border-radius: 50%; |
| pointer-events: none; |
| animation: sparkle-animation 1s ease-out forwards; |
| } |
| |
| @keyframes sparkle-animation { |
| 0% { |
| opacity: 1; |
| transform: translate(0, 0) scale(0); |
| } |
| 100% { |
| opacity: 0; |
| transform: translate(var(--tx), var(--ty)) scale(1); |
| } |
| } |
| |
| |
| .admin-link { |
| position: fixed; |
| bottom: 20px; |
| left: 20px; |
| background: rgba(255, 255, 255, 0.9); |
| padding: 10px 20px; |
| border-radius: 10px; |
| text-decoration: none; |
| color: #666; |
| font-size: 14px; |
| box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); |
| transition: all 0.3s; |
| z-index: 100; |
| } |
| |
| .admin-link:hover { |
| background: white; |
| transform: translateY(-2px); |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); |
| } |
| |
| |
| .music-control { |
| position: fixed; |
| bottom: 20px; |
| right: 20px; |
| background: rgba(255, 255, 255, 0.9); |
| border: none; |
| width: 60px; |
| height: 60px; |
| border-radius: 50%; |
| cursor: pointer; |
| font-size: 24px; |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); |
| transition: all 0.3s; |
| z-index: 100; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| } |
| |
| .music-control:hover { |
| background: white; |
| transform: scale(1.1); |
| box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3); |
| } |
| |
| .music-control:active { |
| transform: scale(0.95); |
| } |
| |
| .music-control.playing { |
| background: linear-gradient(135deg, #ff1744 0%, #e91e63 100%); |
| color: white; |
| animation: music-pulse 2s ease-in-out infinite; |
| } |
| |
| @keyframes music-pulse { |
| 0%, 100% { |
| box-shadow: 0 4px 15px rgba(255, 23, 68, 0.4); |
| } |
| 50% { |
| box-shadow: 0 4px 25px rgba(255, 23, 68, 0.8); |
| } |
| } |
| </style> |
| </head> |
| <body> |
| <div class="hearts" id="hearts"></div> |
| |
| <div class="container"> |
| |
| <img id="sticker1" class="sticker sticker1" style="display: none;"> |
| <img id="sticker2" class="sticker sticker2" style="display: none;"> |
| |
| <h1>Be My <span class="valentine-text">Valentine</span> 💖</h1> |
| |
| |
| <div class="characters-container"> |
| <div class="character stitch"> |
| <img id="stitchImg" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Ctext x='50%25' y='50%25' font-size='120' text-anchor='middle' dominant-baseline='middle'%3E💙%3C/text%3E%3C/svg%3E" alt="Stitch"> |
| </div> |
| |
| <div class="heart-between">💕</div> |
| |
| <div class="character angela"> |
| <img id="angelaImg" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Ctext x='50%25' y='50%25' font-size='120' text-anchor='middle' dominant-baseline='middle'%3E🐱%3C/text%3E%3C/svg%3E" alt="Angela"> |
| </div> |
| </div> |
| |
| <p class="question">Will you be my Valentine?</p> |
| |
| <div class="buttons"> |
| <button class="yes-button" onclick="handleYesClick()">Yes 💖</button> |
| <button class="no-button" id="noButton" onmouseover="moveButton()" onclick="moveButton()">Pookie please...</button> |
| </div> |
| </div> |
|
|
| <div class="success-message" id="successMessage"> |
| <div class="emoji">💕</div> |
| <h2>يااااي! 🎉</h2> |
| <p>I knew you'd say yes! 💖</p> |
| <div class="emoji">😍</div> |
| </div> |
|
|
| <a href="/admin" class="admin-link">⚙️ تخصيص الصور</a> |
|
|
| |
| <audio id="bgMusic" loop> |
| <source id="musicSource" src="" type="audio/mpeg"> |
| </audio> |
|
|
| |
| <button class="music-control" id="musicControl" onclick="toggleMusic()"> |
| <span id="musicIcon">🔇</span> |
| </button> |
|
|
| <script> |
| let messageIndex = 0; |
| const messages = [ |
| "Pookie please... 🥺", |
| "Are you sure? 💔", |
| "Please say yes! 🙏", |
| "Don't break my heart 😢", |
| "Just click Yes! 💕", |
| "Come on! 😭", |
| "Pretty please? 🥹", |
| "I'll be sad... 💔", |
| "Think again! 🤔", |
| "Last chance! 💖" |
| ]; |
| |
| let musicPlaying = false; |
| const bgMusic = document.getElementById('bgMusic'); |
| const musicControl = document.getElementById('musicControl'); |
| const musicIcon = document.getElementById('musicIcon'); |
| |
| |
| function toggleMusic() { |
| if (musicPlaying) { |
| pauseMusic(); |
| } else { |
| playMusic(); |
| } |
| } |
| |
| function playMusic() { |
| if (bgMusic.src && bgMusic.src !== window.location.href) { |
| |
| bgMusic.play().then(() => { |
| musicPlaying = true; |
| musicControl.classList.add('playing'); |
| musicIcon.textContent = '🔊'; |
| }).catch(err => { |
| console.log('Music play failed, using generated melody:', err); |
| playGeneratedMelody(); |
| musicPlaying = true; |
| musicControl.classList.add('playing'); |
| musicIcon.textContent = '🔊'; |
| }); |
| } else { |
| |
| playGeneratedMelody(); |
| musicPlaying = true; |
| musicControl.classList.add('playing'); |
| musicIcon.textContent = '🔊'; |
| } |
| } |
| |
| function pauseMusic() { |
| if (bgMusic) { |
| bgMusic.pause(); |
| } |
| stopGeneratedMelody(); |
| musicPlaying = false; |
| musicControl.classList.remove('playing'); |
| musicIcon.textContent = '🔇'; |
| } |
| |
| |
| function attemptAutoPlay() { |
| |
| const playPromise = bgMusic.play(); |
| |
| if (playPromise !== undefined) { |
| playPromise.then(() => { |
| musicPlaying = true; |
| musicControl.classList.add('playing'); |
| musicIcon.textContent = '🔊'; |
| }).catch(() => { |
| |
| console.log('Auto-play blocked. User interaction required.'); |
| }); |
| } |
| } |
| |
| |
| async function loadCustomMusic() { |
| try { |
| const response = await fetch('/get-music'); |
| const data = await response.json(); |
| |
| if (data.music_file) { |
| document.getElementById('musicSource').src = `/uploads/${data.music_file}`; |
| bgMusic.load(); |
| } else { |
| |
| loadDefaultMusic(); |
| } |
| } catch (error) { |
| |
| loadDefaultMusic(); |
| } |
| } |
| |
| |
| function loadDefaultMusic() { |
| const romanticMusic = [ |
| |
| 'https://cdn.pixabay.com/audio/2022/03/10/audio_2c90ba57ce.mp3', |
| |
| 'https://cdn.pixabay.com/audio/2022/05/27/audio_1808fbf07a.mp3', |
| |
| 'https://cdn.pixabay.com/audio/2023/02/28/audio_bd3b3c6a8b.mp3', |
| |
| 'https://cdn.pixabay.com/audio/2022/03/24/audio_c0b2ea6da7.mp3', |
| |
| 'https://cdn.pixabay.com/audio/2022/10/25/audio_438a304e6e.mp3' |
| ]; |
| |
| |
| const randomMusic = romanticMusic[Math.floor(Math.random() * romanticMusic.length)]; |
| const musicSource = document.getElementById('musicSource'); |
| musicSource.src = randomMusic; |
| bgMusic.load(); |
| |
| |
| bgMusic.onerror = function() { |
| console.log('Failed to load music, trying alternative...'); |
| const currentIndex = romanticMusic.findIndex(url => url === musicSource.src); |
| if (currentIndex !== -1) { |
| const nextIndex = (currentIndex + 1) % romanticMusic.length; |
| if (nextIndex !== currentIndex) { |
| musicSource.src = romanticMusic[nextIndex]; |
| bgMusic.load(); |
| } else { |
| |
| console.log('All external music failed, using generated melody'); |
| playGeneratedMelody(); |
| } |
| } |
| }; |
| } |
| |
| |
| let audioContext; |
| let isGeneratedMusicPlaying = false; |
| |
| function playGeneratedMelody() { |
| if (!audioContext) { |
| audioContext = new (window.AudioContext || window.webkitAudioContext)(); |
| } |
| |
| if (isGeneratedMusicPlaying) return; |
| isGeneratedMusicPlaying = true; |
| |
| |
| const romanticMelody = [ |
| { note: 523.25, duration: 0.5 }, |
| { note: 587.33, duration: 0.5 }, |
| { note: 659.25, duration: 0.5 }, |
| { note: 698.46, duration: 0.5 }, |
| { note: 783.99, duration: 1.0 }, |
| { note: 659.25, duration: 0.5 }, |
| { note: 587.33, duration: 0.5 }, |
| { note: 523.25, duration: 1.0 }, |
| { note: 587.33, duration: 0.5 }, |
| { note: 659.25, duration: 0.5 }, |
| { note: 698.46, duration: 1.0 }, |
| { note: 659.25, duration: 0.5 }, |
| { note: 587.33, duration: 1.5 }, |
| ]; |
| |
| function playNote(frequency, duration, startTime) { |
| const oscillator = audioContext.createOscillator(); |
| const gainNode = audioContext.createGain(); |
| |
| oscillator.connect(gainNode); |
| gainNode.connect(audioContext.destination); |
| |
| oscillator.frequency.value = frequency; |
| oscillator.type = 'sine'; |
| |
| |
| gainNode.gain.setValueAtTime(0, startTime); |
| gainNode.gain.linearRampToValueAtTime(0.3, startTime + 0.05); |
| gainNode.gain.linearRampToValueAtTime(0.2, startTime + duration - 0.1); |
| gainNode.gain.linearRampToValueAtTime(0, startTime + duration); |
| |
| oscillator.start(startTime); |
| oscillator.stop(startTime + duration); |
| } |
| |
| function playMelody() { |
| let currentTime = audioContext.currentTime; |
| |
| romanticMelody.forEach(({ note, duration }) => { |
| playNote(note, duration, currentTime); |
| currentTime += duration; |
| }); |
| |
| |
| if (isGeneratedMusicPlaying) { |
| setTimeout(playMelody, currentTime * 1000 - audioContext.currentTime * 1000); |
| } |
| } |
| |
| playMelody(); |
| } |
| |
| function stopGeneratedMelody() { |
| isGeneratedMusicPlaying = false; |
| } |
| |
| function moveButton() { |
| const button = document.getElementById('noButton'); |
| const buttonsContainer = document.querySelector('.buttons'); |
| |
| |
| messageIndex = (messageIndex + 1) % messages.length; |
| button.textContent = messages[messageIndex]; |
| |
| |
| const currentSize = parseFloat(window.getComputedStyle(button).fontSize); |
| button.style.fontSize = `${Math.max(currentSize * 0.85, 8)}px`; |
| button.style.padding = `${Math.max(parseInt(button.style.padding || 8) * 0.9, 5)}px ${Math.max(parseInt(button.style.padding || 20) * 0.9, 10)}px`; |
| |
| |
| const yesButton = document.querySelector('.yes-button'); |
| const yesCurrentSize = parseFloat(window.getComputedStyle(yesButton).fontSize); |
| yesButton.style.fontSize = `${yesCurrentSize * 1.1}px`; |
| |
| |
| const containerRect = buttonsContainer.getBoundingClientRect(); |
| const buttonRect = button.getBoundingClientRect(); |
| |
| const maxX = containerRect.width - buttonRect.width - 40; |
| const maxY = 100; |
| |
| const randomX = Math.random() * maxX - maxX/2; |
| const randomY = Math.random() * maxY - 50; |
| |
| button.style.transform = `translate(${randomX}px, ${randomY}px)`; |
| |
| |
| createSparkles(button); |
| } |
| |
| function createSparkles(element) { |
| const rect = element.getBoundingClientRect(); |
| for (let i = 0; i < 5; i++) { |
| const sparkle = document.createElement('div'); |
| sparkle.className = 'sparkle'; |
| sparkle.style.left = rect.left + rect.width/2 + 'px'; |
| sparkle.style.top = rect.top + rect.height/2 + 'px'; |
| sparkle.style.setProperty('--tx', `${(Math.random() - 0.5) * 100}px`); |
| sparkle.style.setProperty('--ty', `${(Math.random() - 0.5) * 100}px`); |
| document.body.appendChild(sparkle); |
| setTimeout(() => sparkle.remove(), 1000); |
| } |
| } |
| |
| function handleYesClick() { |
| |
| const successMsg = document.getElementById('successMessage'); |
| successMsg.classList.add('show'); |
| |
| |
| createHearts(); |
| |
| |
| createConfetti(); |
| |
| |
| playSuccessSound(); |
| } |
| |
| function playSuccessSound() { |
| |
| const successAudio = new Audio('https://cdn.pixabay.com/audio/2022/03/15/audio_c30f2c8b91.mp3'); |
| successAudio.volume = 0.5; |
| successAudio.play().catch(err => console.log('Success sound play failed:', err)); |
| } |
| |
| function createHearts() { |
| const heartsContainer = document.getElementById('hearts'); |
| const heartSymbols = ['❤️', '💕', '💖', '💗', '💓', '💝', '💘', '💞']; |
| |
| for (let i = 0; i < 80; i++) { |
| setTimeout(() => { |
| const heart = document.createElement('div'); |
| heart.className = 'heart'; |
| heart.textContent = heartSymbols[Math.floor(Math.random() * heartSymbols.length)]; |
| heart.style.left = Math.random() * 100 + '%'; |
| heart.style.animationDuration = (Math.random() * 3 + 2) + 's'; |
| heart.style.fontSize = (Math.random() * 30 + 20) + 'px'; |
| heartsContainer.appendChild(heart); |
| |
| setTimeout(() => heart.remove(), 5000); |
| }, i * 50); |
| } |
| } |
| |
| function createConfetti() { |
| const colors = ['#ff1744', '#e91e63', '#9c27b0', '#ffd700', '#ff69b4']; |
| for (let i = 0; i < 100; i++) { |
| setTimeout(() => { |
| const confetti = document.createElement('div'); |
| confetti.style.position = 'fixed'; |
| confetti.style.width = '10px'; |
| confetti.style.height = '10px'; |
| confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; |
| confetti.style.left = Math.random() * window.innerWidth + 'px'; |
| confetti.style.top = '-20px'; |
| confetti.style.borderRadius = Math.random() > 0.5 ? '50%' : '0'; |
| confetti.style.zIndex = '10001'; |
| confetti.style.pointerEvents = 'none'; |
| document.body.appendChild(confetti); |
| |
| const animation = confetti.animate([ |
| { transform: 'translateY(0) rotate(0deg)', opacity: 1 }, |
| { transform: `translateY(${window.innerHeight + 100}px) rotate(${Math.random() * 720}deg)`, opacity: 0 } |
| ], { |
| duration: Math.random() * 2000 + 2000, |
| easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)' |
| }); |
| |
| animation.onfinish = () => confetti.remove(); |
| }, i * 30); |
| } |
| } |
| |
| |
| async function loadCustomImages() { |
| try { |
| const response = await fetch('/get-images'); |
| const images = await response.json(); |
| |
| |
| if (images.stitch) { |
| document.getElementById('stitchImg').src = `/uploads/${images.stitch}`; |
| } |
| |
| |
| if (images.angela) { |
| document.getElementById('angelaImg').src = `/uploads/${images.angela}`; |
| } |
| |
| |
| if (images.sticker1) { |
| const sticker1 = document.getElementById('sticker1'); |
| sticker1.src = `/uploads/${images.sticker1}`; |
| sticker1.style.display = 'block'; |
| } |
| |
| if (images.sticker2) { |
| const sticker2 = document.getElementById('sticker2'); |
| sticker2.src = `/uploads/${images.sticker2}`; |
| sticker2.style.display = 'block'; |
| } |
| |
| |
| if (images.background) { |
| document.body.classList.add('custom-bg'); |
| document.body.style.setProperty('--bg-image', `url(/uploads/${images.background})`); |
| } |
| } catch (error) { |
| console.log('Using default images'); |
| } |
| } |
| |
| |
| window.onload = function() { |
| const button = document.getElementById('noButton'); |
| button.style.position = 'absolute'; |
| button.style.transform = 'translate(0, 0)'; |
| |
| |
| loadCustomImages(); |
| |
| |
| loadCustomMusic(); |
| }; |
| |
| |
| document.addEventListener('click', function initMusic() { |
| if (!musicPlaying) { |
| attemptAutoPlay(); |
| } |
| document.removeEventListener('click', initMusic); |
| }, { once: true }); |
| </script> |
| </body> |
| </html> |
|
|