Browse Source

Add Initials If No Image Is Available To Avatar Component

Francesco Baccetti 4 years ago
parent
commit
407736a8f2

+ 30 - 12
packages/components/src/components/Avatar/Avatar.style.tsx

@@ -1,19 +1,37 @@
-import { css } from "@emotion/core";
+import { makeStyles, StyleFn } from "../../utils";
 import { spacing, colors } from "../../theme";
 
 export type AvatarStyleProps = {
-	img?: string;
-	size?: "small" | "default" | "large";
+	size: "small" | "default" | "large";
 };
 
-export let makeStyles = ({ img, size = "default" }: AvatarStyleProps) => {
+const container: StyleFn = (_, { size = "default" }) => {
 	let width = size === "small" ? spacing.xs : size === "default" ? spacing.m : spacing.xl;
-	return css`
-		background-image: ${img ? `url(${img})` : `radial-gradient(${colors.gray[500]}, ${colors.gray[500]})`};
-		background-size: cover;
-		background-position: center;
-		border-radius: 999px;
-		min-width: ${width};
-		min-height: ${width};
-	`;
+	return {
+		borderRadius: 999,
+		minWidth: width,
+		backgroundColor: colors.gray[500],
+		color: colors.white,
+		display: "flex",
+		justifyContent: "center",
+		alignItems: "center",
+
+		"& > span": {
+			textTransform: "uppercase",
+			fontSize: "0.875rem",
+			lineHeight: 1.43,
+		},
+	};
 };
+
+const img: StyleFn = () => ({
+	width: "100%",
+	height: "100%",
+	objectFit: "cover",
+	borderRadius: 999,
+});
+
+export const useCSS = (props: Partial<AvatarStyleProps>) => ({
+	container: makeStyles([container])(props),
+	img: makeStyles([img])(props),
+});

+ 20 - 6
packages/components/src/components/Avatar/Avatar.tsx

@@ -1,13 +1,27 @@
 import React from "react";
 import { SerializedStyles } from "@emotion/core";
-import { makeStyles, AvatarStyleProps } from "./Avatar.style";
+import { useCSS, AvatarStyleProps } from "./Avatar.style";
 
 export type AvatarProps = {
-	onClick?: (e: React.MouseEvent<HTMLElement>) => void;
-	outerStyles?: SerializedStyles;
+	onClick: (e: React.MouseEvent<HTMLElement>) => void;
+	outerStyles: SerializedStyles;
+	img: string;
+	name: string;
 } & AvatarStyleProps;
 
-export default function Avatar({ onClick = () => {}, outerStyles, ...styleProps }: AvatarProps) {
-	let styles = makeStyles(styleProps);
-	return <div css={[styles, outerStyles]} onClick={onClick} />;
+function initialsFromName(name: string): string {
+	const vowels = ["a", "e", "i", "o", "u", "y"];
+	const [first = "", second = ""] = name.split("");
+	return vowels.includes(second) ? first : `${first}${second}`;
 }
+
+const Avatar: React.FC<Partial<AvatarProps>> = ({ img, outerStyles, onClick = () => {}, name, ...styleProps }) => {
+	const styles = useCSS({ ...styleProps });
+	return (
+		<div css={[styles.container, outerStyles]} onClick={onClick}>
+			{img ? <img src={img} css={styles.img} /> : <span>{initialsFromName(name || "")}</span>}
+		</div>
+	);
+};
+
+export default Avatar;

+ 7 - 1
packages/components/src/components/VideoPreview/VideoPreview.tsx

@@ -38,7 +38,13 @@ const VideoPreview: React.FC<Partial<VideoPreviewProps>> = ({
 			</div>
 			<div css={styles.infoContainer}>
 				{showChannel && (
-					<Avatar size="small" img={channelImg} outerStyles={styles.avatar} onClick={onChannelClick} />
+					<Avatar
+						size="small"
+						name={channel}
+						img={channelImg}
+						outerStyles={styles.avatar}
+						onClick={onChannelClick}
+					/>
 				)}
 				<div css={styles.textContainer}>
 					<h3 onClick={onClick}>{title}</h3>