170 lines
17 KiB
Markdown
170 lines
17 KiB
Markdown
|
|
# Audit UI/UX visuel complet — Qualité Discord/Spotify-like
|
|||
|
|
|
|||
|
|
**Date** : 8 février 2025
|
|||
|
|
**Rôle** : Lead Frontend Engineer + Design Systems Architect + UX Reviewer
|
|||
|
|
**Référents** : Discord (densité, sidebar, clarté), Spotify (rythme, listes, player), Linear, Notion
|
|||
|
|
**Source de vérité visuelle** : Storybook (full layout), baselines `visual-tests/`, code shell et tokens.
|
|||
|
|
|
|||
|
|
**Méthodologie** : Analyse fondée sur le code du shell (DashboardLayout, Sidebar, Header, GlobalPlayer), les tokens (`index.css`, DESIGN_TOKENS.md, APP_SHELL.md), les rapports existants (UI_UX_AUDIT_DISCORD_SPOTIFY_QUALITY.md, VISUAL_AUDIT_REPORT.md) et l’analyse des assets dans `visual-tests/baselines/`. Les baselines actuelles (dashboard, library, header) décrivent des écrans de login lorsque l’app est capturée sans session ; pour une observation directe du shell complet, ouvrir Storybook sur `App/Layouts/DashboardLayout` → *Dashboard – full layout* (port 6006).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. Résumé exécutif (10–15 lignes)
|
|||
|
|
|
|||
|
|
L’interface Veza se situe aujourd’hui entre **produit soigné** et **produit premium**. Le shell (sidebar, header, main, player) est **structuré et tokenisé** : largeurs, marges, z-index et transitions sont centralisés dans `index.css` et `APP_SHELL.md`. La hiérarchie typographique et le rythme des pages principales (Dashboard, cartes, listes) sont **maîtrisés** sur les vues authentifiées. Les **écarts qui empêchent le niveau Discord/Spotify** sont : (1) baselines visuelles qui reflètent souvent l’état login (redirection non authentifiée), donc peu de captures du shell complet ; (2) valeurs arbitraires restantes (modales, quelques vues) et typo (`text-[10px]`) ; (3) scrollbar et effets globaux définis à plusieurs endroits ; (4) patterns Error/Empty et focus-visible pas encore systématiques. **Impression utilisateur** : application moderne, dark theme cohérent, player et sidebar soignés ; la dernière couche de polish (micro-interactions, contraste secondaire, un seul système de scrollbar) manque pour atteindre le niveau “premium”.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Constats visuels majeurs (avec références)
|
|||
|
|
|
|||
|
|
### 2.1 Source des observations
|
|||
|
|
|
|||
|
|
- **Storybook** : stories `App/Layouts/DashboardLayout` — *Default* (shell + placeholder), *Dashboard – full layout*, *Playlists – full layout*, *Library – full layout*, *Settings*, *Profile*. Viewport desktop, MSW actif. **Recommandation** : considérer Storybook comme source de vérité pour le shell et lancer les captures Playwright sur ces stories (pas seulement sur l’app avec auth).
|
|||
|
|
- **Baselines actuelles** (`visual-tests/baselines/`) : les captures `dashboard-desktop-dark.png`, `header-desktop-dark.png`, `library-desktop-dark.png` décrivent dans l’analyse des images des **écrans de login** (Welcome Back, Sign in, boutons sociaux). Cela indique soit une redirection login quand l’auth n’est pas disponible pendant la capture, soit un nommage à clarifier. Pour un audit shell complet, s’appuyer sur les stories full layout Storybook.
|
|||
|
|
- **Code** : `DashboardLayout.tsx`, `Sidebar.tsx`, `Header.tsx`, `GlobalPlayer.tsx`, `index.css` (tokens shell), `DESIGN_TOKENS.md`, `APP_SHELL.md`.
|
|||
|
|
|
|||
|
|
### 2.2 Shell & structure globale
|
|||
|
|
|
|||
|
|
| Élément | Constat visuel / code | Niveau |
|
|||
|
|
|--------|------------------------|--------|
|
|||
|
|
| **Sidebar** | Largeur tokenisée : 15rem (expanded), 5rem (collapsed). Classes `w-sidebar-expanded`, `w-sidebar-collapsed`, `transition-shell`. Sections (My Studio, Veza Network, Commerce, Library, System), labels en `text-xs` uppercase, items `px-3 py-2 rounded-lg`, indicateur actif `sidebar-active-indicator`. Densité proche Discord (liste de canaux). | **Correct à premium** |
|
|||
|
|
| **Header** | `h-header` (4rem), `backdrop-blur-md`, position `left-header-expanded` / `left-header-collapsed` selon sidebar. Recherche type Spotify (rounded-full, placeholder “What do you want to play?”). Badge “Online”, notifications, theme toggle, user menu. Rapport avec le main : `pt-main` dégage le header. | **Correct** |
|
|||
|
|
| **Player** | Barre flottante `bottom-6`, `lg:left-main-expanded` / `lg:left-main-collapsed`, `rounded-2xl`, `backdrop-blur-2xl`, barre de progression en haut, `h-20 md:h-24`. Animation d’entrée `slide-in-from-bottom-4 fade-in duration-500`, `player-bar-entrance` avec `prefers-reduced-motion` respecté. Poids visuel fort mais contenu principal reste prioritaire. | **Robuste** |
|
|||
|
|
| **Alignement global** | Main : `pt-main`, `pb-main`, `px-4 md:px-8`, `max-w-layout-content mx-auto`. Marges gauche `lg:ml-main-expanded` / `lg:ml-main-collapsed`. Grille cohérente. | **Correct** |
|
|||
|
|
|
|||
|
|
**Conclusion shell** : **niveau actuel correct à premium**. Structure claire, tokens respectés, transitions fluides. La seule réserve : sur les captures “app” (non-Storybook), si l’utilisateur n’est pas authentifié, le shell n’est pas visible — d’où l’importance des stories full layout pour la régression visuelle.
|
|||
|
|
|
|||
|
|
### 2.3 Rythme visuel & spacing
|
|||
|
|
|
|||
|
|
- **Dashboard** : `space-y-6` page, `gap-4` grille stats, `gap-6` grille activité. Cartes en `Card variant="glass"` avec `transition-all duration-[var(--duration-normal)]`. Padding contenu `p-6 pb-24`.
|
|||
|
|
- **Sidebar** : `space-y-6` entre sections, `space-y-0.5` entre items, `px-3 py-2` items, `px-4 py-4` header sidebar.
|
|||
|
|
- **Tokens** : `--layout-gap`, `--layout-gap-sm`, `--layout-gap-lg` documentés. Échelle Tailwind utilisée (gap-2, gap-3, gap-4, p-3, p-4, etc.).
|
|||
|
|
- **Où le rythme est maîtrisé** : grilles Dashboard, espacement sidebar, padding main, espacement entre cartes.
|
|||
|
|
- **Où il peut casser la lecture** : rapports arbitraires signalent encore des `gap-[Xpx]` ou `p-[Xpx]` dans certains composants (modales, vues métier) ; à migrer vers l’échelle ou tokens pour un rythme 100 % cohérent type Discord/Spotify.
|
|||
|
|
|
|||
|
|
### 2.4 Hiérarchie typographique
|
|||
|
|
|
|||
|
|
- **Titres** : `text-3xl font-display font-bold` (Dashboard welcome), `text-2xl font-bold` (valeurs stats), sous-titres `text-sm` / `text-xs text-muted-foreground`.
|
|||
|
|
- **Sidebar** : sections en `text-xs font-medium uppercase tracking-wider`, items `text-sm font-medium`.
|
|||
|
|
- **Player** : titre piste `text-sm md:text-base font-display font-bold`, artiste `text-xs text-muted-foreground`.
|
|||
|
|
- **Reste de `text-[10px]`** : listé dans `UI_UX_AUDIT_DISCORD_SPOTIFY_QUALITY.md` (Navbar, Badge, Admin, MetadataForm, etc.) — à migrer vers `text-xs` sauf exceptions documentées (ex. avatar xs).
|
|||
|
|
- **Contraste principal / secondaire** : `text-foreground` vs `text-muted-foreground` utilisé ; à vérifier ratio AA sur `muted-foreground` (audit a11y recommandé).
|
|||
|
|
|
|||
|
|
### 2.5 Couleurs, contrastes, surfaces
|
|||
|
|
|
|||
|
|
- **Fonds** : `bg-background`, sidebar `bg-[var(--sidebar)]`, header `bg-transparent backdrop-blur-md`, cartes `variant="glass"`, player `bg-black/80 border border-white/10`.
|
|||
|
|
- **Hover / focus** : `hover:bg-sidebar-accent`, `hover:bg-white/5`, `focus-visible:ring-2 focus-visible:ring-primary/50` sur Sidebar et Header. Cartes `hover:border-primary/50`.
|
|||
|
|
- **Impression** : l’UI “respire” grâce au dark theme, aux espacements et au blur ; pas d’écrasement visuel. Profondeur par bordures légères et ombres sémantiques (shadow-card, shadow-player-hover).
|
|||
|
|
|
|||
|
|
### 2.6 Composants (qualité perçue)
|
|||
|
|
|
|||
|
|
| Composant | Classe | Commentaire |
|
|||
|
|
|-----------|--------|-------------|
|
|||
|
|
| Sidebar (nav items, sections) | **Robuste** | États actif/hover/focus cohérents, transitions tokenisées. |
|
|||
|
|
| Header (search, menu user) | **Correct** | Recherche lisible, menu dropdown ; focus-visible présent. |
|
|||
|
|
| GlobalPlayer (barre, controls) | **Robuste** | Entrée animée, barre de progression, hover sur barre. |
|
|||
|
|
| Cartes Dashboard (stats, activité) | **Correct** | Glass, hover border, pas de surcharge. |
|
|||
|
|
| Boutons (primaire, ghost) | **Correct** | Focus ring, transitions. |
|
|||
|
|
| Inputs (login/register vus en baselines) | **Correct** | Rounded-xl, contraste OK ; lien “Don’t have an account? Sign up” signalé en contraste faible dans les descriptions d’images → à renforcer. |
|
|||
|
|
| Modales (max-h) | **Fragile** | Plusieurs `max-h-[85vh]` / `max-h-[80vh]` encore en dur → migrer vers tokens `.max-h-layout-modal*`. |
|
|||
|
|
|
|||
|
|
### 2.7 Micro-interactions & motion
|
|||
|
|
|
|||
|
|
- **Présent** : `transition-shell` (sidebar), `duration-[var(--duration-fast)]` / `--duration-normal` sur Header, Sidebar, cartes, player. Animation d’entrée player (`slide-in-from-bottom-4`, `fade-in`). `prefers-reduced-motion: reduce` désactive `transition-shell` et `player-bar-entrance`.
|
|||
|
|
- **Où une animation apporte du sens** : déjà en place sur le player (entrée, hover barre). À étendre : feedback hover/focus uniforme sur toutes les listes et cards cliquables ; loading states sur boutons (spinner) pour les actions async.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Points forts (à préserver absolument)
|
|||
|
|
|
|||
|
|
1. **Shell tokenisé** : une seule source (`index.css`) pour sidebar, header, main, player (largeurs, marges, offsets, z-index). Classes utilitaires `.pt-main`, `.pb-main`, `.ml-main-expanded`, `.transition-shell`, etc.
|
|||
|
|
2. **Layout primitives** : `max-w-layout-content`, `min-h-layout-main`, `min-h-layout-page`, tokens modales/lyrics documentés dans DESIGN_TOKENS.md et APP_SHELL.md.
|
|||
|
|
3. **Transitions et durées** : variables `--duration-fast`, `--duration-normal`, `--duration-slow`, `--ease-out`, `--ease-in-out` utilisées dans le shell et les composants critiques ; pas de `duration-200` en dur.
|
|||
|
|
4. **Ombres sémantiques** : `.shadow-card`, `.shadow-modal`, `.shadow-tooltip`, `.shadow-player-thumb`, `.shadow-queue-item-current`, etc. — cohérence et maintenabilité.
|
|||
|
|
5. **Sidebar** : structure claire (sections, labels, indicateur actif), focus-visible et hover cohérents, transition expand/collapse fluide.
|
|||
|
|
6. **GlobalPlayer** : positionnement aligné sur la sidebar (lg:left-main-*), entrée animée, barre de progression toujours visible, reduced-motion respecté.
|
|||
|
|
7. **Stories full layout** : DashboardLayout avec Dashboard, Playlists, Library, Settings, Profile — référence visuelle et base pour tests de régression.
|
|||
|
|
8. **Skeletons** : présents sur de nombreuses vues (Library, Playlist, Track, Chat, Settings, Profile) pour états Loading.
|
|||
|
|
9. **Règles et outillage** : ESLint no-restricted-syntax sur valeurs arbitraires, script `report-arbitrary-values.mjs`, procédure visual-tests documentée.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Points faibles critiques (ce qui empêche le niveau premium)
|
|||
|
|
|
|||
|
|
1. **Captures visuelles shell** : les baselines “dashboard”, “library”, “header” peuvent montrer l’écran de login si l’app est capturée sans session. Le shell complet (sidebar + header + main + player) n’est pas garanti dans la régression actuelle. **Impact** : régressions layout shell non détectées.
|
|||
|
|
2. **Valeurs arbitraires restantes** : modales (`max-h-[85vh]`, etc.), quelques vues (LiveStreamDetailView, APIPlaygroundView, etc.), typo `text-[10px]` dans plusieurs fichiers. **Impact** : incohérence et maintenance difficile.
|
|||
|
|
3. **Scrollbar et effets globaux** : définitions dans `index.css`, `global-effects.css` et `fixDisplayIssues.ts` — risque d’incohérence selon l’ordre de chargement. **Impact** : expérience variable, sentiment “bricolé”.
|
|||
|
|
4. **Contraste secondaire** : texte “Don’t have an account? Sign up” et similaires (muted-foreground) signalés comme faible contraste dans les analyses d’images. **Impact** : accessibilité et lisibilité en dessous du niveau AA sur certains textes secondaires.
|
|||
|
|
5. **Patterns Error / Empty** : pas unifiés (toast vs bannière vs bloc inline ; messages et CTA empty hétérogènes). **Impact** : expérience incohérente en cas d’erreur ou liste vide.
|
|||
|
|
6. **Focus-visible** : pas sur tous les contrôles (Select, certaines listes, certaines cards). **Impact** : navigation clavier et a11y incomplètes.
|
|||
|
|
7. **Réduction de mouvement** : partielle (effets décoratifs) ; pas étendue à toutes les transitions du shell/player dans un seul bloc `prefers-reduced-motion`. **Impact** : utilisateurs sensibles au motion pas toujours respectés.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Top 10 des améliorations à plus fort impact
|
|||
|
|
|
|||
|
|
| # | Amélioration | Impact visuel | Risque | Effort |
|
|||
|
|
|---|--------------|---------------|--------|--------|
|
|||
|
|
| 1 | **Capturer le shell en Storybook** : ajouter des tests Playwright qui ouvrent les stories DashboardLayout (Default, DashboardFullLayout) et capturent sidebar + header + main + player. Mettre à jour la doc visual-tests. | Élevé (régression shell détectée) | Faible | M |
|
|||
|
|
| 2 | **Unifier la scrollbar** : une seule source (index.css ou global-effects) avec variables CSS ; retirer ou cantonner les injections dans fixDisplayIssues. | Élevé (cohérence perçue) | Moyen | S |
|
|||
|
|
| 3 | **Tokens modales** : utiliser `.max-h-layout-modal`, `.max-h-layout-modal-sm`, etc. partout ; supprimer les `max-h-[XXvh]` dans les modales. | Moyen (design system) | Faible | M |
|
|||
|
|
| 4 | **Contraste muted-foreground** : mesurer et ajuster `--muted-foreground` (dark) pour ratio ≥ 4.5:1 ; corriger les liens secondaires (ex. “Sign up”). | Élevé (lisibilité, a11y) | Faible | S |
|
|||
|
|
| 5 | **Pattern Error unifié** : composant ou pattern (page vs liste vs formulaire) + usage systématique. | Moyen (cohérence) | Faible | M |
|
|||
|
|
| 6 | **Pattern Empty unifié** : structure commune (titre, description, CTA) + style cohérent pour librairie vide, playlist vide, queue vide, recherche sans résultat. | Moyen (cohérence) | Faible | M |
|
|||
|
|
| 7 | **Focus-visible sur tous les contrôles** : audit des éléments focusables (Select, listes, cards cliquables) et ajout du ring cohérent. | Élevé (a11y, clavier) | Faible | M |
|
|||
|
|
| 8 | **Migration text-[10px] → text-xs** : avec exceptions documentées (avatar xs, etc.). | Moyen (typo cohérente) | Faible | S |
|
|||
|
|
| 9 | **Réduction de mouvement complète** : étendre `@media (prefers-reduced-motion: reduce)` à toutes les transitions du shell et du player (sidebar, header, player bar). | Moyen (a11y) | Faible | S |
|
|||
|
|
| 10 | **Micro-interactions** : hover/focus explicites sur list items et cards cliquables ; loading spinner sur boutons d’action async. | Moyen (polish) | Faible | M |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. Recommandations structurantes
|
|||
|
|
|
|||
|
|
### 6.1 Design system
|
|||
|
|
|
|||
|
|
- Consolider **une seule** définition des effets globaux (scrollbar, noise) et la documenter dans DESIGN_TOKENS.md.
|
|||
|
|
- Documenter les exceptions typo (avatar xs, etc.) et les tokens modales/lyrics déjà en place.
|
|||
|
|
- Ajouter un court guide “Empty state” et “Error handling” dans `docs/` et les lier depuis DESIGN_TOKENS ou STORYBOOK_CONTRACT.
|
|||
|
|
|
|||
|
|
### 6.2 Layout
|
|||
|
|
|
|||
|
|
- Continuer à utiliser **uniquement** les classes shell tokenisées (`pt-main`, `pb-main`, `lg:ml-main-*`, `left-header-*`, `lg:left-main-*`) ; pas de marges/padding en dur pour le shell.
|
|||
|
|
- Valider les breakpoints 320, 768, 1024, 1280 sur les stories full layout (grilles, listes, sidebar overlay).
|
|||
|
|
|
|||
|
|
### 6.3 Composants
|
|||
|
|
|
|||
|
|
- Classe chaque nouveau composant “feature” avec états Loading (skeleton), Error, Empty dans les stories (référence STORYBOOK_CONTRACT.md).
|
|||
|
|
- Étendre l’usage des ombres sémantiques (shadow-card, shadow-modal) et éviter les `shadow-[...]` arbitraires.
|
|||
|
|
- Boutons : feedback loading (spinner ou disabled) sur toutes les actions async.
|
|||
|
|
|
|||
|
|
### 6.4 Motion
|
|||
|
|
|
|||
|
|
- Utiliser **uniquement** les variables `--duration-*` et `--ease-*` pour les transitions.
|
|||
|
|
- Centraliser la logique `prefers-reduced-motion: reduce` (déjà partiellement en place) pour shell et player ; ne pas ajouter d’animations décoratives sans les désactiver en reduced-motion.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Verdict honnête
|
|||
|
|
|
|||
|
|
> **Aujourd’hui, cette UI est à environ 70–75 % d’une qualité Discord/Spotify-like.**
|
|||
|
|
|
|||
|
|
- **Shell et structure** : 85 % — très proche (tokens, alignements, player).
|
|||
|
|
- **Rythme et spacing** : 75 % — bon sur les pages principales ; reste des arbitraires et quelques incohérences.
|
|||
|
|
- **Typographie** : 70 % — hiérarchie claire ; reste des `text-[10px]` et contraste secondaire à renforcer.
|
|||
|
|
- **Couleurs et surfaces** : 80 % — thème cohérent, ombres sémantiques.
|
|||
|
|
- **Composants** : 70 % — sidebar et player robustes ; modales et patterns Error/Empty à unifier.
|
|||
|
|
- **Motion** : 75 % — transitions tokenisées et reduced-motion partiel ; micro-interactions à étendre.
|
|||
|
|
|
|||
|
|
Les **2–3 prochaines semaines** ciblant : (1) captures shell Storybook + unification scrollbar, (2) tokens modales + contraste muted-foreground, (3) patterns Error/Empty et focus-visible, feront franchir le cap “produit premium” de façon visible et durable.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. Références
|
|||
|
|
|
|||
|
|
- `docs/DESIGN_TOKENS.md` — tokens layout, typo, ombres, transitions.
|
|||
|
|
- `docs/APP_SHELL.md` — shell, variables CSS, classes utilitaires, responsive.
|
|||
|
|
- `docs/UI_UX_AUDIT_DISCORD_SPOTIFY_QUALITY.md` — lacunes détaillées, phases A/B/C.
|
|||
|
|
- `visual-tests/README.md` — procédure capture/compare/update.
|
|||
|
|
- `src/components/layout/DashboardLayout.stories.tsx` — stories full layout.
|
|||
|
|
- `src/index.css` — tokens shell, `.transition-shell`, `.pt-main`, `.pb-main`, etc.
|