Fix count avatar color + align thread preview items (#3695)

Fix count avatar and align items

Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
Thomas Trompette 2024-01-30 15:01:12 +01:00 committed by GitHub
parent 84b6bea2b9
commit 511627ccb8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 56 additions and 48 deletions

View File

@ -77,7 +77,7 @@ export const CommentHeader = ({ comment, actionBar }: CommentHeaderProps) => {
<Avatar <Avatar
avatarUrl={avatarUrl} avatarUrl={avatarUrl}
size="md" size="md"
colorId={author?.id} entityId={author?.id}
placeholder={authorName} placeholder={authorName}
/> />
<StyledName>{authorName}</StyledName> <StyledName>{authorName}</StyledName>

View File

@ -1,6 +1,7 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { CardContent } from '@/ui/layout/card/components/CardContent'; import { CardContent } from '@/ui/layout/card/components/CardContent';
import { grayScale } from '@/ui/theme/constants/colors';
import { Avatar } from '@/users/components/Avatar'; import { Avatar } from '@/users/components/Avatar';
import { TimelineThread } from '~/generated/graphql'; import { TimelineThread } from '~/generated/graphql';
import { formatToHumanReadableDate } from '~/utils'; import { formatToHumanReadableDate } from '~/utils';
@ -15,29 +16,17 @@ const StyledCardContent = styled(CardContent)`
`; `;
const StyledHeading = styled.div<{ unread: boolean }>` const StyledHeading = styled.div<{ unread: boolean }>`
align-items: center; display: flex;
color: ${({ theme, unread }) => color: ${({ theme, unread }) =>
unread ? theme.font.color.primary : theme.font.color.secondary}; unread ? theme.font.color.primary : theme.font.color.secondary};
display: flex;
font-weight: ${({ theme, unread }) => font-weight: ${({ theme, unread }) =>
unread ? theme.font.weight.medium : theme.font.weight.regular}; unread ? theme.font.weight.medium : theme.font.weight.regular};
gap: ${({ theme }) => theme.spacing(1)};
overflow: hidden; overflow: hidden;
width: 160px; width: 20%;
:before {
background-color: ${({ theme, unread }) =>
unread ? theme.color.blue : 'transparent'};
border-radius: ${({ theme }) => theme.border.radius.rounded};
content: '';
display: block;
height: 6px;
width: 6px;
}
`; `;
const StyledParticipantsContainer = styled.div` const StyledParticipantsContainer = styled.div`
align-items: center; align-items: flex-start;
display: flex; display: flex;
`; `;
@ -46,6 +35,7 @@ const StyledAvatar = styled(Avatar)`
`; `;
const StyledSenderNames = styled.span` const StyledSenderNames = styled.span`
display: flex;
margin: ${({ theme }) => theme.spacing(0, 1)}; margin: ${({ theme }) => theme.spacing(0, 1)};
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -56,26 +46,27 @@ const StyledThreadCount = styled.span`
color: ${({ theme }) => theme.font.color.tertiary}; color: ${({ theme }) => theme.font.color.tertiary};
`; `;
const StyledSubject = styled.span<{ unread: boolean }>`
color: ${({ theme, unread }) =>
unread ? theme.font.color.primary : theme.font.color.secondary};
white-space: nowrap;
`;
const StyledBody = styled.span`
color: ${({ theme }) => theme.font.color.tertiary};
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
const StyledSubjectAndBody = styled.div` const StyledSubjectAndBody = styled.div`
display: flex; display: flex;
flex: 1; flex: 1;
gap: ${({ theme }) => theme.spacing(2)}; gap: ${({ theme }) => theme.spacing(2)};
overflow: hidden; overflow: hidden;
`;
const StyledSubject = styled.span<{ unread: boolean }>`
color: ${({ theme, unread }) =>
unread ? theme.font.color.primary : theme.font.color.secondary};
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
flex-shrink: 0;
`;
const StyledBody = styled.span`
color: ${({ theme }) => theme.font.color.tertiary};
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`; `;
const StyledReceivedAt = styled.div` const StyledReceivedAt = styled.div`
@ -104,12 +95,13 @@ export const EmailThreadPreview = ({
? `, ${thread.lastTwoParticipants?.[1]?.displayName}` ? `, ${thread.lastTwoParticipants?.[1]?.displayName}`
: ''); : '');
const [finalDisplayedName, finalAvatarUrl] = const [finalDisplayedName, finalAvatarUrl, isCountIcon] =
thread.participantCount > 3 thread.participantCount > 3
? [`${thread.participantCount}`, ''] ? [`${thread.participantCount}`, '', true]
: [ : [
thread?.lastTwoParticipants?.[1]?.displayName, thread?.lastTwoParticipants?.[1]?.displayName,
thread?.lastTwoParticipants?.[1]?.avatarUrl, thread?.lastTwoParticipants?.[1]?.avatarUrl,
false,
]; ];
return ( return (
@ -133,6 +125,8 @@ export const EmailThreadPreview = ({
avatarUrl={finalAvatarUrl} avatarUrl={finalAvatarUrl}
placeholder={finalDisplayedName} placeholder={finalDisplayedName}
type="rounded" type="rounded"
color={isCountIcon ? grayScale.gray50 : undefined}
backgroundColor={isCountIcon ? grayScale.gray10 : undefined}
/> />
)} )}
</StyledParticipantsContainer> </StyledParticipantsContainer>

View File

@ -328,7 +328,7 @@ export const CommandMenu = () => {
<Avatar <Avatar
type="rounded" type="rounded"
avatarUrl={null} avatarUrl={null}
colorId={person.id} entityId={person.id}
placeholder={ placeholder={
person.name.firstName + person.name.firstName +
' ' + ' ' +
@ -350,7 +350,7 @@ export const CommandMenu = () => {
to={`object/company/${company.id}`} to={`object/company/${company.id}`}
Icon={() => ( Icon={() => (
<Avatar <Avatar
colorId={company.id} entityId={company.id}
placeholder={company.name} placeholder={company.name}
avatarUrl={getLogoUrlFromDomainName( avatarUrl={getLogoUrlFromDomainName(
company.domainName, company.domainName,

View File

@ -46,7 +46,7 @@ export const Favorites = () => {
label={labelIdentifier} label={labelIdentifier}
Icon={() => ( Icon={() => (
<Avatar <Avatar
colorId={recordId} entityId={recordId}
avatarUrl={avatarUrl} avatarUrl={avatarUrl}
type={avatarType} type={avatarType}
placeholder={labelIdentifier} placeholder={labelIdentifier}

View File

@ -43,7 +43,7 @@ export const MultipleObjectRecordSelectItem = ({
avatar={ avatar={
<Avatar <Avatar
avatarUrl={objectRecordForSelect.recordIdentifier.avatarUrl} avatarUrl={objectRecordForSelect.recordIdentifier.avatarUrl}
colorId={objectRecordForSelect.record.id} entityId={objectRecordForSelect.record.id}
placeholder={objectRecordForSelect.recordIdentifier.name} placeholder={objectRecordForSelect.recordIdentifier.name}
size="md" size="md"
type={ type={

View File

@ -40,7 +40,7 @@ export const SelectableMenuItemSelect = ({
avatar={ avatar={
<Avatar <Avatar
avatarUrl={entity.avatarUrl} avatarUrl={entity.avatarUrl}
colorId={entity.id} entityId={entity.id}
placeholder={entity.name} placeholder={entity.name}
size="md" size="md"
type={entity.avatarType ?? 'rounded'} type={entity.avatarType ?? 'rounded'}

View File

@ -69,7 +69,7 @@ export const MultipleRecordSelectDropdown = ({
avatar={ avatar={
<Avatar <Avatar
avatarUrl={record.avatarUrl} avatarUrl={record.avatarUrl}
colorId={record.id} entityId={record.id}
placeholder={record.name} placeholder={record.name}
size="md" size="md"
type={record.avatarType ?? 'rounded'} type={record.avatarType ?? 'rounded'}

View File

@ -64,7 +64,7 @@ export const EntityChip = ({
) : ( ) : (
<Avatar <Avatar
avatarUrl={avatarUrl} avatarUrl={avatarUrl}
colorId={entityId} entityId={entityId}
placeholder={name} placeholder={name}
size="sm" size="sm"
type={avatarType} type={avatarType}

View File

@ -99,7 +99,7 @@ export const ShowPageSummaryCard = ({
avatarUrl={logoOrAvatar} avatarUrl={logoOrAvatar}
onClick={onUploadPicture ? handleAvatarClick : undefined} onClick={onUploadPicture ? handleAvatarClick : undefined}
size="xl" size="xl"
colorId={id} entityId={id}
placeholder={avatarPlaceholder} placeholder={avatarPlaceholder}
type={avatarType} type={avatarType}
/> />

View File

@ -16,21 +16,24 @@ export type AvatarProps = {
className?: string; className?: string;
size?: AvatarSize; size?: AvatarSize;
placeholder: string | undefined; placeholder: string | undefined;
colorId?: string; entityId?: string;
type?: Nullable<AvatarType>; type?: Nullable<AvatarType>;
color?: string;
backgroundColor?: string;
onClick?: () => void; onClick?: () => void;
}; };
const StyledAvatar = styled.div<AvatarProps & { colorId: string }>` export const StyledAvatar = styled.div<
AvatarProps & { color: string; backgroundColor: string }
>`
align-items: center; align-items: center;
background-color: ${({ avatarUrl, colorId }) => background-color: ${({ backgroundColor }) => backgroundColor};
!isNonEmptyString(avatarUrl) ? stringToHslColor(colorId, 75, 85) : 'none'};
${({ avatarUrl }) => ${({ avatarUrl }) =>
isNonEmptyString(avatarUrl) ? `background-image: url(${avatarUrl});` : ''} isNonEmptyString(avatarUrl) ? `background-image: url(${avatarUrl});` : ''}
background-position: center; background-position: center;
background-size: cover; background-size: cover;
border-radius: ${(props) => (props.type === 'rounded' ? '50%' : '2px')}; border-radius: ${(props) => (props.type === 'rounded' ? '50%' : '2px')};
color: ${({ colorId }) => stringToHslColor(colorId, 75, 25)}; color: ${({ color }) => color};
cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')}; cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')};
display: flex; display: flex;
@ -95,9 +98,11 @@ export const Avatar = ({
className, className,
size = 'md', size = 'md',
placeholder, placeholder,
colorId = placeholder, entityId = placeholder,
onClick, onClick,
type = 'squared', type = 'squared',
color,
backgroundColor,
}: AvatarProps) => { }: AvatarProps) => {
const noAvatarUrl = !isNonEmptyString(avatarUrl); const noAvatarUrl = !isNonEmptyString(avatarUrl);
const [isInvalidAvatarUrl, setIsInvalidAvatarUrl] = useState(false); const [isInvalidAvatarUrl, setIsInvalidAvatarUrl] = useState(false);
@ -114,6 +119,13 @@ export const Avatar = ({
} }
}, [avatarUrl]); }, [avatarUrl]);
const fixedColor = color ?? stringToHslColor(entityId ?? '', 75, 25);
const fixedBackgroundColor =
backgroundColor ??
(!isNonEmptyString(avatarUrl)
? stringToHslColor(entityId ?? '', 75, 85)
: 'none');
return ( return (
<StyledAvatar <StyledAvatar
className={className} className={className}
@ -121,8 +133,10 @@ export const Avatar = ({
placeholder={placeholder} placeholder={placeholder}
size={size} size={size}
type={type} type={type}
colorId={colorId ?? ''} entityId={entityId}
onClick={onClick} onClick={onClick}
color={fixedColor}
backgroundColor={fixedBackgroundColor}
> >
{(noAvatarUrl || isInvalidAvatarUrl) && {(noAvatarUrl || isInvalidAvatarUrl) &&
placeholder?.[0]?.toLocaleUpperCase()} placeholder?.[0]?.toLocaleUpperCase()}

View File

@ -40,7 +40,7 @@ export const WorkspaceMemberCard = ({
<StyledContainer> <StyledContainer>
<Avatar <Avatar
avatarUrl={workspaceMember.avatarUrl} avatarUrl={workspaceMember.avatarUrl}
colorId={workspaceMember.id} entityId={workspaceMember.id}
placeholder={workspaceMember.name.firstName || ''} placeholder={workspaceMember.name.firstName || ''}
type="squared" type="squared"
size="xl" size="xl"