| 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>
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 laMalioSidebarà gauche. - La sidebar liste les 6 sections et tous les liens.
- Cliquer un item (ex. « Texte ») change l'URL en
/composant/input/inputTextet 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 formattype : … (#MUI-34).- Plus aucune trace de sidebar maison /
import.meta.globdans.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.