refactor(ui): V3 fully square buttons + inputs (rounded-none, brutalist/Swiss aesthetic)
V3 finalizes the radii pass to a fully brutalist/Swiss visual language: - Buttons (CTAs, submit, secondary, ghost, OAuth provider tiles): rounded-none (0px) - Form inputs (text/email/password/select/textarea/code-entry): rounded-none (0px) - Checkboxes: rounded-none (0px) — was rounded-sm - Small icon tiles (w-10 h-10 / w-12 h-12 grad-bg squares): rounded-none (0px) - Inline code blocks (totp recovery <pre>, secret <code>): rounded-none (0px) - Cards (pricing, bento, content panels, modals, prev/next nav): rounded (4px) — was rounded-lg - Alert / flash boxes: rounded (4px) — was rounded-lg - Pills, badges, status chips, ordres pros avatars, decorative cosmic orbs: rounded-full preserved - Legal _layout.html inline <style> blockquote/pre/code/draft-callout: border-radius 0 — was 4px Updated tests/test_marketing_landing_template.py assertions: - bento icon assertion: "grad-bg rounded " -> "grad-bg rounded-none " - pricing recommended frame: "rounded-lg" -> "rounded" (with strict trailing-char match to avoid rounded-none false positive) Verification: 18/18 legal tests pass, 58/58 marketing landing tests pass, 5/5 root redirect tests pass. Two pre-existing failures in test_marketing_secondary_pages (SOC 2 hedge text + gitea.innova-ai.ca URL) are unrelated to this radii pass.
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="min-h-[calc(100vh-62px)] bg-brand-bg py-16 px-4" aria-labelledby="check-email-title">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded-lg border border-brand-border shadow-cta text-center">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded border border-brand-border shadow-cta text-center">
|
||||
<div class="mx-auto mb-6 w-16 h-16 rounded-full grad-bg flex items-center justify-center text-white text-2xl" aria-hidden="true">✉</div>
|
||||
|
||||
<h1 id="check-email-title" class="text-2xl font-black text-brand-navy mb-2">
|
||||
@@ -30,7 +30,7 @@
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div role="alert" class="mb-3 p-3 rounded-lg text-sm
|
||||
<div role="alert" class="mb-3 p-3 rounded text-sm
|
||||
{% if category == 'danger' %}bg-red-50 text-red-900 border border-red-200
|
||||
{% elif category == 'warning' %}bg-amber-50 text-amber-900 border border-amber-200
|
||||
{% elif category == 'success' %}bg-green-50 text-green-900 border border-green-200
|
||||
@@ -45,7 +45,7 @@
|
||||
<form method="POST" action="{{ url_for('auth.resend_verification') }}" class="mb-4">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<input type="hidden" name="email" value="{{ email }}">
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded-none shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
Renvoyer le lien de vérification
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="min-h-[calc(100vh-62px)] bg-brand-bg py-16 px-4" aria-labelledby="forgot-title">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded-lg border border-brand-border shadow-cta">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded border border-brand-border shadow-cta">
|
||||
<h1 id="forgot-title" class="text-3xl font-black text-brand-navy mb-2">Mot de passe oublié</h1>
|
||||
<p class="text-sm text-brand-navy/70 mb-6">{{ "Entrez votre adresse courriel. Si un compte existe, nous vous enverrons un lien sécurisé pour réinitialiser votre mot de passe (valide 1 heure)." | safe }}</p>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div role="alert" class="mb-3 p-3 rounded-lg text-sm
|
||||
<div role="alert" class="mb-3 p-3 rounded text-sm
|
||||
{% if category == 'danger' %}bg-red-50 text-red-900 border border-red-200
|
||||
{% elif category == 'warning' %}bg-amber-50 text-amber-900 border border-amber-200
|
||||
{% elif category == 'success' %}bg-green-50 text-green-900 border border-green-200
|
||||
@@ -29,11 +29,11 @@
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-brand-navy mb-1">Courriel <span class="text-red-600" aria-hidden="true">*</span></label>
|
||||
<input type="email" id="email" name="email" autocomplete="email" required aria-required="true"
|
||||
class="w-full px-3 py-2 border border-brand-border rounded text-brand-navy focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
class="w-full px-3 py-2 border border-brand-border rounded-none text-brand-navy focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
placeholder="vous@cabinet.qc.ca">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded-none shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
Recevoir un lien de réinitialisation
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="min-h-[calc(100vh-62px)] bg-brand-bg py-16 px-4" aria-labelledby="magic-title">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded-lg border border-brand-border shadow-cta">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded border border-brand-border shadow-cta">
|
||||
<h1 id="magic-title" class="text-3xl font-black text-brand-navy mb-2">Lien de connexion</h1>
|
||||
<p class="text-sm text-brand-navy/70 mb-6">{{ "Recevez un lien par courriel pour vous connecter sans mot de passe. Le lien expire dans 15 minutes." | safe }}</p>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div role="alert" class="mb-3 p-3 rounded-lg text-sm
|
||||
<div role="alert" class="mb-3 p-3 rounded text-sm
|
||||
{% if category == 'danger' %}bg-red-50 text-red-900 border border-red-200
|
||||
{% elif category == 'warning' %}bg-amber-50 text-amber-900 border border-amber-200
|
||||
{% elif category == 'success' %}bg-green-50 text-green-900 border border-green-200
|
||||
@@ -29,11 +29,11 @@
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-brand-navy mb-1">Courriel <span class="text-red-600" aria-hidden="true">*</span></label>
|
||||
<input type="email" id="email" name="email" autocomplete="email" required aria-required="true"
|
||||
class="w-full px-3 py-2 border border-brand-border rounded text-brand-navy focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
class="w-full px-3 py-2 border border-brand-border rounded-none text-brand-navy focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
placeholder="vous@cabinet.qc.ca">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded-none shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
{{ "Recevoir le lien (expire dans 15 minutes)" | safe }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="min-h-[calc(100vh-62px)] bg-brand-bg py-16 px-4" aria-labelledby="finish-title">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded-lg border border-brand-border shadow-cta">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded border border-brand-border shadow-cta">
|
||||
<h1 id="finish-title" class="text-3xl font-black text-brand-navy mb-2">Finaliser votre inscription</h1>
|
||||
<p class="text-sm text-brand-navy/70 mb-6">
|
||||
Vous vous inscrivez via <strong>{{ provider_display or provider | capitalize }}</strong>. Avant de créer votre compte DictIA, nous devons obtenir vos consentements conformément à la {{ "Loi 25" | safe }} du Québec.
|
||||
@@ -14,7 +14,7 @@
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div role="alert" class="mb-3 p-3 rounded-lg text-sm
|
||||
<div role="alert" class="mb-3 p-3 rounded text-sm
|
||||
{% if category == 'danger' %}bg-red-50 text-red-900 border border-red-200
|
||||
{% elif category == 'warning' %}bg-amber-50 text-amber-900 border border-amber-200
|
||||
{% elif category == 'success' %}bg-green-50 text-green-900 border border-green-200
|
||||
@@ -26,7 +26,7 @@
|
||||
{% endwith %}
|
||||
|
||||
{# Pre-filled email from OAuth provider — display only, not editable #}
|
||||
<div class="bg-brand-bg border border-brand-border rounded p-3 mb-6 text-sm">
|
||||
<div class="bg-brand-bg border border-brand-border rounded-none p-3 mb-6 text-sm">
|
||||
<p class="text-brand-navy/70 mb-1">Compte fédéré :</p>
|
||||
<p class="text-brand-navy font-semibold break-all">{{ userinfo.email }}</p>
|
||||
{% if userinfo.name %}<p class="text-brand-navy/80 text-xs mt-1">{{ userinfo.name }}</p>{% endif %}
|
||||
@@ -41,32 +41,32 @@
|
||||
|
||||
<label for="consent_cgu" class="flex items-start gap-2 text-sm text-brand-navy/90">
|
||||
<input type="checkbox" id="consent_cgu" name="consent_cgu" value="y" required aria-required="true"
|
||||
class="mt-1 rounded-sm focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
class="mt-1 rounded-none focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<span>J'accepte les <a href="/legal/conditions" target="_blank" rel="noopener" class="grad-text underline">conditions d'utilisation</a>. <span class="text-red-600" aria-hidden="true">*</span></span>
|
||||
</label>
|
||||
{% if errors.consent_cgu %}<p class="text-xs text-red-900 mt-1" role="alert">{{ errors.consent_cgu }}</p>{% endif %}
|
||||
|
||||
<label for="consent_confidentialite" class="flex items-start gap-2 text-sm text-brand-navy/90">
|
||||
<input type="checkbox" id="consent_confidentialite" name="consent_confidentialite" value="y" required aria-required="true"
|
||||
class="mt-1 rounded-sm focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
class="mt-1 rounded-none focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<span>J'accepte la <a href="/legal/confidentialite" target="_blank" rel="noopener" class="grad-text underline">politique de confidentialité</a>. <span class="text-red-600" aria-hidden="true">*</span></span>
|
||||
</label>
|
||||
{% if errors.consent_confidentialite %}<p class="text-xs text-red-900 mt-1" role="alert">{{ errors.consent_confidentialite }}</p>{% endif %}
|
||||
|
||||
<label for="consent_marketing" class="flex items-start gap-2 text-sm text-brand-navy/90">
|
||||
<input type="checkbox" id="consent_marketing" name="consent_marketing" value="y"
|
||||
class="mt-1 rounded-sm focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
class="mt-1 rounded-none focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<span>J'accepte de recevoir des communications marketing (optionnel, désactivable à tout moment).</span>
|
||||
</label>
|
||||
|
||||
<label for="consent_analytics" class="flex items-start gap-2 text-sm text-brand-navy/90">
|
||||
<input type="checkbox" id="consent_analytics" name="consent_analytics" value="y"
|
||||
class="mt-1 rounded-sm focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
class="mt-1 rounded-none focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<span>J'accepte les statistiques d'usage anonymisées (optionnel, désactivable à tout moment).</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded-none shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
Créer mon compte DictIA
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="min-h-[calc(100vh-62px)] bg-brand-bg py-16 px-4" aria-labelledby="passkey-setup-title">
|
||||
<div class="max-w-2xl mx-auto bg-white p-8 rounded-lg border border-brand-border shadow-cta">
|
||||
<div class="max-w-2xl mx-auto bg-white p-8 rounded border border-brand-border shadow-cta">
|
||||
<h1 id="passkey-setup-title" class="text-3xl font-black text-brand-navy mb-2">Mes passkeys</h1>
|
||||
<p class="text-sm text-brand-navy/70 mb-6">{{ "Une passkey est un second facteur sans mot de passe (clé matérielle YubiKey, biométrie de votre appareil, etc.). Conforme Loi 25." | safe }}</p>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div role="alert" class="mb-3 p-3 rounded-lg text-sm
|
||||
<div role="alert" class="mb-3 p-3 rounded text-sm
|
||||
{% if category == 'danger' %}bg-red-50 text-red-900 border border-red-200
|
||||
{% elif category == 'warning' %}bg-amber-50 text-amber-900 border border-amber-200
|
||||
{% elif category == 'success' %}bg-green-50 text-green-900 border border-green-200
|
||||
@@ -27,7 +27,7 @@
|
||||
{% if credentials %}
|
||||
<ul class="space-y-2 mb-6" role="list">
|
||||
{% for cred in credentials %}
|
||||
<li class="flex items-center justify-between p-3 border border-brand-border rounded-lg">
|
||||
<li class="flex items-center justify-between p-3 border border-brand-border rounded">
|
||||
<div>
|
||||
<p class="font-medium text-brand-navy">{{ cred.name }}</p>
|
||||
<p class="text-xs text-brand-navy/70">Ajoutée le {{ cred.created_at[:10] }}</p>
|
||||
@@ -48,8 +48,8 @@
|
||||
<h2 class="text-base font-semibold text-brand-navy mb-3">Ajouter une passkey</h2>
|
||||
<div class="space-y-3">
|
||||
<label for="passkey-label" class="block text-sm font-medium text-brand-navy">Nom de la passkey (optionnel)</label>
|
||||
<input id="passkey-label" type="text" maxlength="80" placeholder="ex. YubiKey 5C, MacBook Touch ID..." class="w-full px-3 py-2 border border-brand-border rounded text-brand-navy focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button id="passkey-register-btn" type="button" class="w-full grad-bg text-white font-semibold py-3 rounded shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<input id="passkey-label" type="text" maxlength="80" placeholder="ex. YubiKey 5C, MacBook Touch ID..." class="w-full px-3 py-2 border border-brand-border rounded-none text-brand-navy focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button id="passkey-register-btn" type="button" class="w-full grad-bg text-white font-semibold py-3 rounded-none shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
Enregistrer une passkey
|
||||
</button>
|
||||
<p id="passkey-register-status" class="text-xs text-brand-navy/70" role="status" aria-live="polite"></p>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="min-h-[calc(100vh-62px)] bg-brand-bg py-16 px-4" aria-labelledby="reset-title">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded-lg border border-brand-border shadow-cta">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded border border-brand-border shadow-cta">
|
||||
<h1 id="reset-title" class="text-3xl font-black text-brand-navy mb-2">Nouveau mot de passe</h1>
|
||||
<p class="text-sm text-brand-navy/70 mb-6">Choisissez un mot de passe robuste pour sécuriser votre compte DictIA.</p>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div role="alert" class="mb-3 p-3 rounded-lg text-sm
|
||||
<div role="alert" class="mb-3 p-3 rounded text-sm
|
||||
{% if category == 'danger' %}bg-red-50 text-red-900 border border-red-200
|
||||
{% elif category == 'warning' %}bg-amber-50 text-amber-900 border border-amber-200
|
||||
{% elif category == 'success' %}bg-green-50 text-green-900 border border-green-200
|
||||
@@ -29,7 +29,7 @@
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-medium text-brand-navy mb-1">Nouveau mot de passe <span class="text-red-600" aria-hidden="true">*</span></label>
|
||||
<input type="password" id="password" name="password" autocomplete="new-password" minlength="8" required aria-required="true" aria-describedby="password-help"
|
||||
class="w-full px-3 py-2 border border-brand-border rounded text-brand-navy focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
class="w-full px-3 py-2 border border-brand-border rounded-none text-brand-navy focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
placeholder="••••••••">
|
||||
<p id="password-help" class="text-xs text-brand-navy/70 mt-1">{{ "8 caractères minimum, dont une majuscule, une minuscule, un chiffre et un caractère spécial." | safe }}</p>
|
||||
</div>
|
||||
@@ -37,11 +37,11 @@
|
||||
<div>
|
||||
<label for="confirm_password" class="block text-sm font-medium text-brand-navy mb-1">Confirmer le mot de passe <span class="text-red-600" aria-hidden="true">*</span></label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" autocomplete="new-password" minlength="8" required aria-required="true"
|
||||
class="w-full px-3 py-2 border border-brand-border rounded text-brand-navy focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
class="w-full px-3 py-2 border border-brand-border rounded-none text-brand-navy focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
placeholder="••••••••">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded-none shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
Définir mon nouveau mot de passe
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="min-h-[calc(100vh-62px)] bg-brand-bg py-16 px-4" aria-labelledby="totp-setup-title">
|
||||
<div class="max-w-2xl mx-auto bg-white p-8 rounded-lg border border-brand-border shadow-cta">
|
||||
<div class="max-w-2xl mx-auto bg-white p-8 rounded border border-brand-border shadow-cta">
|
||||
<h1 id="totp-setup-title" class="text-3xl font-black text-brand-navy mb-2">Configurer la double authentification</h1>
|
||||
<p class="text-sm text-brand-navy/70 mb-6">{{ "La double authentification (2FA) ajoute une seconde étape lors de la connexion, en plus de votre mot de passe. Une exigence forte recommandée pour les comptes traitant des données confidentielles (Loi 25)." | safe }}</p>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div role="alert" class="mb-3 p-3 rounded-lg text-sm
|
||||
<div role="alert" class="mb-3 p-3 rounded text-sm
|
||||
{% if category == 'danger' %}bg-red-50 text-red-900 border border-red-200
|
||||
{% elif category == 'warning' %}bg-amber-50 text-amber-900 border border-amber-200
|
||||
{% elif category == 'success' %}bg-green-50 text-green-900 border border-green-200
|
||||
@@ -24,7 +24,7 @@
|
||||
{% endwith %}
|
||||
|
||||
{% if error %}
|
||||
<div role="alert" class="mb-4 p-3 rounded-lg text-sm bg-red-50 text-red-900 border border-red-200">{{ error }}</div>
|
||||
<div role="alert" class="mb-4 p-3 rounded text-sm bg-red-50 text-red-900 border border-red-200">{{ error }}</div>
|
||||
{% endif %}
|
||||
|
||||
<ol class="space-y-6">
|
||||
@@ -36,24 +36,24 @@
|
||||
<li>
|
||||
<h2 class="text-lg font-bold text-brand-navy mb-2"><span class="grad-text">2.</span> Scannez le code QR</h2>
|
||||
<div class="flex flex-col md:flex-row gap-6 items-start">
|
||||
<div class="bg-brand-bg border border-brand-border rounded-lg p-4 flex-shrink-0">
|
||||
<div class="bg-brand-bg border border-brand-border rounded p-4 flex-shrink-0">
|
||||
<img src="{{ qr_data_url }}" alt="Code QR pour configurer DictIA dans votre application authenticator" class="w-48 h-48 mx-auto block">
|
||||
</div>
|
||||
<div class="text-sm text-brand-navy/80 space-y-2">
|
||||
<p>Pointez l'appareil photo de votre application authenticator vers ce code QR.</p>
|
||||
<p class="text-xs text-brand-navy/60">Vous ne pouvez pas scanner ?<br>Saisissez la clé manuellement :</p>
|
||||
<code class="block bg-brand-bg border border-brand-border rounded px-3 py-2 text-xs font-mono text-brand-navy break-all select-all">{{ secret }}</code>
|
||||
<code class="block bg-brand-bg border border-brand-border rounded-none px-3 py-2 text-xs font-mono text-brand-navy break-all select-all">{{ secret }}</code>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<h2 class="text-lg font-bold text-brand-navy mb-2"><span class="grad-text">3.</span> Conservez vos codes de récupération</h2>
|
||||
<div role="alert" class="bg-amber-50 border border-amber-200 rounded-lg p-4 mb-3">
|
||||
<div role="alert" class="bg-amber-50 border border-amber-200 rounded p-4 mb-3">
|
||||
<p class="text-sm font-semibold text-amber-900 mb-2">Important — ces codes ne seront affichés qu'une seule fois.</p>
|
||||
<p class="text-xs text-amber-900/90">Imprimez-les ou enregistrez-les dans votre gestionnaire de mots de passe. Chaque code est à usage unique et permettra de vous reconnecter si vous perdez l'accès à votre application authenticator.</p>
|
||||
</div>
|
||||
<pre id="recovery-codes" class="bg-brand-navy text-white text-sm font-mono p-4 rounded-lg whitespace-pre-wrap select-all">{% for c in recovery_codes %}{{ c }}
|
||||
<pre id="recovery-codes" class="bg-brand-navy text-white text-sm font-mono p-4 rounded-none whitespace-pre-wrap select-all">{% for c in recovery_codes %}{{ c }}
|
||||
{% endfor %}</pre>
|
||||
<button type="button" onclick="(function(){var t=document.getElementById('recovery-codes').innerText;if(navigator.clipboard){navigator.clipboard.writeText(t);}var b=document.getElementById('copy-btn');b.textContent='Copié dans le presse-papiers';setTimeout(function(){b.textContent='Copier les codes';},2000);})();"
|
||||
id="copy-btn"
|
||||
@@ -74,11 +74,11 @@
|
||||
<input type="text" id="code" name="code" required aria-required="true"
|
||||
inputmode="numeric" autocomplete="one-time-code"
|
||||
pattern="[0-9]{6}" maxlength="6"
|
||||
class="w-full md:w-48 px-3 py-2 border border-brand-border rounded text-brand-navy text-center text-xl font-mono tracking-widest focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
class="w-full md:w-48 px-3 py-2 border border-brand-border rounded-none text-brand-navy text-center text-xl font-mono tracking-widest focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
placeholder="000000" autofocus>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="grad-bg text-white font-semibold py-3 px-6 rounded shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button type="submit" class="grad-bg text-white font-semibold py-3 px-6 rounded-none shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
Activer la double authentification
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="min-h-[calc(100vh-62px)] bg-brand-bg py-16 px-4" aria-labelledby="totp-verify-title">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded-lg border border-brand-border shadow-cta">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded border border-brand-border shadow-cta">
|
||||
<h1 id="totp-verify-title" class="text-3xl font-black text-brand-navy mb-2">Vérification en deux étapes</h1>
|
||||
<p class="text-sm text-brand-navy/70 mb-6">Entrez le code à 6 chiffres affiché dans votre application authenticator pour terminer la connexion.</p>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div role="alert" class="mb-3 p-3 rounded-lg text-sm
|
||||
<div role="alert" class="mb-3 p-3 rounded text-sm
|
||||
{% if category == 'danger' %}bg-red-50 text-red-900 border border-red-200
|
||||
{% elif category == 'warning' %}bg-amber-50 text-amber-900 border border-amber-200
|
||||
{% elif category == 'success' %}bg-green-50 text-green-900 border border-green-200
|
||||
@@ -24,14 +24,14 @@
|
||||
{% endwith %}
|
||||
|
||||
{% if error %}
|
||||
<div role="alert" class="mb-4 p-3 rounded-lg text-sm bg-red-50 text-red-900 border border-red-200">{{ error }}</div>
|
||||
<div role="alert" class="mb-4 p-3 rounded text-sm bg-red-50 text-red-900 border border-red-200">{{ error }}</div>
|
||||
{% endif %}
|
||||
|
||||
{# B-2.6: Passkey path (only if user has at least one registered passkey) #}
|
||||
{% if has_passkeys %}
|
||||
<section class="mb-6" aria-labelledby="passkey-section-title">
|
||||
<h2 id="passkey-section-title" class="text-base font-semibold text-brand-navy mb-3">Connexion par Passkey</h2>
|
||||
<button id="passkey-auth-btn" type="button" class="w-full grad-bg text-white font-semibold py-3 rounded shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button id="passkey-auth-btn" type="button" class="w-full grad-bg text-white font-semibold py-3 rounded-none shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
Utiliser ma Passkey
|
||||
</button>
|
||||
<p id="passkey-status" class="text-xs text-brand-navy/70 mt-2" role="status" aria-live="polite"></p>
|
||||
@@ -54,11 +54,11 @@
|
||||
<input type="text" id="code" name="code"
|
||||
inputmode="numeric" autocomplete="one-time-code"
|
||||
pattern="[0-9]{6}" maxlength="6"
|
||||
class="w-full px-3 py-3 border border-brand-border rounded text-brand-navy text-center text-2xl font-mono tracking-widest focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
class="w-full px-3 py-3 border border-brand-border rounded-none text-brand-navy text-center text-2xl font-mono tracking-widest focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
placeholder="000000" autofocus>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button type="submit" class="w-full grad-bg text-white font-semibold py-3 rounded-none shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
Vérifier et se connecter
|
||||
</button>
|
||||
</form>
|
||||
@@ -74,11 +74,11 @@
|
||||
<label for="recovery_code" class="block text-sm font-medium text-brand-navy mb-1">Code de récupération <span class="text-red-600" aria-hidden="true">*</span></label>
|
||||
<input type="text" id="recovery_code" name="recovery_code"
|
||||
autocomplete="off"
|
||||
class="w-full px-3 py-2 border border-brand-border rounded text-brand-navy font-mono uppercase focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
class="w-full px-3 py-2 border border-brand-border rounded-none text-brand-navy font-mono uppercase focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
placeholder="XXXXX-XXXXX">
|
||||
<p class="text-xs text-brand-navy/60 mt-1">Format : 5 caractères + tiret + 5 caractères. Chaque code est à usage unique.</p>
|
||||
</div>
|
||||
<button type="submit" class="w-full bg-brand-navy text-white font-semibold py-3 rounded hover:bg-brand-navy2 transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
<button type="submit" class="w-full bg-brand-navy text-white font-semibold py-3 rounded-none hover:bg-brand-navy2 transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
Utiliser le code de récupération
|
||||
</button>
|
||||
<p class="text-xs text-brand-navy/60 text-center" aria-live="polite">{{ recovery_codes_remaining }} code{{ 's' if recovery_codes_remaining != 1 else '' }} de récupération restant{{ 's' if recovery_codes_remaining != 1 else '' }}.</p>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="min-h-[calc(100vh-62px)] bg-brand-bg py-16 px-4" aria-labelledby="verify-success-title">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded-lg border border-brand-border shadow-cta text-center">
|
||||
<div class="max-w-md mx-auto bg-white p-8 rounded border border-brand-border shadow-cta text-center">
|
||||
<div class="mx-auto mb-6 w-16 h-16 rounded-full bg-green-100 text-green-700 flex items-center justify-center text-3xl font-black" aria-hidden="true">✓</div>
|
||||
|
||||
<h1 id="verify-success-title" class="text-2xl font-black text-brand-navy mb-2">Votre courriel a été vérifié</h1>
|
||||
@@ -14,7 +14,7 @@
|
||||
</p>
|
||||
|
||||
<a href="{{ url_for('auth.login') }}"
|
||||
class="inline-block w-full grad-bg text-white font-semibold py-3 rounded shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
class="inline-block w-full grad-bg text-white font-semibold py-3 rounded-none shadow-cta hover:shadow-cta-hover transition focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||
Se connecter
|
||||
</a>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user