Observed since 20 Oct, 21:59 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
@01normandie/launcher
Zone01 Normandie — composants UI partagés
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é.
npm install @01normandie/launcher
React 17+ doit être présent dans l'application (peer dependency).
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.
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.
getServerSession dans le layoutDans 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>
);
}
user vaut null → la sidebar affiche le bouton "Se connecter".user.name vient de session.user.name (fourni par NextAuth/Authentik), et les initiales sont calculées automatiquement ("Alice Leroi" → "AL").Les balises <html> et <body> restent dans le layout — c'est requis par Next.js.
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.
| 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) |
AppIdtype AppId = '01deck' | 'emargement' | 'apprentissage';
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 |
localStorage de l'utilisateur.Échap referme la barre si elle est ouverte.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 → styles
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.0
npm publish
Le build se lance automatiquement avant l'upload (prepublishOnly). Avoir l'application 2FA sous la main pour le code OTP.
npm update @01normandie/launcher
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
tsupEnvironment{
"local_name": "tsup",
"alias": false,
"peer_metadata": null
} | ^8.0.0 | development |
reactEnvironment{
"local_name": "react",
"alias": false,
"peer_metadata": null
} | ^18.0.0 | development |
react-domEnvironment{
"local_name": "react-dom",
"alias": false,
"peer_metadata": null
} | ^18.0.0 | development |
typescriptEnvironment{
"local_name": "typescript",
"alias": false,
"peer_metadata": null
} | ^5.0.0 | development |
@types/reactEnvironment{
"local_name": "@types/react",
"alias": false,
"peer_metadata": null
} | ^18.0.0 | development |
@types/react-domEnvironment{
"local_name": "@types/react-dom",
"alias": false,
"peer_metadata": null
} | ^18.0.0 | development |
reactEnvironment{
"local_name": "react",
"alias": false,
"peer_metadata": null
} | >=17.0.0 | peer |
react-domEnvironment{
"local_name": "react-dom",
"alias": false,
"peer_metadata": null
} | >=17.0.0 | peer |
Source distribution
{
"shasum": "1cfc204b1e5502d83d049a2d197890732887d4f6",
"tarball": "https://registry.npmjs.org/@01normandie/launcher/-/launcher-1.0.0.tgz",
"fileCount": 15,
"integrity": "sha512-GNjerDw8X2tT8xxghACC1sYNCO0WHzu6hp7vx9pyUB60KijwfPbSgrkSSS1OsauMuOhUthf+2MMwXyo7W9Rvbw==",
"signatures": [
{
"sig": "MEUCIQDdBKnYhtKHEiRIFQHAJFoDJDDhjj6yZsEOPH7/+X1QHgIgGUzXYiVFKW2VmY/MKzqB6HwqlqDTNSiinbKoipY9nAk=",
"keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
}
],
"unpackedSize": 104335
}Observed since 20 Oct, 21:59 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:ca5d77358c170cf1821b0b117c1b445ec7154982d79e2aa609f321f845bf2fa7