|
1 | 1 | import { useMemo, useState, useCallback } from 'react'; |
2 | 2 | import { useNavigate } from 'react-router-dom'; |
3 | | -import { Avatar, Text, Box } from 'folds'; |
| 3 | +import { Avatar, Text, Box, toRem } from 'folds'; |
4 | 4 | import { useAtomValue } from 'jotai'; |
5 | 5 | import { Room, SyncState } from '$types/matrix-sdk'; |
6 | 6 | import { useDirects } from '$state/hooks/roomList'; |
@@ -56,62 +56,105 @@ function DMItem({ room, selected }: DMItemProps) { |
56 | 56 | // Get unread info for badge |
57 | 57 | const unread = roomToUnread.get(room.roomId); |
58 | 58 |
|
59 | | - return ( |
60 | | - <SidebarItem active={selected}> |
61 | | - <SidebarItemTooltip tooltip={room.name}> |
62 | | - {(triggerRef) => ( |
63 | | - <SidebarAvatar as="button" ref={triggerRef} outlined onClick={handleClick} size="400"> |
64 | | - {isGroupDM ? ( |
65 | | - <Box className={css.GroupAvatarContainer}> |
66 | | - <Box className={css.GroupAvatarRow}> |
67 | | - {groupMembers.map((member) => { |
68 | | - const avatarUrl = member.avatarUrl |
69 | | - ? (mxcUrlToHttp(mx, member.avatarUrl, useAuthentication, 48, 48, 'crop') ?? |
70 | | - undefined) |
71 | | - : undefined; |
72 | | - |
73 | | - return ( |
74 | | - <Avatar |
75 | | - key={member.userId} |
76 | | - size="200" |
77 | | - radii="300" |
78 | | - className={css.GroupAvatar} |
79 | | - > |
80 | | - <UserAvatar |
81 | | - userId={member.userId} |
82 | | - src={avatarUrl} |
83 | | - alt={member.displayName || member.userId} |
84 | | - renderFallback={() => ( |
85 | | - <Text as="span" size="T300"> |
86 | | - {nameInitials(member.displayName || member.userId)} |
87 | | - </Text> |
88 | | - )} |
89 | | - /> |
90 | | - </Avatar> |
91 | | - ); |
92 | | - })} |
93 | | - </Box> |
94 | | - </Box> |
95 | | - ) : ( |
96 | | - <Avatar size="400" radii="400"> |
97 | | - <RoomAvatar |
98 | | - roomId={room.roomId} |
99 | | - src={getDirectRoomAvatarUrl(mx, room, 96, useAuthentication)} |
100 | | - alt={room.name} |
| 59 | + // Determine avatar src for single group DM member to avoid nested ternary |
| 60 | + const getSingleMemberAvatarSrc = () => { |
| 61 | + if (groupMembers.length !== 1 || !groupMembers[0].avatarUrl) { |
| 62 | + return undefined; |
| 63 | + } |
| 64 | + return ( |
| 65 | + mxcUrlToHttp(mx, groupMembers[0].avatarUrl, useAuthentication, 96, 96, 'crop') ?? undefined |
| 66 | + ); |
| 67 | + }; |
| 68 | + |
| 69 | + // Render appropriate avatar based on DM type |
| 70 | + const renderAvatar = () => { |
| 71 | + if (!isGroupDM) { |
| 72 | + // Regular DM |
| 73 | + return ( |
| 74 | + <Avatar size="400" radii="400"> |
| 75 | + <RoomAvatar |
| 76 | + roomId={room.roomId} |
| 77 | + src={getDirectRoomAvatarUrl(mx, room, 96, useAuthentication)} |
| 78 | + alt={room.name} |
| 79 | + renderFallback={() => ( |
| 80 | + <Text as="span" size="H6"> |
| 81 | + {nameInitials(room.name)} |
| 82 | + </Text> |
| 83 | + )} |
| 84 | + /> |
| 85 | + </Avatar> |
| 86 | + ); |
| 87 | + } |
| 88 | + |
| 89 | + if (groupMembers.length === 1) { |
| 90 | + // Single member in group DM - fill the space like a normal DM |
| 91 | + return ( |
| 92 | + <Avatar size="400" radii="400"> |
| 93 | + <UserAvatar |
| 94 | + userId={groupMembers[0].userId} |
| 95 | + src={getSingleMemberAvatarSrc()} |
| 96 | + alt={groupMembers[0].displayName || groupMembers[0].userId} |
| 97 | + renderFallback={() => ( |
| 98 | + <Text as="span" size="H6"> |
| 99 | + {nameInitials(groupMembers[0].displayName || groupMembers[0].userId)} |
| 100 | + </Text> |
| 101 | + )} |
| 102 | + /> |
| 103 | + </Avatar> |
| 104 | + ); |
| 105 | + } |
| 106 | + |
| 107 | + // Multiple members in group DM - triangle layout |
| 108 | + return ( |
| 109 | + <Box className={css.GroupAvatarContainer}> |
| 110 | + <Box className={css.GroupAvatarRow}> |
| 111 | + {groupMembers.map((member) => { |
| 112 | + const avatarUrl = member.avatarUrl |
| 113 | + ? (mxcUrlToHttp(mx, member.avatarUrl, useAuthentication, 48, 48, 'crop') ?? undefined) |
| 114 | + : undefined; |
| 115 | + |
| 116 | + return ( |
| 117 | + <Avatar key={member.userId} size="200" radii="300" className={css.GroupAvatar}> |
| 118 | + <UserAvatar |
| 119 | + userId={member.userId} |
| 120 | + src={avatarUrl} |
| 121 | + alt={member.displayName || member.userId} |
101 | 122 | renderFallback={() => ( |
102 | | - <Text as="span" size="H6"> |
103 | | - {nameInitials(room.name)} |
| 123 | + <Text as="span" size="T300"> |
| 124 | + {nameInitials(member.displayName || member.userId)} |
104 | 125 | </Text> |
105 | 126 | )} |
106 | 127 | /> |
107 | 128 | </Avatar> |
108 | | - )} |
| 129 | + ); |
| 130 | + })} |
| 131 | + </Box> |
| 132 | + </Box> |
| 133 | + ); |
| 134 | + }; |
| 135 | + |
| 136 | + return ( |
| 137 | + <SidebarItem active={selected}> |
| 138 | + <SidebarItemTooltip tooltip={room.name}> |
| 139 | + {(triggerRef) => ( |
| 140 | + <SidebarAvatar as="button" ref={triggerRef} outlined onClick={handleClick} size="400"> |
| 141 | + {renderAvatar()} |
109 | 142 | </SidebarAvatar> |
110 | 143 | )} |
111 | 144 | </SidebarItemTooltip> |
112 | 145 | {unread && (unread.total > 0 || unread.highlight > 0) && ( |
113 | | - <SidebarItemBadge hasCount={unread.total > 0}> |
114 | | - <UnreadBadge highlight={unread.highlight > 0} count={unread.total} dm /> |
| 146 | + <SidebarItemBadge |
| 147 | + hasCount={unread.total > 0} |
| 148 | + style={{ |
| 149 | + left: unread.total > 0 ? toRem(-6) : toRem(-2), |
| 150 | + right: 'auto', |
| 151 | + }} |
| 152 | + > |
| 153 | + <UnreadBadge |
| 154 | + highlight={unread.highlight > 0} |
| 155 | + count={unread.highlight > 0 ? unread.highlight : unread.total} |
| 156 | + dm |
| 157 | + /> |
115 | 158 | </SidebarItemBadge> |
116 | 159 | )} |
117 | 160 | </SidebarItem> |
|
0 commit comments