fix(ui): wave 2 from critique re-run — AA contrast, unified PageHeader, checkout confirm
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m46s

Nav: teams/settings/services back out of the nav until product-ready (user
decision); teams page was already half-finished (UUID member display is a
backend limitation).

Payment: explicit confirmation dialog (plan, amount, billing period, Stripe
note) before any redirect; ?plan= URL now pre-opens the dialog instead of
triggering a silent checkout.

Contrast AA sweep (71 replacements): functional micro-labels raised to
>=60-65% opacity and >=10px across sidebar, header, pricing, landing;
decorative all-caps 'interface' label removed.

Design unification: new PageHeader component (accent pill + serif
base/accent title) applied to settings, services, reviews, teams; pricing
header returned to the editorial voice (serif + accent pill); dead
GlossaryCard deleted.

i18n residuals: suggestion chips, 'Standard' provider label, notification
close, model-combobox strings extracted (+broken bg-surface/border-border-
subtle tokens fixed); ~45 new keys EN+FR; 13 dead keys removed; zero
missing keys verified.

Reviews: icon-only row actions now carry visible text; 'Approve all' is
two-step armed-confirm.

Accelerators: Ctrl/Cmd+Enter submits; arrow-key navigation in the language
combobox; recent-jobs history cap 8->20 with per-job download; source=target
config rejected; empty 'Master Quality' badge removed.

Cookie consent: reopenable via footer link, emoji replaced with drawn icon.

Verified: build exit 0, vitest 9/9, eslint 64 errors = previous level,
0 missing i18n keys.
This commit is contained in:
2026-08-30 22:02:35 +02:00
parent 50047ea8a2
commit 111f3cb69d
41 changed files with 470 additions and 280 deletions

View File

@@ -0,0 +1,73 @@
---
target: frontend/src (UI complète Wordly.art)
total_score: 24
max_score: 40
na_heuristics:
p0_count: 0
p1_count: 3
timestamp: 2026-08-30T19-50-34Z
slug: frontend-src
---
# Critique de design — Wordly.art (`frontend/src`) — re-run post-correctif
Method: dual-agent (A: agent_8b2492dd-bd0c-48a2-9293-d6c7960dc418 · B: agent_d8eeec19-1e9d-4df5-84a2-7eb2daf6beb0)
## Design Health Score
| # | Heuristique | Score | Problème clé | Δ |
|---|-------------|-------|--------------|---|
| 1 | Visibilité du statut | 3 | Progression aria-live, temps restant API affiché, skeletons ; mais « Tout approuver » boucle sans progression (`reviews/[jobId]/page.tsx:138-148`) et la sauvegarde des consignes simule un délai de 300 ms (`glossaries/page.tsx:64`). | +1 |
| 2 | Correspondance avec le réel | 2 | Jargon non défini : bouton nu « XLIFF » (`reviews/[jobId]/page.tsx:253`), « Phase 2 : Reconstruction contextuelle » (`fr/translate.json:70`) ; membre d'équipe affiché en `user_id.slice(0,8)…` (`teams/page.tsx:197`) ; « Standard » codé en dur EN (`ProviderSelector.tsx:161`). | = |
| 3 | Contrôle et liberté | 3 | Reprise du job après refresh (`useTranslationSubmit.ts:257-278`), sortie honnête « la traduction continue en arrière-plan » ; mais aucune annulation réelle d'un job, et le consentement cookies n'est plus rouvrable (`cookie-consent.tsx:14-26`). | +1 |
| 4 | Cohérence et standards | 2 | Trois systèmes visuels (éditorial serif / font-black pricing-settings / shadcn brut reviews-teams) ; `GlossaryCard.tsx` mort, jamais importé ; aria-label « Close notification » non traduit (`notification.tsx:184`). | +1 |
| 5 | Prévention des erreurs | 3 | Validation extension+taille, avertissements mismatch glossaire avant soumission, submit désactivé avec raison ; mais rien n'empêche source = cible (`useTranslationConfig.ts:233-237`). | +1 |
| 6 | Reconnaissance plutôt que rappel | 3 | Traductions récentes accessibles, récap config pendant l'attente ; mais actions de ligne icône-seule avec `title` seulement (`reviews/[jobId]/page.tsx:364-395`) et onglet « Consignes de contexte » caché sous Glossaires. | = |
| 7 | Flexibilité et efficacité | 1 | Aucun raccourci clavier global ; upload strictement mono-fichier (pas de `multiple`) ; historique plafonné à 8 jobs locaux, aucune page historique serveur ; pas de navigation fléchée dans le combobox langues. | = |
| 8 | Esthétique et minimalisme | 2 | Pricing = 5 plans + comparatif 10 lignes + 4 packs crédits + 4 trust + 2 modèles IA + 7 FAQ ; hiérarchie inversée sur translate — titre décoratif 5xl plus fort que le CTA 12px (`translate/page.tsx:230` vs `:351`). | = |
| 9 | Récupération d'erreurs | 3 | Humanisation en 9 familles, retry avec fichier conservé, cap polling réseau clair ; mais teams/reviews affichent `err.message` brut (`teams/page.tsx:102-105`). | = |
| 10 | Aide et documentation | 2 | Aides contextuelles réelles (glossaire, providers) mais zéro centre d'aide, zéro onboarding première connexion. | = |
| **Total** | | **24/40** | **Acceptable — en limite haute, la bande « Good » (28+) est atteignable** | **+4** |
## Verdict de spécificité design
**LLM assessment** : la landing est « presque signée » — le langage éditorial (Playfair/crème/encre/or) est tenu jusqu'au dashboard, et `SplitTitle` (base + accent italique, `translate/page.tsx:62-64`) est une vraie signature. Le dashboard translate est la meilleure surface : pipeline Upload→Search→Languages→Wrench→Check, glossaire avec paires de langues et ajout inline, providers thémés — rien de réutilisable tel quel par un autre produit. Restent trois failles d'identité : le hero landing (photo Unsplash + fausses cartes UI ne correspondant à aucun écran réel, `landing-page.tsx:139-167`), la page pricing qui parle une typographie opposée (`font-black uppercase tracking-tighter`, `pricing/page.tsx:504`), et reviews/teams jamais passés au design (shadcn brut). Occasion manquée majeure : aucun avant/après de document — LE visuel de la promesse « keep the format ».
**Deterministic scan** : 3 findings (4 avant le correctif). Le `side-tab` du profil est corrigé. Restent 2 `overused-font` Inter (`globals.css:141,147`) — choix assumé « outil sobre » de l'utilisateur, documenté — et 1 `border-accent-on-rounded` (`globals.css:215`) : **faux positif manifeste** (spinner canonique).
**Overlays navigateur** : indisponibles — « Browser is not available in subagent » (identique au run précédent, tentative réelle faite). Fallback : scan CLI.
## Impression générale
Le cœur produit est devenu solide : machine à états propre, reprise après refresh — « peu de SaaS gèrent le rafraîchissement en cours de traitement aussi proprement » —, erreurs humanisées, prévention au point de décision. La confiance n'est plus sabordée. Le plafond suivant se joue sur trois fronts : la conformité AA des micro-labels, l'unification des trois systèmes visuels, et les accélérateurs (batch, raccourcis, historique serveur) qui font la différence pour les utilisateurs intensifs.
## Ce qui fonctionne
1. **La machine à états + persistance du job** : cinq états nets, en-tête réécrit par état, progression réelle backend, localStorage avec TTL 24 h et reprise automatique (`useTranslationSubmit.ts:253-278`).
2. **L'identité éditoriale tenue de la landing au dashboard** : crème/encre/or + serif d'accent + pills, dark mode cohérent, `prefers-reduced-motion`/`prefers-contrast` gérés.
3. **La prévention et la récupération au point de décision** : mapping 9 familles d'erreurs + avertissements mismatch glossaire avant soumission (`GlossarySelector.tsx:340-357`).
## Problèmes prioritaires
1. **[P1] Contraste des micro-labels : illisibles et non-conformes AA.** Textes fonctionnels 9-11px en /20-/40 : nav sidebar `/40` (`DashboardSidebar.tsx:45-48`), stats pricing `text-[9px]/40` (`pricing/page.tsx:636`), « .DOCX » `/20` (`landing-page.tsx:307`). /40 sur crème ≈ 2.5:1. → Fix : plancher 11px, opacité ≥65 %, /20-/30 réservé à la décoration. **`$impeccable audit` + `$impeccable harden`**
2. **[P1] Trois systèmes de design qui ne se parlent pas.** Pricing/settings/services en `font-black uppercase` vs translate/glossaries en serif éditorial vs reviews/teams en shadcn brut ; `GlossaryCard.tsx` mort et divergent. → Fix : composant `PageHeader` unique (pill + titre base/accent) imposé partout ; supprimer GlossaryCard. **`$impeccable layout` + `$impeccable typeset`**
3. **[P1] UI non traduite dans un produit de traduction.** Chips de suggestions des consignes codées en dur FR (`glossaries/page.tsx:22-29`), « Standard » EN (`ProviderSelector.tsx:161`), « Close notification » (`notification.tsx:184`), strings FR sans accents dans `model-combobox.tsx:32,114,135`, littéraux `|| 'français'` résiduels. → Fix : extraire en clés, bannir le littéral JSX. **`$impeccable harden`**
4. **[P2] Actions icône-seule et identité technique exposée.** Éditer/approuver/reset en icônes 12px avec `title` seulement ; membres affichés `user_id.slice(0,8)…`. → Fix : boutons textuels compacts ou icône + libellé visible ; afficher e-mail/nom via l'API. **`$impeccable clarify`**
5. **[P2] Aucun accélérateur pour les utilisateurs intensifs.** Pas de Ctrl+Entrée, upload mono-fichier, historique 8 items locaux sans page serveur, pas de fléchées dans le combobox langues (40 options = 40 Tab). → Fix : raccourci, `multiple` + file d'attente, page Historique API, roving tabindex. **`$impeccable shape`**
## Red flags personas
**Alex (expert pressé)** : la config par défaut rend le flux rapide — mais 10 fichiers = 10 parcours complets (pas de `multiple`) ; « + Nouvelle traduction » réinitialise tout sans « re-traduire avec la même config » ; historique limité à 8 items locaux ; « Tout approuver » sans confirmation ni undo sur 400 segments.
**Sam (accessibilité)** : les fondations sont désormais réelles — `:focus-visible` global, dropzone focusable avec rôle + Entrée/Espace, progression aria-live, `role="switch"` : du sérieux. Échecs restants : contrastes /40-/20 massifs, dropdowns glossaire sans Échap ni gestion de focus out (`GlossarySelector.tsx:121-129`), combobox langues sans navigation fléchée, « edited » signifié par la couleur seule dans la cellule (sauvé par le badge).
**Jordan (premier usage)** : dropzone auto-explicative, chips rassurantes. Mais « XLIFF »/« Reconstruire et télécharger » sans explication, « Phase 2 : Reconstruction contextuelle » jargon interne, onglet « Consignes de contexte » introuvable par déduction, aucun onboarding première connexion, erreur 60 Mo sans limite affichée ni conseil.
## Observations mineures
Cookie consent non rouvrable + emoji 🍪 + chevauchement possible avec la barre mobile · hero Unsplash → vrai screenshot produit · mailto: brut pour Enterprise (sortie d'app) · switch « Traduire les images » fantôme pour les free · timer `formatElapsed` remis à 0 sur certains changements de statut · clés mortes fr/translate.json (« 100% SÉCURISÉ », « Qualité Maître », cancelProcess) · `model-combobox.tsx` référence des tokens inexistants (`bg-surface`, `border-border-subtle`) · nav dupliquée sidebar/header mobile · auto-checkout silencieux par paramètre d'URL `?plan=` sans re-confirmation (`pricing/page.tsx:339-349`).
## Questions à considérer
1. Pourquoi montrer six groupes de configuration à un free dont la moitié est verrouillée ? Que perdriez-vous à une page translate free de trois contrôles exactement ?
2. Où est le avant/après ? La promesse unique est « keep the format » et nulle part l'UI ne montre un document source à côté de sa traduction — surtout en RTL.
3. Pourquoi le paiement, moment de plus haute anxiété, est-il le seul sans écran de confirmation — et combien d'auto-checkouts silencieux par URL coûtent en litiges ?