Favicons are being re-rendered on hover (#5849)
### Description Favicons are being re-rendered on hover ### Refs #3523 ### Demo https://www.loom.com/share/e3944d940a014283af8c26baac1fed57?sid=e3e96a81-3a54-4969-8602-99c64bb3ffe7 Fixes #3523 --------- Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com> Co-authored-by: v1b3m <vibenjamin6@gmail.com> Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -2,7 +2,6 @@ import { EntityChip, EntityChipVariant } from 'twenty-ui';
|
|||||||
|
|
||||||
import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier';
|
import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier';
|
||||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64';
|
|
||||||
|
|
||||||
export type RecordChipProps = {
|
export type RecordChipProps = {
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
@ -28,9 +27,7 @@ export const RecordChip = ({
|
|||||||
entityId={record.id}
|
entityId={record.id}
|
||||||
name={objectRecordIdentifier.name}
|
name={objectRecordIdentifier.name}
|
||||||
avatarType={objectRecordIdentifier.avatarType}
|
avatarType={objectRecordIdentifier.avatarType}
|
||||||
avatarUrl={
|
avatarUrl={objectRecordIdentifier.avatarUrl ?? ''}
|
||||||
getImageAbsoluteURIOrBase64(objectRecordIdentifier.avatarUrl) || ''
|
|
||||||
}
|
|
||||||
linkToEntity={objectRecordIdentifier.linkToShowPage}
|
linkToEntity={objectRecordIdentifier.linkToShowPage}
|
||||||
className={className}
|
className={className}
|
||||||
variant={variant}
|
variant={variant}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { EntityChip } from 'twenty-ui';
|
import { EntityChip } from 'twenty-ui';
|
||||||
|
|
||||||
import { useChipFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useChipFieldDisplay';
|
import { useChipFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useChipFieldDisplay';
|
||||||
import { getImageAbsoluteURIOrBase64 } from '~/utils/image/getImageAbsoluteURIOrBase64';
|
|
||||||
|
|
||||||
export const ChipFieldDisplay = () => {
|
export const ChipFieldDisplay = () => {
|
||||||
const { recordValue, generateRecordChipData } = useChipFieldDisplay();
|
const { recordValue, generateRecordChipData } = useChipFieldDisplay();
|
||||||
@ -17,7 +16,7 @@ export const ChipFieldDisplay = () => {
|
|||||||
entityId={recordValue.id}
|
entityId={recordValue.id}
|
||||||
name={recordChipData.name as any}
|
name={recordChipData.name as any}
|
||||||
avatarType={recordChipData.avatarType}
|
avatarType={recordChipData.avatarType}
|
||||||
avatarUrl={getImageAbsoluteURIOrBase64(recordChipData.avatarUrl) ?? ''}
|
avatarUrl={recordChipData.avatarUrl ?? ''}
|
||||||
linkToEntity={recordChipData.linkToShowPage}
|
linkToEntity={recordChipData.linkToShowPage}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import { isNonEmptyString, isUndefined } from '@sniptt/guards';
|
import { isNonEmptyString, isUndefined } from '@sniptt/guards';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { invalidAvatarUrlsState } from '@ui/display/avatar/components/states/isInvalidAvatarUrlState';
|
||||||
import { Nullable, stringToHslColor } from '@ui/utilities';
|
import { Nullable, stringToHslColor } from '@ui/utilities';
|
||||||
|
|
||||||
import styles from './Avatar.module.css';
|
import styles from './Avatar.module.css';
|
||||||
@ -55,16 +56,20 @@ export const Avatar = ({
|
|||||||
color,
|
color,
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
}: AvatarProps) => {
|
}: AvatarProps) => {
|
||||||
const [isInvalidAvatarUrl, setIsInvalidAvatarUrl] = useState(false);
|
const [invalidAvatarUrls, setInvalidAvatarUrls] = useRecoilState(
|
||||||
|
invalidAvatarUrlsState,
|
||||||
|
);
|
||||||
|
|
||||||
const noAvatarUrl = !isNonEmptyString(avatarUrl);
|
const noAvatarUrl = !isNonEmptyString(avatarUrl);
|
||||||
|
|
||||||
const placeholderChar = placeholder?.[0]?.toLocaleUpperCase();
|
const placeholderChar = placeholder?.[0]?.toLocaleUpperCase();
|
||||||
|
|
||||||
const showPlaceholder = noAvatarUrl || isInvalidAvatarUrl;
|
const showPlaceholder = noAvatarUrl || invalidAvatarUrls.includes(avatarUrl);
|
||||||
|
|
||||||
const handleImageError = () => {
|
const handleImageError = () => {
|
||||||
setIsInvalidAvatarUrl(true);
|
if (isNonEmptyString(avatarUrl)) {
|
||||||
|
setInvalidAvatarUrls((prev) => [...prev, avatarUrl]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fixedColor = color ?? stringToHslColor(entityId ?? '', 75, 25);
|
const fixedColor = color ?? stringToHslColor(entityId ?? '', 75, 25);
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { atom } from 'recoil';
|
||||||
|
|
||||||
|
export const invalidAvatarUrlsState = atom<string[]>({
|
||||||
|
key: 'invalidAvatarUrlsState',
|
||||||
|
default: [],
|
||||||
|
});
|
||||||
@ -1,5 +1,6 @@
|
|||||||
export * from './avatar/components/Avatar';
|
export * from './avatar/components/Avatar';
|
||||||
export * from './avatar/components/AvatarGroup';
|
export * from './avatar/components/AvatarGroup';
|
||||||
|
export * from './avatar/components/states/isInvalidAvatarUrlState';
|
||||||
export * from './checkmark/components/AnimatedCheckmark';
|
export * from './checkmark/components/AnimatedCheckmark';
|
||||||
export * from './checkmark/components/Checkmark';
|
export * from './checkmark/components/Checkmark';
|
||||||
export * from './chip/components/Chip';
|
export * from './chip/components/Chip';
|
||||||
|
|||||||
Reference in New Issue
Block a user