authapi / static /login.html
Arkm20's picture
Update static/login.html
eb1b545 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login / Signup</title>
<style>
:root {
--accent-color: #FF9500;
--background-dark: #121212;
--form-bg-color: rgba(30, 30, 30, 0.65);
--input-bg-color: rgba(50, 50, 50, 0.7);
--text-primary: #FFFFFF;
--text-secondary: #AAAAAA;
--border-color: rgba(255, 255, 255, 0.1);
--error-color: #FF4747;
--success-color: #34C759;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: var(--background-dark);
/* Adding a subtle gradient for a more dynamic background */
background-image: radial-gradient(circle at 10% 20%, rgba(255, 149, 0, 0.15), transparent 50%),
radial-gradient(circle at 80% 90%, rgba(255, 149, 0, 0.1), transparent 40%);
}
.form-container {
width: 100%;
max-width: 400px;
margin: 20px;
background: var(--form-bg-color);
border-radius: 20px;
border: 1px solid var(--border-color);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
overflow: hidden;
transition: height 0.4s ease-in-out;
}
.form-flipper {
position: relative;
width: 100%;
transition: transform 0.6s ease-in-out;
transform-style: preserve-3d;
}
.form-wrapper {
width: 100%;
padding: 2.5rem;
backface-visibility: hidden;
-webkit-backface-visibility: hidden; /* for Safari */
transition: opacity 0.4s ease-in-out, transform 0.4s ease-in-out;
}
#loginFormWrapper {
/* Starts visible */
}
#signupFormWrapper {
position: absolute;
top: 0;
left: 0;
opacity: 0;
transform: translateY(20px);
pointer-events: none; /* Inactive form should not be interactive */
}
/* State classes for switching */
.form-container.show-signup #loginFormWrapper {
opacity: 0;
transform: translateY(-20px);
pointer-events: none;
}
.form-container.show-signup #signupFormWrapper {
opacity: 1;
transform: translateY(0);
pointer-events: all;
}
h2 {
text-align: center;
color: var(--text-primary);
font-size: 2rem;
margin-bottom: 0.5rem;
font-weight: 600;
}
.form-subtitle {
text-align: center;
color: var(--accent-color);
margin-bottom: 2rem;
font-weight: 500;
}
.form-group {
margin-bottom: 1.5rem;
position: relative;
}
label {
display: block;
margin-bottom: .5rem;
color: var(--text-secondary);
font-size: 0.9rem;
font-weight: 500;
}
input {
width: 100%;
padding: 0.85rem 1rem;
box-sizing: border-box;
border: 1px solid transparent;
border-radius: 10px;
background-color: var(--input-bg-color);
color: var(--text-primary);
font-size: 1rem;
transition: border-color 0.3s, box-shadow 0.3s;
}
input:focus {
outline: none;
border-color: var(--accent-color);
box-shadow: 0 0 0 3px rgba(255, 149, 0, 0.3);
}
button {
width: 100%;
padding: 0.9rem;
border: none;
border-radius: 10px;
color: var(--text-primary);
background-color: var(--accent-color);
cursor: pointer;
font-size: 1.1rem;
font-weight: 600;
transition: transform 0.2s, background-color 0.2s;
margin-top: 1rem;
}
button:hover {
transform: translateY(-2px);
background-color: #ffae42; /* A slightly lighter shade for hover */
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: translateY(0);
}
.switch-form-btn {
background: none;
border: none;
color: var(--accent-color);
cursor: pointer;
font-size: 0.9rem;
font-weight: 500;
padding: 0;
margin-top: 1.5rem;
text-align: center;
width: 100%;
display: block;
}
.switch-form-btn:hover {
text-decoration: underline;
transform: none; /* Override button hover */
background: none;
}
#message {
margin-top: 1rem;
text-align: center;
font-weight: 500;
font-size: 0.9rem;
height: 20px; /* Reserve space to prevent layout shift */
transition: color 0.3s;
}
</style>
</head>
<body>
<div class="form-container" id="formContainer">
<div id="loginFormWrapper" class="form-wrapper">
<form id="loginForm">
<h2>Animex</h2>
<p class="form-subtitle">Welcome Back!</p>
<div class="form-group">
<label for="login-username">Username</label>
<input type="text" id="login-username" name="username" required autocomplete="username">
</div>
<div class="form-group">
<label for="login-password">Password</label>
<input type="password" id="login-password" name="password" required autocomplete="current-password">
</div>
<button type="submit" id="loginBtn">Login</button>
</form>
<button class="switch-form-btn" id="showSignup">Don't have an account? Sign Up</button>
</div>
<div id="signupFormWrapper" class="form-wrapper">
<form id="signupForm">
<h2>Animex</h2>
<p class="form-subtitle">Get started with a new account</p>
<div class="form-group">
<label for="signup-username">Username</label>
<input type="text" id="signup-username" name="username" required autocomplete="username">
</div>
<div class="form-group">
<label for="signup-password">Password</label>
<input type="password" id="signup-password" name="password" required autocomplete="new-password">
</div>
<button type="submit" id="signupBtn">Sign Up</button>
</form>
<button class="switch-form-btn" id="showLogin">Already have an account? Login</button>
</div>
<p id="message"></p>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const API_BASE_URL = '';
const formContainer = document.getElementById('formContainer');
const loginFormWrapper = document.getElementById('loginFormWrapper');
const signupFormWrapper = document.getElementById('signupFormWrapper');
const loginForm = document.getElementById('loginForm');
const signupForm = document.getElementById('signupForm');
const loginBtn = document.getElementById('loginBtn');
const signupBtn = document.getElementById('signupBtn');
const showSignupBtn = document.getElementById('showSignup');
const showLoginBtn = document.getElementById('showLogin');
const messageEl = document.getElementById('message');
// Function to adjust container height based on content
const adjustContainerHeight = () => {
// Use a timeout to allow CSS transitions to start
setTimeout(() => {
const activeFormWrapper = formContainer.classList.contains('show-signup')
? signupFormWrapper
: loginFormWrapper;
formContainer.style.height = `${activeFormWrapper.scrollHeight + 70}px`;
}, 100);
};
// Initial height adjustment
adjustContainerHeight();
// --- UI SWITCHING LOGIC ---
showSignupBtn.addEventListener('click', (e) => {
e.preventDefault();
formContainer.classList.add('show-signup');
messageEl.textContent = ''; // Clear message on switch
adjustContainerHeight();
});
showLoginBtn.addEventListener('click', (e) => {
e.preventDefault();
formContainer.classList.remove('show-signup');
messageEl.textContent = ''; // Clear message on switch
adjustContainerHeight();
});
// --- API LOGIC ---
const showMessage = (message, isError = true) => {
messageEl.textContent = message;
messageEl.style.color = isError ? 'var(--error-color)' : 'var(--success-color)';
}
// --- LOGIN LOGIC ---
loginForm.addEventListener('submit', async (e) => {
e.preventDefault();
showMessage('');
loginBtn.disabled = true;
loginBtn.textContent = 'Logging in...';
const formData = new FormData();
formData.append('username', e.target.username.value);
formData.append('password', e.target.password.value);
try {
const response = await fetch(`${API_BASE_URL}/token`, {
method: 'POST',
body: formData
});
const data = await response.json();
if (response.ok) {
const token = data.access_token;
localStorage.setItem('accessToken', token);
if (window.parent) {
window.parent.postMessage({ accessToken: token }, '*');
}
showMessage('Login Successful!', false);
} else {
showMessage(data.detail || 'Login failed.');
}
} catch (error) {
console.error('Login fetch error:', error);
showMessage('An error occurred. Please try again.');
} finally {
loginBtn.disabled = false;
loginBtn.textContent = 'Login';
}
});
// --- SIGNUP LOGIC ---
signupForm.addEventListener('submit', async (e) => {
e.preventDefault();
showMessage('');
signupBtn.disabled = true;
signupBtn.textContent = 'Signing up...';
const username = e.target.username.value;
const password = e.target.password.value;
if (!username || !password) {
showMessage('Please enter a username and password.');
signupBtn.disabled = false;
signupBtn.textContent = 'Sign Up';
return;
}
try {
const response = await fetch(`${API_BASE_URL}/signup`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
if (response.status === 201) {
showMessage('Signup successful! Please log in.', false);
// Automatically switch to login form
setTimeout(() => {
formContainer.classList.remove('show-signup');
adjustContainerHeight();
// Pre-fill username for convenience
loginForm.username.value = username;
loginForm.password.focus();
}, 1500);
} else {
const errorData = await response.json();
showMessage(errorData.detail || 'Signup failed.');
}
} catch (error) {
console.error('Signup error:', error);
showMessage('An error occurred. Please try again.');
} finally {
signupBtn.disabled = false;
signupBtn.textContent = 'Sign Up';
}
});
// Adjust height on window resize
window.addEventListener('resize', adjustContainerHeight);
});
</script>
</body>
</html>