UNPKG

gentelella

Version:

Gentelella v4 — free admin template. 60 pages, 20 chart variants, fully interactive inbox & kanban, live theme generator, component playground, PWA-ready. Vite 8, vanilla JS, no Bootstrap, no jQuery.

113 lines (100 loc) 4.6 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Two-factor verification | Gentelella 2026 v4</title> <link rel="icon" href="../images/favicon.svg" type="image/svg+xml"> <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=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> <script type="module" src="/src/main-v4.js"></script> </head> <body> <div class="auth-page"> <div class="auth-card"> <div class="auth-brand"> <div class="brand-icon">G</div> <div class="brand-name">Gentelella <small style="font-weight:400;color:var(--text-muted);font-size:13px;margin-left:2px">v4</small></div> </div> <div class="auth-title">Two-factor verification</div> <div class="auth-subtitle">Enter the 6-digit code from your authenticator app to continue.</div> <form id="otp-form"> <div class="otp-grid" role="group" aria-label="One-time password"> <input class="otp-input" aria-label="Digit 1 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" autocomplete="one-time-code" autofocus required> <input class="otp-input" aria-label="Digit 2 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" autocomplete="off" required> <input class="otp-input" aria-label="Digit 3 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" autocomplete="off" required> <input class="otp-input" aria-label="Digit 4 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" autocomplete="off" required> <input class="otp-input" aria-label="Digit 5 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" autocomplete="off" required> <input class="otp-input" aria-label="Digit 6 of 6" type="text" inputmode="numeric" pattern="[0-9]" maxlength="1" autocomplete="off" required> </div> <div class="otp-meta"> <span>Didn't get a code? <a href="#" id="resend-code">Resend</a></span> <span id="otp-timer">Expires in <strong>04:59</strong></span> </div> <button type="submit" class="btn btn-primary" style="width:100%;justify-content:center;height:38px"> Verify </button> </form> <div class="auth-divider">or</div> <div style="text-align:center;font-size:12.5px"> <a href="#">Use a backup code</a> </div> <div class="auth-footer"> <a href="login.html">← Back to sign in</a> </div> </div> </div> <script type="module"> const inputs = document.querySelectorAll('.otp-input'); inputs.forEach((input, idx) => { input.addEventListener('input', (e) => { // Strip non-digits e.target.value = e.target.value.replace(/\D/g, '').slice(0, 1); if (e.target.value && idx < inputs.length - 1) inputs[idx + 1].focus(); // Auto-submit when all 6 digits entered const code = Array.from(inputs).map((i) => i.value).join(''); if (code.length === 6) document.getElementById('otp-form').requestSubmit(); }); input.addEventListener('keydown', (e) => { if (e.key === 'Backspace' && !e.target.value && idx > 0) { inputs[idx - 1].focus(); inputs[idx - 1].value = ''; e.preventDefault(); } else if (e.key === 'ArrowLeft' && idx > 0) { inputs[idx - 1].focus(); } else if (e.key === 'ArrowRight' && idx < inputs.length - 1) { inputs[idx + 1].focus(); } }); input.addEventListener('paste', (e) => { e.preventDefault(); const pasted = (e.clipboardData?.getData('text') || '').replace(/\D/g, '').slice(0, 6); pasted.split('').forEach((c, i) => { if (inputs[i]) inputs[i].value = c; }); inputs[Math.min(pasted.length, inputs.length - 1)].focus(); if (pasted.length === 6) document.getElementById('otp-form').requestSubmit(); }); }); document.getElementById('otp-form').addEventListener('submit', (e) => { e.preventDefault(); e.stopPropagation(); // Simulate success window.location.href = 'index.html'; }); // Countdown timer let secs = 4 * 60 + 59; const timer = document.getElementById('otp-timer'); const tick = setInterval(() => { secs -= 1; if (secs <= 0) { clearInterval(tick); timer.innerHTML = '<a href="#">Code expired — resend</a>'; return; } const m = String(Math.floor(secs / 60)).padStart(2, '0'); const s = String(secs % 60).padStart(2, '0'); timer.innerHTML = `Expires in <strong>${m}:${s}</strong>`; }, 1000); </script> </body> </html>