Files
malio-layer-ui/docs/superpowers/plans/2026-05-21-refonte-playground.md
tristan e2dabb0a26 [#MUI-34] Revoir le système de playground (#48)
| Numéro du ticket | Titre du ticket |
|------------------|-----------------|
|                  |                 |

## Description de la PR

## Modification du .env

## Check list

- [ ] Pas de régression
- [ ] TU/TI/TF rédigée
- [ ] TU/TI/TF OK
- [ ] CHANGELOG modifié

Reviewed-on: #48
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-05-21 08:30:23 +00:00

13 KiB

Refonte du playground — Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Remplacer la fausse-SPA du playground (sidebar maison + chargement dynamique dans index.vue) par du vrai routage Nuxt fichier + un layout par défaut qui embarque le composant MalioSidebar de production.

Architecture: Une config de navigation centralisée (.playground/playground.nav.ts) alimente un layout par défaut (.playground/layouts/default.vue) contenant <MalioSidebar> + <slot />. Les pages de démo existantes sous .playground/pages/composant/** deviennent automatiquement des routes et héritent du layout. index.vue devient une simple page d'accueil. Le app/app.vue du layer (<NuxtLayout><NuxtPage /></NuxtLayout>), hérité via extends, applique le layout automatiquement.

Tech Stack: Nuxt 4 (layer + playground via extends), Vue 3 <script setup>, Tailwind (tokens m-*), composant MalioSidebar (auto-importé).

Note sur les tests : Le playground est un harnais de dev, non livré. Vitest est scopé à app/**/*.test.ts (la bibliothèque) et aucune page playground n'a de test. Cette refonte n'introduit donc pas de tests unitaires : les portes de vérification sont npm run dev:prepare (compilation/types), npm run lint, et un contrôle manuel via npm run dev.

Convention de commit (projet) : Conventional Commits avec espace avant les deux-points, type en minuscules, pas de préfixe [#...], suffixe ticket (#MUI-34). Terminer par le trailer Co-Authored-By. Le hook pre-commit lance toute la suite et time out de façon flaky sous WSL2 : réessayer, puis après 2 échecs flaky committer avec --no-verify.


File Structure

Fichier Rôle Action
.playground/playground.nav.ts Source unique des sections/liens de la sidebar (typé SidebarSection[]) Créer
.playground/layouts/default.vue Layout par défaut : MalioSidebar + zone de contenu <slot /> Créer
.playground/pages/index.vue Page d'accueil simple (remplace la fausse-SPA) Réécrire
.claude/skills/creating-malio-component/SKILL.md Doc process création de composant Modifier (étape playground + Common Mistakes)
.playground/pages/composant/**/*.vue Pages de démo Inchangées (déjà des routes)

Task 1 : Config de navigation centralisée

Files:

  • Create: .playground/playground.nav.ts

  • Step 1 : Créer le fichier de navigation

Créer .playground/playground.nav.ts avec ce contenu exact. Chaque to correspond exactement à un fichier existant sous .playground/pages/composant/. Le type est importé du SFC MalioSidebar.

import type {SidebarSection} from '../app/components/malio/sidebar/Sidebar.vue'

export const navSections: SidebarSection[] = [
  {
    label: 'BOUTONS',
    icon: 'mdi:gesture-tap-button',
    items: [
      {label: 'Button', to: '/composant/button/button'},
      {label: 'Button Icon', to: '/composant/button/buttonIcon'},
    ],
  },
  {
    label: 'CHAMPS',
    icon: 'mdi:form-textbox',
    items: [
      {label: 'Texte', to: '/composant/input/inputText'},
      {label: 'Nombre', to: '/composant/input/inputNumber'},
      {label: 'Montant', to: '/composant/input/inputAmount'},
      {label: 'Email', to: '/composant/input/inputEmail'},
      {label: 'Mot de passe', to: '/composant/input/inputPassword'},
      {label: 'Téléphone', to: '/composant/input/inputPhone'},
      {label: 'Zone de texte', to: '/composant/input/inputTextArea'},
      {label: 'Saisie assistée', to: '/composant/input/inputAutocomplete'},
      {label: 'Upload', to: '/composant/input/inputUpload'},
      {label: 'Éditeur riche', to: '/composant/input/inputRichText'},
    ],
  },
  {
    label: 'SÉLECTIONS',
    icon: 'mdi:form-dropdown',
    items: [
      {label: 'Select', to: '/composant/select/select'},
      {label: 'Select Checkbox', to: '/composant/select/selectCheckbox'},
      {label: 'Checkbox', to: '/composant/checkbox/checkbox'},
      {label: 'Radio', to: '/composant/radio/radioButton'},
    ],
  },
  {
    label: 'NAVIGATION',
    icon: 'mdi:navigation-variant',
    items: [
      {label: 'Sidebar', to: '/composant/sidebar/sidebar'},
      {label: 'Drawer', to: '/composant/drawer/drawer'},
      {label: 'Onglets', to: '/composant/tab/tabList'},
    ],
  },
  {
    label: 'DONNÉES',
    icon: 'mdi:table',
    items: [
      {label: 'DataTable', to: '/composant/datatable/datatable'},
    ],
  },
  {
    label: 'DIVERS',
    icon: 'mdi:dots-horizontal',
    items: [
      {label: 'Heure', to: '/composant/time/time'},
      {label: 'Sélecteur de site', to: '/composant/site/siteSelector'},
      {label: 'Formulaire client', to: '/composant/form/client'},
    ],
  },
]
  • Step 2 : Vérifier le lint du fichier

Run: npx eslint .playground/playground.nav.ts Expected: aucune erreur (0 problems). Si ESLint signale un import de type non résolu depuis le .vue, c'est un faux positif de résolution ; il ne bloque pas (warnings only). En cas d'erreur bloquante sur l'import du type, fallback : remplacer la ligne d'import par une définition locale équivalente :

type SidebarItem = {label: string; to: string}
type SidebarSection = {label?: string; icon?: string; items: SidebarItem[]}

(Pas de commit ici — les 3 fichiers de la refonte seront committés ensemble en Task 4, car retirer l'ancien index.vue casse temporairement le glob.)


Task 2 : Layout par défaut

Files:

  • Create: .playground/layouts/default.vue

Pré-requis vérifiés : MalioSidebar est auto-importé (préfixe Malio, pathPrefix: false). Ses slots sont logo et logo-collapsed. Sa prop requise est sections: SidebarSection[]. Les logos LOGO_MALIO.png / LOGO_MALIO_COLLAPSED.png sont servis depuis le public/ du layer (donc accessibles à la racine /).

  • Step 1 : Créer le layout

Créer .playground/layouts/default.vue. Noter : balises <img> sans auto-fermeture (sinon warning ESLint vue/html-self-closing).

<template>
  <div class="flex h-screen">
    <MalioSidebar :sections="navSections">
      <template #logo>
        <NuxtLink to="/">
          <img src="/LOGO_MALIO.png" alt="Malio">
        </NuxtLink>
      </template>
      <template #logo-collapsed>
        <NuxtLink to="/">
          <img src="/LOGO_MALIO_COLLAPSED.png" alt="Malio">
        </NuxtLink>
      </template>
    </MalioSidebar>

    <main class="flex-1 overflow-y-auto p-6">
      <slot />
    </main>
  </div>
</template>

<script setup lang="ts">
import {navSections} from '../playground.nav'
</script>
  • Step 2 : Vérifier le lint du layout

Run: npx eslint .playground/layouts/default.vue Expected: aucune erreur bloquante (0 errors).


Task 3 : Réécrire index.vue en page d'accueil

Files:

  • Modify (réécriture complète): .playground/pages/index.vue

  • Step 1 : Remplacer tout le contenu de index.vue

Remplacer l'intégralité du fichier .playground/pages/index.vue (supprime la sidebar maison + le chargement dynamique par glob) par :

<template>
  <div class="mx-auto max-w-2xl py-16 text-center">
    <h1 class="text-3xl font-bold text-m-text">
      Playground @malio/layer-ui
    </h1>
    <p class="mt-4 text-m-muted">
      Sélectionne un composant dans la barre latérale pour afficher sa page de démonstration.
    </p>
  </div>
</template>

(Page sans <script> : contenu purement statique. Elle hérite du layout default automatiquement.)

  • Step 2 : Vérifier le lint de la page

Run: npx eslint .playground/pages/index.vue Expected: aucune erreur bloquante (0 errors).


Task 4 : Vérification end-to-end + commit de la refonte

Files: (commit groupé)

  • .playground/playground.nav.ts

  • .playground/layouts/default.vue

  • .playground/pages/index.vue

  • Step 1 : Régénérer les types Nuxt (compilation)

Run: npm run dev:prepare Expected: « Types generated in .playground/.nuxt. » sans erreur de compilation. Valide que le layout, le nav et index.vue compilent et que l'import du type SidebarSection se résout.

  • Step 2 : Lint global

Run: npm run lint Expected: 0 errors (des warnings préexistants sur d'autres fichiers sont tolérés ; aucun nouvel error sur les 3 fichiers créés/modifiés).

  • Step 3 : Contrôle manuel dans le navigateur

Run: npm run dev puis ouvrir l'URL affichée. Vérifier :

  • L'accueil (/) affiche le message de bienvenue, avec la MalioSidebar à gauche.
  • La sidebar liste les 6 sections et tous les liens.
  • Cliquer un item (ex. « Texte ») change l'URL en /composant/input/inputText et affiche la démo correspondante dans la zone de contenu.
  • Le bouton collapse de la sidebar fonctionne (plier/déplier).
  • Cliquer le logo ramène à /.

Arrêter le serveur (Ctrl+C) une fois vérifié.

  • Step 4 : Commit de la refonte
git add .playground/playground.nav.ts .playground/layouts/default.vue .playground/pages/index.vue
git commit -m "refactor : refonte du playground avec routage Nuxt et MalioSidebar (#MUI-34)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"

Si le hook pre-commit échoue en timeout flaky 2 fois de suite (échecs non reproductibles sur des tests triviaux), recommencer avec --no-verify (les fichiers modifiés ne sont pas testés par Vitest, scopé à app/).


Task 5 : Mettre à jour le skill creating-malio-component

Le skill décrit encore l'ancien fonctionnement (auto-découverte par index.vue via glob). Il faut documenter l'ajout dans la nav centralisée et corriger le chemin de la page playground (qui est sous un sous-dossier de catégorie).

Files:

  • Modify: .claude/skills/creating-malio-component/SKILL.md

  • Step 1 : Réécrire l'étape 5 (page playground)

Remplacer le bloc de l'étape « ### 5. Créer la page playground » — du titre jusqu'à la ligne **Variantes typiques :** exclue — par :

### 5. Créer la page playground

**Fichier :** `.playground/pages/composant/<categorie>/<nomComposant>.vue` (camelCase, dans le sous-dossier de catégorie)

La page devient automatiquement une route Nuxt (`/composant/<categorie>/<nomComposant>`) et hérite du layout `default` (qui affiche la `MalioSidebar`). **Ajouter ensuite le lien dans la nav centralisée** `.playground/playground.nav.ts` : insérer un `{label, to}` dans la section appropriée (ou créer une nouvelle section), où `to` = `/composant/<categorie>/<nomComposant>`.

Inclure des variantes représentatives dans une grille :

\`\`\`html
<div class="grid grid-cols-1 items-start gap-6 md:grid-cols-2">
  <div class="rounded-lg border p-4">
    <h2 class="mb-4 text-xl font-bold">Titre variante</h2>
    <MalioMonComposant ... />
  </div>
</div>
\`\`\`
  • Step 2 : Mettre à jour la table « Common Mistakes »

Remplacer la ligne :

| Page playground non détectée | Vérifier le nom du fichier en camelCase dans `.playground/pages/composant/` |

par :

| Composant absent de la sidebar du playground | Ajouter son entrée `{label, to}` dans `.playground/playground.nav.ts` (la page n'est plus auto-découverte) |
  • Step 3 : Vérifier la cohérence du diagramme workflow

Lire le bloc digraph en tête du skill. L'étape « 5. Créer la page playground » reste valable telle quelle (le titre n'a pas changé). Aucune modification du diagramme nécessaire — confirmer visuellement puis passer à l'étape suivante.

  • Step 4 : Commit de la mise à jour du skill
git add .claude/skills/creating-malio-component/SKILL.md
git commit -m "docs : maj skill creating-malio-component pour la nav playground (#MUI-34)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"

(Ce fichier n'est pas concerné par le hook de tests ; en cas de timeout flaky, --no-verify.)


Vérification finale (après toutes les tâches)

  • npm run lint → 0 errors.
  • npm run dev → accueil + navigation entre composants OK, logo → accueil, collapse OK.
  • git log --oneline -3 → 2 nouveaux commits au format type : … (#MUI-34).
  • Plus aucune trace de sidebar maison / import.meta.glob dans .playground/pages/index.vue.

Note post-exécution (pour l'agent)

Mettre à jour la mémoire malio-datepicker-conventions.md : la note « Playground : pages auto-découvertes par glob ; pas d'édition d'index.vue » est désormais fausse. Nouvelle réalité : routage Nuxt fichier + layout default + nav centralisée dans .playground/playground.nav.ts à éditer pour chaque nouveau composant.