Header et menu utilisateur¶
Référence du header partagé de Kirexo et de son menu utilisateur déroulant. Le header est un composant d'interface transverse aux trois espaces (public, utilisateur, admin) : cette page décrit le markup qu'il produit, les entrées du menu selon le contexte, et le contrat d'accessibilité du panneau déroulant.
Cette page décrit ce que le header rend et comment il se comporte. Pour le pourquoi (un seul header pour trois contextes, la visibilité de la bascule comme commodité d'affichage), voir l'explication Entête partagé : identité, déconnexion et bascule. Pour les règles générales de couleurs, de thème et d'accessibilité auxquelles ce composant se conforme, voir Design system : tokens, thèmes et accent.
Le composant <twig:Header>¶
Le header est rendu par un composant Twig unique — src/Twig/Components/Header.php et son gabarit templates/components/Header.html.twig — instancié dans chaque layout via une seule balise :
C'est un composant Twig simple (pas un Live Component) : le panneau du menu s'ouvre et se ferme entièrement côté client (assets/js/user-menu.js), sans aller-retour serveur.
Les trois espaces utilisent désormais le même header. En particulier, l'accueil de l'espace utilisateur (/u, templates/user/home.html.twig) a migré de sa topbar custom .ud-topbar vers <twig:Header space="user" /> ; les éléments propres à cette page (barre de recherche, onglets Carnets) restent dans le corps de la page, hors du header.
La prop space¶
Le composant reçoit une unique propriété space ('public', 'user' ou 'admin'), fournie par le layout. Elle pilote l'affichage : brand, présence de l'action principale, route de bascule et de déconnexion, présence du lien Réglages. Elle n'est jamais une donnée de sécurité — le cloisonnement des espaces reste porté par les firewalls (voir Architecture des firewalls).
Méthodes exposées¶
Le composant Header (src/Twig/Components/Header.php) expose les méthodes suivantes au gabarit.
| Méthode | Type retour | Rôle |
|---|---|---|
getUser() |
?User |
Le compte connecté (instanceof User), ou null. |
isMixed() |
bool |
Vrai si le compte porte à la fois ROLE_USER et ROLE_ADMIN. |
getSwitchTarget() |
'admin'\|'user'\|null |
Espace de destination de la bascule selon space, ou null si non éligible (compte non mixte, ou espace public). |
getDisplayName() |
?string |
Prénom du compte connecté (User::getFirstName()), ou null si personne n'est connecté — le bouton du menu n'est alors pas rendu. |
getSwitchLabel() |
'Espace admin'\|'Espace user'\|null |
Libellé UI de la cible de bascule, dérivé de getSwitchTarget(). |
Le nom affiché sur le bouton du menu est toujours le prénom, jamais l'email (règle §3 du design system). getFirstName() renvoie un string non nullable : dès qu'un compte est connecté, un prénom est affiché.
Structure du header rendu¶
Le header rend, de gauche à droite :
- la brand « Kirexo » (logomark + mot), pointant vers l'accueil (
app_home) ; suffixée d'une pastille.tag« Admin » quandspace == 'admin'; - la zone
.header__actions, dont le contenu dépend de l'état de connexion (détaillé ci-dessous).
Compte connecté¶
Deux blocs sont rendus dans .header__actions :
Action principale visible (hors menu) — « Mon espace ». Un lien .header__primary vers app_user_home, rendu uniquement sur l'accueil public (space == 'public'). Il n'apparaît ni dans l'espace utilisateur (on y est déjà sur la home utilisateur), ni dans l'espace admin : là, l'accès à l'espace utilisateur passe par l'entrée « Espace user » de la bascule d'espace du menu, qui joue déjà ce rôle — pas de doublon (design system §2).
Menu utilisateur (disclosure). Un conteneur .user-menu[data-user-menu] avec :
- un bouton déclencheur
.user-menu__trigger[data-user-menu-trigger]portant le prénom (.user-menu__name) et un chevron ; - un panneau
#user-menu-panel.user-menu__panel[data-user-menu-panel], masqué par l'attributhiddenà l'état fermé.
Le panneau regroupe les actions secondaires, dans cet ordre :
| Ordre | Entrée | Condition d'affichage | Cible |
|---|---|---|---|
| 1 | Sélecteur de thème (.theme-toggle, 3 boutons clair / sombre / système) |
toujours | recâblé par assets/js/theme.js |
| 2 | Bascule d'espace (« Espace admin » / « Espace user ») | getSwitchTarget() non nul — comptes mixtes uniquement, hors accueil |
POST app_switch_to_admin / app_switch_to_user (jeton CSRF switch_space) |
| 3 | Réglages | space == 'admin' uniquement |
app_admin_settings |
| — | séparateur .user-menu__sep |
toujours | — |
| 4 | Se déconnecter (.user-menu__action--danger) |
toujours, en dernier | POST app_admin_logout si space == 'admin', sinon app_logout |
Le sélecteur de thème est secondaire une fois connecté : il vit dans le panneau, pas exposé à plat (règle §4 du design system). La bascule d'espace n'apparaît que pour les comptes mixtes ; sa visibilité est une commodité d'affichage, l'autorisation réelle étant portée par CanSwitchSpaceVoter — voir Mécanisme de bascule entre espaces.
Utilisateur anonyme (accueil public)¶
Quand personne n'est connecté et que space == 'public' (hors page de login), il n'y a pas de menu. À la place :
- le sélecteur de thème reste visible à plat dans le header (pas de menu compte où le loger — règle §4 du design system) ;
- un lien « Se connecter » (
.header__login) versapp_login. Aucun lien vers le login admin n'est jamais exposé depuis l'accueil.
Contrat d'accessibilité — pattern disclosure¶
Le menu applique le pattern disclosure de la WAI-ARIA APG, pas un menu (role="menu") : son contenu est une liste de liens et de formulaires POST standards, parcourus à la tabulation naturelle. Ce choix est une règle du projet (§1 du design system) ; il évite d'annoncer un menu applicatif qui attendrait une navigation aux flèches non fournie.
Attributs ARIA¶
| Élément | État fermé | État ouvert |
|---|---|---|
.user-menu__trigger[data-user-menu-trigger] |
aria-expanded="false" |
aria-expanded="true" |
#user-menu-panel[data-user-menu-panel] |
attribut hidden présent |
hidden retiré |
Le trigger porte en permanence aria-controls="user-menu-panel" et aria-haspopup="true". Il n'y a aucun role="menu" ni role="menuitem" dans le panneau.
Comportement clavier et souris¶
Géré par assets/js/user-menu.js :
- Ouverture — clic, Entrée ou Espace sur le trigger (comportement natif du
<button>) : retirehidden, passearia-expandedàtrue. - Échap — ferme le panneau et rend le focus au trigger.
- Clic extérieur — un clic hors d'un
[data-user-menu]ouvert ferme le panneau (sans voler le focus). - Sortie au Tab (
focusoutdont la cible de destination est hors de l'hôte) — ferme le panneau. - Les soumissions des formulaires
POST(bascule, déconnexion) ne sont pas interceptées : le submit natif passe.
Voir aussi¶
- Entête partagé : identité, déconnexion et bascule — pourquoi un seul header pour trois contextes, et pourquoi la visibilité de la bascule n'est qu'une commodité d'affichage.
- Mécanisme de bascule entre espaces — le jeton signé à usage unique derrière l'entrée « Espace admin » / « Espace user » du menu.
- Design system : tokens, thèmes et accent — les variables CSS, le thème
[data-theme]et les contraintes RGAA respectées par le header. - Choisir le thème (clair, sombre ou système) — le sélecteur de thème logé dans le menu.
- Basculer entre l'espace administrateur et l'espace utilisateur — le parcours pas-à-pas de la bascule.