diff --git a/.gitignore b/.gitignore
index 0c461061..46faa2ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,6 @@ next-env.d.ts
*storybook.log
storybook-static
+
+# vscode
+.vscode
diff --git a/src/app/example/page.tsx b/src/app/example/page.tsx
new file mode 100644
index 00000000..7788dd01
--- /dev/null
+++ b/src/app/example/page.tsx
@@ -0,0 +1,17 @@
+import Header from "@/components/header/Header";
+import React from "react";
+
+const Page = () => {
+ return (
+
+
+
+ );
+};
+
+export default Page;
diff --git a/src/app/globals.css b/src/app/globals.css
index dcd564b8..41aeb618 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -33,3 +33,13 @@ body {
* {
box-sizing: border-box;
}
+
+@layer utilities {
+ .flex-center {
+ @apply flex items-center justify-center;
+ }
+
+ .flex-col-center {
+ @apply flex flex-col items-center justify-center;
+ }
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index dde9abb2..262abf1f 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,6 +1,7 @@
import type { Metadata } from "next";
import { sfPro } from "./fonts";
import "./globals.css";
+import { Gnb } from "@/components";
import QueryProvider from "@/providers/query-provider";
export const metadata: Metadata = {
@@ -14,9 +15,12 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
-
-
- {children}
+
+
+
+
+ {children}
+
);
diff --git a/src/components/gnb/Gnb.stories.tsx b/src/components/gnb/Gnb.stories.tsx
new file mode 100644
index 00000000..ddaa356c
--- /dev/null
+++ b/src/components/gnb/Gnb.stories.tsx
@@ -0,0 +1,18 @@
+import { Meta, StoryObj } from "@storybook/nextjs";
+import Gnb from "./Gnb";
+
+const meta = {
+ title: "Components/Gnb",
+ component: Gnb,
+ parameters: {
+ layout: "centered",
+ },
+ tags: ["autodocs"],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Basic: Story = {
+ render: () => ,
+};
diff --git a/src/components/gnb/Gnb.tsx b/src/components/gnb/Gnb.tsx
new file mode 100644
index 00000000..e6caba51
--- /dev/null
+++ b/src/components/gnb/Gnb.tsx
@@ -0,0 +1,37 @@
+import { cn } from "@/lib/utils";
+import Link from "next/link";
+
+const LinkMenu = [
+ { name: "WHYNE", href: "/" },
+ {
+ name: "로그인",
+ href: "/login",
+ style: "underline-offset-2 hover:underline",
+ },
+];
+
+const Gnb = () => {
+ return (
+
+ {/* TODO(지권): 로고 아이콘 추가 및 로그인 상태 추가 */}
+ {LinkMenu.map((menu) => (
+
+ {menu.name}
+
+ ))}
+
+ );
+};
+
+export default Gnb;
diff --git a/src/components/header/Header.stories.tsx b/src/components/header/Header.stories.tsx
new file mode 100644
index 00000000..07e39816
--- /dev/null
+++ b/src/components/header/Header.stories.tsx
@@ -0,0 +1,51 @@
+import type { Meta, StoryObj } from "@storybook/nextjs";
+import Header from "./Header";
+
+const meta: Meta = {
+ title: "Components/Header",
+ component: Header,
+ parameters: {
+ layout: "centered",
+ },
+ argTypes: {
+ review: { control: { type: "text" } },
+ title: { control: { type: "text" } },
+ description: { control: { type: "text" } },
+ price: { control: { type: "text" } },
+ },
+};
+
+export default meta;
+
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ review: "128",
+ title: "샤또 마고 2015",
+ description: "블랙커런트와 바이올렛 아로마, 벨벳 같은 타닌",
+ price: "64,990",
+ },
+};
+
+export const ManyReviews: Story = {
+ name: "리뷰가 많은 경우",
+ args: {
+ review: "12,345",
+ title: "도멘 드 라 로마네 콩티",
+ description: "풍부한 베리 계열 향과 깊은 여운",
+ price: "1,200,000",
+ },
+};
+
+export const LongText: Story = {
+ name: "제목/설명이 긴 경우",
+ args: {
+ review: "87",
+ title:
+ "긴 이름의 와인이 들어갔을 때 줄바꿈과 레이아웃이 자연스러운지 확인합니다",
+ description:
+ "설명도 길어질 때 두 줄 이상이 되었을 때 라인하이트와 간격이 의도대로 나오는지 테스트합니다",
+ price: "199,000",
+ },
+};
diff --git a/src/components/header/Header.tsx b/src/components/header/Header.tsx
new file mode 100644
index 00000000..22bdbd83
--- /dev/null
+++ b/src/components/header/Header.tsx
@@ -0,0 +1,54 @@
+import { cn } from "@/lib/utils";
+
+interface HeaderProps {
+ review: string;
+ title: string;
+ description: string;
+ price: string;
+}
+
+const Header = ({ review, title, description, price }: HeaderProps) => {
+ return (
+
+
+
+ {/* TODO(지권): 별 아이콘 추가 필요 */}
+
⭐️⭐️⭐️⭐️
+
+ {review}개의 후기
+
+
+
+
+ {title}
+
+
+ {description}
+
+
+
+
+ {price}원
+
+
+ );
+};
+
+export default Header;
diff --git a/src/components/index.ts b/src/components/index.ts
new file mode 100644
index 00000000..eff89347
--- /dev/null
+++ b/src/components/index.ts
@@ -0,0 +1,2 @@
+export { default as Gnb } from "./gnb/Gnb";
+export { default as Header } from "./header/Header";
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 2035a651..93070bc2 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -11,12 +11,19 @@ export default {
colors: {
black: "#111111",
white: "#FFFFFF",
+ default: "#31302F",
+ secondary: "#A3A3A3",
gray100: "#FAFAFA",
gray300: "#D1D1D1",
gray600: "#8C8C8B",
gray800: "#484746",
primary: "#1A1918",
},
+ screens: {
+ mobile: { max: "743px" },
+ tablet: { min: "744px", max: "1279px" },
+ pc: { min: "1280px" },
+ },
fontSize: {
"title-hero": ["32px", { lineHeight: "46px", fontWeight: "700" }],
"title-page-md": ["40px", { lineHeight: "52px", fontWeight: "700" }],