Spaces:
Runtime error
Runtime error
| <html lang="ar" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title data-lang-key="pageTitle">SkyData - أداة إزالة الخلفية</title> | |
| <link rel="icon" href="/favicon.ico" type="image/x-icon"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary-color: #007bff; | |
| --primary-hover: #0056b3; | |
| --glow-color-1: #6366f1; | |
| --glow-color-2: #ec4899; | |
| --glow-color-3: #f59e0b; | |
| --dark-bg: #0d0d1a; | |
| --bg-surface: #1a1a2e; | |
| --text-color: #e0e0e0; | |
| --text-muted: #aaa; | |
| --border-color: #333; | |
| --error-color: #EF665B; | |
| --success-color: #28a745; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| -webkit-tap-highlight-color: rgba(0, 0, 0, 0); | |
| tap-highlight-color: rgba(0, 0, 0, 0); | |
| } | |
| #app-container { | |
| width: 100%; | |
| overflow-x: hidden; | |
| position: relative; | |
| transform: translate3d(0, 0, 0); | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| html { } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| direction: rtl; | |
| background-color: var(--dark-bg); | |
| color: var(--text-color); | |
| margin: 0; padding: 0; | |
| } | |
| body::before { | |
| content: ''; | |
| position: fixed; | |
| top: 0; left: 0; right: 0; bottom: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient( | |
| 135deg, | |
| rgba(var(--glow-color-1), 0.15), | |
| rgba(var(--glow-color-2), 0.1), | |
| rgba(var(--glow-color-3), 0.15) | |
| ); | |
| background-size: 400% 400%; | |
| animation: glowingBackground 20s ease infinite; | |
| z-index: -1; | |
| filter: blur(50px); | |
| } | |
| @keyframes glowingBackground { | |
| 0% { background-position: 0% 50%; } | |
| 50% { background-position: 100% 50%; } | |
| 100% { background-position: 0% 50%; } | |
| } | |
| main { | |
| flex-grow: 1; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| padding: 30px 0; | |
| } | |
| .main-wrapper { | |
| max-width: 400px; | |
| width: 95%; | |
| } | |
| .form { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 15px; | |
| padding: 30px; | |
| border-radius: 10px; | |
| position: relative; | |
| background-color: var(--bg-surface); | |
| color: var(--text-color); | |
| border: 1px solid var(--border-color); | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.5); | |
| animation: fadeIn 0.5s ease-out; | |
| } | |
| .title { | |
| font-size: 24px; | |
| font-weight: 600; | |
| letter-spacing: -1px; | |
| position: relative; | |
| display: flex; | |
| align-items: center; | |
| color: var(--primary-color); | |
| margin-bottom: 5px; | |
| padding-right: 30px; | |
| } | |
| .title::before, .title::after { | |
| position: absolute; | |
| content: ""; | |
| height: 16px; | |
| width: 16px; | |
| border-radius: 50%; | |
| right: 0px; | |
| background-color: var(--primary-color); | |
| } | |
| .title::after { animation: pulse 1s linear infinite; } | |
| .message-intro { | |
| font-size: 14.5px; | |
| color: var(--text-muted); | |
| margin-bottom: 10px; | |
| text-align: right; | |
| } | |
| .submit { | |
| border: none; | |
| outline: none; | |
| padding: 14px; | |
| border-radius: 8px; | |
| color: #fff; | |
| font-size: 1.2em; | |
| font-weight: bold; | |
| background-color: var(--primary-color); | |
| cursor: pointer; | |
| box-shadow: 0 4px 8px rgba(0, 123, 255, 0.3); | |
| margin-top: 15px; | |
| transition: all 0.3s ease; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| text-align: center; | |
| text-decoration: none; | |
| } | |
| .submit i { margin-left: 10px; } | |
| [dir="rtl"] .submit i { margin-left: 0; margin-right: 10px; } | |
| .submit:hover { | |
| background-color: var(--primary-hover); | |
| transform: translateY(-1px); | |
| box-shadow: 0 6px 12px rgba(0, 123, 255, 0.4); | |
| } | |
| .submit:disabled { background: #555; cursor: not-allowed; box-shadow: none; } | |
| #download-btn { | |
| background-color: var(--success-color); | |
| } | |
| #download-btn:hover { | |
| background-color: #218838; | |
| } | |
| .cancel-button { | |
| display: block; | |
| width: 100%; | |
| text-decoration: none; | |
| border: 1px solid var(--border-color); | |
| outline: none; | |
| padding: 14px; | |
| border-radius: 8px; | |
| color: var(--text-muted); | |
| font-size: 1.2em; | |
| font-weight: bold; | |
| background-color: transparent; | |
| cursor: pointer; | |
| margin-top: 10px; | |
| transition: all 0.3s ease; | |
| text-align: center; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .cancel-button i { margin-left: 10px; } | |
| [dir="rtl"] .cancel-button i { margin-left: 0; margin-right: 10px; } | |
| .cancel-button:hover { | |
| background-color: var(--border-color); | |
| color: var(--text-color); | |
| } | |
| .cancel-button:disabled { background: #555; cursor: not-allowed; border-color: #555; } | |
| .loader-spinner { | |
| border: 4px solid #333; | |
| border-top: 4px solid var(--primary-color); | |
| border-radius: 50%; | |
| width: 20px; | |
| height: 20px; | |
| animation: spin 1s linear infinite; | |
| display: none; | |
| margin: 15px auto 0; | |
| } | |
| #result-area { | |
| display:none; | |
| margin-top: 25px; | |
| border-top: 1px solid var(--border-color); | |
| padding-top: 25px; | |
| text-align: center; | |
| } | |
| #result-img { | |
| max-width: 100%; | |
| border-radius: 8px; | |
| border: 1px solid var(--border-color); | |
| } | |
| @keyframes pulse { | |
| from { transform: scale(0.9); opacity: 1; } | |
| to { transform: scale(1.8); opacity: 0; } | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| #global-toast { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| width: 320px; | |
| max-width: 90%; | |
| padding: 15px; | |
| display: none; | |
| align-items: center; | |
| gap: 10px; | |
| border-radius: 8px; | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.5); | |
| position: fixed; | |
| bottom: -100px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| z-index: 2000; | |
| transition: opacity 0.3s ease, bottom 0.3s ease; | |
| opacity: 0; | |
| } | |
| #global-toast.show { | |
| display: flex; | |
| opacity: 1; | |
| bottom: 20px; | |
| } | |
| #global-toast.success { | |
| background: #E0F2E9; | |
| border: 1px solid var(--success-color); | |
| } | |
| #global-toast.success .toast-title { color: #155724; } | |
| #global-toast.success .toast-icon { fill: var(--success-color); } | |
| #global-toast.error { | |
| background: #FCE8DB; | |
| border: 1px solid var(--error-color); | |
| } | |
| #global-toast.error .toast-title { color: #71192F; } | |
| #global-toast.error .toast-icon { fill: var(--error-color); } | |
| .toast-icon { | |
| width: 20px; | |
| height: 20px; | |
| flex-shrink: 0; | |
| } | |
| .toast-title { | |
| font-weight: 600; | |
| font-size: 14px; | |
| width: 100%; | |
| line-height: 1.4; | |
| direction: rtl; | |
| } | |
| .toast-close-btn { | |
| background: none; | |
| border: none; | |
| color: var(--text-muted); | |
| cursor: pointer; | |
| font-size: 1.5em; | |
| line-height: 1; | |
| padding: 0 5px; | |
| margin-left: auto; | |
| flex-shrink: 0; | |
| } | |
| [dir="rtl"] .toast-close-btn { | |
| margin-left: 0; | |
| margin-right: auto; | |
| } | |
| #global-toast.success .toast-close-btn { color: #155724; } | |
| #global-toast.error .toast-close-btn { color: #71192F; } | |
| /* (تم حذف media query الخاص بـ logo-container) */ | |
| </style> | |
| </head> | |
| <body> | |
| <div id="app-container"> | |
| <main> | |
| <div class="main-wrapper" id="loginWrapper"> | |
| <div class="form"> | |
| <p class="title" dir="rtl"> | |
| <i class="fas fa-magic" style="margin-left: 10px;"></i> | |
| أداة إزالة الخلفية | |
| </p> | |
| <p class="message-intro"> | |
| ارفع صورتك واحصل عليها بخلفية شفافة. (الحد الأقصى: 10 ميجابايت) | |
| </p> | |
| <input type="file" id="file-input" accept="image/png, image/jpeg" style="display: none;"> | |
| <label for="file-input" class="submit" id="upload-label"> | |
| <i class="fas fa-upload"></i> اختر صورة | |
| </label> | |
| <button id="submit-btn" class="cancel-button" style="display: none;"> | |
| <i class="fas fa-rocket"></i> ابدأ المعالجة | |
| </button> | |
| <div class="loader-spinner" id="loadingSpinner"></div> | |
| <div id="result-area"> | |
| <h3 style="color: var(--text-color);">النتيجة:</h3> | |
| <img id="result-img" alt="الصورة بعد إزالة الخلفية"> | |
| <a href="#" id="download-btn" class="submit" style="display: none; margin-top: 15px;"> | |
| <i class="fas fa-download"></i> تحميل الصورة | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <div id="global-toast"> | |
| <svg class="toast-icon" viewBox="0 0 24 24" height="24" width="24" xmlns="http://www.w3.org/2000/svg"> | |
| <path d="m13 13h-2v-6h2zm0 4h-2v-2h2zm-1-15c-1.3132 0-2.61358.25866-3.82683.7612-1.21326.50255-2.31565 1.23915-3.24424 2.16773-1.87536 1.87537-2.92893 4.41891-2.92893 7.07107 0 2.6522 1.05357 5.1957 2.92893 7.0711.92859.9286 2.03098 1.6651 3.24424 2.1677 1.21325.5025 2.51363.7612 3.82683.7612 2.6522 0 5.1957-1.0536 7.0711-2.9289 1.8753-1.8754 2.9289-4.4189 2.9289-7.0711 0-1.3132-.2587-2.61358-.7612-3.82683-.5026-1.21326-1.2391-2.31565-2.1677-3.24424-.9286-.92858-2.031-1.66518-3.2443-2.16773-1.2132-.50254-2.5136-.7612-3.8268-.7612z"></path> | |
| </svg> | |
| <div class="toast-title" id="toast-title"></div> | |
| <button class="toast-close-btn" id="toast-close-btn">×</button> | |
| </div> | |
| </div> | |
| <script> | |
| // --- عناصر الواجهة --- | |
| const fileInput = document.getElementById('file-input'); | |
| const submitBtn = document.getElementById('submit-btn'); | |
| const uploadLabel = document.getElementById('upload-label'); | |
| const loadingSpinner = document.getElementById('loadingSpinner'); | |
| const resultArea = document.getElementById('result-area'); | |
| const resultImg = document.getElementById('result-img'); | |
| const downloadBtn = document.getElementById('download-btn'); | |
| // --- عناصر الإشعارات (Toast) --- | |
| const globalToast = document.getElementById('global-toast'); | |
| const toastTitle = document.getElementById('toast-title'); | |
| const toastCloseBtn = document.getElementById('toast-close-btn'); | |
| let toastTimer; | |
| // --- دالة إظهار الإشعارات --- | |
| function showToast(message, type = 'success', duration = 5000) { | |
| if (toastTimer) clearTimeout(toastTimer); | |
| toastTitle.innerHTML = message; | |
| globalToast.className = ''; | |
| globalToast.classList.add(type); | |
| globalToast.classList.add('show'); | |
| if (duration > 0) { | |
| toastTimer = setTimeout(() => { | |
| globalToast.classList.remove('show'); | |
| }, duration); | |
| } | |
| } | |
| // --- دالة إخفاء الإشعارات --- | |
| toastCloseBtn.addEventListener('click', () => { | |
| if (toastTimer) clearTimeout(toastTimer); | |
| globalToast.classList.remove('show'); | |
| }); | |
| // --- معالج حدث اختيار الملف --- | |
| fileInput.addEventListener('change', () => { | |
| globalToast.classList.remove('show'); | |
| if (fileInput.files.length > 0) { | |
| const file = fileInput.files[0]; | |
| const MAX_SIZE = 10 * 1024 * 1024; // 10 MB | |
| if (file.size > MAX_SIZE) { | |
| showToast('حجم الملف كبير جداً. الحد الأقصى 10 ميجابايت.', 'error', 0); | |
| fileInput.value = ''; | |
| submitBtn.style.display = 'none'; | |
| resultArea.style.display = 'none'; | |
| downloadBtn.style.display = 'none'; | |
| return; | |
| } | |
| showToast(`تم اختيار: ${file.name}`, 'success', 3000); | |
| submitBtn.style.display = 'flex'; | |
| resultArea.style.display = 'none'; | |
| downloadBtn.style.display = 'none'; | |
| } | |
| }); | |
| // --- معالج حدث الضغط على زر "ابدأ المعالجة" --- | |
| submitBtn.addEventListener('click', async () => { | |
| if (fileInput.files.length === 0) return; | |
| globalToast.classList.remove('show'); | |
| loadingSpinner.style.display = 'block'; | |
| submitBtn.disabled = true; | |
| uploadLabel.style.pointerEvents = 'none'; | |
| uploadLabel.style.opacity = '0.7'; | |
| downloadBtn.style.display = 'none'; | |
| const formData = new FormData(); | |
| const file = fileInput.files[0]; | |
| formData.append('file', file); | |
| try { | |
| const response = await fetch('/remove-bg', { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| if (!response.ok) throw new Error('فشل المعالجة'); | |
| const imageBlob = await response.blob(); | |
| const imageUrl = URL.createObjectURL(imageBlob); | |
| resultImg.src = imageUrl; | |
| resultArea.style.display = 'block'; | |
| const originalFilename = file.name.split('.').slice(0, -1).join('.'); | |
| downloadBtn.download = `${originalFilename}-no-bg.png`; | |
| downloadBtn.href = imageUrl; | |
| downloadBtn.style.display = 'flex'; | |
| showToast('اكتملت المعالجة بنجاح!', 'success', 4000); | |
| } catch (error) { | |
| showToast('⚠️ حدث خطأ. حاول بصورة أخرى أو تأكد من اتصالك.', 'error', 0); | |
| downloadBtn.style.display = 'none'; | |
| } finally { | |
| loadingSpinner.style.display = 'none'; | |
| submitBtn.disabled = false; | |
| uploadLabel.style.pointerEvents = 'auto'; | |
| uploadLabel.style.opacity = '1'; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |