## 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>
8.8 KiB
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.php → SidebarProvider → 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
- Remplacer le
<aside>maison par<MalioSidebar>. - Préserver le filtrage des permissions/rôles/modules côté serveur.
- Re-catégoriser la navigation en 3 groupes : Général / Outils / Administration.
- Mettre le timer et la version dans le footer du composant.
- 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 dansMalioSidebar.
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: truepour 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
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.titlepour Documents,mail.sidebar.title/sidebar.general.mailpour 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 :
- Partir des sections backend (déjà filtrées), mappées en
{ label: t(label), icon, items: items.filter(to !== '/mail').map({label: t, to}) }. - Définir une table
clientItemsindexée par clé de section :sidebar.general.section→ (sicurrentProjectId) Kanban (exact), Groupes, Archives ; puis (siisEmployee) Mes absences.sidebar.tools.section→ (siisMailVisible) Messagerie avec labelMessagerie+ suffixe(N)quandmailStore.globalUnreadCount > 0(99+au-delà) ; puis (sishareEnabled) Documents.
- Pour chaque section backend, append ses items client.
- Si une clé de
clientItemsproduit 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). - Supprimer les sections finales sans items.
- 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.
5. Assets — logo
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 clientisEmployee/isMailVisible/shareEnabledrestent locaux).
Éléments supprimés
- Le
<aside>manuel et son markup (logo, nav, toggle, overlay) dansdefault.vue. - L'usage de
SidebarLinkdans le layout (le composant peut rester s'il est utilisé ailleurs — à vérifier ; sinon suppression possible).
Critères d'acceptation
- La sidebar est rendue par
<MalioSidebar>. - 3 groupes : Général, Outils, Administration (Administration visible
uniquement pour
ROLE_ADMIN/ permissions, comme avant). - Toutes les permissions/rôles/modules sont respectés à l'identique (aucune régression de visibilité pour user/admin).
- Items contextuels présents : Kanban/Groupes/Archives (dans un projet), Documents (partage activé), Mes absences (employé).
- Messagerie affiche
(N)quand il y a des non-lus. - Footer : timer fonctionnel + version (version masquée en replié).
- Logo Malio de Starseed affiché (déplié + replié).
- Collapse/expand et route active fonctionnent.
- Pas de doublon
/mail. Pas de section vide affichée. - 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.