diff --git a/src/pages/MainPage/MainPage.style.ts b/src/pages/MainPage/MainPage.style.ts index 311a3a1..ca22b4b 100644 --- a/src/pages/MainPage/MainPage.style.ts +++ b/src/pages/MainPage/MainPage.style.ts @@ -5,16 +5,40 @@ export const SearchDiv = styled.div` flex-direction: column; justify-content: center; align-items: start; - margin-top: 50px; + margin-top: 30px; width: 75vw; `; +export const CategoryWrapper = styled.div` + display: flex; + align-items: center; + + justify-content: space-between; + width: 100%; + align-items: center; +`; + export const StyledDiv = styled.div` display: flex; flex-direction: column; justify-content: center; align-items: center; width: 100%; + + .title { + color: #424856; + font-family: Inter; + font-size: 32px; + font-style: normal; + font-weight: 700; + line-height: 28px; /* 155.556% */ + + margin-top: 10px; + border-bottom: 1px solid #dee1e6; + align-items: left; + width: 100%; + padding-bottom: 20px; + } `; export const SearchItemDiv = styled.div` position: relative; @@ -23,6 +47,7 @@ export const SearchItemDiv = styled.div` justify-content: center; align-items: center; width: 100%; + margin-bottom: 20px; `; export const StyledForm = styled.form` @@ -62,6 +87,7 @@ export const SearchItemList = styled.div` display: flex; flex-direction: column; gap: 5px; + box-shadow: 0 4px 8px rgba(109, 108, 108, 0.1); `; export const SearchItem = styled.button` @@ -84,7 +110,7 @@ export const CategoryDiv = styled.div` justify-content: center; align-items: center; gap: 10px; - margin-top: 13px; + margin-bottom: 10px; `; export const CategoryItem = styled.button` @@ -111,12 +137,13 @@ export const CategoryItem = styled.button` export const MainContent = styled.div` padding: 20px; display: flex; - margin-top: 30px; + margin-top: 20px; width: 100%; justify-content: center; border-radius: 16px; border: 1px solid #dee1e6; background: #fff; + flex-direction: column; `; // SearchItemList (아이템 리스트) @@ -133,7 +160,7 @@ export const FileItem = styled.div` border-radius: 16px; border: 1px solid #dee1e6; background: #fff; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + box-shadow: 0 4px 8px rgba(109, 108, 108, 0.1); overflow: hidden; cursor: pointer; transition: transform 0.3s ease-in-out; @@ -183,3 +210,115 @@ export const FileDescription = styled.p` margin-bottom: 0px; margin-top: 0px; `; + +export const StyledLankPage = styled.div` + display: flex; + align-items: center; + flex-direction: column; + margin: 20px 16px; + gap: 16px; +`; + +export const PaginationWrapper = styled.div` + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + margin-top: 15px; + margin-bottom: 50px; +`; + +export const PageButton = styled.button<{ active: boolean }>` + padding: 8px 12px; + background-color: ${({ active }) => (active ? "#636ae8" : "#fff")}; + color: ${({ active }) => (active ? "#fff" : "#9095A1")}; + border-radius: 16px; + border: 1px solid ${({ active }) => (active ? "#636ae8" : "#dee1e6")}; + cursor: pointer; + + &:hover { + background-color: ${({ active }) => (active ? "#636ae8" : "#f0f0f0")}; + border-color: #636ae8; /* hover 시 border 색상 변경 */ + } +`; + +export const ArrowButton = styled.button` + padding: 8px; + background-color: #fff; + color: #636ae8; + border-radius: 50%; + cursor: pointer; + + &:hover { + background-color: #fff; /* 화살표 버튼에는 hover 배경색을 없애거나 투명하게 */ + } +`; + +export const Ellipsis = styled.span` + color: #636ae8; +`; + +export const StyledLankLabel = styled.div<{ rank: number }>` + display: flex; + justify-content: center; /* 수평 가운데 정렬 */ + align-items: center; /* 수직 가운데 정렬 */ + \ + color: ${({ rank }) => + rank === 1 + ? "#D5A11E" + : rank === 2 + ? "#A3A3A3" + : rank === 3 + ? "#CD7F32" + : "#9095A1"}; + border-radius: 18px; + padding: 5px 10px; + font-size: 16px; +`; +export const LankDiv = styled.div` + display: flex; + flex-direction: row; + gap: 1px; +`; +export const RankWrapper = styled.div` + display: flex; + flex-direction: column; /* 수직 정렬 */ + align-items: center; + justify-content: center; + width: 200px; + height: 40px; /* 충분히 높이를 키워서 애니메이션이 보이게 설정 */ + overflow: hidden; + margin-bottom: 10px; +`; + +export const RankContent = styled.div` + display: flex; + flex-direction: column; /* 수직으로 배치 */ + animation: slide 9s infinite; /* 슬라이드 애니메이션 */ + + @keyframes slide { + 0% { + transform: translateY(40px); + } + 33.33% { + transform: translateY(0px); /* 첫 번째 아이템이 위로 이동 */ + } + 66.66% { + transform: translateY(-40px); /* 두 번째 아이템이 위로 이동 */ + } + 100% { + transform: translateY(40px); /* 다시 원위치 */ + } + } +`; + +export const RankItem = styled.div` + flex: 0 0 30px; /* 고정된 크기로 설정 */ + height: 30px; + display: flex; + justify-content: center; + align-items: center; + padding: 5px; + margin: 0 10px; + border-radius: 8px; +`; diff --git a/src/pages/MainPage/MainPage.tsx b/src/pages/MainPage/MainPage.tsx index 4ece6ea..c243f18 100644 --- a/src/pages/MainPage/MainPage.tsx +++ b/src/pages/MainPage/MainPage.tsx @@ -4,18 +4,47 @@ import useDebounce from "@/hooks/useDebounce"; import { useState, useEffect } from "react"; import { useNavigate } from "react-router"; import search from "@/assets/image/Search.svg"; +import frontArrow from "@/assets/image/frontArrow.svg"; +import backArrow from "@/assets/image/backArrow.svg"; const MainPage = () => { const [searchTerm, setSearchTerm] = useState(""); const debouncedSearchTerm = useDebounce(searchTerm, 500); const navigate = useNavigate(); - // 데이터를 저장할 상태 선언 const [data, setData] = useState([]); + const [currentPage, setCurrentPage] = useState(1); + const itemsPerPage = 8; // 한 페이지에 보여줄 아이템 수 + const users = [ + { name: "홍길동", rank: 1, points: 5000 }, + { name: "김철수", rank: 2, points: 4500 }, + { name: "박영희", rank: 3, points: 3000 }, + ]; + + const currentData = data.slice( + (currentPage - 1) * itemsPerPage, + currentPage * itemsPerPage + ); + + const totalPages = Math.ceil(data.length / itemsPerPage); + + const createPageButtons = () => { + const pageButtons = []; + const range = 2; // "현재 페이지"를 기준으로 보여줄 범위 + + for ( + let i = Math.max(1, currentPage - range); + i <= Math.min(totalPages, currentPage + range); + i++ + ) { + pageButtons.push(i); + } + + return pageButtons; + }; - // 컴포넌트 마운트 시 데이터를 가져오는 useEffect useEffect(() => { - // JSON 데이터를 서버에서 받는다고 가정 (여기서는 직접 정의) const fetchedData = [ + // 더미 데이터 { id: 1, name: "React로 배우는 프론트엔드", @@ -64,9 +93,50 @@ const MainPage = () => { category: "시험자료", image: "image8.jpg", }, + { + id: 9, + name: "React로 배우는 프론트엔드", + category: "시험자료", + image: "image1.jpg", + }, + { + id: 10, + name: "JavaScript 핵심 문법", + category: "이력서", + image: "image2.jpg", + }, + { + id: 11, + name: "HTML5 & CSS3 마스터", + category: "레포트", + image: "image3.jpg", + }, + { + id: 12, + name: "웹 개발의 기초", + category: "이력서", + image: "image4.jpg", + }, + { + id: 13, + name: "Node.js 기초부터 실전까지", + category: "시험자료", + image: "image5.jpg", + }, + { + id: 14, + name: "디자인 패턴과 아키텍처", + category: "레포트", + image: "image6.jpg", + }, + { + id: 15, + name: "Git으로 협업하는 방법", + category: "이력서", + image: "image7.jpg", + }, ]; - // 데이터를 상태에 저장 setData(fetchedData); }, []); @@ -89,6 +159,51 @@ const MainPage = () => { + + + navigate("/search")}> + 모든자료 + + navigate("/search")}> + 시험 자료 + + navigate("/search")}> + 자소서 + + navigate("/search")}> + 이력서 + + navigate("/search")}> + 레포트 + + navigate("/search")}> + 악보 + + navigate("/search")}> + 기타 + + + + + + + {users.map((user, index) => ( + { + navigate("/lank"); + }} + > + + {user.rank}위 + + {user.name} ({user.points}점) + + ))} + + + + search @@ -120,33 +235,13 @@ const MainPage = () => { )} - - navigate("/search")}> - 모든자료 - - navigate("/search")}> - 시험 자료 - - navigate("/search")}> - 자소서 - - navigate("/search")}> - 이력서 - - navigate("/search")}> - 레포트 - - navigate("/search")}> - 악보 - - navigate("/search")}> - 기타 - - + +
모든 자료
+
- {data.map((item) => ( + {currentData.map((item) => ( {item.name} @@ -159,6 +254,32 @@ const MainPage = () => { ))}
+ + {/* 페이지네이션 */} + + setCurrentPage((prev) => Math.max(prev - 1, 1))} + > + ◁ + + {createPageButtons().map((page: number) => ( + setCurrentPage(page)} + active={page === currentPage} + > + {page} + + ))} + {currentPage + 2 < totalPages && ...} + + setCurrentPage((prev) => Math.min(prev + 1, totalPages)) + } + > + ▷ + +
);