Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Header 컴포넌트 구현 #167

Merged
merged 16 commits into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions packages/wow-icons/src/component/GdscLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { forwardRef } from "react";

import type { IconProps } from "@/types/Icon.ts";

const GdscLogo = forwardRef<SVGSVGElement, IconProps>(
(
{ className, width = "49", height = "24", viewBox = "0 0 49 24", ...rest },
ref
) => {
return (
<svg
aria-label="gdsc-logo icon"
className={className}
fill="none"
height={height}
ref={ref}
viewBox={viewBox}
width={width}
xmlns="http://www.w3.org/2000/svg"
{...rest}
>
<g clipPath="url(#clip0_2093_1197)">
<path
d="M11.6948 12.0594L19.6432 7.40217C21.5086 6.3148 22.1575 3.89388 21.0828 1.98586C20.0082 0.0778397 17.6155 0.558167 15.7298 0.529199L1.98242 8.55108L11.6948 12.0594Z"
fill="#EA4335"
/>
<path
d="M17.6764 23.9997C19.0349 23.9997 20.3529 23.2816 21.0625 22.0096C22.1372 20.1221 21.5086 17.7012 19.6229 16.5933L5.87549 8.57144C4.01006 7.48407 1.61744 8.12008 0.522517 10.0281C0.552134 11.9156 0.0764355 14.3365 1.96214 15.4444L15.7096 23.4663C16.3381 23.8151 17.0275 23.9997 17.6764 23.9997Z"
fill="#4285F4"
/>
<path
d="M31.3633 23.9999C32.0324 23.9999 32.7015 23.8358 33.3098 23.4665L47.0572 15.4446L37.4867 11.8953L29.4167 16.614C27.5513 17.7014 26.9024 20.1223 27.9771 22.0303C28.6868 23.2818 30.0047 23.9999 31.3633 23.9999Z"
fill="#FBBC04"
/>
<path
d="M45.0897 15.9572C46.4482 15.9572 47.7662 15.2392 48.4758 13.9877C49.5505 12.1002 48.9219 9.67923 47.0362 8.57135L33.3091 0.549463C31.4437 0.537903 29.051 0.0981031 27.9561 2.00612C26.8815 3.89362 27.51 6.31455 29.3957 7.42243L43.1431 15.4443C43.7514 15.7931 44.4206 15.9572 45.0897 15.9572Z"
fill="#0F9D58"
/>
</g>
<defs>
<clipPath id="clip0_2093_1197">
<rect fill="white" height={height} width={width} />
</clipPath>
</defs>
</svg>
);
}
);

GdscLogo.displayName = "GdscLogo";
export default GdscLogo;
1 change: 1 addition & 0 deletions packages/wow-icons/src/component/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { default as Check } from "./Check.tsx";
export { default as Close } from "./Close.tsx";
export { default as DownArrow } from "./DownArrow.tsx";
export { default as Edit } from "./Edit.tsx";
export { default as GdscLogo } from "./GdscLogo.tsx";
export { default as Help } from "./Help.tsx";
export { default as LeftArrow } from "./LeftArrow.tsx";
export { default as Link } from "./Link.tsx";
Expand Down
13 changes: 13 additions & 0 deletions packages/wow-icons/src/svg/gdsc-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions packages/wow-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@
"require": "./dist/MultiGroup.cjs",
"import": "./dist/MultiGroup.js"
},
"./Header": {
"types": "./dist/components/Header/index.d.ts",
"require": "./dist/Header.cjs",
"import": "./dist/Header.js"
},
"./DropDownOption": {
"types": "./dist/components/DropDown/DropDownOption.d.ts",
"require": "./dist/DropDownOption.cjs",
Expand Down
1 change: 1 addition & 0 deletions packages/wow-ui/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default {
SingleDatePicker: "./src/components/Picker/SingleDatePicker",
TimePicker: "./src/components/Picker/TimePicker",
MultiGroup: "./src/components/MultiGroup",
Header: "./src/components/Header",
DropDownOption: "./src/components/DropDown/DropDownOption",
DropDown: "./src/components/DropDown",
Divider: "./src/components/Divider",
Expand Down
68 changes: 68 additions & 0 deletions packages/wow-ui/src/components/Header/Header.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { Meta, StoryObj } from "@storybook/react";

import Header from "@/components/Header";

const meta = {
title: "UI/Header",
component: Header,
tags: ["autodocs"],
parameters: {
componentSubtitle: "헤더 컴포넌트",
a11y: {
config: {
rules: [{ id: "color-contrast", enabled: false }],
},
},
},
argTypes: {
variant: {
control: {
type: "select",
options: ["username", "login", "none"],
},
table: {
type: { summary: "username | login | none" },
},
description:
'헤더 종류를 나타냅니다. variant가 "username"인 경우 오른쪽에 사용자 이름을, "login"인 경우 로그인 버튼을, "none"인 경우 아무것도 표시하지 않습니다.',
},
ghdtjgus76 marked this conversation as resolved.
Show resolved Hide resolved
username: {
control: {
type: "text",
},
table: {
type: { summary: "string" },
},
description:
'variant가 "username"인 경우 표시되는 오른쪽 요소입니다. 사용자가 로그인한 경우 사용자 이름을 표시합니다.',
},
onClick: {
action: "clicked",
control: false,
table: {
type: { summary: "function" },
},
description:
'variant가 "login"인 경우 전달할 수 있습니다. 로그인 버튼 클릭 시 호출되는 함수입니다.',
},
},
} satisfies Meta<typeof Header>;

export default meta;

export const Default: StoryObj<typeof Header> = {
args: {},
};

export const Login: StoryObj<typeof Header> = {
args: {
variant: "login",
},
};

export const Username: StoryObj<typeof Header> = {
args: {
variant: "username",
username: "김홍익",
},
};
123 changes: 123 additions & 0 deletions packages/wow-ui/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* @description 헤더 컴포넌트입니다.
* 사이트 로고와 로그인 또는 사용자 이름 표시 기능을 포함합니다.
*
* @template T
* @param {"username" | "login" | "none"} [variant] - Header 종류.
* - "username": 사용자 이름을 표시.
* - "login": 로그인 버튼을 표시.
* - "none": 아무것도 표시하지 않음.
* @param {T extends "username" ? string : never} [username] - variant가 "username"인 경우 표시되는 오른쪽 요소. 사용자가 로그인한 경우 사용자 이름을 표시함.
* @param {T extends "login" ? () => void : never} [onClick] - 로그인 버튼 클릭 시 호출되는 함수.
*/

import { css } from "@styled-system/css";
import { Flex } from "@styled-system/jsx";
import { GdscLogo } from "wowds-icons";

import Button from "@/components/Button";

type RightElementType = "username" | "login" | "none";

export interface HeaderProps<T extends RightElementType> {
variant?: T;
username?: T extends "username" ? string : never;
onClick?: T extends "login" ? () => void : never;
}

const Header = ({
variant = "none",
username,
onClick,
}: HeaderProps<RightElementType>) => {
return (
<header aria-label="header" className={headerStyle} role="banner">
<div className={headerContentStyle}>
<section className={leftElementContainerStyle}>
<GdscLogo aria-label="gdsc-logo" role="img" />
<Flex className={logoTextContainerStyle}>
<div aria-level={1} className={titleStyle} role="heading">
GDSC
</div>
<div aria-level={2} className={subTitleStyle} role="heading">
Hongik Univ.
</div>
ghdtjgus76 marked this conversation as resolved.
Show resolved Hide resolved
</Flex>
</section>
<section>
{variant === "login" && (
<Button size="sm" variant="outline" onClick={onClick}>
로그인/가입하기
</Button>
)}
{variant === "username" && (
<div aria-label={`${username} 님`} className={usernameTextStyle}>
{username} 님
</div>
)}
</section>
</div>
</header>
);
};

export default Header;

const headerStyle = css({
borderBottomStyle: "solid",
borderBottomWidth: 1,
borderBottomColor: "outline",
height: "54px",
width: "100%",
display: "flex",
alignItems: "center",
xsToLg: {
paddingX: "16px",
height: "66px",
},
});

const headerContentStyle = css({
width: "988px",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
margin: "auto",
});

const leftElementContainerStyle = css({
display: "flex",
gap: "xs",
alignItems: "center",
});

const titleStyle = css({
fontFamily: "Product Sans",
fontWeight: 700,
fontSize: "20px",
lineHeight: "130%",
});

const subTitleStyle = css({
fontFamily: "Product Sans",
fontWeight: 400,
fontSize: "14px",
lineHeight: "130%",
color: "primary",
});

const usernameTextStyle = css({
textStyle: "label1",
});

const logoTextContainerStyle = css({
lg: {
gap: "xs",
alignItems: "center",
},
xsToLg: {
flexDirection: "column",
justifyContent: "flex-start",
alignItems: "space-between",
},
});
2 changes: 1 addition & 1 deletion packages/wow-ui/src/components/Spinner/BlueSpinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { LottieComponentProps } from "lottie-react";
import Lottie from "lottie-react";
import type { CSSProperties } from "react";

import blueSpinner from "@/assets/lottie/blueSpinner.json";
import blueSpinner from "@/assets/lotties/blueSpinner.json";

/**
* @description 블루 스피너 컴포넌트입니다.
Expand Down
2 changes: 1 addition & 1 deletion packages/wow-ui/src/components/Spinner/RainbowSpinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { LottieComponentProps } from "lottie-react";
import Lottie from "lottie-react";
import type { CSSProperties } from "react";

import rainbowSpinner from "@/assets/lottie/rainbowSpinner.json";
import rainbowSpinner from "@/assets/lotties/rainbowSpinner.json";

/**
* @description 레인보우 스피너 컴포넌트입니다. Lottie 애니메이션을 사용하여 스피너를 표시합니다.
Expand Down
Loading
Loading