Spaces:
Running
Running
| <html lang="fa" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>سازنده هوشمند استیکر ایتا</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/vazirmatn@5.0.19/index.css"> | |
| <style> | |
| body { | |
| font-family: 'Vazirmatn', sans-serif; | |
| background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 50%, #fed7aa 100%); | |
| min-height: 100vh; | |
| } | |
| .glass-panel { | |
| background: rgba(255, 255, 255, 0.85); | |
| backdrop-filter: blur(12px); | |
| -webkit-backdrop-filter: blur(12px); | |
| border: 1px solid rgba(255, 255, 255, 0.5); | |
| } | |
| .upload-zone { | |
| background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='16' ry='16' stroke='%23EA580C' stroke-width='2' stroke-dasharray='12%2c 12' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e"); | |
| transition: all 0.3s ease; | |
| } | |
| .upload-zone:hover { | |
| background-color: rgba(234, 88, 12, 0.05); | |
| transform: translateY(-2px); | |
| } | |
| .upload-zone.dragover { | |
| background-color: rgba(234, 88, 12, 0.1); | |
| transform: scale(1.02); | |
| } | |
| .fade-in { | |
| animation: fadeIn 0.5s ease-out forwards; | |
| } | |
| .slide-up { | |
| animation: slideUp 0.5s ease-out forwards; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; } | |
| to { opacity: 1; } | |
| } | |
| @keyframes slideUp { | |
| from { opacity: 0; transform: translateY(20px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .spinner { | |
| border: 3px solid rgba(234, 88, 12, 0.1); | |
| border-left-color: #ea580c; | |
| border-radius: 50%; | |
| width: 24px; | |
| height: 24px; | |
| animation: spin 1s linear infinite; | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| .btn-eitaa { | |
| background: linear-gradient(135deg, #ea580c 0%, #c2410c 100%); | |
| transition: all 0.3s ease; | |
| } | |
| .btn-eitaa:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 20px -5px rgba(234, 88, 12, 0.4); | |
| } | |
| .btn-eitaa:active { | |
| transform: translateY(0); | |
| } | |
| </style> | |
| </head> | |
| <body class="flex items-center justify-center p-4"> | |
| <main class="w-full max-w-lg glass-panel rounded-3xl shadow-2xl p-6 md:p-8 slide-up"> | |
| <!-- Header --> | |
| <div class="text-center mb-8"> | |
| <div class="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-orange-100 text-orange-600 mb-4 shadow-sm"> | |
| <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/> | |
| <path d="M19 10v2a7 7 0 0 1-14 0v-2"/> | |
| <line x1="12" y1="19" x2="12" y2="22"/> | |
| </svg> | |
| </div> | |
| <h1 class="text-2xl md:text-3xl font-bold text-gray-800 mb-2">سازنده هوشمند استیکر ایتا</h1> | |
| <p class="text-gray-500 text-sm md:text-base">تبدیل حرفهای و سریع تصاویر به فرمت WebP با کیفیت بالا</p> | |
| </div> | |
| <!-- Upload Zone --> | |
| <div id="uploadZone" class="upload-zone rounded-2xl p-8 text-center cursor-pointer mb-6 relative"> | |
| <input type="file" id="fileInput" accept="image/*" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer"> | |
| <div class="pointer-events-none"> | |
| <svg class="mx-auto h-12 w-12 text-orange-400 mb-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" /> | |
| </svg> | |
| <p class="text-gray-700 font-medium mb-1">برای انتخاب تصویر کلیک کنید</p> | |
| <p class="text-gray-400 text-xs">پشتیبانی از تمام فرمتهای تصویری (JPG, PNG, WEBP, BMP, TIFF و...)</p> | |
| </div> | |
| </div> | |
| <!-- Loading State --> | |
| <div id="loadingState" class="hidden flex-col items-center justify-center py-8"> | |
| <div class="spinner mb-4"></div> | |
| <p class="text-orange-600 font-medium animate-pulse">در حال تحلیل و تبدیل حرفهای به WebP...</p> | |
| </div> | |
| <!-- Error State --> | |
| <div id="errorState" class="hidden bg-red-50 border border-red-200 rounded-2xl p-4 mb-6 fade-in"> | |
| <div class="flex items-start"> | |
| <svg class="h-6 w-6 text-red-500 ml-3 mt-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> | |
| </svg> | |
| <div> | |
| <h3 class="text-red-800 font-bold text-sm mb-1">خطا در پردازش</h3> | |
| <p id="errorMessage" class="text-red-600 text-sm"></p> | |
| </div> | |
| </div> | |
| <button id="resetBtn" class="mt-4 w-full py-2 bg-red-100 text-red-700 rounded-xl font-medium hover:bg-red-200 transition-colors text-sm"> | |
| تلاش مجدد | |
| </button> | |
| </div> | |
| <!-- Success State --> | |
| <div id="successState" class="hidden fade-in"> | |
| <div class="bg-green-50 border border-green-200 rounded-2xl p-4 mb-6 flex items-center"> | |
| <svg class="h-6 w-6 text-green-500 ml-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /> | |
| </svg> | |
| <div> | |
| <p class="text-green-800 font-bold text-sm">تبدیل با موفقیت انجام شد!</p> | |
| <p class="text-green-600 text-xs mt-1" id="fileInfo"></p> | |
| </div> | |
| </div> | |
| <div class="relative rounded-2xl overflow-hidden shadow-lg mb-6 bg-gray-100 border border-gray-200"> | |
| <img id="previewImage" class="w-full h-auto object-contain max-h-96" alt="پیشنمایش استیکر"> | |
| <div class="absolute bottom-2 left-2 bg-black/60 text-white text-xs px-2 py-1 rounded-lg backdrop-blur-sm"> | |
| فرمت: WEBP | |
| </div> | |
| </div> | |
| <div class="space-y-3"> | |
| <button id="shareBtn" class="btn-eitaa w-full py-3.5 rounded-xl text-white font-bold text-base flex items-center justify-center gap-2 shadow-lg shadow-orange-200"> | |
| <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"/> | |
| <polyline points="16 6 12 2 8 6"/> | |
| <line x1="12" y1="2" x2="12" y2="15"/> | |
| </svg> | |
| اشتراکگذاری و ارسال به ایتا | |
| </button> | |
| <button id="downloadBtn" class="w-full py-3 rounded-xl bg-gray-100 text-gray-700 font-bold text-base flex items-center justify-center gap-2 hover:bg-gray-200 transition-colors border border-gray-200"> | |
| <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/> | |
| <polyline points="7 10 12 15 17 10"/> | |
| <line x1="12" y1="15" x2="12" y2="3"/> | |
| </svg> | |
| دانلود فایل WebP | |
| </button> | |
| <p class="text-center text-xs text-gray-400 mt-4 leading-relaxed"> | |
| نکته: در صورت عدم پشتیبانی مرورگر از اشتراکگذاری مستقیم، فایل به صورت خودکار دانلود شده و ایتا باز میشود. | |
| <br> | |
| <a href="https://www.eitaa.com/share/url?url=" target="_blank" class="text-orange-500 hover:underline mt-1 inline-block">قالب اشتراکگذاری ایتا</a> | |
| </p> | |
| </div> | |
| </div> | |
| </main> | |
| <script> | |
| const fileInput = document.getElementById('fileInput'); | |
| const uploadZone = document.getElementById('uploadZone'); | |
| const loadingState = document.getElementById('loadingState'); | |
| const errorState = document.getElementById('errorState'); | |
| const errorMessage = document.getElementById('errorMessage'); | |
| const successState = document.getElementById('successState'); | |
| const previewImage = document.getElementById('previewImage'); | |
| const fileInfo = document.getElementById('fileInfo'); | |
| const resetBtn = document.getElementById('resetBtn'); | |
| const shareBtn = document.getElementById('shareBtn'); | |
| const downloadBtn = document.getElementById('downloadBtn'); | |
| let convertedBlob = null; | |
| let convertedFileName = 'sticker.webp'; | |
| // Drag and Drop effects | |
| uploadZone.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| uploadZone.classList.add('dragover'); | |
| }); | |
| uploadZone.addEventListener('dragleave', () => { | |
| uploadZone.classList.remove('dragover'); | |
| }); | |
| uploadZone.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| uploadZone.classList.remove('dragover'); | |
| if (e.dataTransfer.files.length) { | |
| handleFile(e.dataTransfer.files[0]); | |
| } | |
| }); | |
| fileInput.addEventListener('change', (e) => { | |
| if (e.target.files.length) { | |
| handleFile(e.target.files[0]); | |
| } | |
| }); | |
| resetBtn.addEventListener('click', () => { | |
| errorState.classList.add('hidden'); | |
| uploadZone.classList.remove('hidden'); | |
| fileInput.value = ''; | |
| }); | |
| function formatBytes(bytes, decimals = 2) { | |
| if (bytes === 0) return '0 بایت'; | |
| const k = 1024; | |
| const dm = decimals < 0 ? 0 : decimals; | |
| const sizes = ['بایت', 'کیلوبایت', 'مگابایت']; | |
| const i = Math.floor(Math.log(bytes) / Math.log(k)); | |
| return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; | |
| } | |
| function showError(msg) { | |
| uploadZone.classList.add('hidden'); | |
| loadingState.classList.add('hidden'); | |
| errorState.classList.remove('hidden'); | |
| errorMessage.textContent = msg; | |
| } | |
| function handleFile(file) { | |
| uploadZone.classList.add('hidden'); | |
| errorState.classList.add('hidden'); | |
| successState.classList.add('hidden'); | |
| loadingState.classList.remove('hidden'); | |
| loadingState.classList.add('flex'); | |
| // Validation | |
| if (!file.type.startsWith('image/')) { | |
| showError('این ممکن نیست آن تصویری نیست !'); | |
| return; | |
| } | |
| if (file.type === 'image/gif' || file.type.startsWith('video/')) { | |
| showError('ایتا قابليت استیکر ویدئویی را ندارد !'); | |
| return; | |
| } | |
| // Process Image | |
| const reader = new FileReader(); | |
| reader.onload = (event) => { | |
| const img = new Image(); | |
| img.onload = () => { | |
| processImage(img, file.name); | |
| }; | |
| img.onerror = () => { | |
| showError('خطا در خواندن فایل تصویر. لطفاً فایل دیگری انتخاب کنید.'); | |
| }; | |
| img.src = event.target.result; | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| function processImage(img, originalName) { | |
| const canvas = document.createElement('canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| // Professional resizing: maintain aspect ratio, max dimension 512px (optimal for stickers) | |
| // If user wants original size, we can skip, but 512px is professional standard for Eitaa stickers. | |
| // The prompt says: "اگر اندازه تصویر 512 پیکسل در کل نبود هیچ اشکالی نیست و خروجی می دهد ایتا به اندازه کاری ندارد" | |
| // So we will keep original size but cap at 1024 to prevent browser crash, and ensure high quality. | |
| let width = img.width; | |
| let height = img.height; | |
| const maxDimension = 1024; | |
| if (width > maxDimension || height > maxDimension) { | |
| if (width > height) { | |
| height = Math.round((height * maxDimension) / width); | |
| width = maxDimension; | |
| } else { | |
| width = Math.round((width * maxDimension) / height); | |
| height = maxDimension; | |
| } | |
| } | |
| canvas.width = width; | |
| canvas.height = height; | |
| // High quality rendering | |
| ctx.imageSmoothingEnabled = true; | |
| ctx.imageSmoothingQuality = 'high'; | |
| ctx.drawImage(img, 0, 0, width, height); | |
| // Convert to WebP with high quality (0.95) | |
| canvas.toBlob((blob) => { | |
| if (blob) { | |
| convertedBlob = blob; | |
| convertedFileName = originalName.replace(/\.[^/.]+$/, '') + '.webp'; | |
| const objectUrl = URL.createObjectURL(blob); | |
| previewImage.src = objectUrl; | |
| fileInfo.textContent = `ابعاد: ${width}×${height} پیکسل | حجم: ${formatBytes(blob.size)}`; | |
| loadingState.classList.add('hidden'); | |
| loadingState.classList.remove('flex'); | |
| successState.classList.remove('hidden'); | |
| } else { | |
| showError('خطا در تبدیل فرمت تصویر. لطفاً دوباره تلاش کنید.'); | |
| } | |
| }, 'image/webp', 0.95); | |
| } | |
| downloadBtn.addEventListener('click', () => { | |
| if (!convertedBlob) return; | |
| const url = URL.createObjectURL(convertedBlob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = convertedFileName; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| }); | |
| shareBtn.addEventListener('click', async () => { | |
| if (!convertedBlob) return; | |
| const file = new File([convertedBlob], convertedFileName, { type: 'image/webp' }); | |
| const shareData = { | |
| files: [file], | |
| title: 'استیکر ایتا', | |
| text: 'این استیکر را با سازنده هوشمند استیکر ایتا ساختم!' | |
| }; | |
| // Check if Web Share API with files is supported | |
| if (navigator.share && navigator.canShare && navigator.canShare(shareData)) { | |
| try { | |
| await navigator.share(shareData); | |
| } catch (err) { | |
| if (err.name !== 'AbortError') { | |
| fallbackShare(); | |
| } | |
| } | |
| } else { | |
| fallbackShare(); | |
| } | |
| }); | |
| function fallbackShare() { | |
| // Fallback: Download the file and open Eitaa share URL | |
| const url = URL.createObjectURL(convertedBlob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = convertedFileName; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| // Show alert and open Eitaa | |
| setTimeout(() => { | |
| alert('فایل استیکر دانلود شد.\nاکنون میتوانید آن را در ایتا ضمیمه کنید.\n\nلینک اشتراکگذاری ایتا: https://www.eitaa.com/share/url?url='); | |
| window.open('https://eitaa.com/', '_blank'); | |
| }, 500); | |
| } | |
| </script> | |
| </body> | |
| </html> | |