mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-09-15 07:12:24 +03:00
add member item component in member drawer
This commit is contained in:
parent
1de795ace7
commit
ac0353ea28
2 changed files with 84 additions and 56 deletions
|
@ -1,10 +1,8 @@
|
||||||
import { keyframes, style } from '@vanilla-extract/css';
|
import { keyframes, style } from '@vanilla-extract/css';
|
||||||
import { color, config, toRem } from 'folds';
|
import { config, toRem } from 'folds';
|
||||||
|
|
||||||
export const MembersDrawer = style({
|
export const MembersDrawer = style({
|
||||||
width: toRem(266),
|
width: toRem(266),
|
||||||
backgroundColor: color.Background.Container,
|
|
||||||
color: color.Background.OnContainer,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const MembersDrawerHeader = style({
|
export const MembersDrawerHeader = style({
|
||||||
|
|
|
@ -26,7 +26,7 @@ import {
|
||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
config,
|
config,
|
||||||
} from 'folds';
|
} from 'folds';
|
||||||
import { Room, RoomMember } from 'matrix-js-sdk';
|
import { MatrixClient, Room, RoomMember } from 'matrix-js-sdk';
|
||||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
@ -57,6 +57,67 @@ import { MembershipFilterMenu } from '../../components/MembershipFilterMenu';
|
||||||
import { MemberSortMenu } from '../../components/MemberSortMenu';
|
import { MemberSortMenu } from '../../components/MemberSortMenu';
|
||||||
import { useOpenUserRoomProfile, useUserRoomProfileState } from '../../state/hooks/userRoomProfile';
|
import { useOpenUserRoomProfile, useUserRoomProfileState } from '../../state/hooks/userRoomProfile';
|
||||||
import { useSpaceOptionally } from '../../hooks/useSpace';
|
import { useSpaceOptionally } from '../../hooks/useSpace';
|
||||||
|
import { ContainerColor } from '../../styles/ContainerColor.css';
|
||||||
|
|
||||||
|
type MemberItemProps = {
|
||||||
|
mx: MatrixClient;
|
||||||
|
useAuthentication: boolean;
|
||||||
|
room: Room;
|
||||||
|
member: RoomMember;
|
||||||
|
onClick: MouseEventHandler<HTMLButtonElement>;
|
||||||
|
pressed?: boolean;
|
||||||
|
typing?: boolean;
|
||||||
|
};
|
||||||
|
function MemberItem({
|
||||||
|
mx,
|
||||||
|
useAuthentication,
|
||||||
|
room,
|
||||||
|
member,
|
||||||
|
onClick,
|
||||||
|
pressed,
|
||||||
|
typing,
|
||||||
|
}: MemberItemProps) {
|
||||||
|
const name =
|
||||||
|
getMemberDisplayName(room, member.userId) ?? getMxIdLocalPart(member.userId) ?? member.userId;
|
||||||
|
const avatarMxcUrl = member.getMxcAvatarUrl();
|
||||||
|
const avatarUrl = avatarMxcUrl
|
||||||
|
? mx.mxcUrlToHttp(avatarMxcUrl, 100, 100, 'crop', undefined, false, useAuthentication)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
style={{ padding: `0 ${config.space.S200}` }}
|
||||||
|
aria-pressed={pressed}
|
||||||
|
data-user-id={member.userId}
|
||||||
|
variant="Background"
|
||||||
|
radii="400"
|
||||||
|
onClick={onClick}
|
||||||
|
before={
|
||||||
|
<Avatar size="200">
|
||||||
|
<UserAvatar
|
||||||
|
userId={member.userId}
|
||||||
|
src={avatarUrl ?? undefined}
|
||||||
|
alt={name}
|
||||||
|
renderFallback={() => <Icon size="50" src={Icons.User} filled />}
|
||||||
|
/>
|
||||||
|
</Avatar>
|
||||||
|
}
|
||||||
|
after={
|
||||||
|
typing && (
|
||||||
|
<Badge size="300" variant="Secondary" fill="Soft" radii="Pill" outlined>
|
||||||
|
<TypingIndicator size="300" />
|
||||||
|
</Badge>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Box grow="Yes">
|
||||||
|
<Text size="T400" truncate>
|
||||||
|
{name}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const SEARCH_OPTIONS: UseAsyncSearchOptions = {
|
const SEARCH_OPTIONS: UseAsyncSearchOptions = {
|
||||||
limit: 1000,
|
limit: 1000,
|
||||||
|
@ -140,9 +201,6 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) {
|
||||||
{ wait: 200 }
|
{ wait: 200 }
|
||||||
);
|
);
|
||||||
|
|
||||||
const getName = (member: RoomMember) =>
|
|
||||||
getMemberDisplayName(room, member.userId) ?? getMxIdLocalPart(member.userId) ?? member.userId;
|
|
||||||
|
|
||||||
const handleMemberClick: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
const handleMemberClick: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
||||||
const btn = evt.currentTarget as HTMLButtonElement;
|
const btn = evt.currentTarget as HTMLButtonElement;
|
||||||
const userId = btn.getAttribute('data-user-id');
|
const userId = btn.getAttribute('data-user-id');
|
||||||
|
@ -151,7 +209,11 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className={css.MembersDrawer} shrink="No" direction="Column">
|
<Box
|
||||||
|
className={classNames(css.MembersDrawer, ContainerColor({ variant: 'Background' }))}
|
||||||
|
shrink="No"
|
||||||
|
direction="Column"
|
||||||
|
>
|
||||||
<Header className={css.MembersDrawerHeader} variant="Background" size="600">
|
<Header className={css.MembersDrawerHeader} variant="Background" size="600">
|
||||||
<Box grow="Yes" alignItems="Center" gap="200">
|
<Box grow="Yes" alignItems="Center" gap="200">
|
||||||
<Box grow="Yes" alignItems="Center" gap="200">
|
<Box grow="Yes" alignItems="Center" gap="200">
|
||||||
|
@ -334,60 +396,28 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const member = tagOrMember;
|
|
||||||
const name = getName(member);
|
|
||||||
const avatarMxcUrl = member.getMxcAvatarUrl();
|
|
||||||
const avatarUrl = avatarMxcUrl
|
|
||||||
? mx.mxcUrlToHttp(
|
|
||||||
avatarMxcUrl,
|
|
||||||
100,
|
|
||||||
100,
|
|
||||||
'crop',
|
|
||||||
undefined,
|
|
||||||
false,
|
|
||||||
useAuthentication
|
|
||||||
)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<div
|
||||||
style={{
|
style={{
|
||||||
padding: `0 ${config.space.S200}`,
|
|
||||||
transform: `translateY(${vItem.start}px)`,
|
transform: `translateY(${vItem.start}px)`,
|
||||||
}}
|
}}
|
||||||
aria-pressed={openProfileUserId === member.userId}
|
|
||||||
data-index={vItem.index}
|
|
||||||
data-user-id={member.userId}
|
|
||||||
ref={virtualizer.measureElement}
|
|
||||||
key={`${room.roomId}-${member.userId}`}
|
|
||||||
className={css.DrawerVirtualItem}
|
className={css.DrawerVirtualItem}
|
||||||
variant="Background"
|
data-index={vItem.index}
|
||||||
radii="400"
|
key={`${room.roomId}-${tagOrMember.userId}`}
|
||||||
onClick={handleMemberClick}
|
ref={virtualizer.measureElement}
|
||||||
before={
|
|
||||||
<Avatar size="200">
|
|
||||||
<UserAvatar
|
|
||||||
userId={member.userId}
|
|
||||||
src={avatarUrl ?? undefined}
|
|
||||||
alt={name}
|
|
||||||
renderFallback={() => <Icon size="50" src={Icons.User} filled />}
|
|
||||||
/>
|
|
||||||
</Avatar>
|
|
||||||
}
|
|
||||||
after={
|
|
||||||
typingMembers.find((receipt) => receipt.userId === member.userId) && (
|
|
||||||
<Badge size="300" variant="Secondary" fill="Soft" radii="Pill" outlined>
|
|
||||||
<TypingIndicator size="300" />
|
|
||||||
</Badge>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Box grow="Yes">
|
<MemberItem
|
||||||
<Text size="T400" truncate>
|
mx={mx}
|
||||||
{name}
|
useAuthentication={useAuthentication}
|
||||||
</Text>
|
room={room}
|
||||||
</Box>
|
member={tagOrMember}
|
||||||
</MenuItem>
|
onClick={handleMemberClick}
|
||||||
|
pressed={openProfileUserId === tagOrMember.userId}
|
||||||
|
typing={typingMembers.some(
|
||||||
|
(receipt) => receipt.userId === tagOrMember.userId
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue