diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useGetStandardObjectIcon.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useGetStandardObjectIcon.ts new file mode 100644 index 000000000..92b014d73 --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useGetStandardObjectIcon.ts @@ -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 }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx index 959d09b8c..8e84fa833 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx @@ -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 { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { useContext } from 'react'; +import { AvatarChip, AvatarChipVariant } from 'twenty-ui'; export type RecordIdentifierChipProps = { objectNameSingular: string; @@ -17,7 +17,6 @@ export const RecordIdentifierChip = ({ variant, }: RecordIdentifierChipProps) => { const { onIndexIdentifierClick } = useContext(RecordIndexRootPropsContext); - const { recordChipData } = useRecordChipData({ objectNameSingular, record, @@ -27,6 +26,8 @@ export const RecordIdentifierChip = ({ onIndexIdentifierClick(record.id); }; + const { Icon: LeftIcon, IconColor: LeftIconColor } = + useGetStandardObjectIcon(objectNameSingular); return ( ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx index 482983108..967825f3a 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx @@ -5,6 +5,7 @@ import { ActivityTargetsInlineCell } from '@/activities/inline-cell/components/A import { Note } from '@/activities/types/Note'; import { Task } from '@/activities/types/Task'; import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord'; +import { useGetStandardObjectIcon } from '@/object-metadata/hooks/useGetStandardObjectIcon'; import { useLabelIdentifierFieldMetadataItem } from '@/object-metadata/hooks/useLabelIdentifierFieldMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; @@ -156,7 +157,7 @@ export const RecordShowContainer = ({ objectNameSingular !== CoreObjectNameSingular.Task && fieldMetadataItem.name !== 'taskTargets', ); - + const { Icon, IconColor } = useGetStandardObjectIcon(objectNameSingular); const isReadOnly = objectMetadataItem.isRemote; const isMobile = useIsMobile() || isInRightDrawer; const isPrefetchLoading = useIsPrefetchLoading(); @@ -166,6 +167,8 @@ export const RecordShowContainer = ({ isMobile={isMobile} id={objectRecordId} logoOrAvatar={recordIdentifier?.avatarUrl ?? ''} + icon={Icon} + iconColor={IconColor} avatarPlaceholder={recordIdentifier?.name ?? ''} date={recordFromStore.createdAt ?? ''} loading={isPrefetchLoading || loading || recordLoading} diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx index 3d228d5bd..137bad600 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx @@ -2,7 +2,7 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { ChangeEvent, ReactNode, useRef } from 'react'; 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 { @@ -17,6 +17,8 @@ type ShowPageSummaryCardProps = { date: string; id?: string; logoOrAvatar?: string; + icon?: IconComponent; + iconColor?: string; onUploadPicture?: (file: File) => void; title: ReactNode; loading: boolean; @@ -99,6 +101,8 @@ export const ShowPageSummaryCard = ({ date, id, logoOrAvatar, + icon, + iconColor, onUploadPicture, title, loading, @@ -133,7 +137,9 @@ export const ShowPageSummaryCard = ({ size="xl" placeholderColorSeed={id} placeholder={avatarPlaceholder} - type={avatarType} + type={icon ? 'icon' : avatarType} + Icon={icon} + iconColor={iconColor} /> ; }>` align-items: center; flex-shrink: 0; overflow: hidden; user-select: none; - border-radius: ${({ rounded }) => (rounded ? '50%' : '2px')}; + border-radius: ${({ rounded, type }) => { + return rounded ? '50%' : type === 'icon' ? '4px' : '2px'; + }}; display: flex; font-size: ${({ size }) => AVATAR_PROPERTIES_BY_SIZE[size].fontSize}; height: ${({ size }) => AVATAR_PROPERTIES_BY_SIZE[size].width}; @@ -51,6 +55,8 @@ export type AvatarProps = { size?: AvatarSize; placeholder: string | undefined; placeholderColorSeed?: string; + Icon?: IconComponent; + iconColor?: string; type?: Nullable; color?: string; backgroundColor?: string; @@ -63,6 +69,8 @@ export const Avatar = ({ size = 'md', placeholder, placeholderColorSeed = placeholder, + Icon, + iconColor, onClick, type = 'squared', color, @@ -101,14 +109,26 @@ export const Avatar = ({ return ( - {showPlaceholder ? ( + {Icon ? ( + + ) : showPlaceholder ? ( placeholderChar ) : ( diff --git a/packages/twenty-ui/src/display/avatar/types/AvatarType.ts b/packages/twenty-ui/src/display/avatar/types/AvatarType.ts index 9e9b7dc95..e26755511 100644 --- a/packages/twenty-ui/src/display/avatar/types/AvatarType.ts +++ b/packages/twenty-ui/src/display/avatar/types/AvatarType.ts @@ -1 +1 @@ -export type AvatarType = 'squared' | 'rounded'; +export type AvatarType = 'squared' | 'rounded' | 'icon'; diff --git a/packages/twenty-ui/src/display/chip/components/AvatarChip.tsx b/packages/twenty-ui/src/display/chip/components/AvatarChip.tsx index 2c993ba65..72b0253ee 100644 --- a/packages/twenty-ui/src/display/chip/components/AvatarChip.tsx +++ b/packages/twenty-ui/src/display/chip/components/AvatarChip.tsx @@ -14,6 +14,7 @@ export type AvatarChipProps = { avatarType?: Nullable; variant?: AvatarChipVariant; LeftIcon?: IconComponent; + LeftIconColor?: string; isIconInverted?: boolean; className?: string; placeholderColorSeed?: string; @@ -41,6 +42,7 @@ export const AvatarChip = ({ avatarType = 'rounded', variant = AvatarChipVariant.Regular, LeftIcon, + LeftIconColor, isIconInverted, className, placeholderColorSeed, @@ -71,7 +73,11 @@ export const AvatarChip = ({ /> ) : ( - + ) ) : (