show user avatar in sidebar when available

This commit is contained in:
CREDO23 2026-01-14 15:22:24 +02:00
parent 3ad2dbeeaf
commit 9d3c6f0ee1
4 changed files with 40 additions and 26 deletions

View file

@ -354,7 +354,11 @@ export function LayoutDataProvider({
onChatDelete={handleChatDelete} onChatDelete={handleChatDelete}
onViewAllSharedChats={handleViewAllSharedChats} onViewAllSharedChats={handleViewAllSharedChats}
onViewAllPrivateChats={handleViewAllPrivateChats} onViewAllPrivateChats={handleViewAllPrivateChats}
user={{ email: user?.email || "", name: user?.email?.split("@")[0] }} user={{
email: user?.email || "",
name: user?.display_name || user?.email?.split("@")[0],
avatarUrl: user?.avatar_url || undefined,
}}
onSettings={handleSettings} onSettings={handleSettings}
onManageMembers={handleManageMembers} onManageMembers={handleManageMembers}
onUserSettings={handleUserSettings} onUserSettings={handleUserSettings}

View file

@ -12,6 +12,7 @@ export interface SearchSpace {
export interface User { export interface User {
email: string; email: string;
name?: string; name?: string;
avatarUrl?: string;
} }
export interface NavItem { export interface NavItem {

View file

@ -61,6 +61,34 @@ function getInitials(email: string): string {
return name.slice(0, 2).toUpperCase(); return name.slice(0, 2).toUpperCase();
} }
/**
* User avatar component - shows image if available, otherwise falls back to initials
*/
function UserAvatar({
avatarUrl,
initials,
bgColor,
}: {
avatarUrl?: string;
initials: string;
bgColor: string;
}) {
if (avatarUrl) {
return (
<img src={avatarUrl} alt="User avatar" className="h-8 w-8 shrink-0 rounded-lg object-cover" />
);
}
return (
<div
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-xs font-semibold text-white"
style={{ backgroundColor: bgColor }}
>
{initials}
</div>
);
}
export function SidebarUserProfile({ export function SidebarUserProfile({
user, user,
onUserSettings, onUserSettings,
@ -88,12 +116,7 @@ export function SidebarUserProfile({
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
)} )}
> >
<div <UserAvatar avatarUrl={user.avatarUrl} initials={initials} bgColor={bgColor} />
className="flex h-8 w-8 items-center justify-center rounded-lg text-xs font-semibold text-white"
style={{ backgroundColor: bgColor }}
>
{initials}
</div>
<span className="sr-only">{displayName}</span> <span className="sr-only">{displayName}</span>
</button> </button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
@ -104,12 +127,7 @@ export function SidebarUserProfile({
<DropdownMenuContent className="w-56" side="right" align="end" sideOffset={8}> <DropdownMenuContent className="w-56" side="right" align="end" sideOffset={8}>
<DropdownMenuLabel className="font-normal"> <DropdownMenuLabel className="font-normal">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div <UserAvatar avatarUrl={user.avatarUrl} initials={initials} bgColor={bgColor} />
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-xs font-semibold text-white"
style={{ backgroundColor: bgColor }}
>
{initials}
</div>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="truncate text-sm font-medium">{displayName}</p> <p className="truncate text-sm font-medium">{displayName}</p>
<p className="truncate text-xs text-muted-foreground">{user.email}</p> <p className="truncate text-xs text-muted-foreground">{user.email}</p>
@ -149,13 +167,7 @@ export function SidebarUserProfile({
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
)} )}
> >
{/* Avatar */} <UserAvatar avatarUrl={user.avatarUrl} initials={initials} bgColor={bgColor} />
<div
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-xs font-semibold text-white"
style={{ backgroundColor: bgColor }}
>
{initials}
</div>
{/* Name and email */} {/* Name and email */}
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
@ -171,12 +183,7 @@ export function SidebarUserProfile({
<DropdownMenuContent className="w-56" side="top" align="start" sideOffset={4}> <DropdownMenuContent className="w-56" side="top" align="start" sideOffset={4}>
<DropdownMenuLabel className="font-normal"> <DropdownMenuLabel className="font-normal">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div <UserAvatar avatarUrl={user.avatarUrl} initials={initials} bgColor={bgColor} />
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-xs font-semibold text-white"
style={{ backgroundColor: bgColor }}
>
{initials}
</div>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="truncate text-sm font-medium">{displayName}</p> <p className="truncate text-sm font-medium">{displayName}</p>
<p className="truncate text-xs text-muted-foreground">{user.email}</p> <p className="truncate text-xs text-muted-foreground">{user.email}</p>

View file

@ -8,6 +8,8 @@ export const user = z.object({
is_verified: z.boolean(), is_verified: z.boolean(),
pages_limit: z.number(), pages_limit: z.number(),
pages_used: z.number(), pages_used: z.number(),
display_name: z.string().nullable().optional(),
avatar_url: z.string().nullable().optional(),
}); });
/** /**