anycoder-5f36c8ae / index.html
samirerty's picture
Upload folder using huggingface_hub
e9d16cc verified
<!DOCTYPE html>
<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>