From 64ee801dd9769a423cbf4ab6ed17bd34abf74231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=99=8D=EB=B2=94?= Date: Sun, 22 Dec 2024 19:39:19 +0900 Subject: [PATCH] =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 12 +- .../ingredient/Ingredient.module.css | 2 +- .../ingredient/SearchIngredient.module.css | 2 + .../SearchIngredientList.module.css | 112 ++++++++++++--- .../userIngredient/UsersIngredient.module.css | 130 +++++++++++++----- .../searchIngredient/SearchIngredientList.jsx | 27 +++- .../userIngredient/UsersIngredient.jsx | 55 +++++++- 7 files changed, 273 insertions(+), 67 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 7007531..7aac410 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -2,23 +2,23 @@ import { BrowserRouter, Routes, Route } from "react-router-dom" import Layout from "./pages/layouts/Layout" import Ingredient from "./pages/ingredient/Ingregdient" import Recipe from "./pages/recipe/Recipe" -import {AddRecipe} from "./pages/recipe/AddRecipe" +import { AddRecipe } from "./pages/recipe/AddRecipe" import Join from "./pages/user/Join" function App() { return ( - }> + }> - }/> + } /> {/* } /> */} - } /> - } /> + } /> + } /> - } /> + } /> diff --git a/src/assets/css/Ingredient/ingredient/Ingredient.module.css b/src/assets/css/Ingredient/ingredient/Ingredient.module.css index ce83bd4..a46feaf 100644 --- a/src/assets/css/Ingredient/ingredient/Ingredient.module.css +++ b/src/assets/css/Ingredient/ingredient/Ingredient.module.css @@ -2,7 +2,7 @@ .mainLayout { display: flex; min-height: 100vh; - background-color: #f0fff0; + background-color: #ffffff; } .searchSection { diff --git a/src/assets/css/Ingredient/ingredient/SearchIngredient.module.css b/src/assets/css/Ingredient/ingredient/SearchIngredient.module.css index dad3170..7c9119e 100644 --- a/src/assets/css/Ingredient/ingredient/SearchIngredient.module.css +++ b/src/assets/css/Ingredient/ingredient/SearchIngredient.module.css @@ -2,6 +2,8 @@ .searchContainer { padding: 1rem; width: 100%; + border: 1px solid #e0e0e0; + border-radius: 5px; } .searchSection { diff --git a/src/assets/css/Ingredient/ingredient/SearchIngredientList.module.css b/src/assets/css/Ingredient/ingredient/SearchIngredientList.module.css index 2b39698..10be531 100644 --- a/src/assets/css/Ingredient/ingredient/SearchIngredientList.module.css +++ b/src/assets/css/Ingredient/ingredient/SearchIngredientList.module.css @@ -81,35 +81,39 @@ /* 카드 관련 스타일 */ .cardContainer { + background-color: white; border: 1px solid #e0e0e0; border-radius: 8px; padding: 10px; - display: flex; /* 왼쪽 이미지, 오른쪽 텍스트 영역으로 나누기 */ + display: flex; /* 수평 배치 */ gap: 10px; + width: 100%; /* 전체 너비 사용 */ + height: 120px; /* 카드 높이 고정 */ } .ingredientCard { - background: white; - width: 150px; /* 이미지 영역 너비 고정 */ - height: 100px; position: relative; - border: 1px solid #e0e0e0; + width: 150px; /* 이미지 영역 너비 고정 */ + height: 90px; border-radius: 4px; + overflow: hidden; + flex-shrink: 0; /* 이미지 영역 크기 고정 */ } -.whitespace { +.ingredientImage { width: 100%; height: 100%; - background: white; + object-fit: cover; + border-radius: 4px; } .statusDot { position: absolute; - left: -6px; - bottom: -6px; /* 위치를 하단으로 변경 */ + left: 1px; + bottom: 2px; width: 24px; height: 24px; - background-color: #4caf50; + background-color: rgba(139, 226, 38, 0.912); border-radius: 50%; border: none; color: white; @@ -120,16 +124,21 @@ cursor: pointer; padding: 0; line-height: 1; - z-index: 1; /* 버튼이 다른 요소 위에 올라오도록 */ + z-index: 1; + transition: background-color 0.3s ease; +} + +.statusDot:hover { + background-color: rgba(112, 182, 30, 0.912); + color: white; } .textContent { - flex: 1; /* 남은 공간 모두 차지 */ + flex: 1; display: flex; - flex-direction: column; /* 세로로 배치 */ - justify-content: flex-start; - padding: 5px 0; - gap: 5px; /* 재료명과 카테고리 사이 간격 */ + flex-direction: column; + justify-content: center; + gap: 5px; } .ingredientName { @@ -145,9 +154,10 @@ .ingredientsGrid { display: grid; - grid-template-columns: repeat(2, 1fr); /* 고정적으로 2개의 컬럼 */ + grid-template-columns: repeat(2, 1fr); gap: 1rem; padding: 1rem; + min-height: 600px; } /* 반응형 미디어 쿼리 */ @@ -194,3 +204,71 @@ transform: rotate(360deg); } } +/* 페이지네이션 컨테이너 */ +.pagination { + display: flex; + justify-content: center; + align-items: center; + gap: 8px; + margin: 2rem 0; + padding: 0 1rem; +} + +/* 페이지 버튼 기본 스타일 */ +.pageButton { + min-width: 36px; + height: 36px; + border: 1px solid #e0e0e0; + background-color: white; + border-radius: 6px; + color: #666; + font-size: 14px; + cursor: pointer; + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; +} + +/* 호버 효과 */ +.pageButton:hover { + background-color: #f5f5f5; + border-color: #d0d0d0; + color: #333; +} + +/* 활성화된 페이지 버튼 */ +.activePage { + background-color: #4caf50; + border-color: #4caf50; + color: white; + font-weight: 500; +} + +/* 활성화된 버튼 호버 효과 */ +.activePage:hover { + background-color: #45a049; + border-color: #45a049; + color: white; +} + +/* 비활성화된 버튼 (선택사항) */ +.pageButton:disabled { + background-color: #f5f5f5; + border-color: #e0e0e0; + color: #bdbdbd; + cursor: not-allowed; +} + +/* 반응형 조정 */ +@media (max-width: 768px) { + .pagination { + gap: 4px; + } + + .pageButton { + min-width: 32px; + height: 32px; + font-size: 13px; + } +} diff --git a/src/assets/css/Ingredient/userIngredient/UsersIngredient.module.css b/src/assets/css/Ingredient/userIngredient/UsersIngredient.module.css index 57f5d3e..b43214e 100644 --- a/src/assets/css/Ingredient/userIngredient/UsersIngredient.module.css +++ b/src/assets/css/Ingredient/userIngredient/UsersIngredient.module.css @@ -1,82 +1,65 @@ +/* UserIngredient.module.css */ .container { padding: 1rem; - background-color: #f0fff0; /* 연한 녹색 배경 */ text-align: center; + border: 1px solid #e0e0e0; + border-radius: 5px; } .cardContainer { display: grid; - grid-template-columns: repeat(3, 1fr); /* 기본적으로 3개 열 */ - gap: 1rem; /* 카드 간 간격 */ - justify-content: flex-start; /* 카드들을 왼쪽 정렬 */ + grid-template-columns: repeat(3, 1fr); + gap: 1rem; + justify-content: flex-start; + margin-bottom: 2rem; } /* 대형 화면 (1200px 이상) */ @media (max-width: 1200px) { .cardContainer { - grid-template-columns: repeat(3, 1fr); /* 3개 열 유지 */ + grid-template-columns: repeat(3, 1fr); } } /* 중간 화면 (992px ~ 1200px) */ @media (max-width: 992px) { .cardContainer { - grid-template-columns: repeat(2, 1fr); /* 2개 열로 변경 */ + grid-template-columns: repeat(2, 1fr); } } /* 작은 화면 (768px ~ 992px) */ @media (max-width: 768px) { .cardContainer { - grid-template-columns: repeat(2, 1fr); /* 2개 열 유지 */ + grid-template-columns: repeat(2, 1fr); } } /* 모바일 화면 (768px 미만) */ @media (max-width: 576px) { .cardContainer { - grid-template-columns: 1fr; /* 1개 열로 변경 */ + grid-template-columns: 1fr; } } .header { display: flex; - flex-direction: column; /* 수직으로 배치 */ - align-items: center; /* 수평 가운데 정렬 */ - justify-content: center; /* 수직 가운데 정렬 */ - margin-bottom: 1rem; /* 제목과 카드 간격 추가 */ + flex-direction: column; + align-items: center; + justify-content: center; + margin-bottom: 2rem; padding: 0 1rem; } .header h1 { font-size: 1.8rem; color: #333; - margin: 0 0 0.5rem; /* 아래 간격 추가 */ -} - -.filterDropdown { - padding: 0.5rem 1rem; - font-size: 1rem; - border: 1px solid #ddd; /* 드롭다운 테두리 */ - border-radius: 5px; /* 모서리 둥글게 */ - cursor: pointer; - background-color: #ffffff; /* 드롭다운 배경 */ - color: #333; /* 텍스트 색상 */ - transition: border-color 0.3s ease; -} - -.filterDropdown:focus { - outline: none; - border-color: #28a745; /* 초록색 테두리 */ -} - -.filterDropdown:hover { - border-color: #28a745; /* 호버 시 테두리 색상 */ + margin: 0 0 1rem; } .filters { display: flex; - gap: 1rem; /* 필터 간 간격 */ + gap: 1rem; align-items: center; } @@ -91,6 +74,15 @@ transition: border-color 0.3s ease; } +.filterDropdown:focus { + outline: none; + border-color: #28a745; +} + +.filterDropdown:hover { + border-color: #28a745; +} + .favoriteButton { padding: 0.5rem 1rem; font-size: 1rem; @@ -99,16 +91,78 @@ cursor: pointer; background-color: #ffffff; color: #333; - transition: background-color 0.3s ease, border-color 0.3s ease; + transition: all 0.3s ease; } .favoriteButton.active { - background-color: #28a745; /* 활성화 상태 */ - color: white; /* 텍스트 색상 */ + background-color: #28a745; + color: white; border-color: #28a745; } .favoriteButton:hover { - background-color: #218838; /* Hover 시 어두운 초록색 */ + background-color: #218838; color: white; } + +/* 페이지네이션 스타일 */ +.pagination { + display: flex; + justify-content: center; + align-items: center; + gap: 8px; + margin: 2rem 0; + padding: 0 1rem; +} + +.pageButton { + min-width: 36px; + height: 36px; + border: 1px solid #e0e0e0; + background-color: white; + border-radius: 6px; + color: #666; + font-size: 14px; + cursor: pointer; + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; +} + +.pageButton:hover:not(:disabled) { + background-color: #f5f5f5; + border-color: #d0d0d0; + color: #333; +} + +.activePage { + background-color: #28a745 !important; + border-color: #28a745 !important; + color: white !important; + font-weight: 500; +} + +.activePage:hover { + background-color: #218838 !important; + border-color: #218838 !important; +} + +.pageButton:disabled { + background-color: #f5f5f5; + border-color: #e0e0e0; + color: #bdbdbd; + cursor: not-allowed; +} + +@media (max-width: 768px) { + .pagination { + gap: 4px; + } + + .pageButton { + min-width: 32px; + height: 32px; + font-size: 13px; + } +} diff --git a/src/components/ingredient/searchIngredient/SearchIngredientList.jsx b/src/components/ingredient/searchIngredient/SearchIngredientList.jsx index af230ad..751d4ea 100644 --- a/src/components/ingredient/searchIngredient/SearchIngredientList.jsx +++ b/src/components/ingredient/searchIngredient/SearchIngredientList.jsx @@ -1,4 +1,4 @@ -// components/ingredient/searchIngredient/SearchIngredientList.jsx +// SearchIngredientList.jsx import React, { useState } from 'react'; import style from '../../../assets/css/ingredient/ingredient/SearchIngredientList.module.css'; import AddIngredientModal from '../modal/AddIngredientModal'; @@ -21,6 +21,7 @@ const SearchIngredientList = ({ isLoading, ingredients, onAddIngredient }) => { // 페이지 변경 핸들러 const handlePageChange = (pageNumber) => { setCurrentPage(pageNumber); + window.scrollTo({ top: 0, behavior: 'smooth' }); }; return ( @@ -47,13 +48,17 @@ const SearchIngredientList = ({ isLoading, ingredients, onAddIngredient }) => { getCurrentPageIngredients().map((ingredient) => (
+ {ingredient.ingredientName} -
{ingredient.ingredientName}
@@ -65,8 +70,16 @@ const SearchIngredientList = ({ isLoading, ingredients, onAddIngredient }) => {
{/* 페이지네이션 */} - {ingredients.length > 0 && !isLoading && ( + {ingredients.length > itemsPerPage && !isLoading && (
+ + {Array.from({ length: totalPages }, (_, index) => index + 1).map((pageNumber) => ( ))} + +
)}
diff --git a/src/components/ingredient/userIngredient/UsersIngredient.jsx b/src/components/ingredient/userIngredient/UsersIngredient.jsx index a9b400b..59ee462 100644 --- a/src/components/ingredient/userIngredient/UsersIngredient.jsx +++ b/src/components/ingredient/userIngredient/UsersIngredient.jsx @@ -1,3 +1,4 @@ +// UserIngredient.jsx import { useEffect, useState } from "react"; import { getUsersIngredient } from "../../../sources/api/IngredientAPI"; import UsersIngredientItem from "./UsersIngredientItem"; @@ -8,6 +9,8 @@ function UserIngredient() { const [filteredIngredients, setFilteredIngredients] = useState([]); const [category, setCategory] = useState("전체"); const [showFavoritesOnly, setShowFavoritesOnly] = useState(false); + const [currentPage, setCurrentPage] = useState(1); + const itemsPerPage = 9; // 페이지당 9개 아이템 const categories = [ "전체", "채소", "과일", "육류", "해산물", "유제품", @@ -59,8 +62,25 @@ function UserIngredient() { } setFilteredIngredients(filtered); + setCurrentPage(1); // 필터링이 변경될 때 첫 페이지로 리셋 }, [category, showFavoritesOnly, usersIngredientList]); + // 현재 페이지의 아이템들을 가져오는 함수 + const getCurrentItems = () => { + const indexOfLastItem = currentPage * itemsPerPage; + const indexOfFirstItem = indexOfLastItem - itemsPerPage; + return filteredIngredients.slice(indexOfFirstItem, indexOfLastItem); + }; + + // 페이지 변경 핸들러 + const handlePageChange = (pageNumber) => { + setCurrentPage(pageNumber); + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + // 전체 페이지 수 계산 + const totalPages = Math.ceil(filteredIngredients.length / itemsPerPage); + return (
@@ -86,15 +106,46 @@ function UserIngredient() {
- {filteredIngredients.map((ingredient) => ( + {getCurrentItems().map((ingredient) => ( ))}
+ + {/* 페이지네이션 */} + {filteredIngredients.length > itemsPerPage && ( +
+ + + {Array.from({ length: totalPages }, (_, index) => index + 1).map((pageNumber) => ( + + ))} + + +
+ )}
); } -export default UserIngredient; +export default UserIngredient; \ No newline at end of file