veza/shell_complet_et_vues_full_layout_afbefcf6.plan.md
senke 39b2b642d2 feat(web): UI premium Discord/Spotify-like — tokens, shadows, focus, layout
Plan UI premium 6–8 semaines (design system, shell, Storybook, a11y):

- Design system: DESIGN_TOKENS.md, APP_SHELL.md, FULL_LAYOUT_PAGE.md. Single source
  for layout/shell (index.css), shadows (design-system.css), durations/easing.
- Tokens: shadow-cover-depth, shadow-gold-glow, shadow-fab-glow; layout max-height
  (max-h-layout-drawer, max-h-layout-panel, max-h-layout-list). All duration-200/300/500
  replaced by --duration-fast/normal/slow. Arbitrary shadows replaced by token classes.
- Shell & player: Sidebar, Header, GlobalPlayer, MiniPlayer, PlayerQueue, PlayerControls,
  AudioPlayer use tokens; focus-visible on Sidebar, PlayerQueue, DropdownMenuTrigger/Item,
  TabsTrigger. Typography: text-[10px]/[9px] → text-xs where applicable.
- ESLint: no-restricted-syntax (warn) for w-/h-/rounded-/shadow-/text-/spacing arbitrary.
- Scripts: report-arbitrary-values.mjs, capture/compare/generate visual; visual-complete.spec.ts.
- Stories full layout: Dashboard, Playlists, Library, Settings, Profile in DashboardLayout.stories.
- .cursorrules + README: DESIGN_TOKENS, APP_SHELL, visual commands, no arbitrary without justification.
- apps/web/.gitignore: e2e test artifacts (test-results-visual, playwright-report-visual).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 17:15:58 +01:00

13 KiB
Raw Blame History

name overview todos isProject
Shell complet et vues full layout Définir un shell applicatif 100% token-based (sidebar, header, main, player), documenter sa spec, puis ajouter 23 stories Storybook "full layout" (App shell placeholder, Dashboard, Playlists) avec Dashboard comme référence visuelle.
false

Plan : Shell ultra complet + 23 vues full layout (Dashboard comme guide)

Contexte

  • Le shell actuel est dans DashboardLayout.tsx et Header.tsx mais utilise des valeurs Tailwind en dur (lg:ml-72, lg:ml-28, pt-20, pb-32, left-72, left-20, h-16) au lieu des tokens déjà définis dans index.css (sidebar, layout primitives).
  • Les tokens sidebar existent (.w-sidebar-expanded, .left-sidebar, etc.) mais les marges du main et la position du header ne sont pas en tokens, ce qui crée un écart (ex. ml-72 = 18rem alors que --sidebar-width-expanded = 15rem).
  • Une story DashboardLayout.stories.tsx existe avec du contenu placeholder ; il ny a pas de story "full layout" avec le vrai DashboardPage ni avec PlaylistListPage.

Phase 1 — Tokens du shell et classes utilitaires

Objectif : Toute dimension du shell (header, main, player) est pilotée par des variables CSS ; plus aucune valeur arbitraire dans le layout.

1.1 Ajouter les variables shell dans index.css

Dans la section "Layout primitives" (après --layout-gap-lg), ajouter :

  • --header-height: 4rem (équivalent actuel h-16)
  • --main-offset-top: 5rem (équivalent pt-20, espace sous le header fixe)
  • --main-offset-bottom: 8rem (équivalent pb-32, réserve pour le player)
  • --main-margin-left-expanded: 18rem (marge gauche du main quand sidebar ouverte : 15rem sidebar + 3rem gap)
  • --main-margin-left-collapsed: 7rem (marge gauche quand sidebar fermée : 5rem + 2rem gap)
  • --header-left-expanded: 18rem (bord gauche de la barre header quand sidebar ouverte)
  • --header-left-collapsed: 5rem (bord gauche quand sidebar fermée)

Côté main, on garde le padding horizontal en échelle Tailwind (px-4 md:px-8) sauf si tu veux un token dédié plus tard (optionnel).

1.2 Ajouter les classes utilitaires shell dans index.css

Dans la même zone que .left-sidebar / .z-sidebar (layout sidebar), ajouter :

  • .h-headerheight: var(--header-height)
  • .pt-mainpadding-top: var(--main-offset-top)
  • .pb-mainpadding-bottom: var(--main-offset-bottom)
  • .ml-main-expandedmargin-left: var(--main-margin-left-expanded) (à utiliser avec lg:)
  • .ml-main-collapsedmargin-left: var(--main-margin-left-collapsed) (avec lg:)
  • .left-header-expandedleft: var(--header-left-expanded)
  • .left-header-collapsedleft: var(--header-left-collapsed)

Commente brièvement chaque variable (comme pour --sidebar-width-expanded) pour faciliter la maintenance.


Phase 2 — Remplacer les valeurs en dur dans le layout

Objectif : DashboardLayout et Header nutilisent plus que des classes basées sur les tokens du shell.

2.1 DashboardLayout.tsx

  • Remplacer la className du conteneur principal (la div qui a flex-1 flex flex-col...) :
    • lg:ml-72lg:ml-main-expanded quand sidebarOpen
    • lg:ml-28lg:ml-main-collapsed quand !sidebarOpen
    • Conserver ml-0 pour mobile.
  • Sur la balise <main> :
    • pt-20pt-main
    • pb-32pb-main
    • Garder px-4 md:px-8 et le reste tel quel.

Utiliser cn() pour appliquer ml-main-expanded / ml-main-collapsed selon sidebarOpen (avec préfixe lg:), sans réintroduire de valeurs en dur.

2.2 Header.tsx

  • Sur lélément <header> : h-16h-header.
  • Sur la div interne qui positionne la barre (celle avec left-72 / left-20) :
    • left-72left-header-expanded quand sidebarOpen
    • left-20left-header-collapsed quand !sidebarOpen
    • Conserver h-16h-header sur cette même div.
    • Garder max-lg:left-0.

Vérifier quil ny a pas dautres h-16 / left-* liés au shell dans ce fichier.


Phase 3 — Documentation du shell

Objectif : Une seule référence écrite qui décrit le shell et son usage pour les prochaines évolutions.

3.1 Créer docs/APP_SHELL.md

Contenu minimal :

  • Vue densemble : rôle du shell (sidebar, header, main, player), fichier principal DashboardLayout.tsx et Header.tsx.
  • Variables CSS : tableau ou liste des variables ajoutées en Phase 1 avec leur valeur et leur rôle (header height, main offset top/bottom, main margin-left expanded/collapsed, header left expanded/collapsed).
  • Classes utilitaires : liste des classes (.h-header, .pt-main, .pb-main, .ml-main-expanded, .ml-main-collapsed, .left-header-expanded, .left-header-collapsed) et quand les utiliser.
  • Comportement responsive : sur lg (1024px+) utilisation des marges/positions tokenisées ; en dessous, sidebar en overlay et ml-0 / left-0 pour le header.
  • Référence croisée : lien vers les tokens sidebar existants dans index.css (--sidebar-width-expanded, etc.) pour garder une cohérence sidebar ↔ main.

Pas de code dupliqué : le doc pointe vers index.css et les composants, il ne recopie pas tout le CSS.


Phase 4 — Stories full layout dans Storybook

Objectif : Avoir 23 vues "app entière" dans Storybook (shell + contenu réel ou réaliste), avec Dashboard comme écran pilote/guide.

4.1 Story "App shell" (placeholder)

  • Fichier : DashboardLayout.stories.tsx.
  • Conserver ou renommer la story existante Default en AppShellWithPlaceholder (ou garder "Default" et ajouter un sous-titre / description indiquant "Shell with placeholder content").
  • Contenu : le même placeholder que aujourdhui (titre, paragraphe, grille de cartes, liste ditems) pour valider scroll et proportions.
  • Paramètres : layout: 'fullscreen' (déjà présent), viewport optionnel (ex. 1280x720) pour cohérence avec les captures visuelles.
  • Sassurer que la story utilise bien le décorateur global (aucun décorateur local qui enlève le shell). Aucun changement de décorateur nécessaire si le preview applique déjà StorybookDecorator à toutes les stories.

4.2 Story "Dashboard full layout"

  • Même fichier ou fichier dédié selon préférence (recommandation : même fichier DashboardLayout.stories.tsx pour garder toutes les vues "full layout" au même endroit).
  • Nouvelle story DashboardFullLayout :
    • Rendu : <DashboardLayout><DashboardPage /></DashboardLayout>.
    • Passer parameters.router.initialEntries = ['/dashboard'] pour que useLocation, useNavigate et déventuels liens soient cohérents.
  • Dépendances : DashboardPage utilise useUser(), useLibraryItems() / store library, etc. Les handlers MSW existants (handlers.ts) fournissent déjà auth/me et dashboard. Vérifier que les appels utilisés par DashboardPage (ex. library items si affichés) sont bien mockés, sinon ajouter ou étendre les handlers pour que la page affiche un état "données chargées" et pas un loading infini.
  • Paramètres : layout: 'fullscreen', même viewport que la story shell si besoin.
  • Cette story sert de référence visuelle pour le rendu "Dashboard dans lapp" ; à utiliser pour les comparaisons visuelles et les régressions.

4.3 Story "Playlists full layout"

  • Même fichier ou nouveau fichier (ex. PlaylistListPage.stories.tsx avec une story full layout qui wrap dans DashboardLayout). Recommandation : une story PlaylistsFullLayout dans DashboardLayout.stories.tsx pour centraliser les vues "app entière".
    • Alternative propre : créer apps/web/src/features/playlists/pages/PlaylistListPage.stories.tsx (sil nexiste pas déjà) et y ajouter une story "FullLayout" qui rend <DashboardLayout><PlaylistListPage /></PlaylistListPage> avec initialEntries: ['/playlists']. Si tu préfères tout au même endroit, garder dans DashboardLayout.stories.tsx.
  • Rendu : <DashboardLayout><PlaylistListPage /></DashboardLayout> (importer PlaylistListPage depuis le module playlists).
  • parameters.router.initialEntries = ['/playlists'].
  • Vérifier les handlers MSW pour les listes de playlists ; ajouter ou adapter si nécessaire pour que la page affiche du contenu (liste ou empty state) et pas un loading infini.
  • Paramètres : layout: 'fullscreen', viewport cohérent.

4.4 Cohérence décorateurs et providers

  • Les stories full layout doivent sexécuter avec le décorateur global (.storybook/decorators.tsx) : ThemeProvider, QueryClient, Toast, Audio, AuthProvider, MemoryRouter. Ne pas dupliquer ces providers dans les stories ; utiliser uniquement parameters.router.initialEntries pour la route.
  • Si DashboardPage ou PlaylistListPage dépendent de lauth Zustand (ex. useAuthStore) en plus de lAuthProvider, documenter ou mocker létat auth (ex. via MSW ou un décorateur minimal qui initialise le store) pour que les pages ne redirigent pas vers login. Idéalement, les pages utilisent les mêmes mécanismes quen app (AuthProvider + API mockée), pour éviter des écarts de comportement.

Phase 5 — Vérification et régression

  • Lint : après les changements, sassurer quaucune règle ESLint nest cassée sur les fichiers modifiés.
  • Storybook : lancer npm run build-storybook (ou storybook dev) depuis apps/web et ouvrir les stories App shell, Dashboard full layout et Playlists full layout ; vérifier que le shell saffiche correctement (sidebar, header, main, player), que le contenu scroll et que les données mockées saffichent.
  • App réelle : lancer lapp (npm run dev) et comparer visuellement Dashboard et Playlists avec les mêmes vues dans Storybook pour confirmer lalignement (pas de décalage de marges, hauteurs, etc.).
  • Tests existants : exécuter les tests unitaires qui touchent à DashboardLayout ou Header (DashboardLayout.test.tsx) et corriger si des classNames ou sélecteurs cassent.

Ordre dexécution recommandé

  1. Phase 1 (tokens + classes dans index.css)
  2. Phase 2 (remplacement dans DashboardLayout.tsx et Header.tsx)
  3. Phase 3 (rédaction de docs/APP_SHELL.md)
  4. Phase 4.1 (story App shell / placeholder)
  5. Phase 4.2 (story Dashboard full layout + MSW si besoin)
  6. Phase 4.3 (story Playlists full layout + MSW si besoin)
  7. Phase 5 (vérifications et tests)

Fichiers impactés (résumé)

Fichier Action
apps/web/src/index.css Ajout variables shell + classes utilitaires
apps/web/src/components/layout/DashboardLayout.tsx Remplacer ml/pt/pb par classes token
apps/web/src/components/layout/Header.tsx Remplacer h-16/left-* par classes token
apps/web/docs/APP_SHELL.md Création doc shell
apps/web/src/components/layout/DashboardLayout.stories.tsx Stories App shell, Dashboard full layout, Playlists full layout
apps/web/src/mocks/handlers.ts Ajustements optionnels si endpoints dashboard/playlists/library manquants

Aucun changement à la logique métier des pages ; uniquement layout, tokens et ajout de stories pour valider le rendu "app entière".