Skip to content

Commit

Permalink
Update Avatar to new design spec (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
germain-gg authored Aug 9, 2023
1 parent c437b6d commit 93d2966
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 59 deletions.
45 changes: 20 additions & 25 deletions src/components/Avatar/Avatar.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,80 +16,75 @@ limitations under the License.

.avatar {
display: inline-block;
aspect-ratio: 1 / 1;
width: var(--cpd-avatar-size);
box-sizing: border-box;
line-height: var(--cpd-avatar-size);
text-align: center;
font-size: min(calc(var(--cpd-avatar-size) * 0.75), 60px);
border-radius: var(--cpd-avatar-radius);
font-size: min(calc(var(--cpd-avatar-size) * 0.5625), 60px);
text-transform: uppercase;
speak: none;
pointer-events: none;
font-weight: normal;
font-weight: bold;
overflow: hidden;
user-select: none;
}

img.avatar {
.avatar,
.image {
aspect-ratio: 1 / 1;
width: var(--cpd-avatar-size);
border-radius: var(--cpd-avatar-radius);
}

.image {
object-fit: cover;
overflow: hidden;
}

.avatar:not([src]) {
.avatar:not(:has(.image)) {
/* In the future we'd prefer to pass the HEX code as the data attr
and use `attr(data-color)` to avoid the style declaration from below
but this is currently not supported in all browsers */
background: var(--cpd-avatar-bg);
border: 1px solid var(--cpd-avatar-border);
color: var(--cpd-avatar-color);
}

.avatar[data-color] {
--cpd-avatar-bg: var(--cpd-color-blue-300);
--cpd-avatar-border: var(--cpd-color-blue-400);
--cpd-avatar-color: var(--cpd-color-blue-900);
--cpd-avatar-color: var(--cpd-color-blue-1200);
}

.avatar[data-color="2"] {
--cpd-avatar-bg: var(--cpd-color-fuchsia-300);
--cpd-avatar-border: var(--cpd-color-fuchsia-400);
--cpd-avatar-color: var(--cpd-color-fuchsia-900);
--cpd-avatar-color: var(--cpd-color-fuchsia-1200);
}

.avatar[data-color="3"] {
--cpd-avatar-bg: var(--cpd-color-green-300);
--cpd-avatar-border: var(--cpd-color-green-400);
--cpd-avatar-color: var(--cpd-color-green-900);
--cpd-avatar-color: var(--cpd-color-green-1200);
}

.avatar[data-color="4"] {
--cpd-avatar-bg: var(--cpd-color-pink-300);
--cpd-avatar-border: var(--cpd-color-pink-400);
--cpd-avatar-color: var(--cpd-color-pink-900);
--cpd-avatar-color: var(--cpd-color-pink-1200);
}

.avatar[data-color="5"] {
--cpd-avatar-bg: var(--cpd-color-orange-300);
--cpd-avatar-border: var(--cpd-color-orange-400);
--cpd-avatar-color: var(--cpd-color-orange-900);
--cpd-avatar-color: var(--cpd-color-orange-1200);
}

.avatar[data-color="6"] {
--cpd-avatar-bg: var(--cpd-color-cyan-300);
--cpd-avatar-border: var(--cpd-color-cyan-400);
--cpd-avatar-color: var(--cpd-color-cyan-900);
--cpd-avatar-color: var(--cpd-color-cyan-1200);
}

.avatar[data-color="7"] {
--cpd-avatar-bg: var(--cpd-color-purple-300);
--cpd-avatar-border: var(--cpd-color-purple-400);
--cpd-avatar-color: var(--cpd-color-purple-900);
--cpd-avatar-color: var(--cpd-color-purple-1200);
}

.avatar[data-color="8"] {
--cpd-avatar-bg: var(--cpd-color-lime-300);
--cpd-avatar-border: var(--cpd-color-lime-400);
--cpd-avatar-color: var(--cpd-color-lime-900);
--cpd-avatar-color: var(--cpd-color-lime-1200);
}

.avatar[data-type="round"] {
Expand Down
72 changes: 40 additions & 32 deletions src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,60 +15,68 @@ limitations under the License.
*/

import classnames from "classnames";
import React, { Suspense } from "react";
import React, { Suspense, forwardRef } from "react";
import { getInitialLetter } from "../../utils/string";
import { SuspenseImg } from "../../utils/SuspenseImg";
import styles from "./Avatar.module.css";
import { useIdColorHash } from "./useIdColorHash";

type AvatarProps = {
src?: string;
type AvatarProps = JSX.IntrinsicElements["span"] & {
src?: React.ComponentProps<typeof SuspenseImg>["src"];
id: string;
name: string;
type?: "square" | "round";
className?: string;
size?: CSSStyleDeclaration["height"];
onError?: React.ComponentProps<typeof SuspenseImg>["onError"];
};

export const Avatar: React.FC<AvatarProps> = ({
src,
id,
name = "",
type = "round",
className = "",
size,
}) => {
export const Avatar = forwardRef<HTMLSpanElement, AvatarProps>(function Avatar(
{
src,
id,
name = "",
type = "round",
className = "",
size,
onError,
...props
},
ref,
) {
const hash = useIdColorHash(id);
const style = {
"--cpd-avatar-size": size,
} as React.CSSProperties;
const imagelessAvatar = (
const fallbackInitial = <>{getInitialLetter(name)}</>;

return (
<span
ref={ref}
role="img"
title={id}
{...props}
aria-label=""
data-type={type}
data-color={hash}
className={classnames(styles.avatar, className)}
style={style}
title={id}
>
{getInitialLetter(name)}
{!src ? (
fallbackInitial
) : (
<Suspense fallback={fallbackInitial}>
<SuspenseImg
src={src}
className={classnames(styles.image, className)}
data-type={type}
style={style}
width={size}
height={size}
title={id}
onError={onError}
/>
</Suspense>
)}
</span>
);

return !src ? (
imagelessAvatar
) : (
<Suspense fallback={imagelessAvatar}>
<SuspenseImg
src={src}
className={classnames(styles.avatar, className)}
data-type={type}
style={style}
width={size}
height={size}
title={id}
/>
</Suspense>
);
};
});
4 changes: 2 additions & 2 deletions src/utils/SuspenseImg.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ const imgCache = {
},
};

type SuspenseImgProps = {
type SuspenseImgProps = JSX.IntrinsicElements["img"] & {
src: string;
} & React.ImgHTMLAttributes<HTMLImageElement>;
};

export const SuspenseImg: React.FC<SuspenseImgProps> = ({ src, ...props }) => {
/**
Expand Down

0 comments on commit 93d2966

Please sign in to comment.