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 && (
<>
-