diff --git a/src/components/frontWorkList/CommentBox.jsx b/src/components/frontWorkList/CommentBox.jsx
new file mode 100644
index 0000000..651ffbd
--- /dev/null
+++ b/src/components/frontWorkList/CommentBox.jsx
@@ -0,0 +1,153 @@
+import { useState } from "react";
+import styled from "styled-components";
+import useModal from "../../hooks/useModal";
+
+const CommentBox = ({commentData}) => {
+ const [commentText, setCommentText] = useState('');
+ const [charCount, setCharCount] = useState(0);
+ // useModal 사용해서 글자수 제한 모달 구현
+ const { isModalOpen, openModal, closeModal, Modal } = useModal();
+
+ // 댓글 갯수
+ const commentCount = commentData.length;
+
+ // open modal
+ const handleModal = (e) => {
+ const text = e.target.value;
+ if (text.length <= 1000 && !isModalOpen) {
+ setCommentText(text);
+ setCharCount(text.length);
+ } else {
+ setCommentText(text.slice(0,1000)); // 글자수 제한 초과 부분을 제외하고 저장
+ setCharCount(10);
+ openModal();
+ }
+ };
+
+ // close modal
+ const handelModalConfirm = () => {
+ closeModal();
+ }
+
+ return (
+
+ 댓글 {commentCount}
+
+
+
+ {charCount} / 1000
+
+ 등록
+
+ {/* modal */}
+
+
+
+ 제한된 글자수를 초과했습니다.
+
+
+
+
+
+
+ );
+};
+
+const CommentWrapper = styled.div`
+ padding: 16px;
+ margin: 0 auto 40px;
+ background-color: #3F424E;
+ flex-direction: column;
+ align-items: flex-start;
+`;
+
+const CommentCount = styled.div`
+ margin-bottom: 11px;
+ front-size: 15px;
+`;
+
+const CommentContainer = styled.div`
+ display: flex;
+ justify-content: space-between;
+`;
+
+const TextAreaContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
+
+const CommentTextArea = styled.textarea`
+ padding: 8px;
+ resize: none;
+ background-color: #A7A7A7;
+ color: black;
+ font-size: 13.5px;
+ border: 1px solid #A7A7A7;
+ height: 57px;
+ border-top-left-radius: 6px;
+ border-top-right-radius: 6px;
+ overflow: hidden;
+ outline: none;
+ border: none;
+`;
+
+const CharCount = styled.div`
+ text-align: right;
+ color: #393939;
+ padding: 0 15px;
+ background-color: #A7A7A7;
+ border-bottom-right-radius: 6px;
+ border-bottom-left-radius: 6px;;
+`;
+
+const SubmitButton = styled.button`
+ background-color: #007bff;
+ font-size: 15px;
+ color: black;
+ border: none;
+ padding: 10px 16px;
+ cursor: pointer;
+ background-color: #A7A7A7;
+ margin-left: 11px;
+ align-self: flex-end;
+ border-radius: 6px;
+ width: 91px;
+ height: 91px;
+`;
+
+const ModalContent = styled.div`
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+ height: 100%;
+ margin-top: 60px;
+ font-size: 14px;
+ text-align: center;
+`;
+
+const ModalBody = styled.div`
+ margin-bottom: 20px;
+ color: #c7c7c7;
+ text-align: center;
+ margin-bottom: 30px;
+`;
+
+const Button = styled.button`
+ width: 301px;
+ height: 37px;
+ background-color: #5263ff;
+ font-size: 14px;
+ color: #ffffff;
+ border: none;
+ border-radius: 6px;
+ margin-top: 20px;
+`;
+
+export default CommentBox;
\ No newline at end of file
diff --git a/src/components/frontWorkList/CommentItem.jsx b/src/components/frontWorkList/CommentItem.jsx
new file mode 100644
index 0000000..248cd57
--- /dev/null
+++ b/src/components/frontWorkList/CommentItem.jsx
@@ -0,0 +1,64 @@
+import styled from "styled-components";
+import UserIcon from "../../assets/people.png";
+import LikeIcon from "../../assets/heart.png";
+
+const CommentItem = ({ item }) => {
+ return (
+
+
+ {item.user}
+
+ {item.content}
+
+ {item.date}
+
+ {item.like}
+
+
+
+ );
+};
+
+const Wrapper = styled.div`
+ background-color: transparent;
+ border-color: #868686 transparent;
+ border-style: solid;
+ border-width: 1px 0;
+ padding: 17px;
+
+ &:not(:first-child) {
+ margin-top: -1px; // 첫 번째 div는 마진을 설정 안함
+ }
+`;
+
+const Name = styled.div`
+ display: flex;
+ align-items: center;
+`;
+
+const Content = styled.div`
+ padding: 14px 24px 7px;
+`;
+
+const Date = styled.div`
+ padding: 7px 24px;
+`;
+
+const Like = styled.div`
+ display: flex;
+ align-items: center;
+ background-color: #3F424E;
+ border-radius: 6px;
+ padding: 8px;
+`;
+
+const Icon = styled.img`
+ margin-right: 8px;
+`;
+
+const Container = styled.div`
+ display: flex;
+ justify-content: space-between;
+`;
+
+export default CommentItem;
\ No newline at end of file
diff --git a/src/components/frontWorkList/CommentList.jsx b/src/components/frontWorkList/CommentList.jsx
new file mode 100644
index 0000000..e76ba45
--- /dev/null
+++ b/src/components/frontWorkList/CommentList.jsx
@@ -0,0 +1,125 @@
+import { useState, useEffect } from "react";
+import styled from "styled-components";
+import CommentItem from "./CommentItem";
+import CommentBox from "./CommentBox";
+
+function isEqual(arr1, arr2) {
+ if (arr1.length !== arr2.length) {
+ return false;
+ }
+
+ for (let i = 0; i < arr1.length; i++) {
+ if (arr1[i].id !== arr2[i].id) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+export default function CommentList() {
+ // 임시 댓글 data
+ const commentData = [
+ {id: 0, user: "소밍밍", content: "안녕하세요. 문제가 너무 좋네요. 덕분에 학습 잘 하고 갑니다.", date: "2023.08.20 21:23", like: 7},
+ {id: 1, user: "소밍밍", content: "안녕하세요. 문제가 너무 좋네요. 덕분에 학습 잘 하고 갑니다.", date: "2023.08.23 21:23", like: 5},
+ {id: 2, user: "소밍밍", content: "안녕하세요. 문제가 너무 좋네요. 덕분에 학습 잘 하고 갑니다.", date: "2023.08.10 21:23", like: 0},
+ {id: 3, user: "소밍밍", content: "안녕하세요. 문제가 너무 좋네요. 덕분에 학습 잘 하고 갑니다.", date: "2023.08.09 21:23", like: 5},
+ ];
+
+ const [data, setData] = useState(commentData);
+ const [showMore, setShowMore] = useState(false); // 답안 댓글 토글
+ const [sortOption, setSortOption] = useState('latest'); // 초기 정렬 기준 : 최신순
+
+ useEffect(() => {
+ // 댓글 정렬
+ const sortData = (sortKey) => {
+ const sortedData = [...data]; // 원본 데이터를 변경하지 않기 위해 복사
+
+ if (sortKey === 'latest') {
+ sortedData.sort((a, b) => new Date(b.date) - new Date(a.date)); // 최신순
+ } else if (sortKey === 'oldest') {
+ sortedData.sort((a, b) => new Date(a.date) - new Date(b.date)); // 등록순
+ } else if (sortKey === 'mostLiked') {
+ sortedData.sort((a, b) => b.like - a.like); // 추천순
+ }
+
+ return sortedData;
+ };
+ const sortedData = sortData(sortOption);
+
+ // 정렬된 데이터와 현재 데이터가 다를 경우에만 업데이트
+ if (!isEqual(sortedData, data)) {
+ setData(sortedData);
+ }
+ }, [sortOption, data]);
+
+ const visibleBtn= data.length > 3; // 댓글이 3개 이상일 때만 버튼이 보임
+ const toggleShowMore = () => {
+ setShowMore(!showMore);
+ }
+
+ return(
+
+
+
+
+ setSortOption('latest')}
+ active={sortOption === 'latest'}
+ >
+ 최신순
+
+ setSortOption('oldest')}
+ active={sortOption === 'oldest'}
+ >
+ 등록순
+
+ setSortOption('mostLiked')}
+ active={sortOption === 'mostLiked'}
+ >
+ 추천순
+
+
+
+ {data.slice(0, showMore ? data.length : 3).map((comment, index) => (
+
+ ))}
+ {visibleBtn && (
+
+ {showMore ? "댓글 숨기기" : "댓글 더보기"}
+
+ )}
+
+ );
+};
+
+const SortOptions = styled.div`
+ align-items: center;
+ display: flex;
+ padding: 5px 0;
+ margin-bottom: 11px;
+`;
+
+const SortButton = styled.button`
+ margin-right: 15spx;
+ background-color: transparent;
+ color: ${(props) => (props.active ? '#FFFFFF' : '#838383')};
+ font-size: 16px;
+ border: none;
+ cursor: pointer;
+`;
+
+const ShowMoreBtn = styled.button`
+ width: 1090px;
+ height: 37px;
+ border: none;
+ border-radius: 6px;
+ background-color: #3f424e;
+ color: #ffffff;
+ font-size: 14px;
+ font-weight: 500;
+ margin-bottom: 35px;
+ margin-top: 20px;
+`;
\ No newline at end of file
diff --git a/src/components/frontWorkList/FrontWorkItem.jsx b/src/components/frontWorkList/FrontWorkItem.jsx
new file mode 100644
index 0000000..0d8158e
--- /dev/null
+++ b/src/components/frontWorkList/FrontWorkItem.jsx
@@ -0,0 +1,55 @@
+import styled from "styled-components";
+import { Link } from 'react-router-dom';
+import ViewIcon from "../../assets/see.png";
+import StartBtn from "../../assets/Btn_start.png";
+
+function formatNumber(num) {
+ return num < 10 ? `0${num}` : num.toString();
+}
+
+const FrontWorkItem = ({ item, index}) => {
+ return (
+
+ {formatNumber(index+1)}
+ {item.title}
+ {item.date}
+
+
+ {formatNumber(item.view)}
+
+
+
+
+

+
+
+
+ );
+};
+
+const Container = styled.div`
+ display: flex;
+ position: relative;
+ justify-content: space-between;
+ align-items: center;
+ width: 1090px;
+ font-size: 15px;
+ padding: 5px 0;
+ border-bottom: 1px solid #ddd;
+ border-top: 1px solid #ddd;
+
+ &:not(:first-child) {
+ margin-top: -1px; // 첫 번째 div는 마진을 설정 안함
+ }
+`;
+
+const IconTextWrapper = styled.div`
+ display: flex;
+ align-items: center;
+`;
+
+const Icon = styled.img`
+ padding: 0 5px;
+`;
+
+export default FrontWorkItem;
\ No newline at end of file
diff --git a/src/components/frontWorkList/WorkList.jsx b/src/components/frontWorkList/WorkList.jsx
new file mode 100644
index 0000000..59c646c
--- /dev/null
+++ b/src/components/frontWorkList/WorkList.jsx
@@ -0,0 +1,186 @@
+import { useState, useEffect } from "react";
+import styled from "styled-components";
+import FrontItem from "./FrontWorkItem";
+import SearchBar from "../front/SearchBar";
+import usePagination from "../../hooks/usePagination";
+import LeftIcon from "../../assets/left.png";
+import RightIcon from "../../assets/right.png";
+
+function isEqual(arr1, arr2) {
+ if (arr1.length !== arr2.length) {
+ return false;
+ }
+
+ for (let i = 0; i < arr1.length; i++) {
+ if (arr1[i].id !== arr2[i].id) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+export default function WorkList() {
+ // 임시 프론트 문제집 data
+ const frontWorkData = [
+ {id: 0, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-16", view: 10},
+ {id: 1, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-15", view: 10},
+ {id: 2, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-14", view: 2},
+ {id: 3, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-13", view: 0},
+ {id: 4, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-12", view: 1},
+ {id: 5, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-11", view: 15},
+ {id: 6, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-10", view: 12},
+ {id: 7, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-09", view: 11},
+ {id: 8, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-08", view: 9},
+ {id: 9, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-07", view: 19},
+ {id: 10, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-06", view: 30},
+ {id: 11, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-05", view: 5},
+ {id: 12, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-04", view: 6},
+ {id: 13, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-03", view: 0},
+ {id: 14, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-02", view: 11},
+ {id: 15, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-10-01", view: 10},
+ {id: 16, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-09-30", view: 10},
+ {id: 17, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-09-29", view: 10},
+ {id: 18, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-09-28", view: 10},
+ {id: 19, title: "정보처리기사실기_2023정보처리기사실기_2023", date: "2023-09-27", view: 10},
+ ];
+ const [sortOption, setSortOption] = useState('latest'); // 초기 정렬 기준 : 최신순
+ const [data, setData] = useState(frontWorkData); // 데이터 상태 정의
+
+ const itemsPerPage = 15; // 페이지 당 보여줄 아이템 수
+ const {
+ currentPage,
+ currentItems,
+ totalPages,
+ paginate,
+ goToPrevPage,
+ goToNextPage,
+ } = usePagination(
+ data,
+ itemsPerPage
+ );
+
+ useEffect(() => {
+ // 문제집 리스트 정렬
+ const sortData = (sortKey) => {
+ const sortedData = [...data]; // 원본 데이터를 변경하지 않기 위해 복사
+
+ if (sortKey === 'latest') {
+ sortedData.sort((a, b) => new Date(b.date) - new Date(a.date)); // 최신순
+ } else if (sortKey === 'oldest') {
+ sortedData.sort((a, b) => new Date(a.date) - new Date(b.date)); // 등록순
+ } else if (sortKey === 'mostViewed') {
+ sortedData.sort((a, b) => b.view - a.view); // 조회순
+ }
+
+ return sortedData;
+ };
+ const sortedData = sortData(sortOption);
+
+ // 정렬된 데이터와 현재 데이터가 다를 경우에만 업데이트
+ if (!isEqual(sortedData, data)) {
+ setData(sortedData);
+ }
+ }, [sortOption, data]);
+
+ return(
+
+
+
+ setSortOption('latest')}
+ active={sortOption === 'latest'}
+ >
+ 최신순
+
+ setSortOption('oldest')}
+ active={sortOption === 'oldest'}
+ >
+ 등록순
+
+ setSortOption('mostViewed')}
+ active={sortOption === 'mostViewed'}
+ >
+ 조회순
+
+
+
+
+
+
+ {/* 필터링된 스터디 리스트 표시 */}
+
+ {/* 현재 페이지의 아이템 렌더링 */}
+ {currentItems.map((front, index) => (
+
+ ))}
+
+ {/* 페이지네이션 컴포넌트 렌더링 */}
+
+
+
+
+ {Array.from({ length: totalPages }).map((_, index) => (
+ paginate(index + 1)}
+ isSelected={index + 1 === currentPage}
+ >
+ {index + 1}
+
+ ))}
+
+
+
+
+
+
+ );
+};
+
+const Container = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+`;
+
+const SortOptions = styled.div`
+ align-items: center;
+ display: flex;
+ padding: 5px 0;
+`;
+
+const SortButton = styled.button`
+ margin-right: 15spx;
+ background-color: transparent;
+ color: ${(props) => (props.active ? '#FFFFFF' : '#838383')};
+ font-size: 16px;
+ border: none;
+ cursor: pointer;
+`;
+
+const PaginationContainer = styled.div`
+ display: flex;
+ align-items: center;
+ margin-top: 20px;
+ justify-content: center;
+ margin-bottom: 50px;
+`;
+
+const PaginationButton = styled.button`
+ background-color: transparent;
+ border: none;
+ font-size: 16px;
+ cursor: pointer;
+ margin: 0 5px;
+`;
+
+const PageButton = styled.button`
+ border: none;
+ margin: 10px;
+ background-color: transparent;
+ color: ${(props) => (props.isSelected ? "#5263ff" : "#838383")};
+ font-size: 15px;
+`;
\ No newline at end of file
diff --git a/src/pages/FrontWorkList.jsx b/src/pages/FrontWorkList.jsx
index f6e8321..f7c1739 100644
--- a/src/pages/FrontWorkList.jsx
+++ b/src/pages/FrontWorkList.jsx
@@ -1,5 +1,112 @@
+import styled from "styled-components";
+import { Link } from 'react-router-dom';
+import { useState } from "react";
+import LikeIcon from "../assets/heart.png";
+import CmtIcon from "../assets/chat.png";
+import UserIcon from "../assets/people.png";
+import LikeBtn from "../assets/Btn_like.png";
+import AllBtn from "../assets/Btn_all.png";
+import WorkList from "../components/frontWorkList/WorkList";
+import CommentList from "../components/frontWorkList/CommentList";
+
const FrontWorkList = () => {
- return 프론트엔드 스터디방 메인 페이지입니다
;
+ const [textValue, setTextValue] = useState(0); // 추천수 올리기
+
+ const increaseLike = () => {
+ setTextValue(textValue + 1);
+ };
+
+ return (
+
+
+
+ 정보처리기사 실기_2023 총 91문제
+
+
+
+
+
+ 소밍밍
+
+
+
+ {textValue}
+
+
+ 04
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
};
-export default FrontWorkList;
+const Wrapper = styled.div`
+ max-width: 1090px;
+ margin: 0 auto 50px;
+`;
+
+const TopSection = styled.div`
+ padding: 20px 0;
+ margin-bottom: 50px;
+`;
+
+const TopTitle = styled.div`
+ font-size: 20px;
+ font-weight: bold;
+ display: flex;
+ align-items: center;
+ margin-bottom: 17px;
+`;
+
+const Works = styled.div`
+ font-size: 15px;
+ margin-left: 42px;
+`;
+
+const TopContent = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 16px;
+`;
+
+const WorkbookInfo = styled.div`
+ display: flex;
+ gap: 52px;
+`;
+
+const LikeCmt = styled.div`
+ gap: 17px;
+ display: flex;
+`;
+
+const IconTextWrapper = styled.div`
+ display: flex;
+ align-items: center;
+`;
+
+const Icon = styled.img`
+ margin-right: 5px;
+`;
+
+const Buttons = styled.div`
+ display: flex;
+ gap: 17px;
+ text-align: right;
+ align-items: center;
+`;
+
+export default FrontWorkList;
\ No newline at end of file