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>ورود شیشهای مات | Liquid Retina Login</title> | |
| <!-- ایمپورت فونت وزیرمتن برای ظاهر فارسی استاندارد --> | |
| <link href="https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css" rel="stylesheet" type="text/css" /> | |
| <!-- ایمپورت آیکونهای FontAwesome --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --glass-bg: rgba(30, 41, 59, 0.65); | |
| --glass-border: rgba(255, 255, 255, 0.08); | |
| --glass-highlight: rgba(255, 255, 255, 0.15); | |
| --primary-color: #3b82f6; | |
| --primary-hover: #2563eb; | |
| --text-main: #f8fafc; | |
| --text-muted: #94a3b8; | |
| --error-color: #ef4444; | |
| --success-color: #10b981; | |
| --bg-gradient-1: #0f172a; | |
| --bg-gradient-2: #1e1b4b; | |
| --bg-gradient-3: #312e81; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Vazirmatn', sans-serif; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| body { | |
| min-height: 100vh; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| overflow-x: hidden; | |
| background: radial-gradient(circle at 10% 20%, var(--bg-gradient-1) 0%, var(--bg-gradient-2) 90%); | |
| position: relative; | |
| } | |
| /* المانهای متحرک پسزمینه برای ایجاد عمق */ | |
| .orb { | |
| position: absolute; | |
| border-radius: 50%; | |
| filter: blur(80px); | |
| z-index: -1; | |
| opacity: 0.6; | |
| animation: float 10s infinite ease-in-out; | |
| } | |
| .orb-1 { | |
| width: 300px; | |
| height: 300px; | |
| background: #4f46e5; | |
| top: -50px; | |
| left: -50px; | |
| animation-delay: 0s; | |
| } | |
| .orb-2 { | |
| width: 400px; | |
| height: 400px; | |
| background: #ec4899; | |
| bottom: -100px; | |
| right: -100px; | |
| animation-delay: -5s; | |
| } | |
| @keyframes float { | |
| 0%, 100% { transform: translate(0, 0); } | |
| 50% { transform: translate(30px, 50px); } | |
| } | |
| /* هدر حاوی لینک anycoder */ | |
| header { | |
| position: absolute; | |
| top: 20px; | |
| left: 20px; | |
| z-index: 10; | |
| } | |
| .anycoder-link { | |
| color: rgba(255, 255, 255, 0.4); | |
| text-decoration: none; | |
| font-size: 0.85rem; | |
| transition: color 0.3s ease; | |
| display: flex; | |
| align-items: center; | |
| gap: 5px; | |
| } | |
| .anycoder-link:hover { | |
| color: rgba(255, 255, 255, 0.9); | |
| } | |
| /* کارت شیشهای اصلی */ | |
| .login-card { | |
| width: 100%; | |
| max-width: 420px; | |
| padding: 2.5rem; | |
| border-radius: 24px; | |
| background: var(--glass-bg); | |
| backdrop-filter: blur(20px); | |
| -webkit-backdrop-filter: blur(20px); | |
| border: 1px solid var(--glass-border); | |
| box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); | |
| position: relative; | |
| overflow: hidden; | |
| margin: 20px; | |
| transition: transform 0.3s ease; | |
| } | |
| .login-card::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| height: 1px; | |
| background: linear-gradient(90deg, transparent, var(--glass-highlight), transparent); | |
| } | |
| .logo-area { | |
| text-align: center; | |
| margin-bottom: 2rem; | |
| } | |
| .logo-icon { | |
| font-size: 3rem; | |
| background: linear-gradient(135deg, #60a5fa, #c084fc); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin-bottom: 0.5rem; | |
| filter: drop-shadow(0 0 10px rgba(96, 165, 250, 0.3)); | |
| } | |
| .title { | |
| color: var(--text-main); | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| margin-bottom: 0.25rem; | |
| } | |
| .subtitle { | |
| color: var(--text-muted); | |
| font-size: 0.9rem; | |
| } | |
| /* استایل فرمها */ | |
| .form-group { | |
| margin-bottom: 1.5rem; | |
| position: relative; | |
| } | |
| .input-wrapper { | |
| position: relative; | |
| display: flex; | |
| align-items: center; | |
| } | |
| .input-icon { | |
| position: absolute; | |
| right: 16px; | |
| color: var(--text-muted); | |
| transition: color 0.3s; | |
| } | |
| .form-input { | |
| width: 100%; | |
| padding: 14px 50px 14px 16px; | |
| background: rgba(15, 23, 42, 0.4); | |
| border: 1px solid var(--glass-border); | |
| border-radius: 12px; | |
| color: var(--text-main); | |
| font-size: 1rem; | |
| outline: none; | |
| transition: all 0.3s ease; | |
| } | |
| .form-input:focus { | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1); | |
| background: rgba(15, 23, 42, 0.6); | |
| } | |
| .form-input:focus + .input-icon { | |
| color: var(--primary-color); | |
| } | |
| /* دکمه اصلی */ | |
| .btn-primary { | |
| width: 100%; | |
| padding: 14px; | |
| background: linear-gradient(135deg, var(--primary-color), var(--primary-hover)); | |
| color: white; | |
| border: none; | |
| border-radius: 12px; | |
| font-size: 1rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| gap: 8px; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .btn-primary:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 20px -10px rgba(59, 130, 246, 0.5); | |
| } | |
| .btn-primary:active { | |
| transform: translateY(0); | |
| } | |
| .btn-primary:disabled { | |
| background: #475569; | |
| cursor: not-allowed; | |
| transform: none; | |
| box-shadow: none; | |
| } | |
| /* شبیهسازی کپچا */ | |
| .captcha-wrapper { | |
| display: flex; | |
| align-items: center; | |
| background: rgba(15, 23, 42, 0.3); | |
| border: 1px solid var(--glass-border); | |
| padding: 10px 15px; | |
| border-radius: 12px; | |
| margin-bottom: 1.5rem; | |
| cursor: pointer; | |
| transition: background 0.3s; | |
| } | |
| .captcha-wrapper:hover { | |
| background: rgba(15, 23, 42, 0.5); | |
| } | |
| .custom-checkbox { | |
| width: 20px; | |
| height: 20px; | |
| border: 2px solid var(--text-muted); | |
| border-radius: 4px; | |
| margin-left: 10px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: all 0.2s; | |
| } | |
| .captcha-wrapper.checked .custom-checkbox { | |
| background: var(--success-color); | |
| border-color: var(--success-color); | |
| } | |
| .captcha-text { | |
| color: var(--text-muted); | |
| font-size: 0.85rem; | |
| flex-grow: 1; | |
| } | |
| .captcha-icon { | |
| font-size: 1.5rem; | |
| opacity: 0.5; | |
| } | |
| /* بخش ورود کد OTP */ | |
| .otp-inputs { | |
| display: flex; | |
| justify-content: space-between; | |
| gap: 8px; | |
| margin-bottom: 1.5rem; | |
| direction: ltr; /* برای تایپ راحتتر اعداد */ | |
| } | |
| .otp-box { | |
| width: 45px; | |
| height: 55px; | |
| background: rgba(15, 23, 42, 0.4); | |
| border: 1px solid var(--glass-border); | |
| border-radius: 10px; | |
| color: var(--text-main); | |
| font-size: 1.25rem; | |
| text-align: center; | |
| outline: none; | |
| transition: all 0.3s; | |
| } | |
| .otp-box:focus { | |
| border-color: var(--primary-color); | |
| transform: scale(1.05); | |
| background: rgba(15, 23, 42, 0.7); | |
| } | |
| .timer-text { | |
| text-align: center; | |
| color: var(--text-muted); | |
| font-size: 0.85rem; | |
| margin-top: 1rem; | |
| } | |
| .resend-link { | |
| color: var(--primary-color); | |
| cursor: pointer; | |
| text-decoration: none; | |
| font-weight: 600; | |
| opacity: 0.5; | |
| pointer-events: none; | |
| } | |
| .resend-link.active { | |
| opacity: 1; | |
| pointer-events: auto; | |
| } | |
| /* انیمیشن تغییر صفحات */ | |
| .step-container { | |
| display: none; | |
| animation: fadeIn 0.4s ease-out; | |
| } | |
| .step-container.active { | |
| display: block; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| /* صفحه موفقیت */ | |
| .success-view { | |
| text-align: center; | |
| padding: 20px 0; | |
| } | |
| .success-icon { | |
| font-size: 4rem; | |
| color: var(--success-color); | |
| margin-bottom: 1rem; | |
| animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| } | |
| @keyframes popIn { | |
| from { transform: scale(0); } | |
| to { transform: scale(1); } | |
| } | |
| /* Toast Notification */ | |
| .toast-container { | |
| position: fixed; | |
| bottom: 30px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| z-index: 100; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| } | |
| .toast { | |
| background: rgba(30, 41, 59, 0.95); | |
| color: white; | |
| padding: 12px 24px; | |
| border-radius: 50px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.5); | |
| font-size: 0.9rem; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| animation: slideUp 0.3s ease-out; | |
| border: 1px solid var(--glass-border); | |
| min-width: 300px; | |
| justify-content: center; | |
| } | |
| .toast.error { border-color: var(--error-color); } | |
| .toast.success { border-color: var(--success-color); } | |
| @keyframes slideUp { | |
| from { opacity: 0; transform: translateY(20px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| /* اسپینر لودینگ */ | |
| .spinner { | |
| width: 20px; | |
| height: 20px; | |
| border: 2px solid rgba(255,255,255,0.3); | |
| border-radius: 50%; | |
| border-top-color: white; | |
| animation: spin 0.8s linear infinite; | |
| display: none; | |
| } | |
| .btn-primary.loading .spinner { display: block; } | |
| .btn-primary.loading span { display: none; } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| /* ریسپانسیو */ | |
| @media (max-width: 480px) { | |
| .login-card { | |
| margin: 0; | |
| width: 100%; | |
| height: 100vh; | |
| border-radius: 0; | |
| border: none; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| } | |
| .orb { opacity: 0.4; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- پسزمینه متحرک --> | |
| <div class="orb orb-1"></div> | |
| <div class="orb orb-2"></div> | |
| <!-- هدر لینک --> | |
| <header> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link"> | |
| <i class="fa-solid fa-code"></i> Built with anycoder | |
| </a> | |
| </header> | |
| <!-- کانتینر اصلی --> | |
| <main class="login-card"> | |
| <!-- لوگو و تایتل --> | |
| <div class="logo-area"> | |
| <div class="logo-icon"> | |
| <i class="fa-solid fa-bolt"></i> | |
| </div> | |
| <h1 class="title">خوش آمدید</h1> | |
| <p class="subtitle">برای ادامه وارد حساب کاربری خود شوید</p> | |
| </div> | |
| <!-- مرحله ۱: ورود شماره موبایل --> | |
| <section id="step-phone" class="step-container active"> | |
| <div class="form-group"> | |
| <label style="display:block; margin-bottom:8px; color:var(--text-muted); font-size:0.9rem;">شماره موبایل</label> | |
| <div class="input-wrapper"> | |
| <input type="tel" id="phoneInput" class="form-input" placeholder="09123456789" maxlength="11" inputmode="numeric"> | |
| <i class="fa-solid fa-mobile-screen input-icon"></i> | |
| </div> | |
| </div> | |
| <!-- شبیهسازی کپچا --> | |
| <div class="captcha-wrapper" id="captchaBox" onclick="toggleCaptcha()"> | |
| <div class="custom-checkbox"> | |
| <i class="fa-solid fa-check" style="color:white; font-size:12px; display:none;" id="captchaCheckIcon"></i> | |
| </div> | |
| <div class="captcha-text">من ربات نیستم</div> | |
| <i class="fa-solid fa-robot captcha-icon"></i> | |
| <i class="fa-solid fa-shield-halved captcha-icon" style="margin-right:10px;"></i> | |
| </div> | |
| <button class="btn-primary" onclick="sendCode()" id="sendBtn"> | |
| <span>دریافت کد تایید</span> | |
| <div class="spinner"></div> | |
| </button> | |
| </section> | |
| <!-- مرحله ۲: ورود کد تایید --> | |
| <section id="step-otp" class="step-container"> | |
| <div style="text-align:center; margin-bottom:20px;"> | |
| <p style="color:var(--text-muted); font-size:0.9rem;"> | |
| کد ۶ رقمی ارسال شده به شماره | |
| <span id="displayPhone" style="color:var(--text-main); font-weight:bold;"></span> | |
| را وارد کنید. | |
| </p> | |
| <span onclick="changePhone()" style="color:var(--primary-color); font-size:0.8rem; cursor:pointer; margin-top:5px; display:inline-block;">ویرایش شماره</span> | |
| </div> | |
| <div class="otp-inputs" id="otpContainer"> | |
| <input type="text" class="otp-box" maxlength="1" inputmode="numeric"> | |
| <input type="text" class="otp-box" maxlength="1" inputmode="numeric"> | |
| <input type="text" class="otp-box" maxlength="1" inputmode="numeric"> | |
| <input type="text" class="otp-box" maxlength="1" inputmode="numeric"> | |
| <input type="text" class="otp-box" maxlength="1" inputmode="numeric"> | |
| <input type="text" class="otp-box" maxlength="1" inputmode="numeric"> | |
| </div> | |
| <button class="btn-primary" onclick="verifyCode()" id="verifyBtn"> | |
| <span>تایید و ورود</span> | |
| <div class="spinner"></div> | |
| </button> | |
| <div class="timer-text"> | |
| ارسال مجدد کد تا <span id="timer" style="color:var(--text-main); font-weight:bold;">02:00</span> | |
| <br> | |
| <span class="resend-link" id="resendLink" onclick="resendCode()">ارسال مجدد کد</span> | |
| </div> | |
| </section> | |
| <!-- مرحله ۳: ورود موفق --> | |
| <section id="step-success" class="step-container"> | |
| <div class="success-view"> | |
| <i class="fa-solid fa-circle-check success-icon"></i> | |
| <h2 class="title" style="margin-bottom:10px;">ورود موفق!</h2> | |
| <p class="subtitle">شما با موفقیت وارد پنل کاربری شدید.</p> | |
| <div style="margin-top:30px;"> | |
| <button class="btn-primary" onclick="location.reload()"> | |
| <span>خروج</span> | |
| </button> | |
| </div> | |
| </div> | |
| </section> | |
| </main> | |
| <!-- کانتینر Toast --> | |
| <div class="toast-container" id="toastContainer"></div> | |
| <script> | |
| // متغیرهای سراسری | |
| let isCaptchaChecked = false; | |
| let countdownInterval; | |
| const TOTAL_TIME = 120; // 2 دقیقه | |
| let timeLeft = TOTAL_TIME; | |
| // المانهای DOM | |
| const stepPhone = document.getElementById('step-phone'); | |
| const stepOtp = document.getElementById('step-otp'); | |
| const stepSuccess = document.getElementById('step-success'); | |
| const phoneInput = document.getElementById('phoneInput'); | |
| const captchaBox = document.getElementById('captchaBox'); | |
| const captchaCheckIcon = document.getElementById('captchaCheckIcon'); | |
| const otpInputs = document.querySelectorAll('.otp-box'); | |
| const timerElement = document.getElementById('timer'); | |
| const resendLink = document.getElementById('resendLink'); | |
| // منطق کپچا | |
| function toggleCaptcha() { | |
| isCaptchaChecked = !isCaptchaChecked; | |
| if (isCaptchaChecked) { | |
| captchaBox.classList.add('checked'); | |
| captchaCheckIcon.style.display = 'block'; | |
| } else { | |
| captchaBox.classList.remove('checked'); | |
| captchaCheckIcon.style.display = 'none'; | |
| } | |
| } | |
| // تابع نمایش Toast (پیام اعلان) | |
| function showToast(message, type = 'info') { | |
| const container = document.getElementById('toastContainer'); | |
| const toast = document.createElement('div'); | |
| toast.className = `toast ${type}`; | |
| let icon = ''; | |
| if (type === 'error') icon = '<i class="fa-solid fa-circle-exclamation"></i>'; | |
| else if (type === 'success') icon = '<i class="fa-solid fa-circle-check"></i>'; | |
| else icon = '<i class="fa-solid fa-info-circle"></i>'; | |
| toast.innerHTML = `${icon} <span>${message}</span>`; | |
| container.appendChild(toast); | |
| // حذف خودکار بعد از 3 ثانیه | |
| setTimeout(() => { | |
| toast.style.opacity = '0'; | |
| toast.style.transform = 'translateY(20px)'; | |
| setTimeout(() => toast.remove(), 300); | |
| }, 3000); | |
| } | |
| // اعتبارسنجی و ارسال کد | |
| function sendCode() { | |
| const phone = phoneInput.value; | |
| // اعتبارسنجی شماره موبایل (ایران) | |
| const phoneRegex = /^09\d{9}$/; | |
| if (!phoneRegex.test(phone)) { | |
| showToast('لطفاً شماره موبایل معتبر وارد کنید (مثال: 0912...)', 'error'); | |
| phoneInput.focus(); | |
| return; | |
| } | |
| if (!isCaptchaChecked) { | |
| showToast('لطفاً تیک "من ربات نیستم" را بزنید', 'error'); | |
| return; | |
| } | |
| // شبیهسازی درخواست شبکه | |
| const btn = document.getElementById('sendBtn'); | |
| setLoading(btn, true); | |
| setTimeout(() => { | |
| setLoading(btn, false); | |
| showToast('کد تایید ارسال شد', 'success'); | |
| document.getElementById('displayPhone').textContent = phone; | |
| switchStep(stepPhone, stepOtp); | |
| startTimer(); | |
| otpInputs[0].focus(); | |
| }, 1500); | |
| } | |
| // مدیریت تایمر 2 دقیقهای | |
| function startTimer() { | |
| timeLeft = TOTAL_TIME; | |
| resendLink.classList.remove('active'); | |
| updateTimerDisplay(); | |
| clearInterval(countdownInterval); | |
| countdownInterval = setInterval(() => { | |
| timeLeft--; | |
| updateTimerDisplay(); | |
| if (timeLeft <= 0) { | |
| clearInterval(countdownInterval); | |
| resendLink.classList.add('active'); | |
| timerElement.textContent = "00:00"; | |
| } | |
| }, 1000); | |
| } | |
| function updateTimerDisplay() { | |
| const minutes = Math.floor(timeLeft / 60); | |
| const seconds = timeLeft % 60; | |
| timerElement.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; | |
| } | |
| // ارسال مجدد کد | |
| function resendCode() { | |
| if (timeLeft > 0) return; | |
| showToast('کد جدید ارسال شد', 'success'); | |
| // پاک کردن اینپوتها | |
| otpInputs.forEach(input => input.value = ''); | |
| startTimer(); | |
| otpInputs[0].focus(); | |
| } | |
| // تغییر شماره موبایل (بازگشت به عقب) | |
| function changePhone() { | |
| clearInterval(countdownInterval); | |
| switchStep(stepOtp, stepPhone); | |
| } | |
| // مدیریت ورودیهای OTP (رفتن خودکار به اینپوت بعدی) | |
| otpInputs.forEach((input, index) => { | |
| input.addEventListener('input', (e) => { | |
| // فقط عدد قبول کن | |
| e.target.value = e.target.value.replace(/[^0-9]/g, ''); | |
| if (e.target.value.length === 1) { | |
| if (index < otpInputs.length - 1) { | |
| otpInputs[index + 1].focus(); | |
| } | |
| } | |
| }); | |
| input.addEventListener('keydown', (e) => { | |
| if (e.key === 'Backspace' && e.target.value === '') { | |
| if (index > 0) { | |
| otpInputs[index - 1].focus(); | |
| } | |
| } | |
| }); | |
| // پشتیبانی از Paste برای کد | |
| input.addEventListener('paste', (e) => { | |
| e.preventDefault(); | |
| const pasteData = (e.clipboardData || window.clipboardData).getData('text'); | |
| const numbers = pasteData.replace(/[^0-9]/g, '').split(''); | |
| if (numbers.length > 0) { | |
| otpInputs.forEach((inp, i) => { | |
| if (numbers[i]) inp.value = numbers[i]; | |
| }); | |
| // فوکوس بر آخرین اینپوت پر شده | |
| const focusIndex = Math.min(numbers.length, otpInputs.length) - 1; | |
| if(focusIndex >= 0) otpInputs[focusIndex].focus(); | |
| } | |
| }); | |
| }); | |
| // تایید کد و ورود نهایی | |
| function verifyCode() { | |
| let code = ''; | |
| otpInputs.forEach(input => code += input.value); | |
| if (code.length !== 6) { | |
| showToast('لطفاً کد ۶ رقمی را کامل وارد کنید', 'error'); | |
| return; | |
| } | |
| const btn = document.getElementById('verifyBtn'); | |
| setLoading(btn, true); | |
| // شبیهسازی بررسی سرور | |
| setTimeout(() => { | |
| setLoading(btn, false); | |
| // فرض میکنیم هر کدی صحیح است برای دمو | |
| showToast('ورود با موفقیت انجام شد', 'success'); | |
| switchStep(stepOtp, stepSuccess); | |
| }, 1500); | |
| } | |
| // توابع کمکی رابط کاربری | |
| function switchStep(current, next) { | |
| current.classList.remove('active'); | |
| setTimeout(() => { | |
| current.style.display = 'none'; | |
| next.style.display = 'block'; | |
| // Force reflow | |
| void next.offsetWidth; | |
| next.classList.add('active'); | |
| }, 100); // کمی تاخیر برای انیمیشن نرم | |
| } | |
| function setLoading(btn, isLoading) { | |
| if (isLoading) { | |
| btn.classList.add('loading'); | |
| btn.disabled = true; | |
| } else { | |
| btn.classList.remove('loading'); | |
| btn.disabled = false; | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> |