Files
Lesstime/docs/superpowers/specs/2026-06-25-malio-sidebar-migration-design.md
T
tristan c766e76624
Auto Tag Develop / tag (push) Successful in 8s
feat(sidebar) : migration vers MalioSidebar — 3 groupes, footer timer+version, logo (LST-71) (#26)
## Objectif
Remplacer la sidebar maison par le composant `MalioSidebar` de `@malio/layer-ui` (alignement avec Starseed).

## Changements
- **Backend** : `config/sidebar.php` re-catégorisé en **3 groupes** (Général / Outils / Administration). Tous les gates permission/rôle/module **préservés côté serveur** (rien déplacé côté client).
- **Frontend** : `app/layouts/default.vue` migré vers `<MalioSidebar>`. Un computed `mergedSections` mappe les sections backend et y fusionne les items contextuels (Kanban/Groupes/Archives sous « Projets », Mes absences, Messagerie avec compteur `(N)`, Documents).
- **Footer** : timer (`SidebarTimer`) + version de l'app (masquée en mode replié).
- **Logo** : logos Malio repris de Starseed (`LOGO_MALIO.png` / `LOGO_MALIO_COLLAPSED.png`).
- **Mobile** : `MalioSidebar` étant toujours visible (pas de tiroir off-canvas), le hamburger pilote désormais le repli ; suppression du code de tiroir mobile mort (`sidebarOpen`/`openMobileSidebar`/`closeMobileSidebar`).
- **Nettoyage** : suppression de `SidebarLink.vue` et `LOGO_CARRE.png` (obsolètes). `malio.png` conservé (utilisé par la page login).
- **i18n** : nouvelles clés `sidebar.tools.section`, `sidebar.general.myAbsences`, `sidebar.project.kanban|groups|archives` ; `sidebar.general.section` → « Général ».

## Compromis (limites du composant, lib non modifiée)
- Pas d'icône par item (uniquement icône de section) — design malioUI, comme Starseed.
- Badge mail → suffixe `(N)` dans le libellé.

## Vérifications
- Build Nuxt OK (` Build complete!`, exit 0).
- Revue par task + revue finale whole-branch : aucun Critical/Important.
- Sécurité : filtrage des permissions inchangé (côté serveur).

Specs/plan : `docs/superpowers/specs/2026-06-25-malio-sidebar-migration-design.md`, `docs/superpowers/plans/2026-06-25-malio-sidebar-migration.md`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: #26
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-25 15:30:23 +00:00

8.8 KiB
Raw Blame History

Migration de la sidebar vers MalioSidebar (@malio/layer-ui)

Date : 2026-06-25 Statut : Design validé Scope : Frontend (layout) + backend (config sidebar) + assets

Contexte

La sidebar actuelle de Lesstime est un <aside> fait main dans frontend/app/layouts/default.vue, qui itère sur les sections renvoyées par /api/sidebar et rend chaque item via le composant maison SidebarLink. Le timer et la version sont empilés en bas du <aside>, le toggle collapse et l'overlay mobile sont gérés manuellement.

La librairie @malio/layer-ui (mise à jour) fournit désormais un composant MalioSidebar. Le projet Starseed a déjà effectué cette migration sur une architecture identique (config/sidebar.phpSidebarProvider → composable useSidebar → layout). Cette spec applique la même migration à Lesstime, avec trois spécificités Lesstime : footer (timer + version), re-catégorisation des onglets, et plusieurs items contextuels rendus côté client.

On ne modifie pas la lib @malio/layer-ui (règle CLAUDE.md).

Objectifs

  1. Remplacer le <aside> maison par <MalioSidebar>.
  2. Préserver le filtrage des permissions/rôles/modules côté serveur.
  3. Re-catégoriser la navigation en 3 groupes : Général / Outils / Administration.
  4. Mettre le timer et la version dans le footer du composant.
  5. Reprendre le logo Malio de Starseed.

Décisions validées

  • Catégorisation : 3 groupes (option B).
  • Badge mail : le compteur de non-lus devient un suffixe sur le label (Messagerie (3)), faute de slot badge/icône par item dans MalioSidebar.

Contraintes du composant MalioSidebar

Source : frontend/node_modules/@malio/layer-ui/app/components/malio/sidebar/Sidebar.vue.

  • Props : sections (requis), modelValue (v-model collapse, bool), id, sidebarClass, toggleClass.
  • Types :
    • SidebarItem = { label: string; to: string; exact?: boolean }
    • SidebarSection = { label?: string; icon?: string; items: SidebarItem[] }
  • Slots : #logo, #logo-collapsed, #footer, #footer-collapsed.
  • Events : update:modelValue(boolean).
  • Item : pas d'icône par item ni de badge — uniquement l'icône de section. Route active = match exact ou par préfixe (exact: true pour exact strict).
  • Largeurs fixes : 232px (déplié) / 72px (replié). Toggle interne.

Conséquences (compromis assumés)

  • Perte de l'icône par item (design malioUI = texte + icône de section). Starseed fonctionne ainsi.
  • Le badge mail ne peut pas être une pastille → suffixe (N) dans le label.

Architecture cible

Modèle backend-driven conservé (sécurité serveur intacte). Le frontend mappe les sections renvoyées par /api/sidebar vers le format MalioSidebar et fusionne les items contextuels (qui dépendent d'un état runtime non connu du backend).

1. Backend — config/sidebar.php

Re-catégorisation en 3 sections (gates inchangés, juste réorganisés) :

GÉNÉRAL  (sidebar.general.section, icon mdi:view-dashboard-outline)
  Tableau de bord   /              —
  Mes tâches        /my-tasks      module project-management, perm tasks.view
  Projets           /projects      module project-management, perm projects.view
  Suivi de temps    /time-tracking module time-tracking,      perm entries.view

OUTILS   (sidebar.tools.section, icon mdi:tools)
  Messagerie        /mail          module mail
                    (filtré du rendu backend côté front, ré-injecté avec badge)

ADMINISTRATION (sidebar.admin.section, icon mdi:cog-outline, roles [ROLE_ADMIN])
  Absences équipe   /team-absences module absence
  Répertoire        /directory     module directory
  Rapports          /reporting     module reporting, perm reporting.view
  Administration    /admin         perm core.users.view

/mail reste déclaré pour le gating module (disabledRoutes), mais est filtré des sections rendues et ré-injecté côté client avec son badge, comme aujourd'hui.

2. i18n — frontend/i18n/locales/fr.json

  • Renommer sidebar.general.section : « Gestion de projet » → « Général ».
  • Ajouter sidebar.tools.section : « Outils ».
  • Conserver les clés d'items existantes. Items client : réutiliser les clés existantes quand elles existent (sharedFiles.sidebar.title pour Documents, mail.sidebar.title/sidebar.general.mail pour Messagerie) ; ajouter une clé pour « Mes absences » (aujourd'hui en dur) et pour les contextuels (Kanban/Groupes/Archives, aujourd'hui en dur) si on souhaite les traduire, sinon conserver les libellés en dur actuels.

3. Frontend — frontend/app/layouts/default.vue

Réécriture du template autour de <MalioSidebar> :

<MalioSidebar v-model="ui.sidebarCollapsed" :sections="mergedSections"
              :sidebar-class="ui.sidebarCollapsed ? '' : 'w-[232px]'">
  <template #logo>           <img src="/LOGO_MALIO.png" alt="Malio"/></template>
  <template #logo-collapsed> <img src="/LOGO_MALIO_COLLAPSED.png" alt="Malio"/></template>
  <template #footer>
    <SidebarTimer :collapsed="false" />
    <p class="font-bold">v {{ version }}</p>
  </template>
  <template #footer-collapsed>
    <SidebarTimer :collapsed="true" />
  </template>
</MalioSidebar>

Computed mergedSections : construit les sections finales dans l'ordre canonique [général, outils, administration].

Logique de fusion :

  1. Partir des sections backend (déjà filtrées), mappées en { label: t(label), icon, items: items.filter(to !== '/mail').map({label: t, to}) }.
  2. Définir une table clientItems indexée par clé de section :
    • sidebar.general.section → (si currentProjectId) Kanban (exact), Groupes, Archives ; puis (si isEmployee) Mes absences.
    • sidebar.tools.section → (si isMailVisible) Messagerie avec label Messagerie + suffixe (N) quand mailStore.globalUnreadCount > 0 (99+ au-delà) ; puis (si shareEnabled) Documents.
  3. Pour chaque section backend, append ses items client.
  4. Si une clé de clientItems produit des items mais que la section correspondante n'est pas présente dans la réponse backend (ex. module mail off mais partage on → pas de section « Outils » côté backend), créer la section côté front (label + icône depuis une table locale).
  5. Supprimer les sections finales sans items.
  6. Trier selon l'ordre canonique des clés.

Le reste du <script> (timer title watchers, refData/TimeEntryDrawer, polling mail, ensureShareStatus, currentProjectId, isEmployee, isMailVisible, shareEnabled) est conservé tel quel.

4. Mobile

Starseed a supprimé l'overlay mobile custom et ne garde que watch(route) → ui.closeMobileSidebar(). On s'aligne : suppression du markup overlay (ui.sidebarOpen, .sidebar-overlay) si MalioSidebar gère le responsive. À vérifier à l'implémentation : comportement mobile réel du composant ; si l'ouverture mobile n'est pas couverte, adapter a minima sans modifier la lib.

Copier depuis Starseed vers frontend/public/ :

  • LOGO_MALIO.png (128×44)
  • LOGO_MALIO_COLLAPSED.png (34×40)

Les anciens /malio.png et /LOGO_CARRE.png ne sont plus référencés par le layout (les laisser ou les retirer si plus aucun usage — à vérifier).

Composants / éléments réutilisés

  • SidebarTimer (components/ui/SidebarTimer.vue) : inchangé, déjà piloté par :collapsed.
  • useAppVersion() : inchangé.
  • useSidebar() : inchangé.
  • usePermissions() : inchangé (le filtrage permission reste backend ; les flags client isEmployee/isMailVisible/shareEnabled restent locaux).

Éléments supprimés

  • Le <aside> manuel et son markup (logo, nav, toggle, overlay) dans default.vue.
  • L'usage de SidebarLink dans le layout (le composant peut rester s'il est utilisé ailleurs — à vérifier ; sinon suppression possible).

Critères d'acceptation

  1. La sidebar est rendue par <MalioSidebar>.
  2. 3 groupes : Général, Outils, Administration (Administration visible uniquement pour ROLE_ADMIN / permissions, comme avant).
  3. Toutes les permissions/rôles/modules sont respectés à l'identique (aucune régression de visibilité pour user/admin).
  4. Items contextuels présents : Kanban/Groupes/Archives (dans un projet), Documents (partage activé), Mes absences (employé).
  5. Messagerie affiche (N) quand il y a des non-lus.
  6. Footer : timer fonctionnel + version (version masquée en replié).
  7. Logo Malio de Starseed affiché (déplié + replié).
  8. Collapse/expand et route active fonctionnent.
  9. Pas de doublon /mail. Pas de section vide affichée.
  10. Build Nuxt OK, pas d'erreur TS.

Hors scope

  • Refonte du SiteSelector (n'existe pas dans Lesstime).
  • Modification de la lib @malio/layer-ui.
  • Changement du modèle de permissions backend.