Initial release: DictIA v0.8.14-alpha (fork de Speakr, AGPL-3.0)
This commit is contained in:
178
templates/login.html
Normal file
178
templates/login.html
Normal file
@@ -0,0 +1,178 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet, noimageindex">
|
||||
<title>{{ title }} - DictIA</title>
|
||||
<link rel="icon" href="{{ url_for('static', filename='img/favicon.ico') }}" type="image/svg+xml">
|
||||
<!-- All dependencies bundled locally for offline support -->
|
||||
<script src="{{ url_for('static', filename='vendor/js/tailwind.min.js') }}"></script>
|
||||
<!-- All dependencies bundled locally for offline support -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='vendor/css/fontawesome.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
|
||||
|
||||
<!-- Loading overlay to prevent FOUC -->
|
||||
{% include 'includes/loading_overlay.html' %}
|
||||
|
||||
<script>
|
||||
// Function to apply the theme based on localStorage
|
||||
function applyTheme() {
|
||||
// Guard against early execution
|
||||
if (!document.documentElement) return;
|
||||
|
||||
// Apply dark mode
|
||||
const savedMode = localStorage.getItem('darkMode');
|
||||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
if (savedMode === 'true' || (savedMode === null && prefersDark)) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
|
||||
// Apply color scheme
|
||||
const savedScheme = localStorage.getItem('colorScheme') || 'blue';
|
||||
const isDark = document.documentElement.classList.contains('dark');
|
||||
const themePrefix = isDark ? 'theme-dark-' : 'theme-light-';
|
||||
|
||||
// Remove all other theme classes
|
||||
const themeClasses = ['blue', 'emerald', 'purple', 'rose', 'amber', 'teal'];
|
||||
themeClasses.forEach(theme => {
|
||||
document.documentElement.classList.remove(`theme-light-${theme}`);
|
||||
document.documentElement.classList.remove(`theme-dark-${theme}`);
|
||||
});
|
||||
|
||||
// Add the correct theme class
|
||||
if (savedScheme !== 'blue') {
|
||||
document.documentElement.classList.add(themePrefix + savedScheme);
|
||||
}
|
||||
}
|
||||
applyTheme();
|
||||
</script>
|
||||
</head>
|
||||
<body class="bg-[var(--bg-primary)] text-[var(--text-primary)]">
|
||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8 py-6 flex flex-col min-h-screen">
|
||||
<header class="flex justify-between items-center mb-6 pb-4 border-b border-[var(--border-primary)]">
|
||||
<h1 class="text-3xl font-bold text-[var(--text-primary)]">
|
||||
<a href="{{ url_for('recordings.index') }}" class="flex items-center">
|
||||
<img src="{{ url_for('static', filename='img/logo-dictia.png') }}" alt="DictIA" class="h-14 w-14 mr-3">
|
||||
DictIA
|
||||
</a>
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
<main class="flex-grow flex items-center justify-center">
|
||||
<div class="w-full max-w-md bg-[var(--bg-secondary)] p-8 rounded-xl shadow-lg border border-[var(--border-primary)]">
|
||||
<h2 class="text-2xl font-semibold text-[var(--text-primary)] mb-6 text-center">Connexion</h2>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="mb-4 p-3 rounded-lg {% if category == 'success' %}bg-[var(--bg-success-light)] text-[var(--text-success-strong)]{% elif category == 'danger' %}bg-[var(--bg-danger-light)] text-[var(--text-danger-strong)]{% else %}bg-[var(--bg-info-light)] text-[var(--text-info-strong)]{% endif %}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% if sso_enabled %}
|
||||
<div class="flex flex-col space-y-3 {% if not password_login_disabled %}mb-6{% endif %}">
|
||||
<a href="{{ url_for('auth.sso_login') }}" class="w-full inline-flex items-center justify-center px-4 py-2 bg-[var(--bg-button)] text-[var(--text-button)] rounded-md hover:bg-[var(--bg-button-hover)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--border-focus)] transition-colors duration-200">
|
||||
<i class="fas fa-cloud mr-2"></i> Se connecter avec {{ sso_provider_name }}
|
||||
</a>
|
||||
{% if not password_login_disabled %}
|
||||
<div class="flex items-center text-xs text-[var(--text-muted)]">
|
||||
<span class="flex-grow border-t border-[var(--border-secondary)]"></span>
|
||||
<span class="mx-3 uppercase tracking-wide">ou</span>
|
||||
<span class="flex-grow border-t border-[var(--border-secondary)]"></span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if password_login_disabled %}
|
||||
<div class="mt-4 text-center">
|
||||
<button type="button" onclick="document.getElementById('admin-login-form').classList.toggle('hidden')" class="text-xs text-[var(--text-muted)] hover:text-[var(--text-secondary)]">
|
||||
<i class="fas fa-lock mr-1"></i> Connexion administrateur
|
||||
</button>
|
||||
</div>
|
||||
<form id="admin-login-form" method="POST" action="{{ url_for('auth.login') }}" class="hidden mt-4">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="mb-4">
|
||||
{{ form.email(class="mt-1 block w-full rounded-md border-[var(--border-secondary)] shadow-sm focus:border-[var(--border-focus)] focus:ring-[var(--ring-focus)] focus:ring-opacity-50 bg-[var(--bg-input)] text-[var(--text-primary)]", placeholder="Email administrateur") }}
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
{{ form.password(class="mt-1 block w-full rounded-md border-[var(--border-secondary)] shadow-sm focus:border-[var(--border-focus)] focus:ring-[var(--ring-focus)] focus:ring-opacity-50 bg-[var(--bg-input)] text-[var(--text-primary)]", placeholder="Mot de passe") }}
|
||||
</div>
|
||||
<button type="submit" class="w-full py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-[var(--text-button)] bg-[var(--bg-button)] hover:bg-[var(--bg-button-hover)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--border-focus)]">
|
||||
Se connecter
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form method="POST" action="{{ url_for('auth.login') }}">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="mb-4">
|
||||
{{ form.email.label(class="block text-sm font-medium text-[var(--text-secondary)] mb-1") }}
|
||||
{% if form.email.errors %}
|
||||
{{ form.email(class="mt-1 block w-full rounded-md border-[var(--border-danger)] shadow-sm focus:border-[var(--border-focus)] focus:ring-[var(--ring-focus)] focus:ring-opacity-50 bg-[var(--bg-input)] text-[var(--text-primary)]") }}
|
||||
<div class="text-[var(--text-danger)] text-xs mt-1">
|
||||
{% for error in form.email.errors %}
|
||||
<span>{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
{{ form.email(class="mt-1 block w-full rounded-md border-[var(--border-secondary)] shadow-sm focus:border-[var(--border-focus)] focus:ring-[var(--ring-focus)] focus:ring-opacity-50 bg-[var(--bg-input)] text-[var(--text-primary)]") }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
{{ form.password.label(class="block text-sm font-medium text-[var(--text-secondary)] mb-1") }}
|
||||
{% if form.password.errors %}
|
||||
{{ form.password(class="mt-1 block w-full rounded-md border-[var(--border-danger)] shadow-sm focus:border-[var(--border-focus)] focus:ring-[var(--ring-focus)] focus:ring-opacity-50 bg-[var(--bg-input)] text-[var(--text-primary)]") }}
|
||||
<div class="text-[var(--text-danger)] text-xs mt-1">
|
||||
{% for error in form.password.errors %}
|
||||
<span>{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
{{ form.password(class="mt-1 block w-full rounded-md border-[var(--border-secondary)] shadow-sm focus:border-[var(--border-focus)] focus:ring-[var(--ring-focus)] focus:ring-opacity-50 bg-[var(--bg-input)] text-[var(--text-primary)]") }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<div class="flex items-center">
|
||||
{{ form.remember(class="h-4 w-4 text-[var(--text-accent)] focus:ring-[var(--ring-focus)] border-[var(--border-secondary)] rounded") }}
|
||||
{{ form.remember.label(class="ml-2 block text-sm text-[var(--text-secondary)]") }}
|
||||
</div>
|
||||
<a href="{{ url_for('auth.forgot_password') }}" class="text-sm text-[var(--text-accent)] hover:underline">Mot de passe oublié ?</a>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col space-y-4">
|
||||
{{ form.submit(class="w-full py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-[var(--text-button)] bg-[var(--bg-button)] hover:bg-[var(--bg-button-hover)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--border-focus)]") }}
|
||||
|
||||
<div class="text-center text-sm text-[var(--text-muted)]">
|
||||
<span>Pas encore de compte ?</span>
|
||||
<a href="{{ url_for('auth.register') }}" class="font-medium text-[var(--text-accent)] hover:underline">S'inscrire</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="text-center py-4 mt-8 text-xs text-[var(--text-light)] border-t border-[var(--border-primary)]">
|
||||
<div>© {{ now.year }} InnovA AI · <a href="/politique-confidentialite" class="underline hover:text-[var(--text-primary)]">Politique de confidentialité</a> · <a href="/conditions-utilisation" class="underline hover:text-[var(--text-primary)]">Conditions d'utilisation</a></div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Hide loading overlay when page is ready
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (window.AppLoader) {
|
||||
AppLoader.waitForReady();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user