Skip to content

Commit 4f498b2

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
improvement(ui): reuse avatars for owners and members
1 parent febf5d9 commit 4f498b2

3 files changed

Lines changed: 45 additions & 55 deletions

File tree

‎apps/sim/app/workspace/[workspaceId]/components/resource/components/owner-cell/owner-cell.tsx‎

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { memo } from 'react'
2+
import { Avatar, AvatarFallback, AvatarImage } from '@sim/emcn'
23
import type { ResourceCell } from '@/app/workspace/[workspaceId]/components/resource/resource'
34
import type { WorkspaceMember } from '@/hooks/queries/workspace'
45

@@ -13,21 +14,11 @@ export interface OwnerAvatarProps {
1314
* owner/uploaded-by filter options on every list.
1415
*/
1516
export const OwnerAvatar = memo(function OwnerAvatar({ name, image }: OwnerAvatarProps) {
16-
if (image) {
17-
return (
18-
<img
19-
src={image}
20-
alt={name}
21-
referrerPolicy='no-referrer'
22-
className='size-[14px] rounded-full border border-[var(--border)] object-cover'
23-
/>
24-
)
25-
}
26-
2717
return (
28-
<span className='flex size-[14px] items-center justify-center rounded-full border border-[var(--border)] bg-[var(--surface-3)] font-medium text-[8px] text-[var(--text-secondary)]'>
29-
{name.charAt(0).toUpperCase()}
30-
</span>
18+
<Avatar size='xs'>
19+
{image && <AvatarImage src={image} alt={name} referrerPolicy='no-referrer' />}
20+
<AvatarFallback>{name.charAt(0).toUpperCase()}</AvatarFallback>
21+
</Avatar>
3122
)
3223
})
3324

‎apps/sim/app/workspace/[workspaceId]/settings/components/member-list/member-list.tsx‎

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22

33
import type { ReactNode } from 'react'
4-
import { OverflowText } from '@sim/emcn'
4+
import { Avatar, AvatarFallback, AvatarImage, OverflowText } from '@sim/emcn'
55
import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state'
66
import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section'
77

@@ -18,21 +18,11 @@ interface MemberAvatarProps {
1818
* the member's name when no image is available.
1919
*/
2020
export function MemberAvatar({ name, image }: MemberAvatarProps) {
21-
if (image) {
22-
return (
23-
<img
24-
src={image}
25-
alt={name}
26-
referrerPolicy='no-referrer'
27-
className='size-[14px] shrink-0 rounded-full border border-[var(--border)] object-cover'
28-
/>
29-
)
30-
}
31-
3221
return (
33-
<span className='flex size-[14px] shrink-0 items-center justify-center rounded-full border border-[var(--border)] bg-[var(--surface-3)] font-medium text-[8px] text-[var(--text-secondary)]'>
34-
{name.charAt(0).toUpperCase()}
35-
</span>
22+
<Avatar size='xs'>
23+
{image && <AvatarImage src={image} alt={name} referrerPolicy='no-referrer' />}
24+
<AvatarFallback>{name.charAt(0).toUpperCase()}</AvatarFallback>
25+
</Avatar>
3626
)
3727
}
3828

‎packages/emcn/src/components/avatar/avatar.tsx‎

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ const avatarStatusVariants = cva(
5050
}
5151
)
5252

53+
const AvatarSizeContext = React.createContext<VariantProps<typeof avatarVariants>['size']>('md')
54+
5355
type AvatarStatus = 'online' | 'offline' | 'busy' | 'away'
5456

5557
interface AvatarProps
@@ -93,22 +95,24 @@ interface AvatarProps
9395
*/
9496
const Avatar = React.forwardRef<React.ElementRef<typeof AvatarPrimitive.Root>, AvatarProps>(
9597
({ className, size, status, children, ...props }, ref) => (
96-
<div className='relative inline-flex'>
97-
<AvatarPrimitive.Root
98-
ref={ref}
99-
className={cn(avatarVariants({ size }), className)}
100-
{...props}
101-
>
102-
{children}
103-
</AvatarPrimitive.Root>
104-
{status && (
105-
<span
106-
data-slot='avatar-status'
107-
className={cn(avatarStatusVariants({ status, size }))}
108-
aria-label={`Status: ${status}`}
109-
/>
110-
)}
111-
</div>
98+
<AvatarSizeContext.Provider value={size ?? 'md'}>
99+
<div className='relative inline-flex'>
100+
<AvatarPrimitive.Root
101+
ref={ref}
102+
className={cn(avatarVariants({ size }), className)}
103+
{...props}
104+
>
105+
{children}
106+
</AvatarPrimitive.Root>
107+
{status && (
108+
<span
109+
data-slot='avatar-status'
110+
className={cn(avatarStatusVariants({ status, size }))}
111+
aria-label={`Status: ${status}`}
112+
/>
113+
)}
114+
</div>
115+
</AvatarSizeContext.Provider>
112116
)
113117
)
114118
Avatar.displayName = 'Avatar'
@@ -133,6 +137,7 @@ AvatarImage.displayName = 'AvatarImage'
133137

134138
/**
135139
* Fallback component for Avatar. Displays initials or icon when image is unavailable.
140+
* The xs size uses 8px initials; other sizes retain text-xs.
136141
*
137142
* Carries the package's only hardcoded `font-medium`, and deliberately: one or
138143
* two capitals at `text-xs` on a filled disc are a glyph, not running text, and
@@ -142,16 +147,20 @@ AvatarImage.displayName = 'AvatarImage'
142147
const AvatarFallback = React.forwardRef<
143148
React.ElementRef<typeof AvatarPrimitive.Fallback>,
144149
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
145-
>(({ className, ...props }, ref) => (
146-
<AvatarPrimitive.Fallback
147-
ref={ref}
148-
className={cn(
149-
'flex h-full w-full items-center justify-center rounded-full border border-[var(--border-1)] bg-[var(--surface-4)] font-medium text-[var(--text-secondary)] text-xs',
150-
className
151-
)}
152-
{...props}
153-
/>
154-
))
150+
>(({ className, ...props }, ref) => {
151+
const size = React.useContext(AvatarSizeContext)
152+
return (
153+
<AvatarPrimitive.Fallback
154+
ref={ref}
155+
className={cn(
156+
'flex h-full w-full items-center justify-center rounded-full border border-[var(--border-1)] bg-[var(--surface-4)] font-medium text-[var(--text-secondary)] text-xs',
157+
size === 'xs' && 'text-[8px]',
158+
className
159+
)}
160+
{...props}
161+
/>
162+
)
163+
})
155164
AvatarFallback.displayName = 'AvatarFallback'
156165

157166
export { Avatar, AvatarImage, AvatarFallback, avatarVariants, avatarStatusVariants }

0 commit comments

Comments
 (0)