Aligns DictIA marketing/auth/legal/billing templates with modern SaaS visual conventions (Linear, Vercel, Stripe Dashboard, Notion). Old radii (12-18px) felt dated; new system uses 6-12px for tighter, more contemporary corners. Border radius system: - Buttons (CTA, submit, secondary): rounded-[0.75rem] (12px) -> rounded-lg (8px) - Form inputs (text/email/password/select/textarea/checkbox): rounded-[0.5rem] -> rounded-md (6px) - Cards (pricing, bento, modals, content panels): rounded-[18px]/[14px]/[12px] -> rounded-xl (12px) - Pricing card outer gradient frame: rounded-[20px] -> rounded-xl (matches inner) - Pills / badges / status chips: KEEP rounded-full - Avatars / circular icon containers: KEEP rounded-full - Code blocks: KEEP rounded (4px) Decision tree applied for ambiguous cases: - Button-like clickable CTA -> rounded-lg - Form input -> rounded-md - Card / panel / modal -> rounded-xl - Badge / pill / chip / avatar -> rounded-full (preserved) In-scope templates modified (23): - macros/button.html (central macro, cascades to all callers) - macros/pricing_card.html, macros/bento.html - marketing/landing.html, tarifs.html, fonctionnalites.html, conformite.html, contact.html - auth/check_email.html, forgot_password.html, magic_link_request.html, oauth_finish_signup.html, passkey_setup.html, reset_password.html, totp_setup.html, totp_verify.html, verify_success.html - billing/cancel.html, billing/success.html - legal/_layout.html, legal/index.html - register.html, login.html Out of scope (untouched): index.html, account.html, admin.html, share.html, inquire.html, group-admin.html, components/**, includes/**, modals/** (all legacy Speakr Vue surfaces). Tests: test_marketing_landing_template.py — 2 assertions updated to match new bento icon (rounded-md) and pricing card frame (rounded-xl). All 18 legal tests + 58 marketing landing tests + 9 signup_loi25 tests still pass. Decorative rounded-full preserved on hero cosmic orbs and ordres-pros avatar circles. Diff: 94 insertions / 94 deletions (1:1 mechanical replacement, no class drift). 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-xl 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-md 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-lg 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 %}
|