Skip to content

Commit 2cc9b6d

Browse files
authored
Merge pull request #19 from Team-3-2/design/common-components
#3 Header, Gnb 공통 컴포넌트 구현
2 parents 572dd22 + a0860e4 commit 2cc9b6d

File tree

10 files changed

+206
-3
lines changed

10 files changed

+206
-3
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,6 @@ next-env.d.ts
4343

4444
*storybook.log
4545
storybook-static
46+
47+
# vscode
48+
.vscode

src/app/example/page.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Header from "@/components/header/Header";
2+
import React from "react";
3+
4+
const Page = () => {
5+
return (
6+
<div>
7+
<Header
8+
review="5,446"
9+
title="Sentinel Carbernet Sauvignon 2016"
10+
description="Western Cape, South Africa"
11+
price="64,990"
12+
/>
13+
</div>
14+
);
15+
};
16+
17+
export default Page;

src/app/globals.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,13 @@ body {
3333
* {
3434
box-sizing: border-box;
3535
}
36+
37+
@layer utilities {
38+
.flex-center {
39+
@apply flex items-center justify-center;
40+
}
41+
42+
.flex-col-center {
43+
@apply flex flex-col items-center justify-center;
44+
}
45+
}

src/app/layout.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Metadata } from "next";
22
import { sfPro } from "./fonts";
33
import "./globals.css";
4+
import { Gnb } from "@/components";
45
import QueryProvider from "@/providers/query-provider";
56

67
export const metadata: Metadata = {
@@ -14,9 +15,12 @@ export default function RootLayout({
1415
children: React.ReactNode;
1516
}>) {
1617
return (
17-
<html lang="en" className={sfPro.variable}>
18-
<body className="antialiased">
19-
<QueryProvider>{children}</QueryProvider>
18+
<html lang="ko" className={sfPro.variable}>
19+
<body className="mt-32">
20+
<QueryProvider>
21+
<Gnb />
22+
{children}
23+
</QueryProvider>
2024
</body>
2125
</html>
2226
);

src/components/gnb/Gnb.stories.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Meta, StoryObj } from "@storybook/nextjs";
2+
import Gnb from "./Gnb";
3+
4+
const meta = {
5+
title: "Components/Gnb",
6+
component: Gnb,
7+
parameters: {
8+
layout: "centered",
9+
},
10+
tags: ["autodocs"],
11+
} satisfies Meta<typeof Gnb>;
12+
13+
export default meta;
14+
type Story = StoryObj<typeof meta>;
15+
16+
export const Basic: Story = {
17+
render: () => <Gnb />,
18+
};

src/components/gnb/Gnb.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { cn } from "@/lib/utils";
2+
import Link from "next/link";
3+
4+
const LinkMenu = [
5+
{ name: "WHYNE", href: "/" },
6+
{
7+
name: "로그인",
8+
href: "/login",
9+
style: "underline-offset-2 hover:underline",
10+
},
11+
];
12+
13+
const Gnb = () => {
14+
return (
15+
<header
16+
className={cn(
17+
"fixed left-1/2 top-0 flex -translate-x-1/2 items-center justify-between bg-black",
18+
"h-[50px] w-full gap-[10px] px-5 py-[15px]",
19+
"tablet:rounded-1 tablet:top-10 tablet:h-[70px] tablet:w-[704px] tablet:px-[60px] tablet:py-[11px]",
20+
"pc:rounded-1 pc:top-10 pc:h-[70px] pc:w-[1140px] pc:px-[60px] pc:py-[11px]"
21+
)}
22+
>
23+
{/* TODO(지권): 로고 아이콘 추가 및 로그인 상태 추가 */}
24+
{LinkMenu.map((menu) => (
25+
<Link
26+
key={menu.name}
27+
href={menu.href}
28+
className={cn("leading-[26px] text-white", menu.style)}
29+
>
30+
{menu.name}
31+
</Link>
32+
))}
33+
</header>
34+
);
35+
};
36+
37+
export default Gnb;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import type { Meta, StoryObj } from "@storybook/nextjs";
2+
import Header from "./Header";
3+
4+
const meta: Meta<typeof Header> = {
5+
title: "Components/Header",
6+
component: Header,
7+
parameters: {
8+
layout: "centered",
9+
},
10+
argTypes: {
11+
review: { control: { type: "text" } },
12+
title: { control: { type: "text" } },
13+
description: { control: { type: "text" } },
14+
price: { control: { type: "text" } },
15+
},
16+
};
17+
18+
export default meta;
19+
20+
type Story = StoryObj<typeof Header>;
21+
22+
export const Default: Story = {
23+
args: {
24+
review: "128",
25+
title: "샤또 마고 2015",
26+
description: "블랙커런트와 바이올렛 아로마, 벨벳 같은 타닌",
27+
price: "64,990",
28+
},
29+
};
30+
31+
export const ManyReviews: Story = {
32+
name: "리뷰가 많은 경우",
33+
args: {
34+
review: "12,345",
35+
title: "도멘 드 라 로마네 콩티",
36+
description: "풍부한 베리 계열 향과 깊은 여운",
37+
price: "1,200,000",
38+
},
39+
};
40+
41+
export const LongText: Story = {
42+
name: "제목/설명이 긴 경우",
43+
args: {
44+
review: "87",
45+
title:
46+
"긴 이름의 와인이 들어갔을 때 줄바꿈과 레이아웃이 자연스러운지 확인합니다",
47+
description:
48+
"설명도 길어질 때 두 줄 이상이 되었을 때 라인하이트와 간격이 의도대로 나오는지 테스트합니다",
49+
price: "199,000",
50+
},
51+
};

src/components/header/Header.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { cn } from "@/lib/utils";
2+
3+
interface HeaderProps {
4+
review: string;
5+
title: string;
6+
description: string;
7+
price: string;
8+
}
9+
10+
const Header = ({ review, title, description, price }: HeaderProps) => {
11+
return (
12+
<div
13+
className={cn(
14+
"flex-col-center min-h-[182px] w-full gap-6",
15+
"tablet:min-h-[220px] tablet:w-[304px] tablet:gap-8",
16+
"pc:min-h-[248px] pc:w-[496px] pc:gap-8"
17+
)}
18+
>
19+
<div
20+
className={cn(
21+
"mr-auto flex flex-col gap-[6px]",
22+
"tablet:gap-[8px]",
23+
"pc:gap-[14px]"
24+
)}
25+
>
26+
<div className="flex items-center gap-4">
27+
{/* TODO(지권): 별 아이콘 추가 필요 */}
28+
<div>⭐️⭐️⭐️⭐️</div>
29+
<p className={cn("text-body-sm text-secondary", "pc:text-body-md")}>
30+
<span>{review}</span>개의 후기
31+
</p>
32+
</div>
33+
<div className="flex flex-col items-start justify-start gap-1">
34+
<h1
35+
className={cn(
36+
"text-title-page-sm tracking-[-0.02em] text-default",
37+
"pc:text-title-page-md"
38+
)}
39+
>
40+
{title}
41+
</h1>
42+
<span className="text-body-lg leading-6 tracking-[-0.02em] text-secondary">
43+
{description}
44+
</span>
45+
</div>
46+
</div>
47+
<div className="ml-auto text-body-md text-default">
48+
<span>{price}</span>
49+
</div>
50+
</div>
51+
);
52+
};
53+
54+
export default Header;

src/components/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as Gnb } from "./gnb/Gnb";
2+
export { default as Header } from "./header/Header";

tailwind.config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,19 @@ export default {
1111
colors: {
1212
black: "#111111",
1313
white: "#FFFFFF",
14+
default: "#31302F",
15+
secondary: "#A3A3A3",
1416
gray100: "#FAFAFA",
1517
gray300: "#D1D1D1",
1618
gray600: "#8C8C8B",
1719
gray800: "#484746",
1820
primary: "#1A1918",
1921
},
22+
screens: {
23+
mobile: { max: "743px" },
24+
tablet: { min: "744px", max: "1279px" },
25+
pc: { min: "1280px" },
26+
},
2027
fontSize: {
2128
"title-hero": ["32px", { lineHeight: "46px", fontWeight: "700" }],
2229
"title-page-md": ["40px", { lineHeight: "52px", fontWeight: "700" }],

0 commit comments

Comments
 (0)