diff --git a/.storybook/preview.js b/.storybook/preview.js
index d2b8396..f478437 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -1,16 +1,17 @@
import ko from 'axe-core/locales/ko.json';
-// import React from 'react';
-// import { MemoryRouter } from 'react-router-dom';
-// import { GlobalStyle } from 'styles/GlobalStyle';
+import React from 'react';
+import { GlobalStyle } from 'styles/GlobalStyle';
+import { ThemeProvider } from '@emotion/react';
+import { theme } from 'theme/theme';
-// export const decorators = [
-// (Story) => (
-//
-//
-//
-//
-// ),
-// ];
+export const decorators = [
+ (Story) => (
+
+
+
+
+ ),
+];
export const parameters = {
a11y: {
diff --git a/src/components/Button/Button.stories.tsx b/src/components/Button/Button.stories.tsx
new file mode 100644
index 0000000..d2d8e60
--- /dev/null
+++ b/src/components/Button/Button.stories.tsx
@@ -0,0 +1,48 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import { GiPerspectiveDiceSixFacesRandom } from 'react-icons/gi';
+import { Button } from './Button';
+
+export default {
+ title: 'Button',
+ component: Button,
+} as ComponentMeta;
+
+const Template: ComponentStory = (args) => ;
+
+export const Default = Template.bind({});
+
+export const Outline = Template.bind({});
+
+Outline.args = {
+ variant: 'outlined',
+ color: 'primaryGreen',
+ children: (
+ <>
+
+ REROLL
+ >
+ ),
+ style: {
+ display: 'flex',
+ alignItems: 'center',
+ gap: '10px',
+ },
+ round: true,
+};
+
+export const Fill = Template.bind({});
+
+Fill.args = {
+ type: 'submit',
+ variant: 'filled',
+ color: 'primaryGreen',
+ children: 'Sign In',
+ round: true,
+};
+
+export const Transparent = Template.bind({});
+
+Transparent.args = {
+ variant: 'transparent',
+ children: 'Not registered yet? Sign up here!',
+};
diff --git a/src/components/Button/Button.styled.tsx b/src/components/Button/Button.styled.tsx
new file mode 100644
index 0000000..1ddf08d
--- /dev/null
+++ b/src/components/Button/Button.styled.tsx
@@ -0,0 +1,19 @@
+import styled from '@emotion/styled';
+import { StyledButtonProps } from './Button.types';
+
+export const StyledButton = styled.button`
+ padding: 10px;
+ border: none;
+ background: none;
+ border-radius: ${({ round }) => round && '30px'};
+`;
+
+export const StyledOutlineButton = styled(StyledButton)`
+ border: 1px solid currentColor;
+ color: ${({ color, theme }) => theme.color[color]};
+`;
+
+export const StyledFillButton = styled(StyledButton)`
+ background-color: ${({ color, theme }) => theme.color[color]};
+ color: ${({ theme }) => theme.color.white};
+`;
diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx
new file mode 100644
index 0000000..d38be24
--- /dev/null
+++ b/src/components/Button/Button.tsx
@@ -0,0 +1,33 @@
+import { ButtonProps, StyledButtonProps } from './Button.types';
+import { StyledButton, StyledOutlineButton, StyledFillButton } from './Button.styled';
+
+const renderButton = ({ type, round = false, color, style, variant, children, ...restProps }: ButtonProps) => {
+ const props: StyledButtonProps = { type, round, color, style };
+
+ switch (variant) {
+ case 'transparent':
+ return (
+
+ {children}
+
+ );
+ case 'outlined':
+ return (
+
+ {children}
+
+ );
+ case 'filled':
+ return (
+
+ {children}
+
+ );
+ default:
+ return null;
+ }
+};
+
+export const Button = (props: ButtonProps) => {
+ return renderButton(props);
+};
diff --git a/src/components/Button/Button.types.ts b/src/components/Button/Button.types.ts
new file mode 100644
index 0000000..a513ea2
--- /dev/null
+++ b/src/components/Button/Button.types.ts
@@ -0,0 +1,31 @@
+type Type = 'button' | 'submit';
+type Variant = 'transparent' | 'outlined' | 'filled';
+type Color = 'primaryGreen' | 'primaryOrange' | 'white' | 'black';
+type IconType = 'search' | 'user' | 'heart' | 'close' | 'cart' | 'link' | 'bookmark' | 'bookmarkFill' | 'up';
+type Size = 'small' | 'large';
+
+export interface StyledButtonProps {
+ type: Type;
+ round?: boolean;
+ color: Color;
+ style?: React.CSSProperties;
+ className?: string;
+}
+
+export interface ButtonProps extends StyledButtonProps {
+ variant: Variant;
+ children: React.ReactNode;
+}
+
+export interface StyledIconButtonProps {
+ type: Type;
+ ariaLabel: string;
+ circle: boolean;
+ color: Color;
+ size: Size;
+}
+
+export interface IconButtonProps extends StyledIconButtonProps {
+ iconType: IconType;
+ variant: Variant;
+}
diff --git a/src/components/Button/IconButton.stories.tsx b/src/components/Button/IconButton.stories.tsx
new file mode 100644
index 0000000..cab1eca
--- /dev/null
+++ b/src/components/Button/IconButton.stories.tsx
@@ -0,0 +1,71 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import { IconButton } from './IconButton';
+
+export default {
+ title: 'IconButton',
+ component: IconButton,
+} as ComponentMeta;
+
+const Template: ComponentStory = (args) => ;
+
+export const Default = Template.bind({});
+
+export const Search = Template.bind({});
+
+Search.args = {
+ type: 'submit',
+ ariaLabel: 'search',
+ iconType: 'search',
+ variant: 'transparent',
+ color: 'black',
+ size: 'small',
+};
+
+export const Link = Template.bind({});
+Link.decorators = [
+ (Story) => (
+
+
+
+ ),
+];
+
+Link.args = {
+ type: 'button',
+ ariaLabel: 'copy link',
+ iconType: 'link',
+ variant: 'transparent',
+ color: 'white',
+ size: 'large',
+};
+
+export const Fill = Template.bind({});
+
+Fill.args = {
+ type: 'button',
+ ariaLabel: 'cart',
+ iconType: 'cart',
+ variant: 'filled',
+ color: 'primaryGreen',
+ size: 'large',
+ circle: true,
+};
+
+export const Outline = Template.bind({});
+Outline.decorators = [
+ (Story) => (
+
+
+
+ ),
+];
+
+Outline.args = {
+ type: 'button',
+ ariaLabel: 'heart',
+ iconType: 'heart',
+ variant: 'outlined',
+ color: 'white',
+ size: 'large',
+ circle: true,
+};
diff --git a/src/components/Button/IconButton.styled.tsx b/src/components/Button/IconButton.styled.tsx
new file mode 100644
index 0000000..32f817a
--- /dev/null
+++ b/src/components/Button/IconButton.styled.tsx
@@ -0,0 +1,42 @@
+import styled from '@emotion/styled';
+import { css } from '@emotion/react';
+import { StyledIconButtonProps } from './Button.types';
+
+const sizes = {
+ small: {
+ width: '24px',
+ height: '24px',
+ fontSize: '16px',
+ },
+ large: {
+ width: '50px',
+ height: '50px',
+ fontSize: '32px',
+ },
+};
+
+export const StyledButton = styled.button`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 0;
+ border: none;
+ background: none;
+ border-radius: ${({ circle }) => circle && '50%'};
+ color: ${({ color, theme }) => theme.color[color]};
+
+ ${({ size }) => css`
+ width: ${sizes[size].width};
+ height: ${sizes[size].height};
+ font-size: ${sizes[size].fontSize};
+ `}
+`;
+
+export const StyledOutlineButton = styled(StyledButton)`
+ border: 1px solid currentColor;
+`;
+
+export const StyledFillButton = styled(StyledButton)`
+ background-color: ${({ color, theme }) => theme.color[color]};
+ color: ${({ theme }) => theme.color.white};
+`;
diff --git a/src/components/Button/IconButton.tsx b/src/components/Button/IconButton.tsx
new file mode 100644
index 0000000..f1b312e
--- /dev/null
+++ b/src/components/Button/IconButton.tsx
@@ -0,0 +1,72 @@
+import { FiSearch } from 'react-icons/fi';
+import { FaArrowUp } from 'react-icons/fa';
+import { BsPersonCircle, BsCartCheckFill, BsLink45Deg, BsBookmark, BsFillBookmarkFill } from 'react-icons/bs';
+import { HiHeart } from 'react-icons/hi';
+import { MdClose } from 'react-icons/md';
+import { StyledButton, StyledOutlineButton, StyledFillButton } from './IconButton.styled';
+import { IconButtonProps, StyledIconButtonProps } from './Button.types';
+
+const renderIcon = (iconType: IconButtonProps['iconType']) => {
+ switch (iconType) {
+ case 'search':
+ return ;
+ case 'user':
+ return ;
+ case 'heart':
+ return ;
+ case 'close':
+ return ;
+ case 'cart':
+ return ;
+ case 'link':
+ return ;
+ case 'bookmarkFill':
+ return ;
+ case 'bookmark':
+ return ;
+ case 'up':
+ return ;
+ default:
+ return null;
+ }
+};
+
+const renderButton = ({
+ type,
+ ariaLabel,
+ iconType,
+ circle = false,
+ variant,
+ color,
+ size,
+ ...restProps
+}: IconButtonProps) => {
+ const props: StyledIconButtonProps = { type, ariaLabel, circle, color, size };
+
+ switch (variant) {
+ case 'transparent':
+ return (
+
+ {renderIcon(iconType)}
+
+ );
+ case 'outlined':
+ return (
+
+ {renderIcon(iconType)}
+
+ );
+ case 'filled':
+ return (
+
+ {renderIcon(iconType)}
+
+ );
+ default:
+ return null;
+ }
+};
+
+export const IconButton = (props: IconButtonProps) => {
+ return renderButton(props);
+};
diff --git a/src/components/Logo/Logo.stories.tsx b/src/components/Logo/Logo.stories.tsx
new file mode 100644
index 0000000..f15f5e9
--- /dev/null
+++ b/src/components/Logo/Logo.stories.tsx
@@ -0,0 +1,11 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import { Logo } from './Logo';
+
+export default {
+ title: 'Logo',
+ component: Logo,
+} as ComponentMeta;
+
+const Template: ComponentStory = () => ;
+
+export const Default = Template.bind({});
diff --git a/src/components/Logo/Logo.styled.tsx b/src/components/Logo/Logo.styled.tsx
new file mode 100644
index 0000000..46bafb7
--- /dev/null
+++ b/src/components/Logo/Logo.styled.tsx
@@ -0,0 +1,23 @@
+import styled from '@emotion/styled';
+import { pxToRem, media } from 'utils';
+import { LogoIcon } from './LogoIcon';
+
+export const StyledA = styled.a`
+ display: flex;
+ font-size: ${pxToRem(24)};
+ align-items: center;
+`;
+
+export const StyledIcon = styled(LogoIcon)`
+ margin: 10px;
+`;
+
+export const StyledSpan = styled.span`
+ width: 130px;
+ transition: 400ms width ease;
+
+ ${media.mobile} {
+ width: 0;
+ overflow: hidden;
+ }
+`;
diff --git a/src/components/Logo/Logo.tsx b/src/components/Logo/Logo.tsx
new file mode 100644
index 0000000..12e345e
--- /dev/null
+++ b/src/components/Logo/Logo.tsx
@@ -0,0 +1,15 @@
+import Link from 'next/link';
+import { StyledA, StyledIcon, StyledSpan } from './Logo.styled';
+
+export const Logo = () => {
+ return (
+
+
+
+
+ TwoSpoon
+
+
+
+ );
+};
diff --git a/src/components/Logo/LogoIcon.tsx b/src/components/Logo/LogoIcon.tsx
new file mode 100644
index 0000000..5f61fc6
--- /dev/null
+++ b/src/components/Logo/LogoIcon.tsx
@@ -0,0 +1,13 @@
+export const LogoIcon = () => {
+ return (
+
+ );
+};
diff --git a/src/components/index.ts b/src/components/index.ts
index 4dd0b8f..d174563 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -1,2 +1,3 @@
export * from './CookingInfo/CookingInfo';
+export * from './Logo/Logo';
export * from './Loading/Loading';
diff --git a/src/utils/style.ts b/src/utils/style.ts
index a2116ab..6c6764f 100644
--- a/src/utils/style.ts
+++ b/src/utils/style.ts
@@ -1,3 +1,7 @@
export const pxToRem = (px: number, base = 16): string => {
return `${px / base}rem`;
};
+
+export const media = {
+ mobile: '@media(max-width:767px)',
+};