@01normandie/launcher
v2.0.0
Published
Zone01 Normandie — composants UI partagés
Readme
@01normandie/launcher
Barre de navigation latérale partagée entre toutes les applications Zone01 Normandie.
Le package embarque les icônes, labels et URLs de chaque outil — l'application consommatrice n'a qu'à préciser quelle app est active et passer les infos de l'utilisateur connecté.
Installation
npm install @01normandie/launcherReact 17+ doit être présent dans l'application (peer dependency).
Utilisation
Next.js App Router (app/layout.tsx)
Attention — piège fréquent :
LauncherSidebarutilise des hooks React (useState,useEffect) et des APIs navigateur (localStorage), mais ne déclare pas lui-même'use client'. Dans Next.js App Router, les layouts sont des Server Components par défaut — importerLauncherSidebardirectement danslayout.tsxsans'use client'causera une erreur au runtime.La bonne pratique est de créer un wrapper client fin, et de garder le layout en Server Component pour pouvoir y appeler
getServerSession.
Étape 1 — Créer un wrapper client
Crée components/AppSidebar.tsx :
'use client';
import { LauncherSidebar } from '@01normandie/launcher';
import { signOut } from 'next-auth/react';
import type { ReactNode } from 'react';
interface AppSidebarProps {
user?: { name: string; initials: string } | null;
children: ReactNode;
}
export default function AppSidebar({ user, children }: AppSidebarProps) {
return (
<LauncherSidebar
activeAppId="01deck"
user={user}
onLogout={() => signOut({ callbackUrl: '/' })}
>
{children}
</LauncherSidebar>
);
}Ce composant est le seul à porter 'use client'. Il reçoit user comme prop sérialisable depuis le serveur.
Étape 2 — Utiliser getServerSession dans le layout
Dans app/layout.tsx (Server Component, pas de 'use client') :
import { getServerSession } from 'next-auth';
import { authOptions } from '@/auth';
import AppSidebar from '@/components/AppSidebar';
function computeInitials(name: string): string {
return name
.split(' ')
.map((part) => part[0])
.filter(Boolean)
.slice(0, 2)
.join('')
.toUpperCase();
}
export default async function RootLayout({ children }) {
const session = await getServerSession(authOptions);
const user = session?.user?.name
? { name: session.user.name, initials: computeInitials(session.user.name) }
: null;
return (
<html lang="fr">
<body>
<AppSidebar user={user}>
{children}
</AppSidebar>
</body>
</html>
);
}- Si l'utilisateur n'est pas connecté,
uservautnull→ la sidebar affiche le bouton "Se connecter". - Si connecté,
user.namevient desession.user.name(fourni par NextAuth/Authentik), et les initiales sont calculées automatiquement ("Alice Leroi"→"AL"). - Comme le layout est un Server Component, la session est récupérée côté serveur — aucun flash client, aucune requête supplémentaire.
Les balises <html> et <body> restent dans le layout — c'est requis par Next.js.
React (Vite / CRA)
import { LauncherSidebar } from '@01normandie/launcher';
export default function App() {
const user = { name: 'Alice L.', initials: 'AL' };
return (
<LauncherSidebar
activeAppId="01deck"
user={user}
loginHref="/login"
onLogout={() => { /* ta logique : signOut(), router.push('/login'), etc. */ }}
>
{/* contenu de l'app */}
</LauncherSidebar>
);
}Aucun import CSS nécessaire — les styles sont injectés automatiquement.
Props
| Prop | Type | Requis | Description |
|---|---|---|---|
| activeAppId | AppId | ✅ | ID de l'application courante (met en surbrillance l'entrée correspondante dans la nav) |
| user | { name: string; initials: string } \| null | — | Utilisateur connecté. null affiche un bouton "Se connecter" à la place |
| loginHref | string | — | URL vers laquelle redirige le bouton "Se connecter" |
| onLogout | () => void | — | Fonction appelée au clic sur le bouton de déconnexion — gère ta propre logique (vider le token, rediriger, etc.) |
| children | ReactNode | — | Contenu principal de l'application (affiché à droite de la nav) |
Type AppId
type AppId = '01deck' | 'emargement' | 'apprentissage';Applications incluses
La liste des applications est gérée centralement dans le package. Mettre à jour le package suffit pour que toutes les apps voient apparaître un nouvel outil.
| ID | Label | URL |
|---|---|---|
| 01deck | 01deck | https://deck.zone01normandie.org |
| emargement | Émargement | https://emargement.zone01normandie.org |
| apprentissage | Intra | http://zone01normandie.org |
Comportement
- Mode compact (par défaut) : seules les icônes sont affichées. Cliquer sur le logo Zone01 déploie la barre.
- Mode étendu : icônes + labels + nom de l'utilisateur + bouton de déconnexion.
- L'état expanded/collapsed est persisté dans le
localStoragede l'utilisateur. - La touche
Échapreferme la barre si elle est ouverte.
Mise à jour du package
1. Modifier les sources
Les applications et leurs métadonnées (icône, label, URL, badge) sont dans :
src/LauncherSidebar.tsx → const APPS
src/icons/index.tsx → icônes SVG
src/style.css → styles2. Bumper la version
cd 01launcher
npm version patch # correctif mineur 1.0.0 → 1.0.1
npm version minor # nouvelle fonctionnalité 1.0.0 → 1.1.0
npm version major # changement breaking 1.0.0 → 2.0.03. Publier
npm publishLe build se lance automatiquement avant l'upload (prepublishOnly). Avoir l'application 2FA sous la main pour le code OTP.
4. Mettre à jour dans les apps consommatrices
npm update @01normandie/launcher