Skip to content

Commit 7800fb3

Browse files
committed
fix(settings): use one member avatar with profile photos everywhere
1 parent b4b2625 commit 7800fb3

25 files changed

Lines changed: 140 additions & 133 deletions

File tree

‎.claude/rules/sim-settings-pages.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,11 @@ and — on activatable rows only — the hover band. Never hand-roll any of it,
251251
`RESOURCE_TILE_FILL` for a glyph, `RESOURCE_TILE_PLAIN` for a brand logo or favicon.
252252

253253

254-
**Member avatars are deliberately two components, not one.** `member-list.tsx`
255-
renders a 14px neutral marker for the dense Teammates/Organization roster, where
256-
the email is the primary content; `components/permissions/member-row.tsx` renders
257-
a 36px `getUserColor`-hashed avatar for member *management* rows that carry a name,
258-
an email, and a role control. Same shape, different job — do not merge them.
254+
**One member avatar.** Every member list, owner cell, and ranking renders
255+
`MemberAvatar` from `components/member-avatar/member-avatar` — a 14px photo, or the
256+
initial on the neutral disc. Never hand-roll an avatar or give a person a
257+
`getUserColor` hash; per-person colors belong to live collaboration (presence,
258+
cursors), where the color matches that person's cursor.
259259

260260
## Header action order
261261

‎.cursor/rules/sim-settings-pages.mdc‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,11 @@ and — on activatable rows only — the hover band. Never hand-roll any of it,
248248
`RESOURCE_TILE_FILL` for a glyph, `RESOURCE_TILE_PLAIN` for a brand logo or favicon.
249249

250250

251-
**Member avatars are deliberately two components, not one.** `member-list.tsx`
252-
renders a 14px neutral marker for the dense Teammates/Organization roster, where
253-
the email is the primary content; `components/permissions/member-row.tsx` renders
254-
a 36px `getUserColor`-hashed avatar for member *management* rows that carry a name,
255-
an email, and a role control. Same shape, different job — do not merge them.
251+
**One member avatar.** Every member list, owner cell, and ranking renders
252+
`MemberAvatar` from `components/member-avatar/member-avatar` — a 14px photo, or the
253+
initial on the neutral disc. Never hand-roll an avatar or give a person a
254+
`getUserColor` hash; per-person colors belong to live collaboration (presence,
255+
cursors), where the color matches that person's cursor.
256256

257257
## Header action order
258258

‎apps/sim/app/workspace/[workspaceId]/components/credential-detail/components/credential-members-section.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export function CredentialMembersSection({ credentialId, isAdmin }: CredentialMe
6767
return (
6868
<MemberRow
6969
key={member.id}
70-
member={member}
70+
member={{ ...member, userImage: member.userImage ?? null }}
7171
roleOptions={MEMBER_ROLE_OPTIONS}
7272
lockReason={lockReason}
7373
canManage={isAdmin}

‎apps/sim/app/workspace/[workspaceId]/components/index.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ export { MessageActions } from './message-actions'
1515
export type { BulkOutcome } from './resource/bulk-outcome'
1616
export { reportBulkOutcome } from './resource/bulk-outcome'
1717
export { FloatingOverflowText } from './resource/components/floating-overflow-text'
18-
export type { OwnerAvatarProps } from './resource/components/owner-cell'
19-
export { OwnerAvatar, ownerCell } from './resource/components/owner-cell'
18+
export { ownerCell } from './resource/components/owner-cell'
2019
export {
2120
type ChromeActionSpec,
2221
ResourceChromeFallback,
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
export type { OwnerAvatarProps } from './owner-cell'
2-
export { OwnerAvatar, ownerCell } from './owner-cell'
1+
export { ownerCell } from './owner-cell'
Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,7 @@
1-
import { memo } from 'react'
1+
import { MemberAvatar } from '@/components/member-avatar/member-avatar'
22
import type { ResourceCell } from '@/app/workspace/[workspaceId]/components/resource/resource'
33
import type { WorkspaceMember } from '@/hooks/queries/workspace'
44

5-
export interface OwnerAvatarProps {
6-
name: string
7-
image: string | null
8-
}
9-
10-
/**
11-
* The canonical 14px workspace-member avatar — a photo, or the member's initial on a neutral
12-
* disc. Shared so a member reads identically in a resource row's owner cell and in the
13-
* owner/uploaded-by filter options on every list.
14-
*/
15-
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-
27-
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>
31-
)
32-
})
33-
345
/**
356
* Resolves a user ID into a ResourceCell with an avatar icon and display name.
367
* Returns null label while members are still loading to avoid flashing raw IDs.
@@ -51,7 +22,7 @@ export function ownerCell(
5122
if (!member) return { label: null }
5223

5324
return {
54-
icon: <OwnerAvatar name={member.name} image={member.image} />,
25+
icon: <MemberAvatar name={member.name} image={member.image} />,
5526
label: member.name,
5627
}
5728
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ const Pagination = memo(function Pagination({
562562
})
563563

564564
interface CellContentProps {
565-
/** Pre-rendered icon node (svg/img/span avatar); auto-sized to the chip icon size. */
565+
/** Pre-rendered icon node (a glyph or a `MemberAvatar`); auto-sized to the chip icon size. */
566566
icon?: ReactNode
567567
label: string
568568
content?: ReactNode

‎apps/sim/app/workspace/[workspaceId]/files/files.tsx‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { useParams, useRouter } from 'next/navigation'
2525
import { useQueryStates } from 'nuqs'
2626
import { usePostHog } from 'posthog-js/react'
2727
import { getDocumentIcon } from '@/components/icons/document-icons'
28+
import { MemberAvatar } from '@/components/member-avatar/member-avatar'
2829
import { useLimitUpgradeToast } from '@/lib/billing/client'
2930
import { captureEvent } from '@/lib/posthog/client'
3031
import {
@@ -79,10 +80,7 @@ import {
7980
useFolderRowDragDrop,
8081
} from '@/app/workspace/[workspaceId]/components/folders'
8182
import { ResourceActionBar } from '@/app/workspace/[workspaceId]/components/resource/components/action-bar'
82-
import {
83-
OwnerAvatar,
84-
ownerCell,
85-
} from '@/app/workspace/[workspaceId]/components/resource/components/owner-cell'
83+
import { ownerCell } from '@/app/workspace/[workspaceId]/components/resource/components/owner-cell'
8684
import {
8785
FilesEmptyState,
8886
ResourceNoResults,
@@ -1938,7 +1936,7 @@ function FilesContent() {
19381936
(members ?? []).map((m) => ({
19391937
value: m.userId,
19401938
label: m.name,
1941-
iconElement: <OwnerAvatar name={m.name} image={m.image} />,
1939+
iconElement: <MemberAvatar name={m.name} image={m.image} />,
19421940
})),
19431941
[members]
19441942
)

‎apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { createLogger } from '@sim/logger'
88
import { getErrorMessage } from '@sim/utils/errors'
99
import { useParams, useRouter } from 'next/navigation'
1010
import { useQueryStates } from 'nuqs'
11+
import { MemberAvatar } from '@/components/member-avatar/member-avatar'
1112
import { MAX_KNOWLEDGE_BATCH_ITEMS } from '@/lib/knowledge/constants'
1213
import type { KnowledgeBaseData } from '@/lib/knowledge/types'
1314
import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state'
@@ -39,10 +40,7 @@ import {
3940
} from '@/app/workspace/[workspaceId]/components/folders'
4041
import { reportBulkOutcome } from '@/app/workspace/[workspaceId]/components/resource/bulk-outcome'
4142
import { ResourceActionBar } from '@/app/workspace/[workspaceId]/components/resource/components/action-bar'
42-
import {
43-
OwnerAvatar,
44-
ownerCell,
45-
} from '@/app/workspace/[workspaceId]/components/resource/components/owner-cell'
43+
import { ownerCell } from '@/app/workspace/[workspaceId]/components/resource/components/owner-cell'
4644
import {
4745
KnowledgeEmptyState,
4846
ResourceNoResults,
@@ -1331,7 +1329,7 @@ function KnowledgeContent() {
13311329
(members ?? []).map((m) => ({
13321330
value: m.userId,
13331331
label: m.name,
1334-
iconElement: <OwnerAvatar name={m.name} image={m.image} />,
1332+
iconElement: <MemberAvatar name={m.name} image={m.image} />,
13351333
})),
13361334
[members]
13371335
)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { MemberAvatar, MemberRow, MemberSection } from './member-list'
1+
export { MemberRow, MemberSection } from './member-list'

0 commit comments

Comments
 (0)