V2 sharper radii system aligned with Stripe Dashboard / Linear / Vercel
aesthetic — the v1 rounded-lg (8px) on buttons still felt too soft.
New scale:
- Buttons (CTA, submit, ghost, secondary): rounded-lg → rounded (4px)
- Form inputs (text/email/password/select/textarea): rounded-md → rounded (4px)
- Checkboxes: rounded-sm (2px) added explicitly to consent + remember-me
- Cards (pricing, bento, content panels): rounded-xl → rounded-lg (8px)
- Small icon tiles (w-10 h-10 / w-12 h-12 grad-bg squares): rounded-md → rounded
- Pills, badges, avatars, status orbs: rounded-full (KEPT)
- Inline code in legal CSS: rounded (4px) (KEPT)
- Legal blockquote/pre/draft-callout border-radius: 8px → 4px
Files modified (24):
- templates/macros/{button,bento,pricing_card}.html
- templates/marketing/{landing,tarifs,fonctionnalites,conformite,contact}.html
- templates/auth/{check_email,forgot_password,magic_link_request,
oauth_finish_signup,passkey_setup,reset_password,totp_setup,totp_verify,
verify_success}.html
- templates/billing/{success,cancel}.html
- templates/legal/{_layout,index}.html
- templates/{register,login}.html
- tests/test_marketing_landing_template.py (assertions updated to match v2)
Verification:
- 18/18 legal page tests pass (tests/_run_legal_pages_windows.py)
- 58/58 marketing landing tests pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
94 lines
6.2 KiB
HTML
94 lines
6.2 KiB
HTML
{% extends 'marketing/base.html' %}
|
|
|
|
{% block title %}Configurer la double authentification — DictIA{% endblock %}
|
|
{% block description %}Activez la double authentification (TOTP) sur votre compte DictIA pour protéger vos données conformément aux exigences Loi 25.{% endblock %}
|
|
|
|
{% 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">
|
|
<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
|
|
{% 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
|
|
{% else %}bg-blue-50 text-blue-900 border border-blue-200{% endif %}">
|
|
{{ message }}
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% 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>
|
|
{% endif %}
|
|
|
|
<ol class="space-y-6">
|
|
<li>
|
|
<h2 class="text-lg font-bold text-brand-navy mb-2"><span class="grad-text">1.</span> Installez une application d'authentification</h2>
|
|
<p class="text-sm text-brand-navy/80">Sur votre téléphone, installez par exemple <strong>Google Authenticator</strong>, <strong>Microsoft Authenticator</strong>, <strong>Authy</strong> ou <strong>1Password</strong>.</p>
|
|
</li>
|
|
|
|
<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">
|
|
<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>
|
|
</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">
|
|
<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 }}
|
|
{% 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"
|
|
class="mt-2 inline-flex items-center gap-2 text-xs font-semibold text-brand-b1 hover:underline focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
|
Copier les codes
|
|
</button>
|
|
</li>
|
|
|
|
<li>
|
|
<h2 class="text-lg font-bold text-brand-navy mb-2"><span class="grad-text">4.</span> Confirmez avec un code à 6 chiffres</h2>
|
|
<p class="text-sm text-brand-navy/70 mb-4">Entrez le code à 6 chiffres affiché actuellement dans votre application authenticator pour valider l'installation.</p>
|
|
|
|
<form method="POST" action="{{ url_for('auth.totp_setup') }}" class="space-y-4" novalidate>
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
|
|
<div>
|
|
<label for="code" class="block text-sm font-medium text-brand-navy mb-1">Code à 6 chiffres <span class="text-red-600" aria-hidden="true">*</span></label>
|
|
<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"
|
|
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">
|
|
Activer la double authentification
|
|
</button>
|
|
</form>
|
|
</li>
|
|
</ol>
|
|
|
|
<p class="text-center text-sm text-brand-navy/70 mt-8 pt-6 border-t border-brand-border">
|
|
<a href="{{ url_for('auth.account') }}" class="grad-text font-semibold">← Annuler et retourner au compte</a>
|
|
</p>
|
|
</div>
|
|
</section>
|
|
{% endblock %}
|