257 lines
8.9 KiB
HTML
257 lines
8.9 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Login - FINA{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
<style>
|
|
.material-icons {
|
|
font-family: 'Material Icons';
|
|
font-weight: normal;
|
|
font-style: normal;
|
|
font-size: 24px;
|
|
display: inline-block;
|
|
line-height: 1;
|
|
text-transform: none;
|
|
letter-spacing: normal;
|
|
word-wrap: normal;
|
|
white-space: nowrap;
|
|
direction: ltr;
|
|
-webkit-font-smoothing: antialiased;
|
|
text-rendering: optimizeLegibility;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
font-feature-settings: 'liga';
|
|
}
|
|
|
|
.radial-blue-bg {
|
|
background: radial-gradient(circle, #1e3a8a 0%, #1e293b 50%, #0f172a 100%);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.radial-blue-bg::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: -50%;
|
|
left: -50%;
|
|
width: 200%;
|
|
height: 200%;
|
|
background:
|
|
repeating-conic-gradient(from 0deg at 50% 50%,
|
|
transparent 0deg,
|
|
rgba(43, 140, 238, 0.1) 2deg,
|
|
transparent 4deg);
|
|
animation: rotate 60s linear infinite;
|
|
}
|
|
|
|
@keyframes rotate {
|
|
from { transform: rotate(0deg); }
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
.login-input {
|
|
border-radius: 25px;
|
|
padding: 12px 20px;
|
|
font-size: 14px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.light .login-input {
|
|
background: #f8fafc;
|
|
border: 1px solid #e2e8f0;
|
|
color: #0f172a;
|
|
}
|
|
|
|
.dark .login-input,
|
|
:root:not(.light) .login-input {
|
|
background: #1e293b;
|
|
border: 1px solid #334155;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.login-input:focus {
|
|
outline: none;
|
|
border-color: #3b82f6;
|
|
}
|
|
|
|
.light .login-input:focus {
|
|
background: #ffffff;
|
|
}
|
|
|
|
.dark .login-input:focus,
|
|
:root:not(.light) .login-input:focus {
|
|
background: #1e293b;
|
|
}
|
|
|
|
.light .login-input::placeholder {
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.dark .login-input::placeholder,
|
|
:root:not(.light) .login-input::placeholder {
|
|
color: #64748b;
|
|
}
|
|
|
|
.login-input:-webkit-autofill,
|
|
.login-input:-webkit-autofill:hover,
|
|
.login-input:-webkit-autofill:focus {
|
|
transition: background-color 5000s ease-in-out 0s;
|
|
}
|
|
|
|
.light .login-input:-webkit-autofill,
|
|
.light .login-input:-webkit-autofill:hover,
|
|
.light .login-input:-webkit-autofill:focus {
|
|
-webkit-text-fill-color: #0f172a;
|
|
-webkit-box-shadow: 0 0 0px 1000px #f8fafc inset;
|
|
}
|
|
|
|
.dark .login-input:-webkit-autofill,
|
|
.dark .login-input:-webkit-autofill:hover,
|
|
.dark .login-input:-webkit-autofill:focus,
|
|
:root:not(.light) .login-input:-webkit-autofill,
|
|
:root:not(.light) .login-input:-webkit-autofill:hover,
|
|
:root:not(.light) .login-input:-webkit-autofill:focus {
|
|
-webkit-text-fill-color: #ffffff;
|
|
-webkit-box-shadow: 0 0 0px 1000px #1e293b inset;
|
|
}
|
|
|
|
.login-btn {
|
|
background: #3b82f6;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 25px;
|
|
padding: 12px 40px;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
box-shadow: 0 0 20px rgba(59, 130, 246, 0.3);
|
|
}
|
|
|
|
.login-btn:hover {
|
|
background: #2563eb;
|
|
transform: translateX(2px);
|
|
box-shadow: 0 0 30px rgba(59, 130, 246, 0.5);
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block body %}
|
|
<div class="min-h-screen flex">
|
|
<!-- Left Side - Logo with Radial Background -->
|
|
<div class="hidden lg:flex lg:w-1/2 radial-blue-bg items-center justify-center relative">
|
|
<div class="relative z-10">
|
|
<img src="{{ url_for('static', filename='icons/logo.png') }}" alt="FINA Logo" class="w-96 h-96 rounded-full shadow-2xl">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Side - Login Form -->
|
|
<div class="w-full lg:w-1/2 flex items-center justify-center bg-background-light dark:bg-slate-900 p-8">
|
|
<div class="w-full max-w-md">
|
|
<!-- Mobile Logo -->
|
|
<div class="lg:hidden flex justify-center mb-8">
|
|
<img src="{{ url_for('static', filename='icons/logo.png') }}" alt="FINA Logo" class="w-24 h-24 rounded-full shadow-lg">
|
|
</div>
|
|
|
|
<!-- Login Header -->
|
|
<h1 class="text-3xl font-bold text-text-main dark:text-white mb-8">Login Here!</h1>
|
|
|
|
<!-- Login Form -->
|
|
<form id="login-form" class="space-y-6">
|
|
<!-- Username Field -->
|
|
<div class="flex items-center gap-3">
|
|
<span class="material-icons text-text-muted dark:text-slate-400 text-[24px]">person</span>
|
|
<input type="text" name="username" required autofocus
|
|
class="login-input flex-1"
|
|
placeholder="username or email">
|
|
</div>
|
|
|
|
<!-- Password Field -->
|
|
<div class="flex items-center gap-3">
|
|
<span class="material-icons text-text-muted dark:text-slate-400 text-[24px]">lock</span>
|
|
<div class="flex-1 relative">
|
|
<input type="password" name="password" id="password" required
|
|
class="login-input w-full pr-12"
|
|
placeholder="password">
|
|
<button type="button" onclick="togglePassword()" class="absolute right-4 top-1/2 -translate-y-1/2 text-text-muted dark:text-slate-400 hover:text-primary dark:hover:text-blue-400">
|
|
<span class="material-icons text-[20px]" id="eye-icon">visibility</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 2FA Field (hidden by default) -->
|
|
<div id="2fa-field" class="hidden flex items-center gap-3">
|
|
<span class="material-icons text-text-muted dark:text-slate-400 text-[24px]">security</span>
|
|
<input type="text" name="two_factor_code"
|
|
class="login-input flex-1"
|
|
placeholder="2FA code">
|
|
</div>
|
|
|
|
<!-- Remember Password & Login Button -->
|
|
<div class="flex items-center justify-between">
|
|
<label class="flex items-center text-sm text-text-muted dark:text-slate-300">
|
|
<input type="checkbox" name="remember" id="remember" class="mr-2 rounded border-border-light dark:border-slate-500 bg-background-light dark:bg-slate-700 text-blue-600">
|
|
<span>Remember Password</span>
|
|
</label>
|
|
|
|
<button type="submit" class="login-btn">
|
|
<span>LOGIN</span>
|
|
<span class="material-icons text-[18px]">arrow_forward</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- Register Link -->
|
|
<div class="mt-8 text-center text-sm text-text-muted dark:text-slate-300">
|
|
Don't have an account?
|
|
<a href="{{ url_for('auth.register') }}" class="text-primary dark:text-blue-400 hover:text-primary/80 dark:hover:text-blue-300 hover:underline font-medium">Create your account <span class="underline">here</span>!</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function togglePassword() {
|
|
const passwordInput = document.getElementById('password');
|
|
const eyeIcon = document.getElementById('eye-icon');
|
|
|
|
if (passwordInput.type === 'password') {
|
|
passwordInput.type = 'text';
|
|
eyeIcon.textContent = 'visibility_off';
|
|
} else {
|
|
passwordInput.type = 'password';
|
|
eyeIcon.textContent = 'visibility';
|
|
}
|
|
}
|
|
|
|
document.getElementById('login-form').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const formData = new FormData(e.target);
|
|
const data = Object.fromEntries(formData);
|
|
|
|
try {
|
|
const response = await fetch('/auth/login', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.requires_2fa) {
|
|
document.getElementById('2fa-field').classList.remove('hidden');
|
|
showToast('Please enter your 2FA code', 'info');
|
|
} else if (result.success) {
|
|
window.location.href = result.redirect;
|
|
} else {
|
|
showToast(result.message || 'Login failed', 'error');
|
|
}
|
|
} catch (error) {
|
|
showToast('An error occurred', 'error');
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|