123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- import {css} from '@emotion/react';
- import styled from '@emotion/styled';
- import TeamAvatar from 'sentry/components/avatar/teamAvatar';
- import UserAvatar from 'sentry/components/avatar/userAvatar';
- import {Tooltip} from 'sentry/components/tooltip';
- import {AvatarUser, Team} from 'sentry/types';
- type UserAvatarProps = React.ComponentProps<typeof UserAvatar>;
- type Props = {
- avatarSize?: number;
- className?: string;
- maxVisibleAvatars?: number;
- renderTooltip?: UserAvatarProps['renderTooltip'];
- teams?: Team[];
- tooltipOptions?: UserAvatarProps['tooltipOptions'];
- typeAvatars?: string;
- users?: AvatarUser[];
- };
- function AvatarList({
- avatarSize = 28,
- maxVisibleAvatars = 5,
- typeAvatars = 'users',
- tooltipOptions = {},
- className,
- users = [],
- teams = [],
- renderTooltip,
- }: Props) {
- const numTeams = teams.length;
- const numVisibleTeams = maxVisibleAvatars - numTeams > 0 ? numTeams : maxVisibleAvatars;
- const maxVisibleUsers =
- maxVisibleAvatars - numVisibleTeams > 0 ? maxVisibleAvatars - numVisibleTeams : 0;
- // Reverse the order since css flex-reverse is used to display the avatars
- const visibleTeamAvatars = teams.slice(0, numVisibleTeams).reverse();
- const visibleUserAvatars = users.slice(0, maxVisibleUsers).reverse();
- const numCollapsedAvatars = users.length - visibleUserAvatars.length;
- if (!tooltipOptions.position) {
- tooltipOptions.position = 'top';
- }
- return (
- <AvatarListWrapper className={className}>
- {!!numCollapsedAvatars && (
- <Tooltip title={`${numCollapsedAvatars} other ${typeAvatars}`}>
- <CollapsedAvatars size={avatarSize} data-test-id="avatarList-collapsedavatars">
- {numCollapsedAvatars < 99 && <Plus>+</Plus>}
- {numCollapsedAvatars}
- </CollapsedAvatars>
- </Tooltip>
- )}
- {visibleUserAvatars.map(user => (
- <StyledUserAvatar
- key={`${user.id}-${user.email}`}
- user={user}
- size={avatarSize}
- renderTooltip={renderTooltip}
- tooltipOptions={tooltipOptions}
- hasTooltip
- />
- ))}
- {visibleTeamAvatars.map(team => (
- <StyledTeamAvatar
- key={`${team.id}-${team.name}`}
- team={team}
- size={avatarSize}
- tooltipOptions={tooltipOptions}
- hasTooltip
- />
- ))}
- </AvatarListWrapper>
- );
- }
- export default AvatarList;
- // used in releases list page to do some alignment
- export const AvatarListWrapper = styled('div')`
- display: flex;
- flex-direction: row-reverse;
- `;
- const AvatarStyle = p => css`
- border: 2px solid ${p.theme.background};
- margin-left: -8px;
- cursor: default;
- &:hover {
- z-index: 1;
- }
- `;
- const StyledUserAvatar = styled(UserAvatar)`
- overflow: hidden;
- border-radius: 50%;
- ${AvatarStyle};
- `;
- const StyledTeamAvatar = styled(TeamAvatar)`
- overflow: hidden;
- ${AvatarStyle}
- `;
- const CollapsedAvatars = styled('div')<{size: number}>`
- display: flex;
- align-items: center;
- justify-content: center;
- position: relative;
- text-align: center;
- font-weight: 600;
- background-color: ${p => p.theme.gray200};
- color: ${p => p.theme.gray300};
- font-size: ${p => Math.floor(p.size / 2.3)}px;
- width: ${p => p.size}px;
- height: ${p => p.size}px;
- border-radius: 50%;
- ${AvatarStyle};
- `;
- const Plus = styled('span')`
- font-size: 10px;
- margin-left: 1px;
- margin-right: -1px;
- `;
|