diff --git a/frontend/reply-module/.storybook/main.js b/frontend/reply-module/.storybook/main.js
index 26dfeaf66..82a742044 100644
--- a/frontend/reply-module/.storybook/main.js
+++ b/frontend/reply-module/.storybook/main.js
@@ -1,10 +1,4 @@
module.exports = {
- "stories": [
- "../src/**/*.stories.mdx",
- "../src/**/*.stories.@(js|jsx|ts|tsx)"
- ],
- "addons": [
- "@storybook/addon-links",
- "@storybook/addon-essentials"
- ]
-}
\ No newline at end of file
+ stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
+ addons: ["@storybook/addon-links", "@storybook/addon-essentials"]
+};
diff --git a/frontend/reply-module/.storybook/preview.css b/frontend/reply-module/.storybook/preview.css
new file mode 100644
index 000000000..ec23d958f
--- /dev/null
+++ b/frontend/reply-module/.storybook/preview.css
@@ -0,0 +1,4 @@
+#root {
+ width: 100%;
+ max-width: 1080px;
+}
diff --git a/frontend/reply-module/.storybook/preview.js b/frontend/reply-module/.storybook/preview.js
index 48afd568a..02afa7473 100644
--- a/frontend/reply-module/.storybook/preview.js
+++ b/frontend/reply-module/.storybook/preview.js
@@ -1,9 +1,23 @@
+import { configure, addDecorator } from "@storybook/react";
+import GlobalStyles from "../src/styles/GlobalStyles";
+import "./preview.css";
+
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
+ layout: "centered",
controls: {
matchers: {
color: /(background|color)$/i,
- date: /Date$/,
- },
- },
-}
\ No newline at end of file
+ date: /Date$/
+ }
+ }
+};
+
+addDecorator(style => (
+ <>
+
+ <>{style()}>
+ >
+));
+
+configure(require.context("../src", true, /\.stories\.js?$/), module);
diff --git a/frontend/reply-module/src/App.tsx b/frontend/reply-module/src/App.tsx
index a5e22d64a..49837e41c 100644
--- a/frontend/reply-module/src/App.tsx
+++ b/frontend/reply-module/src/App.tsx
@@ -1,5 +1,5 @@
const App = () => {
- return <>Hello World>;
+ return null;
};
export default App;
diff --git a/frontend/reply-module/src/assets/svg/three-dots.svg b/frontend/reply-module/src/assets/svg/three-dots.svg
new file mode 100644
index 000000000..bd4058aaa
--- /dev/null
+++ b/frontend/reply-module/src/assets/svg/three-dots.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/reply-module/src/components/atoms/Avatar/Avatar.stories.tsx b/frontend/reply-module/src/components/atoms/Avatar/Avatar.stories.tsx
new file mode 100644
index 000000000..cc19a8f65
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/Avatar/Avatar.stories.tsx
@@ -0,0 +1,16 @@
+import { Story } from "@storybook/react";
+import Avatar, { Props } from ".";
+
+export default {
+ title: "atoms/Avatar",
+ component: Avatar,
+ argTypes: { children: { control: "text" } }
+};
+
+const Template: Story = args => ;
+
+export const Default = Template.bind({});
+
+Default.args = {
+ imageURL: "data:image/jpeg;base64,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"
+};
diff --git a/frontend/reply-module/src/components/atoms/Avatar/index.tsx b/frontend/reply-module/src/components/atoms/Avatar/index.tsx
new file mode 100644
index 000000000..37402cf45
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/Avatar/index.tsx
@@ -0,0 +1,14 @@
+import { Container } from "./styles";
+
+export type Size = "SM" | "MD" | "LG";
+
+export interface Props {
+ imageURL: string;
+ size?: Size;
+}
+
+const Avatar = ({ imageURL, size = "MD" }: Props) => {
+ return ;
+};
+
+export default Avatar;
diff --git a/frontend/reply-module/src/components/atoms/Avatar/styles.ts b/frontend/reply-module/src/components/atoms/Avatar/styles.ts
new file mode 100644
index 000000000..286d2c87e
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/Avatar/styles.ts
@@ -0,0 +1,17 @@
+import styled from "styled-components";
+
+import { Size } from ".";
+
+const avatarSizeBySize = {
+ SM: 30,
+ MD: 40,
+ LG: 90
+};
+
+const Container = styled.img<{ size: Size }>`
+ border-radius: 50%;
+ width: ${props => `${avatarSizeBySize[props.size]}px`};
+ height: ${props => `${avatarSizeBySize[props.size]}px`};
+`;
+
+export { Container };
diff --git a/frontend/reply-module/src/components/atoms/CommentOption/CommentOption.stories.tsx b/frontend/reply-module/src/components/atoms/CommentOption/CommentOption.stories.tsx
new file mode 100644
index 000000000..8e127a394
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/CommentOption/CommentOption.stories.tsx
@@ -0,0 +1,14 @@
+import { Story } from "@storybook/react";
+import CommentOption, { Props } from ".";
+
+export default {
+ title: "atoms/CommentOption",
+ component: CommentOption,
+ argTypes: { children: { control: "text" } }
+};
+
+const Template: Story = args => ;
+
+export const Default = Template.bind({});
+
+Default.args = {};
diff --git a/frontend/reply-module/src/components/atoms/CommentOption/index.tsx b/frontend/reply-module/src/components/atoms/CommentOption/index.tsx
new file mode 100644
index 000000000..d352943e3
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/CommentOption/index.tsx
@@ -0,0 +1,29 @@
+import { useState } from "react";
+import threeDots from "../../../assets/svg/three-dots.svg";
+import { Container, DeleteButton, EditButton, OptionContainer, OptionIcon } from "./styles";
+
+export interface Props {
+ onEdit?: () => void;
+ onDelete?: () => void;
+}
+
+const CommentOption = ({ onEdit, onDelete }: Props) => {
+ const [isShowOptionBox, setShowOptionBox] = useState(false);
+ const onShowOptionBox = () => {
+ setShowOptionBox(state => !state);
+ };
+
+ return (
+
+
+ {isShowOptionBox && (
+
+ 수정
+ 삭제
+
+ )}
+
+ );
+};
+
+export default CommentOption;
diff --git a/frontend/reply-module/src/components/atoms/CommentOption/styles.ts b/frontend/reply-module/src/components/atoms/CommentOption/styles.ts
new file mode 100644
index 000000000..5fe7d3414
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/CommentOption/styles.ts
@@ -0,0 +1,63 @@
+import styled from "styled-components";
+import { PALETTE } from "../../../styles/palette";
+
+const Container = styled.div`
+ position: absolute;
+`;
+
+const OptionIcon = styled.img`
+ cursor: pointer;
+`;
+
+const OptionContainer = styled.div`
+ position: absolute;
+ right: -5px;
+ width: 6rem;
+ box-shadow: 1.04082px 1.04082px 6.24491px rgba(0, 0, 0, 0.25);
+ border-radius: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ background-color: ${PALETTE.WHITE};
+
+ ::before {
+ content: "";
+ position: absolute;
+ top: -5px;
+ right: 8px;
+
+ border-bottom: 10px solid ${PALETTE.WHITE};
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ }
+
+ & > button {
+ width: 100%;
+ border: none;
+ outline: none;
+ background-color: ${PALETTE.WHITE};
+ cursor: pointer;
+ font-weight: 600;
+ margin-bottom: 0.3rem;
+
+ :first-child {
+ padding-top: 0.5rem;
+ border-radius: 10px 10px 0 0;
+ }
+
+ :last-child {
+ margin-bottom: 0;
+ padding-bottom: 0.5rem;
+ border-radius: 0 0 10px 10px;
+ }
+ }
+`;
+
+const EditButton = styled.button`
+ color: ${PALETTE.BLACK_700};
+`;
+const DeleteButton = styled.button`
+ color: ${PALETTE.RED_600};
+`;
+
+export { Container, OptionIcon, OptionContainer, EditButton, DeleteButton };
diff --git a/frontend/reply-module/src/components/atoms/CommentTextBox/CommentTextBox.stories.tsx b/frontend/reply-module/src/components/atoms/CommentTextBox/CommentTextBox.stories.tsx
new file mode 100644
index 000000000..d653da56b
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/CommentTextBox/CommentTextBox.stories.tsx
@@ -0,0 +1,17 @@
+import { Story } from "@storybook/react";
+import CommentTextBox, { Props } from ".";
+
+export default {
+ title: "atoms/CommentTextBox",
+ component: CommentTextBox,
+ argTypes: { children: { control: "text" } }
+};
+
+const Template: Story = args => ;
+
+export const Default = Template.bind({});
+
+Default.args = {
+ name: "곤이",
+ contentEditable: true
+};
diff --git a/frontend/reply-module/src/components/atoms/CommentTextBox/index.tsx b/frontend/reply-module/src/components/atoms/CommentTextBox/index.tsx
new file mode 100644
index 000000000..185c730c3
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/CommentTextBox/index.tsx
@@ -0,0 +1,18 @@
+import { Container, Name, Text } from "./styles";
+
+export interface Props {
+ name: string;
+ children: string;
+ contentEditable?: boolean;
+}
+
+const CommentTextBox = ({ name, children, contentEditable = false }: Props) => {
+ return (
+
+ {name}
+ {children}
+
+ );
+};
+
+export default CommentTextBox;
diff --git a/frontend/reply-module/src/components/atoms/CommentTextBox/styles.ts b/frontend/reply-module/src/components/atoms/CommentTextBox/styles.ts
new file mode 100644
index 000000000..920d837ee
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/CommentTextBox/styles.ts
@@ -0,0 +1,27 @@
+import styled from "styled-components";
+import { PALETTE } from "../../../styles/palette";
+
+const Container = styled.div`
+ width: 100%;
+ background-color: ${PALETTE.GRAY_200};
+ border-radius: 10px;
+ padding: 0.8rem 1rem;
+ display: flex;
+ flex-direction: column;
+`;
+
+const Name = styled.span`
+ font-weight: 700;
+ font-size: 1.4rem;
+ margin-bottom: 0.7rem;
+`;
+
+const Text = styled.div`
+ outline-color: ${PALETTE.BLACK_700};
+ background-color: ${props => (props.contentEditable ? PALETTE.WHITE : PALETTE.GRAY_200)};
+ border-radius: 10px;
+ min-width: 10rem;
+ max-width: 20rem;
+`;
+
+export { Container, Name, Text };
diff --git a/frontend/reply-module/src/components/atoms/SubmitButton/SubmitButton.stories.tsx b/frontend/reply-module/src/components/atoms/SubmitButton/SubmitButton.stories.tsx
new file mode 100644
index 000000000..a6ba8f1db
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/SubmitButton/SubmitButton.stories.tsx
@@ -0,0 +1,14 @@
+import { Story } from "@storybook/react";
+import SubmitButton, { Props } from ".";
+
+export default {
+ title: "atoms/SubmitButton",
+ component: SubmitButton,
+ argTypes: { children: { control: "text" } }
+};
+
+const Template: Story = args => ;
+
+export const Default = Template.bind({});
+
+Default.args = {};
diff --git a/frontend/reply-module/src/components/atoms/SubmitButton/index.tsx b/frontend/reply-module/src/components/atoms/SubmitButton/index.tsx
new file mode 100644
index 000000000..7e56e3894
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/SubmitButton/index.tsx
@@ -0,0 +1,12 @@
+import { Button } from "./styles";
+
+export interface Props {
+ children: string;
+ onClick: () => void;
+}
+
+const SubmitButton = ({ children, onClick }: Props) => {
+ return ;
+};
+
+export default SubmitButton;
diff --git a/frontend/reply-module/src/components/atoms/SubmitButton/styles.ts b/frontend/reply-module/src/components/atoms/SubmitButton/styles.ts
new file mode 100644
index 000000000..41cf756b3
--- /dev/null
+++ b/frontend/reply-module/src/components/atoms/SubmitButton/styles.ts
@@ -0,0 +1,15 @@
+import { PALETTE } from "./../../../styles/palette";
+import styled from "styled-components";
+
+const Button = styled.button`
+ width: 6rem;
+ height: 3.6rem;
+ background-color: ${PALETTE.PRIMARY};
+ color: ${PALETTE.WHITE};
+ font-size: 1.6rem;
+ font-weight: 500;
+ border: none;
+ border-radius: 10px;
+`;
+
+export { Button };
diff --git a/frontend/reply-module/src/components/molecules/Comment/Comment.stories.tsx b/frontend/reply-module/src/components/molecules/Comment/Comment.stories.tsx
new file mode 100644
index 000000000..355a594b4
--- /dev/null
+++ b/frontend/reply-module/src/components/molecules/Comment/Comment.stories.tsx
@@ -0,0 +1,28 @@
+import { Story } from "@storybook/react";
+import Comment, { Props } from ".";
+
+export default {
+ title: "molecules/Comment",
+ component: Comment,
+ argTypes: { children: { control: "text" } }
+};
+
+const Template: Story = args => ;
+
+export const Default = Template.bind({});
+
+Default.args = {
+ comment: {
+ id: 1,
+ content: "Donec accumsan neque enim sodales. Neque eget vulputate viverra convallis pharetra.",
+ user: {
+ id: 1,
+ imageURL:
+ "https://static.independent.co.uk/s3fs-public/thumbnails/image/2015/06/06/15/Chris-Pratt.jpg?width=982&height=726&auto=webp&quality=75",
+ nickName: "Robert Hill",
+ type: "Authorized"
+ },
+ createdAt: "1시간 전"
+ },
+ shouldShowOption: true
+};
diff --git a/frontend/reply-module/src/components/molecules/Comment/index.tsx b/frontend/reply-module/src/components/molecules/Comment/index.tsx
new file mode 100644
index 000000000..539f80af6
--- /dev/null
+++ b/frontend/reply-module/src/components/molecules/Comment/index.tsx
@@ -0,0 +1,33 @@
+import { Comment as CommentType } from "../../../types";
+import Avatar from "../../atoms/Avatar";
+import CommentOption from "../../atoms/CommentOption";
+import CommentTextBox from "../../atoms/CommentTextBox";
+import { Container, CommentTextBoxWrapper, Time, CommentOptionWrapper } from "./styles";
+
+export interface Props {
+ comment: CommentType;
+ align?: "left" | "right";
+
+ shouldShowOption?: boolean;
+ onEdit?: () => void;
+ onDelete?: () => void;
+}
+
+const Comment = ({ comment, align = "left", shouldShowOption, onEdit, onDelete }: Props) => {
+ return (
+
+
+
+ {comment.content}
+
+ {shouldShowOption && (
+
+
+
+ )}
+
+
+ );
+};
+
+export default Comment;
diff --git a/frontend/reply-module/src/components/molecules/Comment/styles.ts b/frontend/reply-module/src/components/molecules/Comment/styles.ts
new file mode 100644
index 000000000..af2340a0d
--- /dev/null
+++ b/frontend/reply-module/src/components/molecules/Comment/styles.ts
@@ -0,0 +1,27 @@
+import styled from "styled-components";
+
+const Container = styled.div<{ align: "left" | "right" }>`
+ display: flex;
+ flex-direction: ${props => (props.align === "left" ? "row" : "row-reverse")};
+`;
+
+const CommentTextBoxWrapper = styled.div<{ align: "left" | "right" }>`
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: ${props => (props.align === "left" ? "flex-start" : "flex-end")};
+ margin: ${props => (props.align === "left" ? "0 0 0 0.6rem" : "0 0.6rem 0 0")};
+`;
+
+const Time = styled.span`
+ margin: 0 1rem;
+ margin-top: 0.3rem;
+`;
+
+const CommentOptionWrapper = styled.div`
+ position: absolute;
+ right: 30px;
+ top: 8px;
+`;
+
+export { Container, CommentTextBoxWrapper, Time, CommentOptionWrapper };
diff --git a/frontend/reply-module/src/components/organisms/CommentInput/CommentInput.stories.tsx b/frontend/reply-module/src/components/organisms/CommentInput/CommentInput.stories.tsx
new file mode 100644
index 000000000..07836f452
--- /dev/null
+++ b/frontend/reply-module/src/components/organisms/CommentInput/CommentInput.stories.tsx
@@ -0,0 +1,14 @@
+import { Story } from "@storybook/react";
+import CommentInput, { Props } from ".";
+
+export default {
+ title: "organisms/CommentInput",
+ component: CommentInput,
+ argTypes: { children: { control: "text" } }
+};
+
+const Template: Story = args => ;
+
+export const Default = Template.bind({});
+
+Default.args = {};
diff --git a/frontend/reply-module/src/components/organisms/CommentInput/index.tsx b/frontend/reply-module/src/components/organisms/CommentInput/index.tsx
new file mode 100644
index 000000000..862d3fdf5
--- /dev/null
+++ b/frontend/reply-module/src/components/organisms/CommentInput/index.tsx
@@ -0,0 +1,27 @@
+import SubmitButton from "../../atoms/SubmitButton";
+import { Container, TextArea, Wrapper, GuestInfo } from "./styles";
+
+export interface Props {}
+
+const CommentInput = () => {
+ const isGuest = true;
+
+ return (
+
+
+
+
+ {isGuest && (
+
+
+
+
+ )}
+
+ {}}>등록
+
+
+ );
+};
+
+export default CommentInput;
diff --git a/frontend/reply-module/src/components/organisms/CommentInput/styles.ts b/frontend/reply-module/src/components/organisms/CommentInput/styles.ts
new file mode 100644
index 000000000..0462ef684
--- /dev/null
+++ b/frontend/reply-module/src/components/organisms/CommentInput/styles.ts
@@ -0,0 +1,35 @@
+import styled from "styled-components";
+import { InputCSS } from "../../../styles/css";
+
+const Container = styled.div`
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+`;
+
+const TextArea = styled.textarea`
+ ${InputCSS};
+ padding: 1.6rem;
+ height: 9rem;
+ margin-bottom: 1.6rem;
+`;
+
+const Wrapper = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+`;
+
+const GuestInfo = styled.input`
+ ${InputCSS};
+ padding: 1.1rem 1.6rem;
+ width: 10rem;
+ height: 3.6rem;
+ line-height: 1.4rem;
+
+ :first-child {
+ margin-right: 1.6rem;
+ }
+`;
+
+export { Container, TextArea, Wrapper, GuestInfo };
diff --git a/frontend/reply-module/src/components/organisms/CommentList/CommentList.stories.tsx b/frontend/reply-module/src/components/organisms/CommentList/CommentList.stories.tsx
new file mode 100644
index 000000000..e415e5336
--- /dev/null
+++ b/frontend/reply-module/src/components/organisms/CommentList/CommentList.stories.tsx
@@ -0,0 +1,41 @@
+import { Story } from "@storybook/react";
+import CommentList, { Props } from ".";
+
+export default {
+ title: "organisms/CommentList",
+ component: CommentList,
+ argTypes: { children: { control: "text" } }
+};
+
+const Template: Story = args => ;
+
+export const Default = Template.bind({});
+
+Default.args = {
+ comments: [
+ {
+ id: 1,
+ content: "Donec accumsan neque enim sodales. Neque eget vulputate viverra convallis pharetra.",
+ user: {
+ id: 1,
+ imageURL:
+ "https://static.independent.co.uk/s3fs-public/thumbnails/image/2015/06/06/15/Chris-Pratt.jpg?width=982&height=726&auto=webp&quality=75",
+ nickName: "Robert Hill",
+ type: "Authorized"
+ },
+ createdAt: "1시간 전"
+ },
+ {
+ id: 2,
+ content: "Donec accumsan neque enim sodales. Neque eget vulputate viverra convallis pharetra.",
+ user: {
+ id: 1,
+ imageURL:
+ "https://static.independent.co.uk/s3fs-public/thumbnails/image/2015/06/06/15/Chris-Pratt.jpg?width=982&height=726&auto=webp&quality=75",
+ nickName: "Robert Hill",
+ type: "Authorized"
+ },
+ createdAt: "1시간 전"
+ }
+ ]
+};
diff --git a/frontend/reply-module/src/components/organisms/CommentList/index.tsx b/frontend/reply-module/src/components/organisms/CommentList/index.tsx
new file mode 100644
index 000000000..7bd53fa30
--- /dev/null
+++ b/frontend/reply-module/src/components/organisms/CommentList/index.tsx
@@ -0,0 +1,28 @@
+import { Comment as CommentType } from "../../../types";
+import Comment from "../../molecules/Comment";
+import { CommentContainer, Container, OrderButton, OrderButtonCotainer, OrderButtonWrapper } from "./styles";
+
+export interface Props {
+ comments: CommentType[];
+}
+
+const CommentList = ({ comments }: Props) => {
+ return (
+
+
+
+ 최신순
+ 공감순
+ 과거순
+
+
+
+ {comments.map(comment => (
+
+ ))}
+
+
+ );
+};
+
+export default CommentList;
diff --git a/frontend/reply-module/src/components/organisms/CommentList/styles.ts b/frontend/reply-module/src/components/organisms/CommentList/styles.ts
new file mode 100644
index 000000000..0d934c6cb
--- /dev/null
+++ b/frontend/reply-module/src/components/organisms/CommentList/styles.ts
@@ -0,0 +1,44 @@
+import { PALETTE } from "./../../../styles/palette";
+import styled from "styled-components";
+
+const Container = styled.section`
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+`;
+
+const OrderButtonCotainer = styled.div`
+ width: 100%;
+ display: flex;
+ justify-content: flex-end;
+ align-items: flex-start;
+ border-bottom: 1px solid ${PALETTE.BLACK_700};
+ padding-bottom: 1.6rem;
+`;
+
+const OrderButtonWrapper = styled.div`
+ display: flex;
+`;
+
+const OrderButton = styled.button`
+ color: ${PALETTE.BLACK_700};
+ font-size: 1.6rem;
+ font-weight: 700;
+ background-color: transparent;
+`;
+
+const CommentContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ margin: 3rem 0;
+
+ & > * {
+ margin-bottom: 1.6rem;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+`;
+
+export { Container, OrderButtonCotainer, OrderButtonWrapper, OrderButton, CommentContainer };
diff --git a/frontend/reply-module/src/components/templates/CommentArea/CommentArea.stories.tsx b/frontend/reply-module/src/components/templates/CommentArea/CommentArea.stories.tsx
new file mode 100644
index 000000000..2e07aa129
--- /dev/null
+++ b/frontend/reply-module/src/components/templates/CommentArea/CommentArea.stories.tsx
@@ -0,0 +1,14 @@
+import { Story } from "@storybook/react";
+import CommentArea from ".";
+
+export default {
+ title: "templates/CommentArea",
+ component: CommentArea,
+ argTypes: { children: { control: "text" } }
+};
+
+const Template: Story = args => ;
+
+export const Default = Template.bind({});
+
+Default.args = {};
diff --git a/frontend/reply-module/src/components/templates/CommentArea/index.tsx b/frontend/reply-module/src/components/templates/CommentArea/index.tsx
new file mode 100644
index 000000000..f90e16ed2
--- /dev/null
+++ b/frontend/reply-module/src/components/templates/CommentArea/index.tsx
@@ -0,0 +1,16 @@
+import { Comment } from "../../../types";
+import CommentInput from "../../organisms/CommentInput";
+import CommentList from "../../organisms/CommentList";
+import { Container } from "./styles";
+
+const CommentArea = () => {
+ const comments: Comment[] = [];
+ return (
+
+
+
+
+ );
+};
+
+export default CommentArea;
diff --git a/frontend/reply-module/src/components/templates/CommentArea/styles.ts b/frontend/reply-module/src/components/templates/CommentArea/styles.ts
new file mode 100644
index 000000000..cb24198c3
--- /dev/null
+++ b/frontend/reply-module/src/components/templates/CommentArea/styles.ts
@@ -0,0 +1,11 @@
+import styled from "styled-components";
+
+const Container = styled.section`
+ display: flex;
+ flex-direction: column;
+ & > *:first-child {
+ margin-bottom: 2.4rem;
+ }
+`;
+
+export { Container };
diff --git a/frontend/reply-module/src/index.tsx b/frontend/reply-module/src/index.tsx
index ce92b1cc4..87ec77447 100644
--- a/frontend/reply-module/src/index.tsx
+++ b/frontend/reply-module/src/index.tsx
@@ -1,4 +1,11 @@
import ReactDOM from "react-dom";
import App from "./App";
+import GlobalStyles from "./styles/GlobalStyles";
-ReactDOM.render(, document.getElementById("root"));
+ReactDOM.render(
+ <>
+
+
+ >,
+ document.getElementById("root")
+);
diff --git a/frontend/reply-module/src/styles/GlobalStyles.ts b/frontend/reply-module/src/styles/GlobalStyles.ts
new file mode 100644
index 000000000..7f2fea6b2
--- /dev/null
+++ b/frontend/reply-module/src/styles/GlobalStyles.ts
@@ -0,0 +1,59 @@
+import { createGlobalStyle } from "styled-components";
+
+const GlobalStyles = createGlobalStyle`
+ @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700;800&display=swap');
+
+ * {
+ box-sizing: border-box;
+ }
+ html {
+ font-size: 10px;
+ font-family: 'Noto Sans KR', sans-serif;
+ }
+ html, body {
+ margin: 0;
+ padding: 0;
+ min-height: 100vh;
+ width: 100%;
+ }
+ ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
+ h1,
+ h2,
+ h3,
+ h4,
+ h5 {
+ font-size: 1rem;
+ margin: 0;
+ padding: 0;
+ }
+ a {
+ text-decoration: none;
+ outline: none;
+ color: black;
+ &:link,
+ &:visited,
+ &:hover,
+ &:active,
+ &:focus {
+ text-decoration: none;
+ }
+ }
+ img {
+ object-fit: cover;
+ }
+ button {
+ font-family: inherit;
+ outline: none;
+ border: none;
+ cursor: pointer;
+ }
+ input, textarea {
+ font-family: inherit;
+ }
+`;
+
+export default GlobalStyles;
diff --git a/frontend/reply-module/src/styles/constants.ts b/frontend/reply-module/src/styles/constants.ts
new file mode 100644
index 000000000..cbe71441e
--- /dev/null
+++ b/frontend/reply-module/src/styles/constants.ts
@@ -0,0 +1 @@
+const pageMaxWidth = "1080px";
diff --git a/frontend/reply-module/src/styles/css.ts b/frontend/reply-module/src/styles/css.ts
new file mode 100644
index 000000000..9890157f8
--- /dev/null
+++ b/frontend/reply-module/src/styles/css.ts
@@ -0,0 +1,16 @@
+import { css } from "styled-components";
+import { PALETTE } from "./palette";
+
+const InputCSS = css`
+ border: 1px solid ${PALETTE.BLACK_700};
+ border-radius: 10px;
+ color: ${PALETTE.BLACK_700};
+ font-size: 1.4rem;
+ outline: none;
+
+ &::placeholder {
+ color: ${PALETTE.BLACK_700};
+ }
+`;
+
+export { InputCSS };
diff --git a/frontend/reply-module/src/styles/palette.ts b/frontend/reply-module/src/styles/palette.ts
new file mode 100644
index 000000000..aa08971e4
--- /dev/null
+++ b/frontend/reply-module/src/styles/palette.ts
@@ -0,0 +1,9 @@
+export enum PALETTE {
+ "PRIMARY" = "#10DF99",
+ "SECONDARY" = "#0BC586",
+ "TERTIARY" = "#FFE200",
+ "WHITE" = "#FFFFFF",
+ "BLACK_700" = "#303030",
+ "GRAY_200" = "#F0F2F5",
+ "RED_600" = "#E41E1E"
+}
diff --git a/frontend/reply-module/src/types/comment.ts b/frontend/reply-module/src/types/comment.ts
new file mode 100644
index 000000000..35b1b10d1
--- /dev/null
+++ b/frontend/reply-module/src/types/comment.ts
@@ -0,0 +1,11 @@
+export interface Comment {
+ id: number;
+ content: string;
+ user: {
+ id: number;
+ imageURL: string;
+ nickName: string;
+ type: string;
+ };
+ createdAt: string;
+}
diff --git a/frontend/reply-module/src/types/index.ts b/frontend/reply-module/src/types/index.ts
new file mode 100644
index 000000000..24c3a9798
--- /dev/null
+++ b/frontend/reply-module/src/types/index.ts
@@ -0,0 +1 @@
+export { Comment } from "./comment";
diff --git a/frontend/reply-module/src/type.d.ts b/frontend/reply-module/src/types/type.d.ts
similarity index 100%
rename from frontend/reply-module/src/type.d.ts
rename to frontend/reply-module/src/types/type.d.ts
diff --git a/frontend/reply-module/tsconfig.json b/frontend/reply-module/tsconfig.json
index 806b500a9..57030af4d 100644
--- a/frontend/reply-module/tsconfig.json
+++ b/frontend/reply-module/tsconfig.json
@@ -19,5 +19,5 @@
"strictNullChecks": true,
"noImplicitReturns": true
},
- "include": ["./src/**/*", "./src**/*.ts"]
+ "include": ["./src/**/*"]
}