Introduced Specific Icons image identifier for Notes and Tasks (#6997)

Fixes #6486
This commit is contained in:
nitin
2024-09-24 15:17:20 +05:30
committed by GitHub
parent e3547582d0
commit fcaa9d9aed
7 changed files with 86 additions and 11 deletions

View File

@@ -0,0 +1,37 @@
import { useTheme } from '@emotion/react';
import { IconCheckbox, IconComponent, IconNotes } from 'twenty-ui';
export const useGetStandardObjectIcon = (objectNameSingular: string) => {
const theme = useTheme();
const getIconForObjectType = (
objectType: string,
): IconComponent | undefined => {
switch (objectType) {
case 'note':
return IconNotes;
case 'task':
return IconCheckbox;
default:
return undefined;
}
};
const getIconColorForObjectType = (objectType: string): string => {
switch (objectType) {
case 'note':
return theme.color.yellow;
case 'task':
return theme.color.blue;
default:
return 'currentColor';
}
};
const { Icon, IconColor } = {
Icon: getIconForObjectType(objectNameSingular),
IconColor: getIconColorForObjectType(objectNameSingular),
};
return { Icon, IconColor };
};

View File

@@ -1,9 +1,9 @@
import { AvatarChip, AvatarChipVariant } from 'twenty-ui'; import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandardObjectIcon';
import { useRecordChipData } from '@/object-record/hooks/useRecordChipData'; import { useRecordChipData } from '@/object-record/hooks/useRecordChipData';
import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext'; import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext';
import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { useContext } from 'react'; import { useContext } from 'react';
import { AvatarChip, AvatarChipVariant } from 'twenty-ui';
export type RecordIdentifierChipProps = { export type RecordIdentifierChipProps = {
objectNameSingular: string; objectNameSingular: string;
@@ -17,7 +17,6 @@ export const RecordIdentifierChip = ({
variant, variant,
}: RecordIdentifierChipProps) => { }: RecordIdentifierChipProps) => {
const { onIndexIdentifierClick } = useContext(RecordIndexRootPropsContext); const { onIndexIdentifierClick } = useContext(RecordIndexRootPropsContext);
const { recordChipData } = useRecordChipData({ const { recordChipData } = useRecordChipData({
objectNameSingular, objectNameSingular,
record, record,
@@ -27,6 +26,8 @@ export const RecordIdentifierChip = ({
onIndexIdentifierClick(record.id); onIndexIdentifierClick(record.id);
}; };
const { Icon: LeftIcon, IconColor: LeftIconColor } =
useGetStandardObjectIcon(objectNameSingular);
return ( return (
<AvatarChip <AvatarChip
placeholderColorSeed={record.id} placeholderColorSeed={record.id}
@@ -35,6 +36,8 @@ export const RecordIdentifierChip = ({
avatarUrl={recordChipData.avatarUrl ?? ''} avatarUrl={recordChipData.avatarUrl ?? ''}
onClick={handleAvatarChipClick} onClick={handleAvatarChipClick}
variant={variant} variant={variant}
LeftIcon={LeftIcon}
LeftIconColor={LeftIconColor}
/> />
); );
}; };

View File

@@ -5,6 +5,7 @@ import { ActivityTargetsInlineCell } from '@/activities/inline-cell/components/A
import { Note } from '@/activities/types/Note'; import { Note } from '@/activities/types/Note';
import { Task } from '@/activities/types/Task'; import { Task } from '@/activities/types/Task';
import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord'; import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord';
import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandardObjectIcon';
import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/useLabelIdentifierFieldMetadataItem'; import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/useLabelIdentifierFieldMetadataItem';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
@@ -156,7 +157,7 @@ export const RecordShowContainer = ({
objectNameSingular !== CoreObjectNameSingular.Task && objectNameSingular !== CoreObjectNameSingular.Task &&
fieldMetadataItem.name !== 'taskTargets', fieldMetadataItem.name !== 'taskTargets',
); );
const { Icon, IconColor } = useGetStandardObjectIcon(objectNameSingular);
const isReadOnly = objectMetadataItem.isRemote; const isReadOnly = objectMetadataItem.isRemote;
const isMobile = useIsMobile() || isInRightDrawer; const isMobile = useIsMobile() || isInRightDrawer;
const isPrefetchLoading = useIsPrefetchLoading(); const isPrefetchLoading = useIsPrefetchLoading();
@@ -166,6 +167,8 @@ export const RecordShowContainer = ({
isMobile={isMobile} isMobile={isMobile}
id={objectRecordId} id={objectRecordId}
logoOrAvatar={recordIdentifier?.avatarUrl ?? ''} logoOrAvatar={recordIdentifier?.avatarUrl ?? ''}
icon={Icon}
iconColor={IconColor}
avatarPlaceholder={recordIdentifier?.name ?? ''} avatarPlaceholder={recordIdentifier?.name ?? ''}
date={recordFromStore.createdAt ?? ''} date={recordFromStore.createdAt ?? ''}
loading={isPrefetchLoading || loading || recordLoading} loading={isPrefetchLoading || loading || recordLoading}

View File

@@ -2,7 +2,7 @@ import { useTheme } from '@emotion/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { ChangeEvent, ReactNode, useRef } from 'react'; import { ChangeEvent, ReactNode, useRef } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { AppTooltip, Avatar, AvatarType } from 'twenty-ui'; import { AppTooltip, Avatar, AvatarType, IconComponent } from 'twenty-ui';
import { v4 as uuidV4 } from 'uuid'; import { v4 as uuidV4 } from 'uuid';
import { import {
@@ -17,6 +17,8 @@ type ShowPageSummaryCardProps = {
date: string; date: string;
id?: string; id?: string;
logoOrAvatar?: string; logoOrAvatar?: string;
icon?: IconComponent;
iconColor?: string;
onUploadPicture?: (file: File) => void; onUploadPicture?: (file: File) => void;
title: ReactNode; title: ReactNode;
loading: boolean; loading: boolean;
@@ -99,6 +101,8 @@ export const ShowPageSummaryCard = ({
date, date,
id, id,
logoOrAvatar, logoOrAvatar,
icon,
iconColor,
onUploadPicture, onUploadPicture,
title, title,
loading, loading,
@@ -133,7 +137,9 @@ export const ShowPageSummaryCard = ({
size="xl" size="xl"
placeholderColorSeed={id} placeholderColorSeed={id}
placeholder={avatarPlaceholder} placeholder={avatarPlaceholder}
type={avatarType} type={icon ? 'icon' : avatarType}
Icon={icon}
iconColor={iconColor}
/> />
<StyledFileInput <StyledFileInput
ref={inputFileRef} ref={inputFileRef}

View File

@@ -7,6 +7,7 @@ import { invalidAvatarUrlsState } from '@ui/display/avatar/components/states/isI
import { AVATAR_PROPERTIES_BY_SIZE } from '@ui/display/avatar/constants/AvatarPropertiesBySize'; import { AVATAR_PROPERTIES_BY_SIZE } from '@ui/display/avatar/constants/AvatarPropertiesBySize';
import { AvatarSize } from '@ui/display/avatar/types/AvatarSize'; import { AvatarSize } from '@ui/display/avatar/types/AvatarSize';
import { AvatarType } from '@ui/display/avatar/types/AvatarType'; import { AvatarType } from '@ui/display/avatar/types/AvatarType';
import { IconComponent } from '@ui/display/icon/types/IconComponent';
import { ThemeContext } from '@ui/theme'; import { ThemeContext } from '@ui/theme';
import { Nullable, getImageAbsoluteURI, stringToHslColor } from '@ui/utilities'; import { Nullable, getImageAbsoluteURI, stringToHslColor } from '@ui/utilities';
@@ -17,13 +18,16 @@ const StyledAvatar = styled.div<{
color: string; color: string;
backgroundColor: string; backgroundColor: string;
backgroundTransparentLight: string; backgroundTransparentLight: string;
type?: Nullable<AvatarType>;
}>` }>`
align-items: center; align-items: center;
flex-shrink: 0; flex-shrink: 0;
overflow: hidden; overflow: hidden;
user-select: none; user-select: none;
border-radius: ${({ rounded }) => (rounded ? '50%' : '2px')}; border-radius: ${({ rounded, type }) => {
return rounded ? '50%' : type === 'icon' ? '4px' : '2px';
}};
display: flex; display: flex;
font-size: ${({ size }) => AVATAR_PROPERTIES_BY_SIZE[size].fontSize}; font-size: ${({ size }) => AVATAR_PROPERTIES_BY_SIZE[size].fontSize};
height: ${({ size }) => AVATAR_PROPERTIES_BY_SIZE[size].width}; height: ${({ size }) => AVATAR_PROPERTIES_BY_SIZE[size].width};
@@ -51,6 +55,8 @@ export type AvatarProps = {
size?: AvatarSize; size?: AvatarSize;
placeholder: string | undefined; placeholder: string | undefined;
placeholderColorSeed?: string; placeholderColorSeed?: string;
Icon?: IconComponent;
iconColor?: string;
type?: Nullable<AvatarType>; type?: Nullable<AvatarType>;
color?: string; color?: string;
backgroundColor?: string; backgroundColor?: string;
@@ -63,6 +69,8 @@ export const Avatar = ({
size = 'md', size = 'md',
placeholder, placeholder,
placeholderColorSeed = placeholder, placeholderColorSeed = placeholder,
Icon,
iconColor,
onClick, onClick,
type = 'squared', type = 'squared',
color, color,
@@ -101,14 +109,26 @@ export const Avatar = ({
return ( return (
<StyledAvatar <StyledAvatar
size={size} size={size}
backgroundColor={showBackgroundColor ? fixedBackgroundColor : 'none'} backgroundColor={
Icon
? theme.background.tertiary
: showBackgroundColor
? fixedBackgroundColor
: 'none'
}
color={fixedColor} color={fixedColor}
clickable={!isUndefined(onClick)} clickable={!isUndefined(onClick)}
rounded={type === 'rounded'} rounded={type === 'rounded'}
type={type}
onClick={onClick} onClick={onClick}
backgroundTransparentLight={theme.background.transparent.light} backgroundTransparentLight={theme.background.transparent.light}
> >
{showPlaceholder ? ( {Icon ? (
<Icon
color={iconColor ? iconColor : 'currentColor'}
size={theme.icon.size.xl}
/>
) : showPlaceholder ? (
placeholderChar placeholderChar
) : ( ) : (
<StyledImage src={avatarImageURI} onError={handleImageError} alt="" /> <StyledImage src={avatarImageURI} onError={handleImageError} alt="" />

View File

@@ -1 +1 @@
export type AvatarType = 'squared' | 'rounded'; export type AvatarType = 'squared' | 'rounded' | 'icon';

View File

@@ -14,6 +14,7 @@ export type AvatarChipProps = {
avatarType?: Nullable<AvatarType>; avatarType?: Nullable<AvatarType>;
variant?: AvatarChipVariant; variant?: AvatarChipVariant;
LeftIcon?: IconComponent; LeftIcon?: IconComponent;
LeftIconColor?: string;
isIconInverted?: boolean; isIconInverted?: boolean;
className?: string; className?: string;
placeholderColorSeed?: string; placeholderColorSeed?: string;
@@ -41,6 +42,7 @@ export const AvatarChip = ({
avatarType = 'rounded', avatarType = 'rounded',
variant = AvatarChipVariant.Regular, variant = AvatarChipVariant.Regular,
LeftIcon, LeftIcon,
LeftIconColor,
isIconInverted, isIconInverted,
className, className,
placeholderColorSeed, placeholderColorSeed,
@@ -71,7 +73,11 @@ export const AvatarChip = ({
/> />
</StyledInvertedIconContainer> </StyledInvertedIconContainer>
) : ( ) : (
<LeftIcon size={theme.icon.size.md} stroke={theme.icon.stroke.sm} /> <LeftIcon
size={theme.icon.size.md}
stroke={theme.icon.stroke.sm}
color={LeftIconColor || 'currentColor'}
/>
) )
) : ( ) : (
<Avatar <Avatar