Skip to content

Commit 7fd9eba

Browse files
committed
revert(settings): keep the dense member roster avatar
Consolidating the Teammates/Organization avatar onto the credential member row's was a redesign, not a deduplication. The two encode different things: the roster is a dense list keyed on email where the avatar is a 14px neutral marker, while a member management row carries a name, an email, and a role control and earns a 36px hashed avatar. Merging them made those rows ~70% taller, gave every workspace in a permission group a colour-hashed "avatar" seeded on its name, and cut the Add Members picker from ~7 visible rows to ~5 inside its fixed-height box. Restores both avatars and the containers that owned their bleed, and records in the rule why they stay separate. Keeps only the unrelated fix in that area: the picker row was the one settings row rounded at `sm`.
1 parent f381712 commit 7fd9eba

6 files changed

Lines changed: 61 additions & 59 deletions

File tree

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,13 @@ navigation chevron. Never hand-roll any of it, and never wrap the row in your ow
233233
(`app/workspace/[workspaceId]/components/resource-tile` — note: *not* under
234234
`settings/`, unlike the other `…/` paths on this page) — the 36px tile chrome, for the rare tile
235235
outside a row (a detail heading). `ResourceTile` wraps the filled pairing.
236-
- **`MemberAvatar`** (`@/components/permissions/member-avatar`) — the one avatar
237-
for any member row.
236+
237+
238+
**Member avatars are deliberately two components, not one.** `member-list.tsx`
239+
renders a 14px neutral marker for the dense Teammates/Organization roster, where
240+
the email is the primary content; `components/permissions/member-row.tsx` renders
241+
a 36px `getUserColor`-hashed avatar for member *management* rows that carry a name,
242+
an email, and a role control. Same shape, different job — do not merge them.
238243

239244
## Deleting a resource
240245

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
export { MemberAvatar } from '@/components/permissions/member-avatar'
2-
export { MemberRow, MemberSection } from './member-list'
1+
export { MemberAvatar, MemberRow, MemberSection } from './member-list'

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

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

33
import type { ReactNode } from 'react'
4-
import { MemberAvatar } from '@/components/permissions/member-avatar'
54
import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state'
6-
import { RESOURCE_LIST_STACK } from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row'
75
import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section'
86

9-
const ROW_CLASSES = '-mx-2 flex items-center gap-2.5 rounded-lg p-2'
7+
const ROW_CLASSES = 'flex items-center gap-2.5 p-2'
108
const ROW_EMAIL_CLASSES = 'min-w-0 flex-1 truncate text-[var(--text-body)] text-sm'
119
const ROW_STATUS_CLASSES = 'flex-shrink-0 text-[var(--text-muted)] text-caption'
1210

11+
interface MemberAvatarProps {
12+
name: string
13+
image: string | null
14+
}
15+
16+
/**
17+
* 14px circular avatar used in member rows. Falls back to the first letter of
18+
* the member's name when no image is available.
19+
*/
20+
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] flex-shrink-0 rounded-full border border-[var(--border)] object-cover'
28+
/>
29+
)
30+
}
31+
32+
return (
33+
<span className='flex size-[14px] flex-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>
36+
)
37+
}
38+
1339
interface MemberRowProps {
1440
name: string
1541
email: string
@@ -30,7 +56,7 @@ interface MemberRowProps {
3056
export function MemberRow({ name, email, image, status, roleControl, menu }: MemberRowProps) {
3157
return (
3258
<div className={ROW_CLASSES}>
33-
<MemberAvatar name={name} image={image} colorSeed={email || name} />
59+
<MemberAvatar name={name} image={image} />
3460
<span className={ROW_EMAIL_CLASSES}>{email}</span>
3561
<span className={ROW_STATUS_CLASSES}>{status}</span>
3662
{roleControl}
@@ -65,7 +91,7 @@ export function MemberSection({
6591
{isEmpty ? (
6692
<SettingsEmptyState variant='inline'>{emptyText}</SettingsEmptyState>
6793
) : (
68-
<div className={RESOURCE_LIST_STACK}>{children}</div>
94+
<div className='-mx-2 flex flex-col gap-y-0.5'>{children}</div>
6995
)}
7096
</SettingsSection>
7197
)

apps/sim/components/permissions/member-avatar.tsx

Lines changed: 0 additions & 29 deletions
This file was deleted.

apps/sim/components/permissions/member-row.tsx

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

3-
import { Chip, ChipDropdown, cn } from '@sim/emcn'
4-
import { MemberAvatar } from '@/components/permissions/member-avatar'
3+
import { Avatar, AvatarFallback, Chip, ChipDropdown, cn } from '@sim/emcn'
4+
import { getUserColor } from '@/lib/workspaces/colors'
55
import type { MemberRole } from './member-role-options'
66
import { RoleLockTooltip } from './role-lock'
77

@@ -49,16 +49,20 @@ export function MemberRow<TRole extends string = MemberRole>({
4949
return (
5050
<div
5151
className={cn(
52-
'-mx-2 grid items-center gap-2 rounded-lg p-2',
52+
'grid items-center gap-2',
5353
canManage ? 'grid-cols-[1fr_120px_72px]' : 'grid-cols-[1fr_200px]'
5454
)}
5555
>
5656
<div className='flex min-w-0 items-center gap-2.5'>
57-
<MemberAvatar
58-
name={member.userName || member.userEmail || '?'}
59-
colorSeed={member.userId || member.userEmail || ''}
60-
/>
61-
<div className='flex min-w-0 flex-col justify-center gap-[1px]'>
57+
<Avatar className='size-9 flex-shrink-0'>
58+
<AvatarFallback
59+
style={{ background: getUserColor(member.userId || member.userEmail || '') }}
60+
className='border border-[var(--border-1)] text-small text-white'
61+
>
62+
{(member.userName || member.userEmail || '?').charAt(0).toUpperCase()}
63+
</AvatarFallback>
64+
</Avatar>
65+
<div className='flex min-w-0 flex-col'>
6266
<span className='truncate text-[var(--text-body)] text-sm'>
6367
{member.userName || member.userEmail || member.userId}
6468
</span>

apps/sim/ee/access-control/components/group-detail.tsx

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import { getErrorMessage } from '@sim/utils/errors'
2828
import { formatDate } from '@sim/utils/formatting'
2929
import { ChevronDown, Plus } from 'lucide-react'
3030
import { useQueryState } from 'nuqs'
31-
import { MemberAvatar } from '@/components/permissions/member-avatar'
3231
import { saveDiscardActions } from '@/components/settings/save-discard-actions'
3332
import type { ShareAuthType } from '@/lib/api/contracts/public-shares'
3433
import { isBlockTypeAccessControlExempt } from '@/lib/permission-groups/block-access'
@@ -42,11 +41,13 @@ import {
4241
groupTabParam,
4342
groupTabUrlKeys,
4443
} from '@/app/workspace/[workspaceId]/settings/[section]/search-params'
45-
import { MemberRow } from '@/app/workspace/[workspaceId]/settings/components/member-list'
44+
import {
45+
MemberAvatar,
46+
MemberRow,
47+
} from '@/app/workspace/[workspaceId]/settings/components/member-list'
4648
import { RowActionsMenu } from '@/app/workspace/[workspaceId]/settings/components/row-actions-menu'
4749
import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state'
4850
import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel'
49-
import { RESOURCE_LIST_STACK } from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row'
5051
import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section'
5152
import { useSettingsUnsavedGuard } from '@/app/workspace/[workspaceId]/settings/hooks/use-settings-unsaved-guard'
5253
import { getAllBlocks } from '@/blocks'
@@ -453,11 +454,7 @@ function AddMembersModal({
453454
className='flex items-center gap-2.5 rounded-lg p-2 text-left transition-colors hover-hover:bg-[var(--surface-active)]'
454455
>
455456
<Checkbox checked={isSelected} />
456-
<MemberAvatar
457-
name={name}
458-
image={member.user?.image ?? null}
459-
colorSeed={member.userId || email}
460-
/>
457+
<MemberAvatar name={name} image={member.user?.image ?? null} />
461458
<div className='min-w-0 flex-1'>
462459
<div className='truncate text-[var(--text-body)] text-sm'>{name}</div>
463460
<div className='truncate text-[var(--text-muted)] text-caption'>
@@ -1622,7 +1619,7 @@ export function GroupDetail({
16221619
/>
16231620
</div>
16241621
{viewingGroup.workspaces.length > 0 && (
1625-
<div className={RESOURCE_LIST_STACK}>
1622+
<div className='-mx-2 flex flex-col gap-y-0.5'>
16261623
{viewingGroup.workspaces.map((ws) => (
16271624
<MemberRow
16281625
key={ws.id}
@@ -1657,17 +1654,17 @@ export function GroupDetail({
16571654
</Chip>
16581655
</div>
16591656
{membersLoading ? (
1660-
<div className={RESOURCE_LIST_STACK}>
1657+
<div className='-mx-2 flex flex-col gap-y-0.5'>
16611658
{[1, 2].map((i) => (
1662-
<div key={i} className='-mx-2 flex items-center gap-2.5 rounded-lg p-2'>
1663-
<Skeleton className='size-9 flex-shrink-0 rounded-full' />
1659+
<div key={i} className='flex items-center gap-2.5 p-2'>
1660+
<Skeleton className='size-[14px] flex-shrink-0 rounded-full' />
16641661
<Skeleton className='h-[14px] w-[180px]' />
16651662
</div>
16661663
))}
16671664
</div>
16681665
) : (
16691666
members.length > 0 && (
1670-
<div className={RESOURCE_LIST_STACK}>
1667+
<div className='-mx-2 flex flex-col gap-y-0.5'>
16711668
{members.map((member) => (
16721669
<MemberRow
16731670
key={member.id}

0 commit comments

Comments
 (0)