Skip to content

Commit

Permalink
Feat: Avatar 컴포넌트 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
haeyonghahn committed Jan 22, 2024
1 parent 60c1792 commit 6a3699c
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 2 deletions.
34 changes: 34 additions & 0 deletions src/_shared/icons/avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
interface IBasicProps {
[key: string]: JSX.Element;
}

const avatar: IBasicProps = {
user: (
<>
<path
d="M0 20C0 8.95431 8.95431 0 20 0V0C31.0457 0 40 8.95431 40 20V20C40 31.0457 31.0457 40 20 40V40C8.95431 40 0 31.0457 0 20V20Z"
fill="#F1F3F5"
/>
<g clipPath="url(#clip0_447_15831)">
<path
d="M0 20C0 8.95431 8.95431 0 20 0V0C31.0457 0 40 8.95431 40 20V20C40 31.0457 31.0457 40 20 40V40C8.95431 40 0 31.0457 0 20V20Z"
fill="#F1F3F5"
/>
<path
d="M40 34.9887V40.0004H0V35.007C2.32658 31.8978 5.34651 29.3743 8.81965 27.6371C12.2928 25.9 16.1233 24.9971 20.0067 25.0004C28.18 25.0004 35.44 28.9237 40 34.9887ZM26.67 14.9987C26.67 16.7668 25.9676 18.4625 24.7174 19.7127C23.4671 20.963 21.7714 21.6654 20.0033 21.6654C18.2352 21.6654 16.5395 20.963 15.2893 19.7127C14.039 18.4625 13.3367 16.7668 13.3367 14.9987C13.3367 13.2306 14.039 11.5349 15.2893 10.2847C16.5395 9.03441 18.2352 8.33203 20.0033 8.33203C21.7714 8.33203 23.4671 9.03441 24.7174 10.2847C25.9676 11.5349 26.67 13.2306 26.67 14.9987Z"
fill="#CED4DA"
/>
</g>
<defs>
<clipPath id="clip0_447_15831">
<path
d="M0 20C0 8.95431 8.95431 0 20 0V0C31.0457 0 40 8.95431 40 20V20C40 31.0457 31.0457 40 20 40V40C8.95431 40 0 31.0457 0 20V20Z"
fill="white"
/>
</clipPath>
</defs>
</>
),
};

export default avatar;
1 change: 1 addition & 0 deletions src/_shared/icons/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as social } from "./social";
export { default as icons } from "./basic";
export { default as avatar } from "./avatar";
5 changes: 5 additions & 0 deletions src/assets/default.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/puppy.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
106 changes: 106 additions & 0 deletions src/components/Avatar/Avatar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import styled from "styled-components";
import Avatar from "./Avatar";
import Typography from "@/foundations/Typography/Typography";
import Background from "@/foundations/Background";

export default {
title: "Components/Avatar",
component: Avatar,
};

export const AllTypes = () => (
<>
<Background theme="dark">
<AvatarBox>
<Typography text="Default" type="h3" />
<TypeBox>
<Avatar size="large" theme="dark" />
<Avatar size="medium" theme="dark" />
<Avatar size="small" theme="dark" />
</TypeBox>
</AvatarBox>
<AvatarBox>
<Typography text="Images" type="h3" />
<TypeBox>
<Avatar size="large" theme="dark" src="src\assets\default.svg" />
<Avatar size="medium" theme="dark" src="src\assets\default.svg" />
<Avatar size="small" theme="dark" src="src\assets\default.svg" />
</TypeBox>
<TypeBox>
<Avatar size="large" theme="dark" src="src\assets\puppy.jpg" />
<Avatar size="medium" theme="dark" src="src\assets\puppy.jpg" />
<Avatar size="small" theme="dark" src="src\assets\puppy.jpg" />
</TypeBox>
</AvatarBox>
<AvatarBox>
<Typography text="Lodings" type="h3" />
<TypeBox>
<Avatar size="large" isloading="true" theme="dark" />
<Avatar size="medium" isloading="true" theme="dark" />
<Avatar size="small" isloading="true" theme="dark" />
</TypeBox>
</AvatarBox>
<AvatarBox>
<Typography text="Initials" type="h3" />
<TypeBox>
<Avatar size="large" theme="dark" username="[email protected]" />
<Avatar size="medium" theme="dark" username="[email protected]" />
<Avatar size="small" theme="dark" username="[email protected]" />
</TypeBox>
</AvatarBox>
</Background>
<Background theme="light">
<AvatarBox>
<Typography text="Default" type="h3" />
<TypeBox>
<Avatar size="large" theme="light" />
<Avatar size="medium" theme="light" />
<Avatar size="small" theme="light" />
</TypeBox>
</AvatarBox>
<AvatarBox>
<Typography text="Images" type="h3" />
<TypeBox>
<Avatar size="large" theme="light" src="src\assets\default.svg" />
<Avatar size="medium" theme="light" src="src\assets\default.svg" />
<Avatar size="small" theme="light" src="src\assets\default.svg" />
</TypeBox>
<TypeBox>
<Avatar size="large" theme="light" src="src\assets\puppy.jpg" />
<Avatar size="medium" theme="light" src="src\assets\puppy.jpg" />
<Avatar size="small" theme="light" src="src\assets\puppy.jpg" />
</TypeBox>
</AvatarBox>
<AvatarBox>
<Typography text="Lodings" type="h3" />
<TypeBox>
<Avatar size="large" isloading="true" theme="light" />
<Avatar size="medium" isloading="true" theme="light" />
<Avatar size="small" isloading="true" theme="light" />
</TypeBox>
</AvatarBox>
<AvatarBox>
<Typography text="Initials" type="h3" />
<TypeBox>
<Avatar size="large" theme="light" username="[email protected]" />
<Avatar size="medium" theme="light" username="[email protected]" />
<Avatar size="small" theme="light" username="[email protected]" />
</TypeBox>
</AvatarBox>
</Background>
</>
);

const TypeBox = styled.div`
display: flex;
flex-direction: row;
gap: 1rem;
padding: 1rem;
align-items: center;
`;

const AvatarBox = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
`;
77 changes: 77 additions & 0 deletions src/components/Avatar/Avatar.styled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { colors } from "@/_shared/colors";
import loadings from "@/_shared/animations/loadings";
import styled, { css } from "styled-components";

interface IObjectProps {
[key: string]: string;
}

interface IAvatarProps {
size: string;
isloading?: string;
theme: string;
}

const fontSize: IObjectProps = {
extraLarge: "3rem",
large: "1.25rem",
medium: "0.875rem",
small: "0.625rem",
};

const sizeNum: IObjectProps = {
extraLarge: "100px",
large: "40px",
medium: "28px",
small: "20px",
};

export const Image = styled.figure<IAvatarProps>`
display: inline-block;
object-fit: cover;
height: ${(props) => sizeNum[props.size]};
width: ${(props) => sizeNum[props.size]};
min-width: ${(props) => sizeNum[props.size]};
margin: 0;
border-radius: 50%;
background-color: ${colors.gray100};
line-height: ${(props) => sizeNum[props.size]};
user-select: none;
text-transform: uppercase;
user-select: none;
img {
width: 100%;
height: auto;
display: block;
object-fit: cover;
border-radius: 50%;
}
svg {
position: relative;
height: 100%;
width: 100%;
vertical-align: top;
}
${(props) =>
props.isloading === "true"
? css`
backdrop-filter: blur(4px);
cursor: progress;
${props.theme === "dark" ? loadings.dark : loadings.light}
`
: null}
`;

export const Initial = styled.div<IAvatarProps>`
text-align: center;
color: ${colors.gray800};
user-select: none;
font-size: ${(props) => fontSize[props.size]};
line-height: "100px";
`;
30 changes: 30 additions & 0 deletions src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Image, Initial } from "./Avatar.styled";
import AvatarBase from "./AvatarBase";

interface Avatar {
size: string;
isloading?: string;
theme: string;
username?: string;
src?: string;
}

const Avatar = ({ size, isloading, theme, src, username }: Avatar) => {
let avatarFigure = <AvatarBase image="user" />;
if (isloading === "true") {
avatarFigure = <></>;
} else if (src) {
avatarFigure = <img src={src} alt={username}></img>;
} else if (username) {
avatarFigure = <Initial size={size}>{username.substring(0, 1)}</Initial>;
}
return (
<>
<Image size={size} isloading={isloading} theme={theme}>
{avatarFigure}
</Image>
</>
);
};

export default Avatar;
21 changes: 21 additions & 0 deletions src/components/Avatar/AvatarBase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { avatar } from "@/_shared/icons";

interface IAvatarBaseProps {
image: string;
}

const AvatarBase = ({ image }: IAvatarBaseProps) => {
return (
<svg
width="40"
height="40"
viewBox="0 0 40 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
{avatar[image]}
</svg>
);
};

export default AvatarBase;
15 changes: 14 additions & 1 deletion src/components/Input/Input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,23 @@ export const AllTypes = () => (
status="default"
placeholder="닉네임 입력 (15자 이내)"
theme="dark"
handleChange={() => console.log("handleChange")}
/>
<Input
status="default"
title="라벨"
theme="dark"
placeholder="닉네임 입력 (15자 이내)"
message="This is a hint text to help user."
handleChange={() => console.log("handleChange")}
/>
<Input
status="error"
title="닉네임"
theme="dark"
placeholder="닉네임 입력 (15자 이내)"
message="This is error message."
handleChange={() => console.log("handleChange")}
/>
<Input
status="default"
Expand All @@ -39,6 +42,7 @@ export const AllTypes = () => (
placeholder="이메일"
message="가입한 이메일 주소를 입력해주세요."
icon="email"
handleChange={() => console.log("handleChange")}
/>
<Input
status="error"
Expand All @@ -47,24 +51,31 @@ export const AllTypes = () => (
icon="isDarkCancel"
icondirection="right"
message="15자 이내로 입력해주세요."
handleChange={() => console.log("handleChange")}
/>
</TypeBox>
</Background>
<Background theme="white">
<TypeBox>
<Typography type="h3" text="Default" />
<Input status="default" placeholder="닉네임 입력 (15자 이내)" />
<Input
status="default"
placeholder="닉네임 입력 (15자 이내)"
handleChange={() => console.log("handleChange")}
/>
<Input
status="default"
placeholder="닉네임 입력 (15자 이내)"
title="라벨"
message="This is a hint text to help user."
handleChange={() => console.log("handleChange")}
/>
<Input
status="error"
placeholder="닉네임 입력 (15자 이내)"
title="닉네임"
message="This is error message."
handleChange={() => console.log("handleChange")}
/>
<Input
status="default"
Expand All @@ -73,6 +84,7 @@ export const AllTypes = () => (
placeholder="이메일"
message="가입한 이메일 주소를 입력해주세요."
icon="email"
handleChange={() => console.log("handleChange")}
/>
<Input
status="error"
Expand All @@ -81,6 +93,7 @@ export const AllTypes = () => (
icon="isWhiteCancel"
icondirection="right"
message="15자 이내로 입력해주세요."
handleChange={() => console.log("handleChange")}
/>
</TypeBox>
</Background>
Expand Down
1 change: 0 additions & 1 deletion src/foundations/Color/Color.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import styled from "styled-components";
import { colors } from "@/_shared/colors";
import { fontSize } from "@/_shared/typography";

export default {
title: "Foundations/Color",
Expand Down

0 comments on commit 6a3699c

Please sign in to comment.