@col/user-panel
Versie: 1.0.0 Toegevoegd: 2026-08-04
Herkomst
Geëxtraheerd uit growerportal2/src/components/layout/app-shell.tsx
(regels ~339-372), het gebruikersblok onderin de zijbalk: een avatar met
initialen, naam en e-mailadres, en daaronder taal, thema en uitloggen.
Waarvoor
Het gebruikersblok voor de linkerzijbalk van een ingelogde app — de andere
navigatievorm dan @col/user-menu. Een Avatar met initialen naast naam en
e-mailadres, en een tweede rij met besturingselementen (meestal taal en
thema) links en één actie (meestal uitloggen) rechts.
Gebruik het niet in een app met een bovenbalk — daar hoort @col/user-menu
bij, een dropdown in plaats van een blok onderin een kolom.
Wat je app moet leveren
| Prop | Type | Betekenis |
|---|---|---|
name |
string |
Getoond naast de avatar. Verplicht. |
email |
string? |
Getoond onder de naam, gedempt. Weglaten betekent geen tweede regel. |
initials |
string? |
Initialen in de avatar. Zonder dit worden ze uit name afgeleid: de eerste letter van het eerste en het laatste woord, in hoofdletters ("Jan de Vries" → "JV", "Jan" → "J"). |
onSelect |
() => void? |
Aangeroepen bij een klik op het gebruikersblok (naam + avatar). Weglaten maakt het blok niet-klikbaar: het rendert dan als een div zonder hover-effect, in plaats van een button met hover:bg-accent. |
controls |
ReactNode? |
Besturingselementen linksonder, bijvoorbeeld LanguageSelector en ThemeSwitcher. |
action |
ReactNode? |
Eén actie rechtsonder, meestal een uitlog-knop. |
Voorbeeld:
<UserPanel
name={user.name}
email={user.email}
onSelect={() => setDialogOpen(true)}
controls={
<>
<LanguageSelector current={locale} languages={languages} onChange={setLocale} align="start" />
<ThemeSwitcher theme={theme} onChange={setTheme} />
</>
}
action={
<Button variant="ghost" size="icon" className="h-8 w-8" onClick={() => signOut()}>
<LogOut className="h-4 w-4" />
</Button>
}
/>
Bestanden
| Bestand | Landt in | Soort |
|---|---|---|
user-panel.tsx |
components/nav/ |
beheerd |
Upstream shadcn-afhankelijkheden: avatar, separator. Geen cssVars.
De avatar-primitive stond nog niet in deze repo. De bron
(growerportal2/src/components/ui/avatar.tsx) is inmiddels op Base UI
overgestapt (@base-ui/react/avatar), terwijl de rest van deze repo op de
radix-ui-meta-package draait (zie separator.tsx, dropdown-menu.tsx). Om
die reden is components/ui/avatar.tsx niet letterlijk gekopieerd, maar
geschreven als het gebruikelijke shadcn-avatar op radix-ui — hetzelfde
pakket dat hier al voor andere primitives gebruikt wordt, dus geen nieuwe
afhankelijkheid nodig. Functioneel gelijk: Avatar, AvatarImage,
AvatarFallback met dezelfde props.
Gebruikt door
| App | Sinds versie | Opmerkingen |
|---|---|---|
| — | — | Nog geen consumers. growerportal2 is de bron van dit patroon en draait nog op zijn eigen kopie in src/components/layout/app-shell.tsx; die kan hierop over wanneer het uitkomt. |
Bewuste keuzes
hover:bg-accentop de knop-variant, niethover:bg-sidebar-accent. De bron gebruikt overalsidebar-tokens, en die bestaan hier ook (zieapp/globals.css) en worden gebruikt voor de avatar-ring (ring-sidebar-border), de avatar-achtergrond (bg-sidebar-accent), de scheidingslijn (bg-sidebar-border) en het e-mailadres (text-sidebar-foreground/50). Het hover-effect van het klikbare blok is bewust de gewoneaccent-token: dat werkt ook als iemand dit component ooit buiten een daadwerkelijkebg-sidebar-context gebruikt, terwijl de andere tokens juist bedoeld zijn om samen met die achtergrond te kleuren.- Initialen-afleiding uit
name, niet verplicht. De bron berekende initialen zelf uit de sessie; hier is dat een pure functie geworden zodat de app het kan overschrijven (bijvoorbeeld als er al initialen in het gebruikersprofiel staan) zonder de afleiding zelf opnieuw te schrijven. - Eén
action-slot, geen lijst. De bron had precies één knop (uitloggen) naast de besturingselementen. EenReactNodein plaats van een eigen item-API houdt dit component klein; wie meer acties wil, geeft een eigen samengesteld element mee.
Bekende beperkingen
- Geen ingebouwde
ChangePasswordDialogof vergelijkbare klik-actie — dat regelt de app zelf viaonSelect. - Geen submenu of dropdown op het gebruikersblok zelf; voor een menu met
meerdere acties in een bovenbalk is
@col/user-menuhet juiste startpunt, niet dit item.
Vergelijking met @col/user-menu
user-menu |
user-panel |
|
|---|---|---|
| Navigatievorm | Bovenbalk | Zijbalk |
| Weergave | Knop met naam + pijltje, opent dropdown | Vast blok: avatar, naam, e-mail |
| Acties | items[], elk met eigen onSelect en icoon |
Eén action-slot, vrije vorm |
| Extra besturing | — | controls-slot (taal, thema) |
| Klikbaar maken | Altijd (opent het menu) | Optioneel via onSelect |
Geen rangorde — de keuze volgt uit de navigatievorm van de app, niet uit een voorkeur voor het ene component boven het andere.