From e080bd0aedf5f154c1cca248762eeddaae5b2369 Mon Sep 17 00:00:00 2001 From: DenisVorop Date: Mon, 28 Aug 2023 19:20:08 +0300 Subject: [PATCH] fix(UserPic): show colored circle by default --- src/components/Circle.tsx | 26 +++++++++++++++ src/components/Gravatar.tsx | 43 +++++++++++++------------ src/components/UserPic.tsx | 63 ++++++++----------------------------- src/utils/getInitials.ts | 5 +++ src/utils/preloadImage.ts | 15 +++++++++ 5 files changed, 80 insertions(+), 72 deletions(-) create mode 100644 src/components/Circle.tsx create mode 100644 src/utils/getInitials.ts create mode 100644 src/utils/preloadImage.ts diff --git a/src/components/Circle.tsx b/src/components/Circle.tsx new file mode 100644 index 00000000..401f4924 --- /dev/null +++ b/src/components/Circle.tsx @@ -0,0 +1,26 @@ +import styled from 'styled-components'; + +import { stringToColor, isColorDark } from '../utils/stringToColor'; + +export const Circle = styled.div<{ size: number; str: string }>` + border-radius: 100%; + + ${({ size, str }) => { + const mainColor = stringToColor(str); + return { + width: `${size}px`, + height: `${size}px`, + background: `linear-gradient(90deg,${mainColor},${stringToColor(str.toUpperCase())})`, + color: `${isColorDark(mainColor) ? 'white' : 'black'}`, + fontSize: `calc(${size / 2}px - 2px)`, + }; + }}; + + display: flex; + align-items: center; + justify-content: center; + + letter-spacing: -1.5px; + font-weight: 600; + user-select: none; +`; diff --git a/src/components/Gravatar.tsx b/src/components/Gravatar.tsx index 814f0d06..a6aa37cb 100644 --- a/src/components/Gravatar.tsx +++ b/src/components/Gravatar.tsx @@ -1,9 +1,12 @@ -import React, { FC, useCallback, useEffect, useRef } from 'react'; +import React, { FC, useState } from 'react'; import md5Hash from 'md5'; import styled from 'styled-components'; import { isRetina } from '../utils/isRetina'; -import { useMounted } from '../hooks'; +import { preloadImage } from '../utils/preloadImage'; +import { getInitials } from '../utils/getInitials'; + +import { Circle } from './Circle'; interface GravatarProps extends React.HTMLAttributes { email?: string | null; @@ -13,8 +16,8 @@ interface GravatarProps extends React.HTMLAttributes { def?: string; className?: string; domain?: string; + name?: string | null; - onLoadError?: () => void; onClick?: () => void; } @@ -30,13 +33,11 @@ export const Gravatar: FC = ({ domain = process.env.NEXT_PUBLIC_GRAVATAR_HOST || 'www.gravatar.com', email, md5, - onLoadError, + name, ...props }) => { - const mounted = useMounted(); - const imgRef = useRef(null); - - const base = `//${domain}/avatar/`; + const [isError, setIsError] = useState(false); + const [isLoad, setIsLoad] = useState(false); const query = new URLSearchParams({ s: String(size), @@ -52,14 +53,6 @@ export const Gravatar: FC = ({ const formattedEmail = email?.trim().toLowerCase() || ''; - const onError: React.ReactEventHandler = useCallback( - ({ currentTarget }) => { - currentTarget.onerror = null; - onLoadError?.(); - }, - [onLoadError], - ); - let hash; if (md5) { hash = md5; @@ -71,14 +64,20 @@ export const Gravatar: FC = ({ return