diff --git a/src/components/CommentInfo.module.scss b/src/components/CommentInfo.module.scss
new file mode 100644
index 0000000..7cd7396
--- /dev/null
+++ b/src/components/CommentInfo.module.scss
@@ -0,0 +1,202 @@
+.commentInfo {
+ margin: 0;
+
+ .commentHeader {
+ margin-bottom: 18px;
+ display: flex;
+
+ .commentUser {
+ flex: 1;
+ .userLink {
+ display: flex;
+
+ .userImage {
+ display: flex;
+ align-items: center;
+ border: solid 1px rgba(0, 0, 0, 0.08);
+ border-radius: 50%;
+ flex-shrink: 0;
+ width: 20px;
+ height: 20px;
+ margin: 3px 5px 3px 0;
+ overflow: hidden;
+
+ img {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ .userDate {
+ display: flex;
+ align-items: center;
+
+ .userName {
+ font-size: 12px;
+ font-weight: 400;
+ letter-spacing: -0.2px;
+ color: #4a4a4a;
+ line-height: 16px;
+ }
+
+ .date {
+ margin-left: 4px;
+ font-size: 12px;
+ font-weight: 400;
+ letter-spacing: -0.2px;
+ color: #787878;
+ line-height: 16px;
+ }
+ }
+ }
+
+ .movieName {
+ color: rgb(0, 0, 0);
+ font-size: 16px;
+ letter-spacing: -0.6px;
+ line-height: 21px;
+ margin-top: 3px;
+ }
+
+ .releaseYear {
+ color: rgb(120, 120, 120);
+ font-size: 12px;
+ letter-spacing: -0.2px;
+ line-height: 16px;
+ margin-top: 3px;
+ }
+ .ratingDiv {
+ margin-top: 5px;
+ width: 53px;
+
+ .rating {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: rgb(74, 74, 74);
+ font-weight: 400;
+ letter-spacing: -0.3px;
+ font-size: 13px;
+ line-height: 16px;
+ height: 24px;
+ padding-right: 8px;
+ padding-left: 8px;
+ border: 1px solid rgb(234, 234, 234);
+ border-radius: 13px;
+
+ .ratingText {
+ margin-left: 4px;
+ }
+ }
+ }
+ }
+
+ .poster {
+ overflow: hidden;
+ width: 72px;
+ height: 106px;
+ border: 0.5px solid rgba(0, 0, 0, 0.16);
+ border-radius: 3px;
+
+ img {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .commentBody {
+ color: rgb(74, 74, 74);
+ margin-bottom: 22px;
+ font-size: 15px;
+ font-weight: 400;
+ letter-spacing: -0.2px;
+ line-height: 24px;
+ word-wrap: break-word;
+ white-space: pre-line;
+ overflow: hidden;
+ }
+
+ .commentLikeReply {
+ height: 40px;
+ color: rgb(120, 120, 120);
+ font-size: 12px;
+ letter-spacing: -0.2px;
+ line-height: 40px;
+ margin-top: 32px;
+
+ .likes {
+ margin-right: 18px;
+ }
+ }
+
+ .likeReplyBar {
+ margin: 0;
+
+ hr {
+ border: 0;
+ border-bottom: 1px solid #f0f0f0;
+ }
+
+ .likeReplyGrid {
+ margin: 0 20px;
+ display: grid;
+ position: relative;
+ grid-template-columns: 1fr 1fr;
+ grid-gap: 1px;
+ height: 43px;
+
+ button {
+ background: none;
+ padding: 0;
+ border: none;
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: #67686a;
+ font-size: 15px;
+ letter-spacing: -0.3px;
+ line-height: 18px;
+ border-radius: 5px;
+ margin: 3px;
+ cursor: pointer;
+ transition: all 70ms linear 0s;
+ }
+
+ button:hover {
+ background-color: rgba(41, 42, 50, 0.08);
+ color: rgba(41, 42, 50, 1);
+ svg :not([fill="none"]) {
+ fill: rgba(41, 42, 50, 1);
+ }
+ }
+
+ .likeButton::after {
+ content: "";
+ position: absolute;
+ right: -4px;
+ background: #f0f0f0;
+ width: 1px;
+ height: 14px;
+ }
+
+ .likeButtonLiked {
+ color: rgb(255, 47, 110);
+ .likeSvg {
+ color: rgb(255, 47, 110);
+ }
+ }
+
+ .fillTarget {
+ transition: all 70ms linear 0s;
+ }
+
+ svg {
+ width: 20px;
+ height: 20px;
+ margin-right: 5px;
+ }
+ }
+ }
+}
diff --git a/src/components/CommentInfo.tsx b/src/components/CommentInfo.tsx
new file mode 100644
index 0000000..511c564
--- /dev/null
+++ b/src/components/CommentInfo.tsx
@@ -0,0 +1,176 @@
+import { Link } from "react-router-dom";
+import userImage from "../assets/user_default.jpg";
+import styles from "./CommentInfo.module.scss";
+import { MovieType } from "./ContentList";
+import ReplyList from "./ReplyList";
+import elapsedTime from "../utils/elapsedTime";
+
+export type ReplyType = {
+ userName: string;
+ date: Date;
+ content: string;
+ likes: number;
+ liked: boolean;
+};
+
+type CommentType = {
+ userName: string;
+ movie: MovieType;
+ rating: number;
+ content: string;
+ date: Date;
+ likes: number;
+ liked: boolean;
+ replyNumber: number;
+ replies: ReplyType[];
+};
+
+function CommentHeader({
+ userName,
+ movie,
+ rating,
+ date,
+}: {
+ userName: string;
+ movie: MovieType;
+ rating: number;
+ date: Date;
+}) {
+ return (
+
+
+
+
+
+
+
+
{userName}
+
{elapsedTime(date)}
+
+
+
+
{movie.name}
+
영화 · {movie.releaseYear}
+
+
+
+
+
{rating.toFixed(1)}
+
+
+
+
+
+
+
+
+
+ );
+}
+
+function CommentBody({ content }: { content: string }) {
+ return {content}
;
+}
+
+function CommentLikeReply({
+ likes,
+ replies,
+}: {
+ likes: number;
+ replies: number;
+}) {
+ return (
+
+ 좋아요 {likes}
+ 댓글 {replies}
+
+ );
+}
+
+function LikeReplyBar({ liked }: { liked: boolean }) {
+ console.log(liked);
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default function CommentInfo({ comment }: { comment: CommentType }) {
+ return (
+
+ );
+}
diff --git a/src/components/Content.module.scss b/src/components/Content.module.scss
index a5fa865..dd4505c 100644
--- a/src/components/Content.module.scss
+++ b/src/components/Content.module.scss
@@ -57,7 +57,9 @@
width: 280px;
height: 400px;
margin-bottom: 30px;
- transition: width 0.3s, height 0.3s;
+ transition:
+ width 0.3s,
+ height 0.3s;
@media (max-width: #{$medium-screen + 100}) {
width: 200px;
diff --git a/src/components/Content.tsx b/src/components/Content.tsx
index bf31038..5467de6 100644
--- a/src/components/Content.tsx
+++ b/src/components/Content.tsx
@@ -1,4 +1,5 @@
import { useState } from "react";
+import { Link } from "react-router-dom";
import styles from "./Content.module.scss";
import { Carousel } from "./Carousel";
import profileDefault from "../assets/user_default.jpg";
diff --git a/src/components/Footer.module.scss b/src/components/Footer.module.scss
index 23e34fc..0f88456 100644
--- a/src/components/Footer.module.scss
+++ b/src/components/Footer.module.scss
@@ -33,6 +33,7 @@ footer {
.companyInfoDiv {
margin: 0 20px;
display: flex;
+ max-width: 1320px;
@media (min-width: 760px) {
margin: 0 3.5%;
diff --git a/src/components/ReplyList.module.scss b/src/components/ReplyList.module.scss
new file mode 100644
index 0000000..3897f47
--- /dev/null
+++ b/src/components/ReplyList.module.scss
@@ -0,0 +1,146 @@
+.replyList {
+ margin-top: 35px;
+ margin-left: 0px;
+ margin-right: 0px;
+
+ .replyListHeader {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 3px 0px 9px;
+
+ button {
+ background: none;
+ color: rgb(255, 47, 110);
+ font-size: 14px;
+ font-weight: 500;
+ letter-spacing: -0.5px;
+ line-height: 18px;
+ padding: 0px;
+ border: none;
+ }
+
+ button:hover {
+ text-decoration: underline;
+ cursor: pointer;
+ }
+
+ div {
+ color: rgb(140, 140, 140);
+ font-size: 13px;
+ font-weight: 400;
+ letter-spacing: -0.2px;
+ line-height: 16px;
+ }
+ }
+
+ .replies {
+ display: flex;
+ flex-direction: column-reverse;
+
+ .reply {
+ width: 100%;
+ padding: 12px 0px;
+ border-top: 1px solid rgba(0, 0, 0, 0.06);
+ display: flex;
+
+ .userImage {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ overflow: hidden;
+ box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 0px 1px inset;
+
+ img {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ .replyBody {
+ width: calc(100% - 40px);
+ margin-left: auto;
+
+ .replyHeader {
+ display: flex;
+ align-items: center;
+
+ .userName {
+ color: rgba(0, 0, 0, 0.8);
+ font-size: 14px;
+ font-weight: 700;
+ letter-spacing: -0.3px;
+ line-height: 18px;
+ }
+
+ .timeAgo {
+ color: rgb(140, 140, 140);
+ font-size: 13px;
+ font-weight: 400;
+ letter-spacing: -0.2px;
+ line-height: 16px;
+ margin-left: auto;
+ }
+ }
+
+ .replyContent {
+ color: rgb(74, 74, 74);
+ font-size: 15px;
+ font-weight: 400;
+ letter-spacing: -0.55px;
+ line-height: 22px;
+ white-space: pre-wrap;
+ width: calc(100% - 40px);
+ margin-top: 4px;
+ margin-bottom: 8px;
+ }
+
+ .liked {
+ display: flex;
+ align-items: center;
+ color: rgb(255, 47, 110);
+ font-size: 14px;
+ font-weight: 400;
+ letter-spacing: -0.3px;
+ line-height: 18px;
+ height: 24px;
+ padding: 0px 9px;
+ border-radius: 5px;
+ margin-left: -8px;
+ width: fit-content;
+ }
+
+ .liked:hover {
+ background: rgba(255, 47, 110, 0.08);
+ cursor: pointer;
+ }
+
+ .unliked {
+ display: flex;
+ align-items: center;
+ color: rgb(135, 137, 139);
+ font-size: 14px;
+ font-weight: 400;
+ letter-spacing: -0.3px;
+ line-height: 18px;
+ height: 24px;
+ padding: 0px 9px;
+ border-radius: 5px;
+ margin-left: -8px;
+ width: fit-content;
+ }
+
+ .unliked:hover {
+ background: rgba(41, 42, 50, 0.08);
+ cursor: pointer;
+ }
+
+ svg {
+ width: 14px;
+ height: 14px;
+ margin-right: 6px;
+ }
+ }
+ }
+ }
+}
diff --git a/src/components/ReplyList.tsx b/src/components/ReplyList.tsx
new file mode 100644
index 0000000..8df137f
--- /dev/null
+++ b/src/components/ReplyList.tsx
@@ -0,0 +1,88 @@
+import { ReplyType } from "./CommentInfo";
+import styles from "./ReplyList.module.scss";
+import userImage from "../assets/user_default.jpg";
+import { Link } from "react-router-dom";
+import elapsedTime from "../utils/elapsedTime";
+
+function Reply({ reply }: { reply: ReplyType }) {
+ return (
+
+
+
+
+
+
+
+
+
+
{reply.userName}
+
+
{elapsedTime(reply.date)}
+
+
{reply.content}
+
+ {reply.liked ? (
+
+ ) : (
+
+ )}
+ {reply.likes}
+
+
+
+ );
+}
+
+export default function ReplyList({
+ replyNumber,
+ replies,
+}: {
+ replyNumber: number;
+ replies: ReplyType[];
+}) {
+ return (
+
+
+
+
+ {replyNumber}개 중 {replies.length}개
+
+
+
+ {replies.map((reply: ReplyType, index: number) => (
+
+ ))}
+
+
+ );
+}
diff --git a/src/index.css b/src/index.css
index 98e14fa..8fb0040 100644
--- a/src/index.css
+++ b/src/index.css
@@ -23,5 +23,6 @@ input {
}
a {
+ color: black;
text-decoration: none;
}
diff --git a/src/pages/CommentPage.module.scss b/src/pages/CommentPage.module.scss
new file mode 100644
index 0000000..73d72eb
--- /dev/null
+++ b/src/pages/CommentPage.module.scss
@@ -0,0 +1,23 @@
+.commentPage {
+ max-width: 1320px;
+ margin-top: 80px;
+ margin-left: 15px;
+ margin-right: 15px;
+ margin-bottom: 55px;
+
+ @media (min-width: 760px) {
+ margin-left: 3.5%;
+ margin-right: 3.5%;
+ }
+
+ @media (min-width: 760px) {
+ margin-left: 60px;
+ margin-right: 60px;
+ }
+
+ @media (min-width: 1440px) {
+ margin-left: auto;
+ margin-right: auto;
+ width: 1320px;
+ }
+}
diff --git a/src/pages/CommentPage.tsx b/src/pages/CommentPage.tsx
index 6e7a80f..89851d8 100644
--- a/src/pages/CommentPage.tsx
+++ b/src/pages/CommentPage.tsx
@@ -1,7 +1,39 @@
+import styles from "./CommentPage.module.scss";
+import CommentInfo from "../components/CommentInfo";
+
export default function CommentPage() {
+ const comment = {
+ userName: "이동진",
+ movie: {
+ name: "오펜하이머",
+ releaseYear: "2023",
+ country: "영국",
+ posterUrl:
+ "https://an2-img.amz.wtchn.net/image/v2/TnfLooyFVulaY3fZhLMNIw.jpg?jwt=ZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKdmNIUnpJanBiSW1SZk5Ea3dlRGN3TUhFNE1DSmRMQ0p3SWpvaUwzWXlMM04wYjNKbEwybHRZV2RsTHpFMk9UQTFNRFk1TWpBNU9ERTVNamt5TkRNaWZRLmdfM0lvai1JZGVCbjVFRXhYQ3VFODMwdEN4MnNEa2JKbXV4VEk3QlJPYVE",
+ rating: 4.0,
+ },
+ rating: 4.5,
+ date: new Date("2024-01-15 12:00"),
+ content: `줄리어스 로버트 오펜하이머..
+ 줄리어스 로버트 오펜하이머..
+ 자기 이야기가 영화로 만들어진다니.
+ 로버트는 얼마나 좋았을까.
+ `,
+ likes: 200,
+ liked: false,
+ replyNumber: 1000,
+ replies: new Array(9).fill({
+ userName: "J. Robert Oppenheimer",
+ date: new Date("2024-01-15 10:00"),
+ content: "I felt good.",
+ likes: 100,
+ liked: false,
+ }),
+ };
+
return (
-
-
단일 코멘트 페이지
-
+
);
}
diff --git a/src/pages/Layout.module.scss b/src/pages/Layout.module.scss
new file mode 100644
index 0000000..bbdd684
--- /dev/null
+++ b/src/pages/Layout.module.scss
@@ -0,0 +1,11 @@
+.mainSection {
+ margin: 0;
+ padding-top: 0px;
+ padding-bottom: unset;
+ .mainDiv {
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+ justify-content: space-between;
+ }
+}
diff --git a/src/pages/Layout.tsx b/src/pages/Layout.tsx
index 0defef9..96db726 100644
--- a/src/pages/Layout.tsx
+++ b/src/pages/Layout.tsx
@@ -1,4 +1,5 @@
import { Outlet } from "react-router-dom";
+import styles from "./Layout.module.scss";
import Header from "../components/Header";
import Footer from "../components/Footer";
import SignupModal from "../components/SignupModal";
@@ -19,8 +20,12 @@ export default function Layout() {
)}
-
-
+
);
}
diff --git a/src/utils/elapsedTime.ts b/src/utils/elapsedTime.ts
new file mode 100644
index 0000000..369d90b
--- /dev/null
+++ b/src/utils/elapsedTime.ts
@@ -0,0 +1,23 @@
+export default function elapsedTime(date: Date) {
+ const start = date;
+ const end = new Date();
+
+ const diff = (end.getTime() - start.getTime()) / 1000;
+
+ const times = [
+ { name: "년", milliSeconds: 60 * 60 * 24 * 365 },
+ { name: "개월", milliSeconds: 60 * 60 * 24 * 30 },
+ { name: "일", milliSeconds: 60 * 60 * 24 },
+ { name: "시간", milliSeconds: 60 * 60 },
+ { name: "분", milliSeconds: 60 },
+ ];
+
+ for (const value of times) {
+ const betweenTime = Math.floor(diff / value.milliSeconds);
+
+ if (betweenTime > 0) {
+ return `${betweenTime}${value.name} 전`;
+ }
+ }
+ return "방금 전";
+}