From 03f6e56f048b38fc34d71cf0b6d89159a24d1519 Mon Sep 17 00:00:00 2001 From: Allison Date: Wed, 29 Apr 2026 09:09:40 -0400 Subject: [PATCH] =?UTF-8?q?feat(marketing):=20section=20interactive=20'Com?= =?UTF-8?q?ment=20=C3=A7a=20marche'=20(r=C3=A9acteur=20DictIA=20cyclant=20?= =?UTF-8?q?6=20features)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajoute une nouvelle section interactive sous les 6 fonctionnalités (préservées intégralement) reproduisant le composant React dictai-narrative.tsx en CSS pur + Alpine.js — sans Framer Motion ni autre lib JS. - Réacteur central holographique : 3 anneaux concentriques rotatifs (15 s / 22 s / 30 s) + 8 particules orbitales (cyan/blue/fuchsia) + wordmark DictIA glow pulsant - Auto-cycle Alpine.js entre 6 features (1.6 s) avec pause au hover/focus et reprise au leave/blur - Panneau feature active avec aria-live='polite' pour annonce lecteur d'écran (Transcription · Diarisation · 99+ langues · Exports · Utilisateurs illimités · Partage & Classement) - Card 'IA intégrée Mistral 7B LOCAL' avec 3 bullets souveraineté - Spec list cliquable / hover déclenchant feature dans réacteur - Layout responsive grid 2 cols desktop, stack mobile - prefers-reduced-motion désactive rings + orbites + auto-cycle - Position : APRÈS '6 fonctionnalités', AVANT 'Intégrations' - Sub-nav reste à 4 ancres (sous-partie visuelle de Fonctionnalités) - Tests : nouveau test_fonctionnalites_how_it_works_reactor_section valide structure, contenu canonique, a11y et Alpine bindings Co-Authored-By: Claude Opus 4.7 (1M context) --- static/css/marketing.css | 31 ++++ templates/marketing/fonctionnalites.html | 215 +++++++++++++++++++++++ tests/test_marketing_secondary_pages.py | 49 ++++++ 3 files changed, 295 insertions(+) diff --git a/static/css/marketing.css b/static/css/marketing.css index 21694c1..5d7c00c 100644 --- a/static/css/marketing.css +++ b/static/css/marketing.css @@ -984,6 +984,9 @@ .min-h-\[110px\] { min-height: 110px; } + .min-h-\[480px\] { + min-height: 480px; + } .min-h-\[calc\(100vh-62px\)\] { min-height: calc(100vh - 62px); } @@ -1140,6 +1143,9 @@ .max-w-\[300px\] { max-width: 300px; } + .max-w-\[320px\] { + max-width: 320px; + } .max-w-\[820px\] { max-width: 820px; } @@ -1242,6 +1248,10 @@ --tw-translate-y: calc(var(--spacing) * 0); translate: var(--tw-translate-x) var(--tw-translate-y); } + .translate-y-1 { + --tw-translate-y: calc(var(--spacing) * 1); + translate: var(--tw-translate-x) var(--tw-translate-y); + } .translate-y-2 { --tw-translate-y: calc(var(--spacing) * 2); translate: var(--tw-translate-x) var(--tw-translate-y); @@ -1916,6 +1926,12 @@ border-color: color-mix(in oklab, var(--color-white) 8%, transparent); } } + .border-white\/\[0\.10\] { + border-color: color-mix(in srgb, #fff 10%, transparent); + @supports (color: color-mix(in lab, red, red)) { + border-color: color-mix(in oklab, var(--color-white) 10%, transparent); + } + } .border-white\/\[0\.12\] { border-color: color-mix(in srgb, #fff 12%, transparent); @supports (color: color-mix(in lab, red, red)) { @@ -2950,6 +2966,10 @@ --tw-tracking: 0.10em; letter-spacing: 0.10em; } + .tracking-\[0\.14em\] { + --tw-tracking: 0.14em; + letter-spacing: 0.14em; + } .tracking-\[0\.16em\] { --tw-tracking: 0.16em; letter-spacing: 0.16em; @@ -5064,6 +5084,12 @@ text-align: right; } } + .sm\:text-6xl { + @media (width >= 40rem) { + font-size: var(--text-6xl); + line-height: var(--tw-leading, var(--text-6xl--line-height)); + } + } .sm\:text-base { @media (width >= 40rem) { font-size: var(--text-base); @@ -5457,6 +5483,11 @@ grid-template-columns: 1fr 240px; } } + .lg\:grid-cols-\[1fr_minmax\(0\,360px\)\] { + @media (width >= 64rem) { + grid-template-columns: 1fr minmax(0,360px); + } + } .lg\:grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,420px\)\] { @media (width >= 64rem) { grid-template-columns: minmax(0,1fr) minmax(0,420px); diff --git a/templates/marketing/fonctionnalites.html b/templates/marketing/fonctionnalites.html index 3960f6b..bdcbc1b 100644 --- a/templates/marketing/fonctionnalites.html +++ b/templates/marketing/fonctionnalites.html @@ -249,6 +249,221 @@ +{# ===== COMMENT ÇA MARCHE — RÉACTEUR INTERACTIF ===== + Sous-partie visuelle de la section Fonctionnalités (sub-nav reste à 4 ancres). + Reproduit dictai-narrative.tsx (Website-Sanity) en CSS pur + Alpine.js. +#} +
+ + +
+
+

+ + COMMENT ÇA MARCHE +

+

+ Du fichier au résumé — en temps réel +

+

+ Survolez une fonctionnalité pour voir la machine en action. Glissez pour calculer votre gain de productivité. +

+
+ +
+ + {# ── COLONNE GAUCHE : Réacteur central holographique ── #} +
+ {# Backdrop radial #} + + + {# 3 anneaux concentriques rotatifs #} + + + {# Auto badge — top right #} +
+ + Auto +
+ + {# Centre : DictIA wordmark + glow + feature panel #} +
+
+ +

DictIA

+
+ + {# Panneau feature active — swap fluide via x-transition #} +
+ +
+
+
+ + {# ── COLONNE DROITE : IA intégrée Mistral 7B + spec list cliquable ── #} +
+ + {# Card "IA intégrée Mistral 7B LOCAL" #} +
+
+

IA intégrée

+ Local +
+

Mistral 7B

+

Résumé · Points d'action · Q&R

+
    +
  • + {{ icon_check | safe }} + Données hébergées sur VOS serveurs · jamais partagées +
  • +
  • + {{ icon_check | safe }} + Zéro connexion OpenAI · Google · Microsoft +
  • +
  • + {{ icon_check | safe }} + Inférence hors-ligne · résultats en secondes +
  • +
+
+ + {# Spec list cliquable / hover — déclenche feature dans réacteur #} +
+

Fonctions clés

+
    + +
+
+ +
+
+ +
+
+ {# ===== INTÉGRATIONS ===== #}
diff --git a/tests/test_marketing_secondary_pages.py b/tests/test_marketing_secondary_pages.py index 07f7eb0..121c9e8 100644 --- a/tests/test_marketing_secondary_pages.py +++ b/tests/test_marketing_secondary_pages.py @@ -131,6 +131,55 @@ def test_fonctionnalites_renders_6_bento_cards(): assert kw in body +def test_fonctionnalites_how_it_works_reactor_section(): + """New 'Comment ça marche' interactive reactor section (post-6-features, pre-integrations). + + Validates structure (heading + reactor + spec list + Mistral card), 6 cycling features, + canonical content, and a11y signals (aria-labelledby + aria-live status panel). + """ + client = app.test_client() + body = client.get('/fonctionnalites').data.decode('utf-8') + + # Section heading + canonical phrasing + assert 'how-it-works-title' in body, "Missing how-it-works section anchor" + assert 'COMMENT ÇA MARCHE' in body, "Missing canonical eyebrow" + assert 'Du fichier au résumé' in body, "Missing canonical H2 phrasing" + assert 'en temps réel' in body + assert 'Survolez une fonctionnalité pour voir la machine en action' in body + + # 6 cycling features (canonical names) + for feat in ['Transcription', 'Diarisation', '99+ langues', 'Exports', + 'Utilisateurs illimités', 'Partage & Classement']: + assert feat in body, f"Missing cycling feature: {feat}" + + # Reactor visual: rings, orbits, wordmark, Auto badge + assert 'reactor-ring' in body and 'ring-outer' in body and 'ring-mid' in body and 'ring-inner' in body + assert 'orbit orbit-1' in body and 'orbit orbit-8' in body, "Missing 8 orbital particles" + assert '>DictIA<' in body, "Missing reactor centre wordmark" + + # Mistral 7B IA intégrée card with 3 canonical bullets + assert 'Mistral 7B' in body + assert 'IA intégrée' in body + assert 'Données hébergées sur VOS serveurs' in body + assert 'Zéro connexion OpenAI' in body + assert 'Inférence hors-ligne' in body + + # Alpine reactor data + auto-cycle + hover/focus stop logic + assert "active: \"Transcription\"" in body + assert 'isHovered' in body + assert 'setActive(feat)' in body + assert 'resumeCycle()' in body + # Hover, focus + blur listeners on each list item + assert '@mouseenter="setActive(feat)"' in body + assert '@mouseleave="resumeCycle()"' in body + assert '@focus="setActive(feat)"' in body + assert '@blur="resumeCycle()"' in body + + # Accessibility: aria-live status panel, prefers-reduced-motion guard + assert 'aria-live="polite"' in body + assert 'prefers-reduced-motion' in body, "Reduced-motion guard missing" + + def test_fonctionnalites_export_formats_section(): client = app.test_client() body = client.get('/fonctionnalites').data.decode('utf-8')