feat(marketing): section interactive 'Comment ça marche' (réacteur DictIA cyclant 6 features)

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) <noreply@anthropic.com>
This commit is contained in:
Allison
2026-04-29 09:09:40 -04:00
parent e06cba2123
commit 03f6e56f04
3 changed files with 295 additions and 0 deletions

View File

@@ -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 &amp; 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')