agent_tracker/templates/register.html
nickviljoen 08038b066f Rebrand UI to OLIVER template: Montserrat, yellow accents, sticky nav, tab fixes
Swap the muddy #f3ae3e palette for the real OLIVER brand pulled from the master
PPT template: yellow #FFCB05 + near-black #1A1A1A + off-white #F6F7F7, Montserrat
font. White-first page with a brand-yellow highlight rectangle behind page titles,
stat tiles with yellow left-strip, and a short yellow accent line under each
card section title — picks up the template's "01" chapter-marker rhythm.

Fixes two production bugs along the way:
- Nav stays pinned at top while page scrolls. The conflicting
  `.navbar { position: relative !important }` rule was removed from nav.html
  so the `position: fixed` from style.css can take effect.
- Clicking admin tabs no longer scrolls the page. Converted
  `<a href="#users">` to `<button data-bs-target="#users">` (Bootstrap 5's
  recommended pattern), so the anchor jump can't happen.

Other refinements: table padding loosened, `transform: scale` row hover
removed (jittery on dense rows), modal headers switched to near-black,
Chart.js palette aligned with brand tokens.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 10:12:18 +02:00

334 lines
9.6 KiB
HTML

{% extends "base.html" %}
{% block title %}Register - AgentHub{% endblock %}
{% block content %}
<div class="container my-5">
<div class="row justify-content-center">
<div class="col-md-6 col-lg-5">
<div class="card shadow-lg border-0">
<div class="card-body p-5">
<div class="text-center mb-4">
<div class="register-icon mb-3">
<i class="fas fa-user-plus"></i>
</div>
<h2 class="card-title mb-2">Create Account</h2>
<p class="text-muted">Join our community today</p>
</div>
<form method="POST" id="registerForm">
<div class="row">
<div class="col-md-6 mb-4">
<label for="firstName" class="form-label">
<i class="fas fa-user me-2"></i>First Name
</label>
<input type="text"
name="first-name"
class="form-control form-control-lg"
id="firstName"
placeholder="Enter your first name"
required>
</div>
<div class="col-md-6 mb-4">
<label for="lastName" class="form-label">
<i class="fas fa-user me-2"></i>Last Name
</label>
<input type="text"
name="last-name"
class="form-control form-control-lg"
id="lastName"
placeholder="Enter your last name"
required>
</div>
</div>
<div class="mb-4">
<label for="userEmail" class="form-label">
<i class="fas fa-envelope me-2"></i>Email Address
</label>
<input type="email"
name="user-email"
class="form-control form-control-lg"
id="userEmail"
placeholder="Enter your email"
required>
<div class="form-text">
<i class="fas fa-shield-alt me-1"></i>
We'll never share your email with anyone else.
</div>
</div>
<div class="mb-4">
<label for="userPassword" class="form-label">
<i class="fas fa-lock me-2"></i>Password
</label>
<div class="password-input-group">
<input type="password"
name="user-password"
class="form-control form-control-lg"
id="userPassword"
placeholder="Create a strong password"
required
minlength="8">
<button type="button" class="password-toggle" onclick="togglePassword('userPassword')">
<i class="fas fa-eye" id="passwordIcon"></i>
</button>
</div>
<div class="password-strength mt-2">
<div class="strength-bar">
<div class="strength-fill" id="strengthFill"></div>
</div>
<small class="form-text text-muted" id="strengthText">
Password should be at least 8 characters long
</small>
</div>
</div>
<div class="mb-4">
<label for="confirmPassword" class="form-label">
<i class="fas fa-lock me-2"></i>Confirm Password
</label>
<div class="password-input-group">
<input type="password"
name="confirm-password"
class="form-control form-control-lg"
id="confirmPassword"
placeholder="Confirm your password"
required
minlength="8">
<button type="button" class="password-toggle" onclick="togglePassword('confirmPassword')">
<i class="fas fa-eye" id="confirmPasswordIcon"></i>
</button>
</div>
<small class="form-text text-muted" id="passwordMatch"></small>
</div>
<div class="mb-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="agreeTerms" required>
<label class="form-check-label" for="agreeTerms">
I agree to the <a href="#" class="text-decoration-none">Terms of Service</a>
and <a href="#" class="text-decoration-none">Privacy Policy</a>
</label>
</div>
</div>
<div class="d-grid mb-4">
<button type="submit" class="btn btn-primary btn-lg">
<i class="fas fa-user-plus me-2"></i>Create Account
</button>
</div>
<div class="text-center">
<p class="text-muted mb-0">
Already have an account?
<a href="{{ base_path }}/login" class="text-decoration-none fw-bold">
Sign in here
</a>
</p>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<style>
.register-icon {
width: 80px;
height: 80px;
border-radius: 8px;
background: var(--brand-yellow);
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
font-size: 2rem;
color: var(--brand-dark);
}
.password-input-group {
position: relative;
}
.password-toggle {
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
color: var(--text-light);
cursor: pointer;
padding: 0;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.password-toggle:hover {
color: var(--primary-color);
}
.strength-bar {
width: 100%;
height: 4px;
background-color: var(--border-color);
border-radius: 2px;
overflow: hidden;
margin-bottom: 4px;
}
.strength-fill {
height: 100%;
width: 0%;
transition: all 0.3s ease;
border-radius: 2px;
}
.strength-weak {
background-color: #ef4444;
width: 33%;
}
.strength-medium {
background-color: #f59e0b;
width: 66%;
}
.strength-strong {
background-color: #10b981;
width: 100%;
}
.form-control-lg {
padding: 12px 16px;
font-size: 1rem;
}
.card {
border-radius: 20px;
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.95);
}
.form-check-input:checked {
background-color: var(--primary-color);
border-color: var(--primary-color);
}
@media (max-width: 576px) {
.card-body {
padding: 2rem 1.5rem !important;
}
.register-icon {
width: 60px;
height: 60px;
font-size: 1.5rem;
}
}
</style>
<script>
function togglePassword(inputId) {
const passwordInput = document.getElementById(inputId);
let iconId = 'passwordIcon';
if (inputId === 'confirmPassword') {
iconId = 'confirmPasswordIcon';
}
const icon = document.getElementById(iconId);
if (passwordInput.type === 'password') {
passwordInput.type = 'text';
icon.className = 'fas fa-eye-slash';
} else {
passwordInput.type = 'password';
icon.className = 'fas fa-eye';
}
}
// Password strength checker
document.getElementById('userPassword').addEventListener('input', function() {
const password = this.value;
const strengthFill = document.getElementById('strengthFill');
const strengthText = document.getElementById('strengthText');
let strength = 0;
let text = '';
if (password.length >= 8) strength += 1;
if (password.match(/[a-z]/) && password.match(/[A-Z]/)) strength += 1;
if (password.match(/[0-9]/)) strength += 1;
if (password.match(/[^a-zA-Z0-9]/)) strength += 1;
strengthFill.className = 'strength-fill';
if (password.length === 0) {
text = 'Password should be at least 8 characters long';
} else if (strength <= 2) {
strengthFill.classList.add('strength-weak');
text = 'Weak password';
} else if (strength === 3) {
strengthFill.classList.add('strength-medium');
text = 'Medium strength password';
} else {
strengthFill.classList.add('strength-strong');
text = 'Strong password';
}
strengthText.textContent = text;
// Check password match when password changes
checkPasswordMatch();
});
// Password confirmation checker
document.getElementById('confirmPassword').addEventListener('input', checkPasswordMatch);
function checkPasswordMatch() {
const password = document.getElementById('userPassword').value;
const confirmPassword = document.getElementById('confirmPassword').value;
const matchText = document.getElementById('passwordMatch');
if (confirmPassword.length === 0) {
matchText.textContent = '';
return;
}
if (password === confirmPassword) {
matchText.textContent = '✓ Passwords match';
matchText.className = 'form-text text-success';
} else {
matchText.textContent = '✗ Passwords do not match';
matchText.className = 'form-text text-danger';
}
}
// Form validation before submit
document.getElementById('registerForm').addEventListener('submit', function(e) {
const password = document.getElementById('userPassword').value;
const confirmPassword = document.getElementById('confirmPassword').value;
if (password !== confirmPassword) {
e.preventDefault();
alert('Passwords do not match. Please check your passwords and try again.');
return false;
}
if (password.length < 8) {
e.preventDefault();
alert('Password must be at least 8 characters long.');
return false;
}
return true;
});
</script>
{% endblock %}