626 lines
21 KiB
HTML
626 lines
21 KiB
HTML
<!doctype html>
|
||
<html lang="fa" dir="rtl">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>ایلو · ورود و ثبتنام</title>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;500;600;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="styles.css" />
|
||
|
||
<style>
|
||
body { background: var(--bg); }
|
||
.auth-shell {
|
||
min-height: 100vh;
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
}
|
||
.auth-side {
|
||
background: linear-gradient(150deg, oklch(0.94 0.04 40), oklch(0.96 0.02 60));
|
||
position: relative;
|
||
overflow: hidden;
|
||
padding: 48px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
.auth-side::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -20% -10% auto auto;
|
||
width: 480px; height: 480px;
|
||
border-radius: 50%;
|
||
background: radial-gradient(circle, oklch(0.78 0.10 40 / 0.4), transparent 70%);
|
||
filter: blur(40px);
|
||
}
|
||
.auth-side::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: auto auto -20% -10%;
|
||
width: 380px; height: 380px;
|
||
border-radius: 50%;
|
||
background: radial-gradient(circle, oklch(0.78 0.08 80 / 0.4), transparent 70%);
|
||
filter: blur(40px);
|
||
}
|
||
.auth-side > * { position: relative; z-index: 1; }
|
||
|
||
.brand-row {
|
||
display: flex; align-items: center; gap: 12px;
|
||
}
|
||
.brand-mark {
|
||
width: 44px; height: 44px;
|
||
border-radius: 13px;
|
||
background: linear-gradient(140deg, var(--accent), var(--accent-2));
|
||
display: grid; place-items: center;
|
||
color: white;
|
||
font-weight: 700;
|
||
font-family: var(--font-en);
|
||
font-size: 18px;
|
||
letter-spacing: -0.02em;
|
||
box-shadow: 0 4px 16px oklch(0.72 0.14 40 / 0.3);
|
||
}
|
||
|
||
.auth-pitch {
|
||
max-width: 480px;
|
||
}
|
||
.auth-pitch h1 {
|
||
font-size: 40px;
|
||
line-height: 1.25;
|
||
letter-spacing: -0.02em;
|
||
font-weight: 700;
|
||
margin: 0 0 16px;
|
||
}
|
||
.auth-pitch h1 em {
|
||
font-style: normal;
|
||
background: linear-gradient(120deg, var(--accent), var(--accent-2));
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
}
|
||
.auth-pitch p {
|
||
color: var(--ink-2);
|
||
font-size: 16px;
|
||
line-height: 1.7;
|
||
margin: 0 0 24px;
|
||
}
|
||
.auth-bullets {
|
||
display: flex; flex-direction: column; gap: 14px;
|
||
}
|
||
.auth-bullet {
|
||
display: flex; align-items: center; gap: 12px;
|
||
font-size: 14px;
|
||
color: var(--ink-2);
|
||
}
|
||
.auth-bullet .b-ic {
|
||
width: 28px; height: 28px;
|
||
border-radius: 8px;
|
||
background: white;
|
||
color: var(--accent);
|
||
display: grid; place-items: center;
|
||
box-shadow: 0 2px 6px rgba(0,0,0,.06);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.auth-foot {
|
||
display: flex; gap: 24px;
|
||
color: var(--ink-3);
|
||
font-size: 12.5px;
|
||
}
|
||
|
||
.auth-main {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 48px;
|
||
background: var(--surface);
|
||
}
|
||
.auth-card {
|
||
width: 100%;
|
||
max-width: 420px;
|
||
display: flex; flex-direction: column;
|
||
}
|
||
|
||
.auth-stepper {
|
||
display: flex; align-items: center; gap: 8px;
|
||
margin-bottom: 32px;
|
||
}
|
||
.step-dot {
|
||
width: 26px; height: 26px;
|
||
border-radius: 50%;
|
||
display: grid; place-items: center;
|
||
font-size: 12px; font-weight: 600;
|
||
background: var(--surface-2);
|
||
color: var(--ink-3);
|
||
border: 1px solid var(--line);
|
||
}
|
||
.step-dot.active {
|
||
background: var(--accent);
|
||
color: white;
|
||
border-color: transparent;
|
||
}
|
||
.step-dot.done {
|
||
background: var(--accent-soft);
|
||
color: var(--accent-ink);
|
||
border-color: transparent;
|
||
}
|
||
.step-line {
|
||
flex: 1; height: 2px;
|
||
background: var(--line);
|
||
border-radius: 999px;
|
||
}
|
||
.step-line.done { background: var(--accent); }
|
||
|
||
.auth-h1 {
|
||
font-size: 26px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.015em;
|
||
margin: 0 0 8px;
|
||
}
|
||
.auth-sub {
|
||
color: var(--ink-3);
|
||
font-size: 14px;
|
||
margin: 0 0 28px;
|
||
}
|
||
|
||
.field-stack { display: flex; flex-direction: column; gap: 16px; margin-bottom: 24px; }
|
||
.field-lbl {
|
||
font-size: 12.5px;
|
||
font-weight: 500;
|
||
color: var(--ink-2);
|
||
margin-bottom: 6px;
|
||
display: block;
|
||
}
|
||
|
||
.phone-inp {
|
||
display: flex;
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
border-radius: var(--r-sm);
|
||
overflow: hidden;
|
||
transition: border-color .15s, box-shadow .15s;
|
||
}
|
||
.phone-inp:focus-within {
|
||
border-color: var(--accent);
|
||
box-shadow: 0 0 0 3px var(--accent-soft);
|
||
}
|
||
.phone-cc {
|
||
padding: 12px 14px;
|
||
background: var(--surface-2);
|
||
border-inline-end: 1px solid var(--line);
|
||
display: flex; align-items: center; gap: 8px;
|
||
color: var(--ink-2);
|
||
font-family: var(--font-num);
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
}
|
||
.phone-inp input {
|
||
flex: 1;
|
||
border: 0; outline: 0; background: transparent;
|
||
padding: 12px 14px;
|
||
font: inherit; font-size: 16px;
|
||
letter-spacing: 0.5px;
|
||
color: var(--ink);
|
||
direction: ltr;
|
||
text-align: start;
|
||
font-family: var(--font-num);
|
||
}
|
||
|
||
.role-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 12px;
|
||
margin-bottom: 24px;
|
||
}
|
||
.role-card {
|
||
border: 1.5px solid var(--line);
|
||
border-radius: var(--r-md);
|
||
background: var(--surface);
|
||
padding: 20px;
|
||
cursor: pointer;
|
||
transition: all .15s;
|
||
text-align: start;
|
||
display: flex; flex-direction: column; gap: 12px;
|
||
}
|
||
.role-card:hover {
|
||
border-color: var(--ink-4);
|
||
background: var(--surface-2);
|
||
}
|
||
.role-card.selected {
|
||
border-color: var(--accent);
|
||
background: var(--accent-soft);
|
||
box-shadow: 0 0 0 3px var(--accent-soft);
|
||
}
|
||
.role-ic {
|
||
width: 36px; height: 36px;
|
||
border-radius: 10px;
|
||
background: color-mix(in oklch, var(--accent) 18%, transparent);
|
||
color: var(--accent);
|
||
display: grid; place-items: center;
|
||
}
|
||
.role-card.selected .role-ic {
|
||
background: var(--accent);
|
||
color: white;
|
||
}
|
||
.role-card h3 { margin: 0; font-size: 15px; font-weight: 600; }
|
||
.role-card p { margin: 0; font-size: 12px; color: var(--ink-3); line-height: 1.55; }
|
||
|
||
.channel-row {
|
||
display: flex; gap: 8px;
|
||
padding: 4px;
|
||
background: var(--surface-2);
|
||
border-radius: var(--r-sm);
|
||
margin-bottom: 24px;
|
||
}
|
||
.channel-btn {
|
||
flex: 1;
|
||
appearance: none;
|
||
border: 0;
|
||
background: transparent;
|
||
padding: 10px;
|
||
border-radius: 6px;
|
||
font: inherit;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: var(--ink-3);
|
||
cursor: pointer;
|
||
display: flex; align-items: center; justify-content: center; gap: 6px;
|
||
}
|
||
.channel-btn.active {
|
||
background: var(--surface);
|
||
color: var(--ink);
|
||
box-shadow: 0 1px 2px rgba(0,0,0,.06);
|
||
}
|
||
|
||
.otp-row {
|
||
display: flex; gap: 8px;
|
||
direction: ltr;
|
||
margin-bottom: 8px;
|
||
}
|
||
.otp-cell {
|
||
flex: 1 1 0;
|
||
min-width: 0;
|
||
width: 0;
|
||
height: 64px;
|
||
border: 1.5px solid var(--line);
|
||
background: var(--surface);
|
||
border-radius: var(--r-sm);
|
||
font: inherit;
|
||
font-size: 22px;
|
||
font-weight: 700;
|
||
text-align: center;
|
||
color: var(--ink);
|
||
outline: none;
|
||
transition: all .15s;
|
||
font-family: var(--font-num);
|
||
}
|
||
.otp-cell:focus,
|
||
.otp-cell.filled {
|
||
border-color: var(--accent);
|
||
box-shadow: 0 0 0 3px var(--accent-soft);
|
||
}
|
||
|
||
.resend-row {
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
font-size: 12.5px;
|
||
color: var(--ink-3);
|
||
margin-bottom: 24px;
|
||
}
|
||
.resend-row b { color: var(--ink); font-weight: 600; font-family: var(--font-num); }
|
||
.resend-btn {
|
||
appearance: none; border: 0; background: 0;
|
||
color: var(--accent);
|
||
font: inherit; font-weight: 600; font-size: 13px;
|
||
cursor: pointer;
|
||
}
|
||
.resend-btn:disabled { color: var(--ink-4); cursor: default; }
|
||
|
||
.btn.full { width: 100%; justify-content: center; padding: 12px 16px; font-size: 14px; font-weight: 600; }
|
||
|
||
.legal {
|
||
font-size: 11.5px;
|
||
color: var(--ink-3);
|
||
text-align: center;
|
||
margin-top: 24px;
|
||
line-height: 1.6;
|
||
}
|
||
.legal a { color: var(--ink-2); text-decoration: underline; }
|
||
|
||
.switch-row {
|
||
text-align: center;
|
||
font-size: 13px;
|
||
color: var(--ink-3);
|
||
margin-top: 28px;
|
||
}
|
||
.switch-row a {
|
||
color: var(--accent);
|
||
text-decoration: none;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.success-icon {
|
||
width: 64px; height: 64px;
|
||
border-radius: 50%;
|
||
background: oklch(0.94 0.05 155);
|
||
color: oklch(0.55 0.14 155);
|
||
display: grid; place-items: center;
|
||
margin: 0 auto 24px;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.auth-shell { grid-template-columns: 1fr; }
|
||
.auth-side { display: none; }
|
||
}
|
||
</style>
|
||
|
||
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
||
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
||
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
||
</head>
|
||
<body>
|
||
<div id="root"></div>
|
||
<script type="text/babel" src="icons.jsx"></script>
|
||
<script type="text/babel">
|
||
function Stepper({ step, total }) {
|
||
return (
|
||
<div className="auth-stepper">
|
||
{Array.from({ length: total }).map((_, i) => (
|
||
<React.Fragment key={i}>
|
||
<div className={`step-dot ${i === step ? 'active' : i < step ? 'done' : ''}`}>
|
||
{i < step ? <Icon name="check" className="ic-sm" /> : String(i+1).replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d])}
|
||
</div>
|
||
{i < total - 1 && <div className={`step-line ${i < step ? 'done' : ''}`} />}
|
||
</React.Fragment>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// OTP digit input row
|
||
function OtpInput({ value, onChange }) {
|
||
const refs = React.useRef([]);
|
||
const handle = (i, v) => {
|
||
const digit = v.replace(/\D/g, '').slice(-1);
|
||
const next = (value + '').padEnd(5, ' ').split('');
|
||
next[i] = digit || ' ';
|
||
const joined = next.join('').replace(/ /g, '');
|
||
onChange(joined);
|
||
if (digit && i < 4) refs.current[i + 1]?.focus();
|
||
};
|
||
const handleKey = (i, e) => {
|
||
if (e.key === 'Backspace' && !value[i] && i > 0) refs.current[i - 1]?.focus();
|
||
};
|
||
const handlePaste = (e) => {
|
||
const text = (e.clipboardData.getData('text') || '').replace(/\D/g, '').slice(0, 5);
|
||
if (text) { e.preventDefault(); onChange(text); refs.current[Math.min(text.length, 4)]?.focus(); }
|
||
};
|
||
return (
|
||
<div className="otp-row" onPaste={handlePaste}>
|
||
{[0,1,2,3,4].map(i => (
|
||
<input key={i} ref={el => refs.current[i] = el}
|
||
className={`otp-cell ${value[i] ? 'filled' : ''}`}
|
||
inputMode="numeric" maxLength={1}
|
||
value={value[i] || ''}
|
||
onChange={e => handle(i, e.target.value)}
|
||
onKeyDown={e => handleKey(i, e)} />
|
||
))}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function App() {
|
||
const [step, setStep] = React.useState(0); // 0=role, 1=phone, 2=otp, 3=done
|
||
const [mode, setMode] = React.useState('signup'); // signup | signin
|
||
const [role, setRole] = React.useState('instructor');
|
||
const [channel, setChannel] = React.useState('sms');
|
||
const [phone, setPhone] = React.useState('');
|
||
const [otp, setOtp] = React.useState('');
|
||
const [resendIn, setResendIn] = React.useState(0);
|
||
|
||
React.useEffect(() => {
|
||
if (resendIn > 0) {
|
||
const t = setTimeout(() => setResendIn(resendIn - 1), 1000);
|
||
return () => clearTimeout(t);
|
||
}
|
||
}, [resendIn]);
|
||
|
||
const phoneOk = phone.length === 10 && phone.startsWith('9');
|
||
const otpOk = otp.length === 5;
|
||
|
||
const sendOtp = () => {
|
||
setOtp('');
|
||
setResendIn(60);
|
||
setStep(2);
|
||
};
|
||
|
||
const fa = (s) => String(s).replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d]);
|
||
|
||
// — Step 0: welcome / role —
|
||
const StepRole = (
|
||
<>
|
||
<h1 className="auth-h1">{mode === 'signup' ? 'به ایلو خوش اومدی 👋' : 'دوباره خوش اومدی'}</h1>
|
||
<p className="auth-sub">
|
||
{mode === 'signup' ? 'برای شروع، نقش خودت رو انتخاب کن.' : 'وارد حساب کاربریات شو.'}
|
||
</p>
|
||
|
||
{mode === 'signup' && (
|
||
<div className="role-grid">
|
||
<button className={`role-card ${role === 'instructor' ? 'selected' : ''}`}
|
||
onClick={() => setRole('instructor')}>
|
||
<div className="role-ic"><Icon name="trophy" /></div>
|
||
<h3>مدرس هستم</h3>
|
||
<p>میخوام دوره بسازم و بفروشم</p>
|
||
</button>
|
||
<button className={`role-card ${role === 'student' ? 'selected' : ''}`}
|
||
onClick={() => setRole('student')}>
|
||
<div className="role-ic"><Icon name="book" /></div>
|
||
<h3>دانشجو هستم</h3>
|
||
<p>میخوام چیز جدیدی یاد بگیرم</p>
|
||
</button>
|
||
</div>
|
||
)}
|
||
|
||
<button className="btn primary full" onClick={() => setStep(1)}>
|
||
ادامه
|
||
<Icon name="chevron" className="ic-sm flipx" />
|
||
</button>
|
||
|
||
<div className="switch-row">
|
||
{mode === 'signup' ? 'قبلاً ثبتنام کردی؟ ' : 'حساب نداری؟ '}
|
||
<a onClick={() => setMode(mode === 'signup' ? 'signin' : 'signup')}>
|
||
{mode === 'signup' ? 'وارد شو' : 'ثبتنام کن'}
|
||
</a>
|
||
</div>
|
||
</>
|
||
);
|
||
|
||
// — Step 1: phone —
|
||
const StepPhone = (
|
||
<>
|
||
<h1 className="auth-h1">شماره موبایلت رو وارد کن</h1>
|
||
<p className="auth-sub">
|
||
یک کد ۵ رقمی برای تأیید برات ارسال میکنیم.
|
||
</p>
|
||
|
||
<div className="channel-row">
|
||
<button className={`channel-btn ${channel === 'sms' ? 'active' : ''}`}
|
||
onClick={() => setChannel('sms')}>
|
||
<Icon name="phone" className="ic-sm" />
|
||
پیامک
|
||
</button>
|
||
<button className={`channel-btn ${channel === 'bale' ? 'active' : ''}`}
|
||
onClick={() => setChannel('bale')}>
|
||
<Icon name="send" className="ic-sm" />
|
||
بله
|
||
</button>
|
||
</div>
|
||
|
||
<div className="field-stack">
|
||
<div>
|
||
<label className="field-lbl">شماره موبایل</label>
|
||
<div className="phone-inp">
|
||
<div className="phone-cc">
|
||
<span>🇮🇷</span>
|
||
<span>+۹۸</span>
|
||
</div>
|
||
<input value={phone} onChange={e => setPhone(e.target.value.replace(/\D/g,'').slice(0,10))}
|
||
placeholder="9XX XXX XXXX" inputMode="numeric" autoFocus />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<button className="btn primary full" disabled={!phoneOk}
|
||
style={{ opacity: phoneOk ? 1 : 0.5, cursor: phoneOk ? 'pointer' : 'not-allowed' }}
|
||
onClick={sendOtp}>
|
||
ارسال کد تأیید
|
||
<Icon name="chevron" className="ic-sm flipx" />
|
||
</button>
|
||
|
||
<div className="legal">
|
||
با ادامه دادن، با <a>قوانین استفاده</a> و <a>سیاست حریم خصوصی</a> ایلو موافقت میکنی.
|
||
</div>
|
||
</>
|
||
);
|
||
|
||
// — Step 2: OTP —
|
||
const StepOtp = (
|
||
<>
|
||
<h1 className="auth-h1">کد تأیید</h1>
|
||
<p className="auth-sub">
|
||
کد ۵ رقمی به {channel === 'sms' ? 'پیامک' : 'پیام بله'} شماره <b className="num" style={{ direction: 'ltr', display: 'inline-block' }}>+۹۸ {fa(phone)}</b> ارسال شد.
|
||
</p>
|
||
|
||
<OtpInput value={otp} onChange={setOtp} />
|
||
|
||
<div className="resend-row" style={{ marginTop: 16 }}>
|
||
{resendIn > 0
|
||
? <span>ارسال مجدد در <b>{fa(resendIn)} ثانیه</b></span>
|
||
: <span>کد رو دریافت نکردی؟</span>}
|
||
<button className="resend-btn" disabled={resendIn > 0} onClick={() => setResendIn(60)}>
|
||
ارسال مجدد
|
||
</button>
|
||
</div>
|
||
|
||
<button className="btn primary full" disabled={!otpOk}
|
||
style={{ opacity: otpOk ? 1 : 0.5, cursor: otpOk ? 'pointer' : 'not-allowed' }}
|
||
onClick={() => setStep(3)}>
|
||
تأیید و ورود
|
||
<Icon name="check" className="ic-sm" />
|
||
</button>
|
||
|
||
<div className="switch-row">
|
||
<a onClick={() => setStep(1)}>← تغییر شماره موبایل</a>
|
||
</div>
|
||
</>
|
||
);
|
||
|
||
// — Step 3: done —
|
||
const StepDone = (
|
||
<div style={{ textAlign: 'center' }}>
|
||
<div className="success-icon">
|
||
<Icon name="check" style={{ width: 32, height: 32, strokeWidth: 2.5 }} />
|
||
</div>
|
||
<h1 className="auth-h1">حساب با موفقیت ساخته شد</h1>
|
||
<p className="auth-sub" style={{ marginBottom: 32 }}>
|
||
{role === 'instructor'
|
||
? 'حالا میتونی اولین دورهات رو بسازی و دانشجوها رو دعوت کنی.'
|
||
: 'به دنیای ایلو خوش اومدی! بیا یه دوره عالی پیدا کنیم.'}
|
||
</p>
|
||
<a className="btn primary full"
|
||
href={role === 'instructor' ? 'Ilo Instructor Panel.html' : 'Ilo Student.html'}
|
||
style={{ textDecoration: 'none' }}>
|
||
{role === 'instructor' ? 'ورود به پنل مدرس' : 'مشاهدهی دورهها'}
|
||
<Icon name="chevron" className="ic-sm flipx" />
|
||
</a>
|
||
</div>
|
||
);
|
||
|
||
return (
|
||
<div className="auth-shell">
|
||
<aside className="auth-side">
|
||
<div className="brand-row">
|
||
<div className="brand-mark">il</div>
|
||
<div>
|
||
<div style={{ fontSize: 18, fontWeight: 700 }}>ایلو</div>
|
||
<div style={{ fontSize: 11.5, color: 'var(--ink-3)' }} className="en">platform for teachers</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="auth-pitch">
|
||
<h1>پلتفرمی برای <em>مدرسها</em>،<br/>که میخوان حرفهایتر یاد بدن.</h1>
|
||
<p>محتوات رو آپلود کن، مسیر یادگیری بساز، با دانشجوها در ارتباط باش و درآمدت رو رشد بده — همه در یکجا.</p>
|
||
<div className="auth-bullets">
|
||
<div className="auth-bullet"><div className="b-ic"><Icon name="upload" className="ic-sm" /></div>آپلود راحت ویدیو، PDF و فایل صوتی</div>
|
||
<div className="auth-bullet"><div className="b-ic"><Icon name="users" className="ic-sm" /></div>مدیریت دانشجوها و پیگیری پیشرفت</div>
|
||
<div className="auth-bullet"><div className="b-ic"><Icon name="store" className="ic-sm" /></div>سایت اختصاصی با نام و برند خودت</div>
|
||
<div className="auth-bullet"><div className="b-ic"><Icon name="chart" className="ic-sm" /></div>تحلیل درآمد و رفتار دانشجویان</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="auth-foot">
|
||
<span>© ۱۴۰۳ ایلو</span>
|
||
<span>·</span>
|
||
<span>پشتیبانی: <span className="num" dir="ltr">۰۲۱-۹۱۰۰۰۰۰۰</span></span>
|
||
</div>
|
||
</aside>
|
||
|
||
<main className="auth-main">
|
||
<div className="auth-card">
|
||
{step < 3 && mode === 'signup' && <Stepper step={step} total={3} />}
|
||
{step < 3 && mode === 'signin' && <Stepper step={Math.max(0, step - 1)} total={2} />}
|
||
{step === 0 && StepRole}
|
||
{step === 1 && StepPhone}
|
||
{step === 2 && StepOtp}
|
||
{step === 3 && StepDone}
|
||
</div>
|
||
</main>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
|
||
</script>
|
||
</body>
|
||
</html>
|