Skip to content

Commit c15a272

Browse files
Avatar badges & adjustments
1 parent 452917b commit c15a272

6 files changed

Lines changed: 158 additions & 73 deletions

File tree

src/components/Avatar/Avatar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export type AvatarProps = {
1515
/** Online status indicator, not rendered if not of type boolean */
1616
isOnline?: boolean;
1717

18-
size: 'xl' | 'lg' | 'md' | 'sm' | 'xs' | null;
18+
size: '2xl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs' | null;
1919
} & ComponentPropsWithoutRef<'div'>;
2020

2121
const getInitials = (name?: string) => {

src/components/Avatar/AvatarStack.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import { type AvatarProps, Avatar as DefaultAvatar } from './Avatar';
44
import clsx from 'clsx';
55

66
export function AvatarStack({
7-
badgeCount,
87
component: Component = 'div',
98
displayInfo = [],
9+
overflowCount,
1010
size,
1111
}: {
1212
component?: ElementType;
1313
displayInfo?: (Pick<AvatarProps, 'imageUrl' | 'userName'> & { id?: string })[];
14-
badgeCount?: number;
14+
overflowCount?: number;
1515
size: 'sm' | 'xs' | null;
1616
}) {
1717
const { Avatar = DefaultAvatar } = useComponentContext(AvatarStack.name);
@@ -34,8 +34,8 @@ export function AvatarStack({
3434
userName={info.userName}
3535
/>
3636
))}
37-
{typeof badgeCount === 'number' && (
38-
<div className='str-chat__avatar-stack-badge-count'>{badgeCount}</div>
37+
{typeof overflowCount === 'number' && overflowCount > 0 && (
38+
<div className='str-chat__avatar-stack__count-badge'>{overflowCount}</div>
3939
)}
4040
</Component>
4141
);

src/components/Avatar/GroupAvatar.tsx

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import type { GroupChannelDisplayInfo } from '../ChannelPreview';
66
export type GroupAvatarProps = ComponentPropsWithoutRef<'div'> & {
77
/** Mapping of image URLs to names which initials will be used as fallbacks in case image assets fail to load. */
88
groupChannelDisplayInfo: GroupChannelDisplayInfo;
9-
size: 'xl' | 'lg' | null;
9+
size: '2xl' | 'xl' | 'lg' | null;
1010
isOnline?: boolean;
11+
overflowCount?: number;
1112
};
1213

1314
/**
@@ -19,9 +20,12 @@ export const GroupAvatar = ({
1920
className,
2021
groupChannelDisplayInfo,
2122
isOnline,
23+
overflowCount,
2224
size,
2325
...rest
2426
}: GroupAvatarProps) => {
27+
const displayCountBadge = typeof overflowCount === 'number' && overflowCount > 0;
28+
2529
if (!groupChannelDisplayInfo || groupChannelDisplayInfo.length < 2) {
2630
const [firstUser] = groupChannelDisplayInfo || [];
2731

@@ -37,9 +41,10 @@ export const GroupAvatar = ({
3741
}
3842

3943
let avatarSize: AvatarProps['size'] = null;
40-
41-
if (size === 'xl') {
44+
if (size === '2xl') {
4245
avatarSize = 'lg';
46+
} else if (size === 'xl') {
47+
avatarSize = 'md';
4348
} else if (size === 'lg') {
4449
avatarSize = 'sm';
4550
}
@@ -59,14 +64,19 @@ export const GroupAvatar = ({
5964
role='button'
6065
{...rest}
6166
>
62-
{groupChannelDisplayInfo.slice(0, 4).map(({ imageUrl, userName }, index) => (
63-
<Avatar
64-
imageUrl={imageUrl}
65-
key={`${userName}-${imageUrl}-${index}`}
66-
size={avatarSize}
67-
userName={userName}
68-
/>
69-
))}
67+
{groupChannelDisplayInfo
68+
.slice(0, displayCountBadge ? 2 : 4)
69+
.map(({ imageUrl, userName }, index) => (
70+
<Avatar
71+
imageUrl={imageUrl}
72+
key={`${userName}-${imageUrl}-${index}`}
73+
size={avatarSize}
74+
userName={userName}
75+
/>
76+
))}
77+
{displayCountBadge && (
78+
<div className='str-chat__avatar-group__count-badge'>+{overflowCount}</div>
79+
)}
7080
</div>
7181
);
7282
};

src/components/Avatar/styling/Avatar.scss

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@
44
display: flex;
55
justify-content: center;
66
align-items: center;
7-
border-radius: var(--radius-max, 9999px);
8-
background: var(--avatar-bg-default, #e3edff);
9-
color: var(--avatar-text-default, #142f63);
7+
border-radius: var(--radius-max);
8+
background: var(--avatar-bg-default);
9+
color: var(--avatar-text-default);
1010
text-align: center;
1111

1212
font-weight: var(--typography-font-weight-semi-bold);
13+
font-style: normal;
1314
line-height: 1;
1415
text-transform: uppercase;
1516
width: var(--avatar-size);
1617
height: var(--avatar-size);
17-
--avatar-badge-angle: -45deg;
18+
--avatar-online-badge-angle: -45deg;
1819

1920
// FIXME: temporary thing, should be removed when we get rid of the old CSS
2021
grid-area: avatar;
@@ -47,65 +48,74 @@
4748
aspect-ratio: 1/1;
4849
content: '';
4950
position: absolute;
50-
width: var(--avatar-badge-size);
51+
width: var(--avatar-online-badge-size);
5152

5253
left: calc(
5354
var(--avatar-size) / 2 + var(--avatar-size) / 2 *
54-
cos(var(--avatar-badge-angle)) - var(--avatar-badge-size) / 2
55+
cos(var(--avatar-online-badge-angle)) - var(--avatar-online-badge-size) / 2
5556
);
5657
top: calc(
5758
var(--avatar-size) / 2 + var(--avatar-size) / 2 *
58-
sin(var(--avatar-badge-angle)) - var(--avatar-badge-size) / 2
59+
sin(var(--avatar-online-badge-angle)) - var(--avatar-online-badge-size) / 2
5960
);
6061

6162
border-radius: var(--radius-max, 9999px);
6263
border-style: solid;
63-
border-color: var(--presence-border, #fff);
64+
border-color: var(--presence-border);
6465
border-width: 2px;
6566
}
6667

6768
&.str-chat__avatar--online::after {
68-
background: var(--presence-bg-online, #00c384);
69+
background: var(--presence-bg-online);
6970
}
7071

7172
&.str-chat__avatar--offline::after {
72-
background: var(--presence-bg-offline, #687385);
73+
background: var(--presence-bg-offline);
7374
}
7475

75-
&.str-chat__avatar--size-xl {
76+
&.str-chat__avatar--size-2xl {
7677
--avatar-size: 64px;
77-
--avatar-badge-size: 16px;
78-
--avatar-icon-size: 32px;
78+
--avatar-online-badge-size: 16px;
79+
--avatar-icon-size: var(--icon-size-lg);
80+
--avatar-icon-stroke-width: 1.5px;
81+
82+
font-size: var(--typography-font-size-xl);
83+
}
84+
85+
&.str-chat__avatar--size-xl {
86+
--avatar-size: 48px;
87+
--avatar-online-badge-size: 16px;
88+
--avatar-icon-size: var(--size-24); // TODO: missing icon size
7989
--avatar-icon-stroke-width: 1.5px;
8090

81-
font-size: var(--typography-font-size-xl, 20px);
91+
font-size: var(--typography-font-size-xl);
8292
}
8393

8494
&.str-chat__avatar--size-lg {
8595
--avatar-size: 40px;
86-
--avatar-badge-size: 14px;
87-
--avatar-icon-size: 20px;
96+
--avatar-online-badge-size: 14px;
97+
--avatar-icon-size: var(--icon-size-md);
8898
--avatar-icon-stroke-width: 1.5px;
8999

90-
font-size: var(--typography-font-size-md, 15px);
100+
font-size: var(--typography-font-size-md);
91101
}
92102

93-
&.str-chat__avatar--size-md {
103+
&.str-chat__avatar--size-md {
94104
--avatar-size: 32px;
95-
--avatar-badge-size: 12px;
96-
--avatar-icon-size: 16px;
105+
--avatar-online-badge-size: 12px;
106+
--avatar-icon-size: var(--icon-size-md);
97107
--avatar-icon-stroke-width: 1.5px;
98108

99-
font-size: var(--typography-font-size-sm, 13px);
109+
font-size: var(--typography-font-size-sm);
100110
}
101111

102112
&.str-chat__avatar--size-sm {
103113
--avatar-size: 24px;
104-
--avatar-badge-size: 8px;
105-
--avatar-icon-size: 12px;
114+
--avatar-online-badge-size: 8px;
115+
--avatar-icon-size: var(--icon-size-sm);
106116
--avatar-icon-stroke-width: 1.2px;
107117

108-
font-size: var(--typography-font-size-sm, 13px);
118+
font-size: var(--typography-font-size-sm);
109119

110120
&.str-chat__avatar--offline::after,
111121
&.str-chat__avatar--online::after {
@@ -115,11 +125,11 @@
115125

116126
&.str-chat__avatar--size-xs {
117127
--avatar-size: 20px;
118-
--avatar-badge-size: 8px;
128+
--avatar-online-badge-size: 8px;
119129
--avatar-icon-size: 10px;
120130
--avatar-icon-stroke-width: 1.2px;
121131

122-
font-size: var(--typography-font-size-xs, 12px);
132+
font-size: var(--typography-font-size-xs);
123133

124134
&.str-chat__avatar--offline::after,
125135
&.str-chat__avatar--online::after {

src/components/Avatar/styling/AvatarStack.scss

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
align-items: center;
44

55
& > .str-chat__avatar:not(:first-child),
6-
.str-chat__avatar-stack-badge-count {
6+
.str-chat__avatar-stack__count-badge {
77
margin-left: calc(var(--spacing-xs) * -1);
88
}
99

@@ -16,25 +16,34 @@
1616
border-radius: inherit;
1717
}
1818

19-
&.str-chat__avatar-stack--size-xs {
20-
--avatar-stack-badge-count-size: 20px;
21-
--avatar-stack-badge-count-font-size: var(--typography-font-size-xxs);
22-
}
23-
2419
&.str-chat__avatar-stack--size-sm {
25-
--avatar-stack-badge-count-size: 24px;
20+
--avatar-stack-count-badge-size: 24px;
2621
// FIXME?: should be sm but it looks way too big
27-
--avatar-stack-badge-count-font-size: var(--typography-font-size-xs);
22+
--avatar-stack-count-badge-font-size: var(--typography-font-size-xs);
23+
24+
.str-chat__avatar-stack__count-badge {
25+
padding-inline: var(--spacing-xs);
26+
}
27+
}
28+
29+
&.str-chat__avatar-stack--size-xs {
30+
--avatar-stack-count-badge-size: 20px;
31+
--avatar-stack-count-badge-font-size: var(--typography-font-size-xxs);
32+
33+
.str-chat__avatar-stack__count-badge {
34+
padding-inline: var(--spacing-xxs);
35+
}
2836
}
2937

30-
.str-chat__avatar-stack-badge-count {
31-
font-size: var(--avatar-stack-badge-count-font-size);
38+
.str-chat__avatar-stack__count-badge {
39+
font-size: var(--avatar-stack-count-badge-font-size);
3240
font-weight: var(--typography-font-weight-bold);
3341
display: flex;
3442
justify-content: center;
3543
align-items: center;
36-
height: var(--avatar-stack-badge-count-size);
37-
width: var(--avatar-stack-badge-count-size);
44+
height: var(--avatar-stack-count-badge-size);
45+
min-width: var(--avatar-stack-count-badge-size);
46+
min-height: var(--avatar-stack-count-badge-size);
3847
border-radius: var(--radius-max);
3948
border: 1px solid var(--border-core-subtle);
4049
background: var(--badge-bg-default);

0 commit comments

Comments
 (0)