feat: add avatar border color customization and improve text contrast across user profile components

This commit is contained in:
2026-03-12 23:08:05 +11:00
parent 67f3ae4d34
commit 37f4297972
8 changed files with 127 additions and 48 deletions

View File

@@ -37,7 +37,7 @@ import { getMxIdLocalPart, mxcUrlToHttp } from '../../../utils/matrix';
import { UserAvatar } from '../../../components/user-avatar';
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
import { useAuthenticatedMediaUrl } from '../../../hooks/useAuthenticatedMediaUrl';
import { nameInitials, getContrastingTextColor } from '../../../utils/common';
import { nameInitials, getContrastingTextColor, stripAlphaFromColor, getTextShadowColor } from '../../../utils/common';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { useFilePicker } from '../../../hooks/useFilePicker';
import { useObjectURL } from '../../../hooks/useObjectURL';
@@ -563,6 +563,11 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
? rgbaToHex(localBorderColor)
: profileStyle.avatarBorderColor;
const previewPillBgColor = previewBorderColor ? stripAlphaFromColor(previewBorderColor) : undefined;
const previewProfileColor = previewBorderColor ? stripAlphaFromColor(previewBorderColor) : (userColor || colorMXID(userId));
const previewTextShadow = `0 1px 4px ${getTextShadowColor(previewProfileColor)}`;
return (
<Box direction="Column" gap="300">
<Box
@@ -710,7 +715,7 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
as="button"
onClick={handleAvatarClick}
style={{
backgroundColor: color.Surface.Container,
backgroundColor: previewBorderColor || color.Surface.Container,
border: 'none',
padding: 0,
cursor: 'pointer',
@@ -718,6 +723,7 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
}}
>
<AvatarPresence
badgeBackgroundColor={previewBorderColor}
badge={
presence && (
<PresenceBadge presence={presence.presence} status={presence.status} />
@@ -727,6 +733,8 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
<Avatar
size="500"
style={{
width: toRem(72),
height: toRem(72),
outline: previewBorderColor
? `${toRem(4)} solid ${previewBorderColor}`
: `${config.borderWidth.B600} solid ${color.Surface.Container}`,
@@ -905,7 +913,7 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
size="H4"
className={classNames(BreakWord, LineClamp3)}
title={profile.displayName || getMxIdLocalPart(userId)}
style={{ color: userColor || colorMXID(userId) }}
style={{ color: previewProfileColor, textShadow: previewTextShadow }}
>
{profile.displayName || getMxIdLocalPart(userId) || userId}
</Text>
@@ -937,7 +945,7 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
size="T200"
className={BreakWord}
title={userId}
style={{ color: userColor || colorMXID(userId), opacity: 0.8 }}
style={{ color: previewProfileColor, textShadow: previewTextShadow }}
>
{userId}
</Text>
@@ -947,8 +955,8 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
onMouseEnter={() => setHoveredArea('status')}
onMouseLeave={() => setHoveredArea(null)}
style={{
backgroundColor: previewBorderColor || color.Surface.Container,
border: previewBorderColor ? 'none' : `${toRem(1)} solid ${color.Surface.ContainerLine}`,
backgroundColor: previewPillBgColor || color.Surface.Container,
border: previewPillBgColor ? 'none' : `${toRem(1)} solid ${color.Surface.ContainerLine}`,
padding: `${toRem(6)} ${toRem(10)}`,
borderRadius: toRem(16),
maxWidth: toRem(250),
@@ -998,16 +1006,15 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
size="T300"
className={BreakWord}
style={{
opacity: presence?.status ? 1 : 0.5,
fontStyle: presence?.status ? 'normal' : 'italic',
color: previewBorderColor ? getContrastingTextColor(previewBorderColor) : undefined,
color: previewPillBgColor ? getContrastingTextColor(previewPillBgColor) : undefined,
}}
>
{presence?.status || 'Click to set a custom status...'}</Text>
</Box>
{presence?.status && hoveredArea === 'status' && (
<>
<Icon size="50" src={Icons.Pencil} style={{ color: previewBorderColor ? getContrastingTextColor(previewBorderColor) : undefined }} />
<Icon size="50" src={Icons.Pencil} style={{ color: previewPillBgColor ? getContrastingTextColor(previewPillBgColor) : undefined }} />
<Box
as="button"
onClick={(e) => {
@@ -1038,8 +1045,8 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
<Box alignItems="Center" gap="200" wrap="Wrap" justifyContent="Center">
<Box
style={{
backgroundColor: previewBorderColor || color.Surface.Container,
border: previewBorderColor ? 'none' : `${toRem(1)} solid ${color.Surface.ContainerLine}`,
backgroundColor: previewPillBgColor || color.Surface.Container,
border: previewPillBgColor ? 'none' : `${toRem(1)} solid ${color.Surface.ContainerLine}`,
padding: `${toRem(4)} ${toRem(8)}`,
borderRadius: toRem(16),
}}
@@ -1047,7 +1054,7 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
<Text
size="B300"
style={{
color: previewBorderColor ? getContrastingTextColor(previewBorderColor) : undefined,
color: previewPillBgColor ? getContrastingTextColor(previewPillBgColor) : undefined,
}}
>
ruv.wtf
@@ -1055,8 +1062,8 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
</Box>
<Box
style={{
backgroundColor: previewBorderColor || color.Surface.Container,
border: previewBorderColor ? 'none' : `${toRem(1)} solid ${color.Surface.ContainerLine}`,
backgroundColor: previewPillBgColor || color.Surface.Container,
border: previewPillBgColor ? 'none' : `${toRem(1)} solid ${color.Surface.ContainerLine}`,
padding: `${toRem(4)} ${toRem(8)}`,
borderRadius: toRem(16),
}}
@@ -1064,7 +1071,7 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
<Text
size="B300"
style={{
color: previewBorderColor ? getContrastingTextColor(previewBorderColor) : undefined,
color: previewPillBgColor ? getContrastingTextColor(previewPillBgColor) : undefined,
}}
>
Share
@@ -1072,8 +1079,8 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
</Box>
<Box
style={{
backgroundColor: previewBorderColor || color.Surface.Container,
border: previewBorderColor ? 'none' : `${toRem(1)} solid ${color.Surface.ContainerLine}`,
backgroundColor: previewPillBgColor || color.Surface.Container,
border: previewPillBgColor ? 'none' : `${toRem(1)} solid ${color.Surface.ContainerLine}`,
padding: `${toRem(4)} ${toRem(8)}`,
borderRadius: toRem(16),
}}
@@ -1081,7 +1088,7 @@ function ProfileBanner({ avatarRef, nameRef }: { avatarRef: React.RefObject<HTML
<Text
size="B300"
style={{
color: previewBorderColor ? getContrastingTextColor(previewBorderColor) : undefined,
color: previewPillBgColor ? getContrastingTextColor(previewPillBgColor) : undefined,
}}
>
Admin