lilo / admin.html
Alsmwal's picture
Upload 12 files
66aef7e verified
<!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">
<!-- Stitch Upload -->
<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>
<!-- Angela Upload -->
<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>
<!-- Sticker 1 Upload -->
<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>
<!-- Sticker 2 Upload -->
<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>
<!-- Background Upload -->
<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>
<!-- Music Upload -->
<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;
}
// هنا يمكن إضافة endpoint لحذف كل الصور
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>