| <!DOCTYPE html> |
| <html lang="ar" dir="rtl"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>لوحة التحكم - تخصيص الصور 💖</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; |
| padding: 20px; |
| } |
| |
| .container { |
| max-width: 1200px; |
| margin: 0 auto; |
| background: white; |
| border-radius: 20px; |
| padding: 40px; |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); |
| } |
| |
| h1 { |
| text-align: center; |
| color: #ff1744; |
| margin-bottom: 10px; |
| font-size: 2.5em; |
| } |
| |
| .subtitle { |
| text-align: center; |
| color: #666; |
| margin-bottom: 40px; |
| font-size: 1.1em; |
| } |
| |
| .upload-sections { |
| display: grid; |
| grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); |
| gap: 30px; |
| margin-bottom: 40px; |
| } |
| |
| .upload-card { |
| background: #f8f9fa; |
| border-radius: 15px; |
| padding: 25px; |
| border: 2px dashed #ddd; |
| transition: all 0.3s; |
| } |
| |
| .upload-card:hover { |
| border-color: #ff1744; |
| transform: translateY(-5px); |
| box-shadow: 0 5px 20px rgba(255, 23, 68, 0.2); |
| } |
| |
| .upload-card h3 { |
| color: #ff1744; |
| margin-bottom: 15px; |
| display: flex; |
| align-items: center; |
| gap: 10px; |
| } |
| |
| .upload-card p { |
| color: #666; |
| font-size: 0.9em; |
| margin-bottom: 15px; |
| } |
| |
| .file-input-wrapper { |
| position: relative; |
| overflow: hidden; |
| display: inline-block; |
| width: 100%; |
| } |
| |
| .file-input-wrapper input[type=file] { |
| position: absolute; |
| left: -9999px; |
| } |
| |
| .file-input-label { |
| display: block; |
| padding: 15px; |
| background: #ff1744; |
| color: white; |
| text-align: center; |
| border-radius: 10px; |
| cursor: pointer; |
| transition: all 0.3s; |
| font-weight: bold; |
| } |
| |
| .file-input-label:hover { |
| background: #d81b60; |
| transform: scale(1.02); |
| } |
| |
| .file-input-label:active { |
| transform: scale(0.98); |
| } |
| |
| .preview-container { |
| margin-top: 15px; |
| min-height: 150px; |
| background: white; |
| border-radius: 10px; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| overflow: hidden; |
| position: relative; |
| } |
| |
| .preview-container img { |
| max-width: 100%; |
| max-height: 150px; |
| object-fit: contain; |
| } |
| |
| .preview-container .placeholder { |
| color: #999; |
| font-size: 3em; |
| } |
| |
| .delete-btn { |
| position: absolute; |
| top: 5px; |
| left: 5px; |
| background: #f44336; |
| color: white; |
| border: none; |
| padding: 8px 12px; |
| border-radius: 5px; |
| cursor: pointer; |
| font-size: 0.8em; |
| opacity: 0; |
| transition: opacity 0.3s; |
| } |
| |
| .preview-container:hover .delete-btn { |
| opacity: 1; |
| } |
| |
| .delete-btn:hover { |
| background: #d32f2f; |
| } |
| |
| .status-message { |
| padding: 15px; |
| border-radius: 10px; |
| margin-bottom: 20px; |
| display: none; |
| text-align: center; |
| font-weight: bold; |
| } |
| |
| .status-message.success { |
| background: #d4edda; |
| color: #155724; |
| border: 1px solid #c3e6cb; |
| display: block; |
| } |
| |
| .status-message.error { |
| background: #f8d7da; |
| color: #721c24; |
| border: 1px solid #f5c6cb; |
| display: block; |
| } |
| |
| .action-buttons { |
| display: flex; |
| gap: 20px; |
| justify-content: center; |
| margin-top: 40px; |
| } |
| |
| .btn { |
| padding: 15px 40px; |
| border: none; |
| border-radius: 10px; |
| font-size: 1.1em; |
| cursor: pointer; |
| transition: all 0.3s; |
| font-weight: bold; |
| text-decoration: none; |
| display: inline-block; |
| } |
| |
| .btn-primary { |
| background: #ff1744; |
| color: white; |
| } |
| |
| .btn-primary:hover { |
| background: #d81b60; |
| transform: translateY(-2px); |
| box-shadow: 0 5px 15px rgba(255, 23, 68, 0.4); |
| } |
| |
| .btn-secondary { |
| background: #6c757d; |
| color: white; |
| } |
| |
| .btn-secondary:hover { |
| background: #5a6268; |
| transform: translateY(-2px); |
| } |
| |
| .gallery { |
| margin-top: 40px; |
| padding-top: 40px; |
| border-top: 2px solid #eee; |
| } |
| |
| .gallery h2 { |
| color: #ff1744; |
| margin-bottom: 20px; |
| text-align: center; |
| } |
| |
| .gallery-grid { |
| display: grid; |
| grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); |
| gap: 15px; |
| } |
| |
| .gallery-item { |
| position: relative; |
| aspect-ratio: 1; |
| border-radius: 10px; |
| overflow: hidden; |
| background: #f8f9fa; |
| cursor: pointer; |
| transition: transform 0.3s; |
| } |
| |
| .gallery-item:hover { |
| transform: scale(1.05); |
| } |
| |
| .gallery-item img { |
| width: 100%; |
| height: 100%; |
| object-fit: cover; |
| } |
| |
| .gallery-item .delete-gallery-btn { |
| position: absolute; |
| top: 5px; |
| left: 5px; |
| background: rgba(244, 67, 54, 0.9); |
| color: white; |
| border: none; |
| padding: 5px 10px; |
| border-radius: 5px; |
| cursor: pointer; |
| font-size: 0.8em; |
| opacity: 0; |
| transition: opacity 0.3s; |
| } |
| |
| .gallery-item:hover .delete-gallery-btn { |
| opacity: 1; |
| } |
| |
| .loading { |
| display: none; |
| text-align: center; |
| margin: 20px 0; |
| } |
| |
| .loading.show { |
| display: block; |
| } |
| |
| .spinner { |
| border: 4px solid #f3f3f3; |
| border-top: 4px solid #ff1744; |
| border-radius: 50%; |
| width: 40px; |
| height: 40px; |
| animation: spin 1s linear infinite; |
| margin: 0 auto; |
| } |
| |
| @keyframes spin { |
| 0% { transform: rotate(0deg); } |
| 100% { transform: rotate(360deg); } |
| } |
| |
| .instructions { |
| background: #fff3cd; |
| border: 1px solid #ffc107; |
| border-radius: 10px; |
| padding: 20px; |
| margin-bottom: 30px; |
| } |
| |
| .instructions h3 { |
| color: #856404; |
| margin-bottom: 10px; |
| } |
| |
| .instructions ul { |
| color: #856404; |
| margin-right: 20px; |
| } |
| |
| .instructions li { |
| margin-bottom: 8px; |
| } |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <h1>🎨 لوحة تحكم التصميم</h1> |
| <p class="subtitle">ارفع الصور المفضلة لديك لتخصيص صفحة Valentine</p> |
|
|
| <div class="instructions"> |
| <h3>📋 إرشادات الاستخدام:</h3> |
| <ul> |
| <li><strong>ستيتش:</strong> صورة ستيتش اللي هتظهر على اليسار</li> |
| <li><strong>أنجيلا:</strong> صورة أنجيلا اللي هتظهر على اليمين</li> |
| <li><strong>ستيكر 1:</strong> ستيكر في الركن الأيمن العلوي</li> |
| <li><strong>ستيكر 2:</strong> ستيكر في الركن الأيسر السفلي</li> |
| <li><strong>خلفية:</strong> صورة خلفية للصفحة كاملة</li> |
| <li><strong>🎵 موسيقى:</strong> ملف صوتي يشتغل في الخلفية (MP3, WAV, OGG)</li> |
| <li>⚠️ الصور المدعومة: PNG, JPG, GIF, WEBP (حد أقصى 16MB)</li> |
| <li>⚠️ الصوتيات المدعومة: MP3, WAV, OGG (حد أقصى 16MB)</li> |
| <li>💡 للحصول على أفضل نتيجة، استخدم صور بخلفية شفافة (PNG)</li> |
| <li>🎼 يمكنك استخدام موسيقى رومانسية هادئة من مكتبتك</li> |
| </ul> |
| </div> |
|
|
| <div id="statusMessage" class="status-message"></div> |
| |
| <div class="loading" id="loading"> |
| <div class="spinner"></div> |
| <p>جاري الرفع...</p> |
| </div> |
|
|
| <div class="upload-sections"> |
| |
| <div class="upload-card"> |
| <h3>💙 ستيتش</h3> |
| <p>صورة ستيتش (الشخصية على اليسار)</p> |
| <div class="file-input-wrapper"> |
| <input type="file" id="stitchInput" accept="image/*" onchange="uploadImage('stitch', this)"> |
| <label for="stitchInput" class="file-input-label"> |
| 📤 اختر صورة ستيتش |
| </label> |
| </div> |
| <div class="preview-container" id="stitchPreview"> |
| <span class="placeholder">💙</span> |
| </div> |
| </div> |
|
|
| |
| <div class="upload-card"> |
| <h3>🐱 أنجيلا</h3> |
| <p>صورة أنجيلا (الشخصية على اليمين)</p> |
| <div class="file-input-wrapper"> |
| <input type="file" id="angelaInput" accept="image/*" onchange="uploadImage('angela', this)"> |
| <label for="angelaInput" class="file-input-label"> |
| 📤 اختر صورة أنجيلا |
| </label> |
| </div> |
| <div class="preview-container" id="angelaPreview"> |
| <span class="placeholder">🐱</span> |
| </div> |
| </div> |
|
|
| |
| <div class="upload-card"> |
| <h3>⭐ ستيكر 1</h3> |
| <p>ستيكر للركن الأيمن العلوي</p> |
| <div class="file-input-wrapper"> |
| <input type="file" id="sticker1Input" accept="image/*" onchange="uploadImage('sticker1', this)"> |
| <label for="sticker1Input" class="file-input-label"> |
| 📤 اختر ستيكر 1 |
| </label> |
| </div> |
| <div class="preview-container" id="sticker1Preview"> |
| <span class="placeholder">⭐</span> |
| </div> |
| </div> |
|
|
| |
| <div class="upload-card"> |
| <h3>✨ ستيكر 2</h3> |
| <p>ستيكر للركن الأيسر السفلي</p> |
| <div class="file-input-wrapper"> |
| <input type="file" id="sticker2Input" accept="image/*" onchange="uploadImage('sticker2', this)"> |
| <label for="sticker2Input" class="file-input-label"> |
| 📤 اختر ستيكر 2 |
| </label> |
| </div> |
| <div class="preview-container" id="sticker2Preview"> |
| <span class="placeholder">✨</span> |
| </div> |
| </div> |
|
|
| |
| <div class="upload-card"> |
| <h3>🎨 خلفية الصفحة</h3> |
| <p>صورة خلفية للصفحة كاملة</p> |
| <div class="file-input-wrapper"> |
| <input type="file" id="backgroundInput" accept="image/*" onchange="uploadImage('background', this)"> |
| <label for="backgroundInput" class="file-input-label"> |
| 📤 اختر صورة خلفية |
| </label> |
| </div> |
| <div class="preview-container" id="backgroundPreview"> |
| <span class="placeholder">🎨</span> |
| </div> |
| </div> |
|
|
| |
| <div class="upload-card"> |
| <h3>🎵 موسيقى الخلفية</h3> |
| <p>ملف صوتي للموسيقى (MP3, WAV, OGG)</p> |
| <div class="file-input-wrapper"> |
| <input type="file" id="musicInput" accept="audio/*" onchange="uploadMusic(this)"> |
| <label for="musicInput" class="file-input-label"> |
| 📤 اختر ملف موسيقى |
| </label> |
| </div> |
| <div class="preview-container" id="musicPreview"> |
| <span class="placeholder">🎵</span> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="action-buttons"> |
| <a href="/" class="btn btn-primary">👀 معاينة الصفحة</a> |
| <button onclick="resetAll()" class="btn btn-secondary">🔄 إعادة تعيين الكل</button> |
| </div> |
|
|
| {% if images %} |
| <div class="gallery"> |
| <h2>📸 معرض الصور المرفوعة</h2> |
| <div class="gallery-grid"> |
| {% for image in images %} |
| <div class="gallery-item"> |
| <img src="/uploads/{{ image }}" alt="{{ image }}"> |
| <button class="delete-gallery-btn" onclick="deleteImage('{{ image }}')">🗑️</button> |
| </div> |
| {% endfor %} |
| </div> |
| </div> |
| {% endif %} |
| </div> |
|
|
| <script> |
| function showMessage(message, type) { |
| const msgEl = document.getElementById('statusMessage'); |
| msgEl.textContent = message; |
| msgEl.className = `status-message ${type}`; |
| setTimeout(() => { |
| msgEl.className = 'status-message'; |
| }, 5000); |
| } |
| |
| function showLoading(show) { |
| const loadingEl = document.getElementById('loading'); |
| loadingEl.className = show ? 'loading show' : 'loading'; |
| } |
| |
| async function uploadImage(type, input) { |
| const file = input.files[0]; |
| if (!file) return; |
| |
| |
| const reader = new FileReader(); |
| reader.onload = function(e) { |
| const preview = document.getElementById(`${type}Preview`); |
| preview.innerHTML = ` |
| <img src="${e.target.result}" alt="${type}"> |
| <button class="delete-btn" onclick="deleteImage('${type}')">🗑️ حذف</button> |
| `; |
| }; |
| reader.readAsDataURL(file); |
| |
| |
| const formData = new FormData(); |
| formData.append('file', file); |
| formData.append('image_type', type); |
| |
| showLoading(true); |
| |
| try { |
| const response = await fetch('/upload', { |
| method: 'POST', |
| body: formData |
| }); |
| |
| const result = await response.json(); |
| |
| if (result.success) { |
| showMessage(`✅ ${result.message}`, 'success'); |
| } else { |
| showMessage(`❌ ${result.error}`, 'error'); |
| } |
| } catch (error) { |
| showMessage('❌ حدث خطأ أثناء رفع الصورة', 'error'); |
| console.error('Upload error:', error); |
| } finally { |
| showLoading(false); |
| } |
| } |
| |
| async function uploadMusic(input) { |
| const file = input.files[0]; |
| if (!file) return; |
| |
| |
| const validTypes = ['audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/ogg']; |
| if (!validTypes.includes(file.type) && !file.name.match(/\.(mp3|wav|ogg)$/i)) { |
| showMessage('❌ يرجى اختيار ملف صوتي (MP3, WAV, OGG)', 'error'); |
| return; |
| } |
| |
| |
| const preview = document.getElementById('musicPreview'); |
| preview.innerHTML = ` |
| <div style="padding: 20px; text-align: center;"> |
| <div style="font-size: 3em; margin-bottom: 10px;">🎵</div> |
| <div style="font-size: 0.9em; color: #666;">${file.name}</div> |
| <audio controls style="width: 100%; margin-top: 10px;"> |
| <source src="${URL.createObjectURL(file)}" type="${file.type}"> |
| </audio> |
| </div> |
| <button class="delete-btn" onclick="deleteImage('music')">🗑️ حذف</button> |
| `; |
| |
| |
| const formData = new FormData(); |
| formData.append('file', file); |
| formData.append('image_type', 'music'); |
| |
| showLoading(true); |
| |
| try { |
| const response = await fetch('/upload', { |
| method: 'POST', |
| body: formData |
| }); |
| |
| const result = await response.json(); |
| |
| if (result.success) { |
| showMessage('✅ تم رفع الموسيقى بنجاح! 🎵', 'success'); |
| } else { |
| showMessage(`❌ ${result.error}`, 'error'); |
| } |
| } catch (error) { |
| showMessage('❌ حدث خطأ أثناء رفع الموسيقى', 'error'); |
| console.error('Upload error:', error); |
| } finally { |
| showLoading(false); |
| } |
| } |
| |
| async function deleteImage(filename) { |
| if (!confirm('هل أنت متأكد من حذف هذه الصورة؟')) { |
| return; |
| } |
| |
| showLoading(true); |
| |
| try { |
| const response = await fetch(`/delete/${filename}`, { |
| method: 'POST' |
| }); |
| |
| const result = await response.json(); |
| |
| if (result.success) { |
| showMessage('✅ تم حذف الصورة بنجاح', 'success'); |
| |
| setTimeout(() => location.reload(), 1000); |
| } else { |
| showMessage(`❌ ${result.error}`, 'error'); |
| } |
| } catch (error) { |
| showMessage('❌ حدث خطأ أثناء حذف الصورة', 'error'); |
| console.error('Delete error:', error); |
| } finally { |
| showLoading(false); |
| } |
| } |
| |
| function resetAll() { |
| if (!confirm('هل أنت متأكد من حذف جميع الصور؟')) { |
| return; |
| } |
| |
| |
| showMessage('⚠️ هذه الميزة قيد التطوير', 'error'); |
| } |
| |
| |
| async function loadExistingImages() { |
| try { |
| const response = await fetch('/get-images'); |
| const images = await response.json(); |
| |
| |
| Object.entries(images).forEach(([type, filename]) => { |
| const preview = document.getElementById(`${type}Preview`); |
| if (preview) { |
| preview.innerHTML = ` |
| <img src="/uploads/${filename}" alt="${type}"> |
| <button class="delete-btn" onclick="deleteImage('${filename}')">🗑️ حذف</button> |
| `; |
| } |
| }); |
| } catch (error) { |
| console.log('No existing images found'); |
| } |
| } |
| |
| |
| window.onload = loadExistingImages; |
| </script> |
| </body> |
| </html> |
|
|