From f0a7963a0ac0f1888eb7abb1a84ade13dca7e9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Comerci?= <45410089+ncomerci@users.noreply.github.com> Date: Mon, 26 Jun 2023 11:11:05 -0300 Subject: [PATCH] refactor: Replace dcl-gatsby Avatar component (#1041) * refactor: dcl-gatsby Avatar replaced * loading & extra props removed --- src/components/Common/Avatar.css | 138 ++++++++++++++++++ src/components/Common/Avatar.tsx | 59 ++++++++ .../Grants/GrantCard/GrantCardHeadline.css | 4 +- .../IdentityConnectModal/PostConnection.tsx | 2 +- src/components/Modal/Votes/VotesList.css | 4 +- .../VotingPowerDelegationCandidatesList.css | 2 +- .../Proposal/Comments/ProposalComment.tsx | 2 +- src/components/Proposal/ProposalItem.css | 2 +- src/components/Transparency/MemberCard.tsx | 2 +- src/components/User/Username.css | 2 +- src/components/User/Username.tsx | 26 ++-- src/hooks/useProfile.ts | 4 +- 12 files changed, 222 insertions(+), 25 deletions(-) create mode 100644 src/components/Common/Avatar.css create mode 100644 src/components/Common/Avatar.tsx diff --git a/src/components/Common/Avatar.css b/src/components/Common/Avatar.css new file mode 100644 index 000000000..b2c9a7065 --- /dev/null +++ b/src/components/Common/Avatar.css @@ -0,0 +1,138 @@ +@keyframes Avatar--loading-animation { + to { + background-position-x: -200%; + } +} + +.Avatar { + height: auto; + border-radius: 100%; + background-color: #7a7a7a; + vertical-align: middle; + max-width: 256px; + margin: 0; +} + +.Avatar.Avatar--loading { + opacity: 0.6; + background-size: 200% 100%; + animation: 1.5s Avatar--loading-animation linear infinite; + background-image: linear-gradient(110deg, #7a7a7a 18%, #949494 28%, #7a7a7a 43%); +} + +.Avatar.Avatar--0, +.Avatar.Avatar--1 { + background-color: #4e79a7; +} + +.Avatar.Avatar--0.Avatar--loading, +.Avatar.Avatar--1.Avatar--loading { + background-image: linear-gradient(110deg, #4e79a7 18%, #6e93bb 28%, #4e79a7 43%); +} + +.Avatar.Avatar--2, +.Avatar.Avatar--3 { + background-color: #f28e2c; +} + +.Avatar.Avatar--2.Avatar--loading, +.Avatar.Avatar--3.Avatar--loading { + background-image: linear-gradient(110deg, #f28e2c 18%, #f4a456 28%, #f28e2c 43%); +} + +.Avatar.Avatar--4, +.Avatar.Avatar--5 { + background-color: #e15759; +} + +.Avatar.Avatar--4.Avatar--loading, +.Avatar.Avatar--5.Avatar--loading { + background-image: linear-gradient(110deg, #e15759 18%, #e6787a 28%, #e15759 43%); +} + +.Avatar.Avatar--6, +.Avatar.Avatar--7 { + background-color: #76b7b2; +} + +.Avatar.Avatar--6.Avatar--loading, +.Avatar.Avatar--7.Avatar--loading { + background-image: linear-gradient(110deg, #76b7b2 18%, #91c5c1 28%, #76b7b2 43%); +} + +.Avatar.Avatar--8, +.Avatar.Avatar--9 { + background-color: #59a14f; +} + +.Avatar.Avatar--8.Avatar--loading, +.Avatar.Avatar--9.Avatar--loading { + background-image: linear-gradient(110deg, #59a14f 18%, #77b76e 28%, #59a14f 43%); +} + +.Avatar.Avatar--a, +.Avatar.Avatar--b { + background-color: #edc949; +} + +.Avatar.Avatar--a.Avatar--loading, +.Avatar.Avatar--b.Avatar--loading { + background-image: linear-gradient(110deg, #edc949 18%, #f0d36d 28%, #edc949 43%); +} + +.Avatar.Avatar--c, +.Avatar.Avatar--d { + background-color: #af7aa1; +} + +.Avatar.Avatar--c.Avatar--loading, +.Avatar.Avatar--d.Avatar--loading { + background-image: linear-gradient(110deg, #af7aa1 18%, #bf94b3 28%, #af7aa1 43%); +} + +.Avatar.Avatar--e, +.Avatar.Avatar--f { + background-color: #ff9da7; +} + +.Avatar.Avatar--e.Avatar--loading, +.Avatar.Avatar--f.Avatar--loading { + background-image: linear-gradient(110deg, #ff9da7 18%, #feb0b8 28%, #ff9da7 43%); +} + +.Avatar.Avatar--mini { + width: 20px; +} + +.Avatar.Avatar--tiny { + width: 24px; +} + +.Avatar.Avatar--small { + width: 32px; +} + +.Avatar, +.Avatar.Avatar--medium { + width: 44px; +} + +.Avatar.Avatar--large { + width: 52px; +} + +.Avatar.Avatar--big { + width: 66px; +} + +.Avatar.Avatar--huge { + width: 90px; +} + +.Avatar.Avatar--massive { + width: 122px; +} + +.Avatar.Avatar--full { + width: 100%; +} diff --git a/src/components/Common/Avatar.tsx b/src/components/Common/Avatar.tsx new file mode 100644 index 000000000..eb1f7778c --- /dev/null +++ b/src/components/Common/Avatar.tsx @@ -0,0 +1,59 @@ +import React, { useState } from 'react' + +import classNames from 'classnames' + +import useProfile from '../../hooks/useProfile' + +import './Avatar.css' + +export enum AvatarSize { + Mini = 'mini', + Tiny = 'tiny', + Small = 'small', + Medium = 'medium', + Large = 'large', + Big = 'big', + Huge = 'huge', + Massive = 'massive', + Full = 'full', +} + +const DEFAULT_AVATAR = 'https://decentraland.org/images/male.png' +type Props = { + size?: `${AvatarSize}` + src?: string + address?: string + className?: string +} + +export default function Avatar({ address, size, src, className }: Props) { + const [failed, setFailed] = useState(false) + + const { profile, isLoadingProfile } = useProfile(address) + + const getTarget = () => { + const avatar = profile?.avatar?.snapshots?.face256 || profile?.avatar?.snapshots?.face + if (src) { + return src + } else if (failed || !avatar) { + return DEFAULT_AVATAR + } + + return avatar + } + + return ( + setFailed(true)} + className={classNames( + 'Avatar', + `Avatar--${size || AvatarSize.Mini}`, + `Avatar--${((address || '')[2] || '').toLowerCase()}`, + !src && isLoadingProfile && `Avatar--loading`, + className + )} + /> + ) +} diff --git a/src/components/Grants/GrantCard/GrantCardHeadline.css b/src/components/Grants/GrantCard/GrantCardHeadline.css index cd512ee8f..d3aa88c3a 100644 --- a/src/components/Grants/GrantCard/GrantCardHeadline.css +++ b/src/components/Grants/GrantCard/GrantCardHeadline.css @@ -39,8 +39,8 @@ margin-right: 0 !important; } - .GrantCardHeadline__Avatar .dg.dcl-avatar, - .dg.dcl-avatar.dcl-avatar--medium { + .GrantCardHeadline__Avatar .Avatar, + .Avatar.Avatar--medium { width: 44px; margin-right: 0; } diff --git a/src/components/Modal/IdentityConnectModal/PostConnection.tsx b/src/components/Modal/IdentityConnectModal/PostConnection.tsx index 0a5f6adc7..a6396cc1f 100644 --- a/src/components/Modal/IdentityConnectModal/PostConnection.tsx +++ b/src/components/Modal/IdentityConnectModal/PostConnection.tsx @@ -1,11 +1,11 @@ import React from 'react' import Markdown from 'decentraland-gatsby/dist/components/Text/Markdown' -import Avatar from 'decentraland-gatsby/dist/components/User/Avatar' import useFormatMessage from 'decentraland-gatsby/dist/hooks/useFormatMessage' import { Button } from 'decentraland-ui/dist/components/Button/Button' import { Modal } from 'decentraland-ui/dist/components/Modal/Modal' +import Avatar from '../../Common/Avatar' import ForumBlue from '../../Icon/ForumBlue' import LinkFailed from '../../Icon/LinkFailed' import LinkSucceded from '../../Icon/LinkSucceded' diff --git a/src/components/Modal/Votes/VotesList.css b/src/components/Modal/Votes/VotesList.css index d2100c547..578efcd4f 100644 --- a/src/components/Modal/Votes/VotesList.css +++ b/src/components/Modal/Votes/VotesList.css @@ -56,7 +56,7 @@ border-bottom: none; } -.VotesList .dg.dcl-avatar { +.VotesList .Avatar { margin: 0 0.25em 0 0; } @@ -129,7 +129,7 @@ font-size: 13px; } - .VotesList .dg.dcl-avatar { + .VotesList .Avatar { margin: 0 0.25em 0 0; width: 20px; } diff --git a/src/components/Modal/VotingPowerDelegationModal/VotingPowerDelegationCandidatesList.css b/src/components/Modal/VotingPowerDelegationModal/VotingPowerDelegationCandidatesList.css index 90555122f..be4d6eecf 100644 --- a/src/components/Modal/VotingPowerDelegationModal/VotingPowerDelegationCandidatesList.css +++ b/src/components/Modal/VotingPowerDelegationModal/VotingPowerDelegationCandidatesList.css @@ -67,7 +67,7 @@ margin-left: 5px; } -.VotingPowerDelegationCandidatesList .dg.dcl-avatar { +.VotingPowerDelegationCandidatesList .Avatar { margin-right: 11px; } diff --git a/src/components/Proposal/Comments/ProposalComment.tsx b/src/components/Proposal/Comments/ProposalComment.tsx index 1215acbcf..c4f6fded6 100644 --- a/src/components/Proposal/Comments/ProposalComment.tsx +++ b/src/components/Proposal/Comments/ProposalComment.tsx @@ -1,6 +1,5 @@ import React from 'react' -import Avatar from 'decentraland-gatsby/dist/components/User/Avatar' import { Link } from 'decentraland-gatsby/dist/plugins/intl' import DOMPurify from 'dompurify' import isEthereumAddress from 'validator/lib/isEthereumAddress' @@ -8,6 +7,7 @@ import isEthereumAddress from 'validator/lib/isEthereumAddress' import { getUserProfileUrl } from '../../../entities/User/utils' import useProfile from '../../../hooks/useProfile' import Time from '../../../utils/date/Time' +import Avatar from '../../Common/Avatar' import Text from '../../Common/Text/Text' import ValidatedProfile from '../../Icon/ValidatedProfile' diff --git a/src/components/Proposal/ProposalItem.css b/src/components/Proposal/ProposalItem.css index 76b8d4717..cbad0c84d 100644 --- a/src/components/Proposal/ProposalItem.css +++ b/src/components/Proposal/ProposalItem.css @@ -102,7 +102,7 @@ color: var(--black-600); } -.ProposalItem__Details > span.Username > img.dg.dcl-avatar { +.ProposalItem__Details > span.Username > img.Avatar { margin: 0 !important; } diff --git a/src/components/Transparency/MemberCard.tsx b/src/components/Transparency/MemberCard.tsx index e9b9bdd79..9af96098b 100644 --- a/src/components/Transparency/MemberCard.tsx +++ b/src/components/Transparency/MemberCard.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from 'react' -import Avatar from 'decentraland-gatsby/dist/components/User/Avatar' +import Avatar from '../Common/Avatar' import './MemberCard.css' diff --git a/src/components/User/Username.css b/src/components/User/Username.css index 6dc0ef894..575464ec7 100644 --- a/src/components/User/Username.css +++ b/src/components/User/Username.css @@ -17,7 +17,7 @@ a.Username span.address { color: inherit; } -.Username img.dcl-avatar { +.Username img.Avatar { margin-right: 0.5rem; } diff --git a/src/components/User/Username.tsx b/src/components/User/Username.tsx index 44673d8db..aa72308d5 100644 --- a/src/components/User/Username.tsx +++ b/src/components/User/Username.tsx @@ -1,8 +1,6 @@ import React from 'react' import classNames from 'classnames' -import { Size, SizeProps } from 'decentraland-gatsby/dist/components/Props/types' -import Avatar from 'decentraland-gatsby/dist/components/User/Avatar' import { Link } from 'decentraland-gatsby/dist/plugins/intl' import { Address } from 'decentraland-ui/dist/components/Address/Address' import { Blockie } from 'decentraland-ui/dist/components/Blockie/Blockie' @@ -10,6 +8,7 @@ import { Blockie } from 'decentraland-ui/dist/components/Blockie/Blockie' import { getChecksumAddress } from '../../entities/Snapshot/utils' import useProfile from '../../hooks/useProfile' import locations from '../../utils/locations' +import Avatar, { AvatarSize } from '../Common/Avatar' import './Username.css' @@ -19,7 +18,8 @@ enum UsernameVariant { Full = 'full', } -type Props = SizeProps & { +type Props = { + size?: `${AvatarSize}` address: string linked?: boolean className?: string @@ -30,23 +30,23 @@ type Props = SizeProps & { function getBlockieScale(size?: string) { const DEFAULT_BLOCKIE_SCALE = 3.35 switch (size) { - case Size.Mini: + case AvatarSize.Mini: return 3 - case Size.Tiny: + case AvatarSize.Tiny: return DEFAULT_BLOCKIE_SCALE - case Size.Small: + case AvatarSize.Small: return 4.9 - case Size.Medium: + case AvatarSize.Medium: return 7 - case Size.Large: + case AvatarSize.Large: return 8.4 - case Size.Big: + case AvatarSize.Big: return 10.5 - case Size.Huge: + case AvatarSize.Huge: return 14.5 - case Size.Massive: + case AvatarSize.Massive: return 20 - case Size.Full: + case AvatarSize.Full: return 42.5 default: return DEFAULT_BLOCKIE_SCALE @@ -74,7 +74,7 @@ const Username = ({ address, size, linked, variant = UsernameVariant.Full, stron <> {hasDclProfile && ( <> - + {profileHasName && !isAvatarVariant && {profile!.name}} {!profileHasName && !isAvatarVariant &&
} diff --git a/src/hooks/useProfile.ts b/src/hooks/useProfile.ts index d397e442e..56892f165 100644 --- a/src/hooks/useProfile.ts +++ b/src/hooks/useProfile.ts @@ -8,7 +8,7 @@ export default function useProfile(address?: string | null) { if (!address) return null return profiles.load(address) } - const { data: profile } = useQuery({ + const { data: profile, isLoading: isLoadingProfile } = useQuery({ queryKey: [`userProfile#${address?.toLowerCase()}`], queryFn: () => fetchProfile(), staleTime: DEFAULT_QUERY_STALE_TIME, @@ -18,5 +18,5 @@ export default function useProfile(address?: string | null) { const profileHasName = hasDclProfile && profile!.name && profile!.name.length > 0 const displayableAddress = profileHasName ? profile.name : address - return { profile, hasDclProfile, displayableAddress } + return { profile, hasDclProfile, displayableAddress, isLoadingProfile } }