mirror of
https://github.com/lingble/twenty.git
synced 2025-11-07 16:23:16 +00:00
Introduced Specific Icons image identifier for Notes and Tasks (#6997)
Fixes #6486
This commit is contained in:
@@ -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 };
|
||||||
|
};
|
||||||
@@ -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}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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="" />
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export type AvatarType = 'squared' | 'rounded';
|
export type AvatarType = 'squared' | 'rounded' | 'icon';
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user