diff --git a/vite-project/.gitignore b/vite-project/.gitignore
index a547bf36..ac3b64f3 100644
--- a/vite-project/.gitignore
+++ b/vite-project/.gitignore
@@ -17,6 +17,7 @@ dist-ssr
!.vscode/extensions.json
.idea
.DS_Store
+.env
*.suo
*.ntvs*
*.njsproj
diff --git a/vite-project/index.html b/vite-project/index.html
index 0c589ecc..ee5a71ed 100644
--- a/vite-project/index.html
+++ b/vite-project/index.html
@@ -1,10 +1,9 @@
-
-
+
+
-
-
- Edit src/App.jsx and save to test HMR
-
+
+
+
+
+ {/* 페이지별 콘텐츠 */}
+
+ } />
+ } />
+ } />
+
-
- Click on the Vite and React logos to learn more
-
- >
- )
+
+ );
}
-export default App
+export default App;
diff --git a/vite-project/src/api/axiosInstance.js b/vite-project/src/api/axiosInstance.js
new file mode 100644
index 00000000..a950ccef
--- /dev/null
+++ b/vite-project/src/api/axiosInstance.js
@@ -0,0 +1,32 @@
+// api/axiosInstance.js
+import axios from "axios";
+
+// axios 인스턴스 생성
+const apiClient = axios.create({
+ baseURL: import.meta.env.VITE_API_BASE_URL,
+ timeout: 10000,
+});
+
+// 요청 인터셉터
+apiClient.interceptors.request.use(
+ (config) => {
+ console.log("API Request:", config.method?.toUpperCase(), config.url);
+ return config;
+ },
+ (error) => {
+ return Promise.reject(error);
+ }
+);
+
+// 응답 인터셉터
+apiClient.interceptors.response.use(
+ (response) => {
+ return response;
+ },
+ (error) => {
+ console.error("API Error:", error.response?.status, error.message);
+ return Promise.reject(error);
+ }
+);
+
+export default apiClient;
diff --git a/vite-project/src/api/products/getBestProducts.js b/vite-project/src/api/products/getBestProducts.js
new file mode 100644
index 00000000..8e57bf01
--- /dev/null
+++ b/vite-project/src/api/products/getBestProducts.js
@@ -0,0 +1,21 @@
+// api/products/getBestProducts.js
+import apiClient from "../axiosInstance";
+
+export const getBestProducts = async (limit = 4) => {
+ try {
+ const response = await apiClient.get("/products", {
+ params: {
+ page: 1,
+ pageSize: limit,
+ orderBy: "favorite",
+ },
+ });
+ return response.data;
+ } catch (error) {
+ throw new Error(
+ error.response?.data?.message ||
+ error.message ||
+ "베스트 상품을 불러오는데 실패했습니다."
+ );
+ }
+};
diff --git a/vite-project/src/api/products/getProducts.js b/vite-project/src/api/products/getProducts.js
new file mode 100644
index 00000000..2ae0e458
--- /dev/null
+++ b/vite-project/src/api/products/getProducts.js
@@ -0,0 +1,22 @@
+// api/products/getProducts.js
+import apiClient from "../axiosInstance";
+
+export const getProducts = async (params = {}) => {
+ try {
+ const response = await apiClient.get("/products", {
+ params: {
+ page: params.page || 1,
+ pageSize: params.pageSize || 10,
+ orderBy: params.orderBy || "recent",
+ ...(params.keyword && { keyword: params.keyword }),
+ },
+ });
+ return response.data;
+ } catch (error) {
+ throw new Error(
+ error.response?.data?.message ||
+ error.message ||
+ "상품을 불러오는데 실패했습니다."
+ );
+ }
+};
diff --git a/vite-project/src/api/products/index.js b/vite-project/src/api/products/index.js
new file mode 100644
index 00000000..b86dd0e4
--- /dev/null
+++ b/vite-project/src/api/products/index.js
@@ -0,0 +1,4 @@
+// api/products/index.js
+export { getProducts } from "./getProducts";
+export { getBestProducts } from "./getBestProducts";
+export { searchProducts } from "./searchProducts";
diff --git a/vite-project/src/api/products/searchProducts.js b/vite-project/src/api/products/searchProducts.js
new file mode 100644
index 00000000..5150f0d0
--- /dev/null
+++ b/vite-project/src/api/products/searchProducts.js
@@ -0,0 +1,26 @@
+// api/products/searchProducts.js
+import apiClient from "../axiosInstance";
+
+export const searchProducts = async (keyword, params = {}) => {
+ try {
+ if (!keyword || !keyword.trim()) {
+ throw new Error("검색어를 입력해주세요.");
+ }
+
+ const response = await apiClient.get("/products", {
+ params: {
+ page: params.page || 1,
+ pageSize: params.pageSize || 10,
+ orderBy: params.orderBy || "recent",
+ keyword: keyword.trim(),
+ },
+ });
+ return response.data;
+ } catch (error) {
+ throw new Error(
+ error.response?.data?.message ||
+ error.message ||
+ "상품 검색에 실패했습니다."
+ );
+ }
+};
diff --git a/vite-project/src/assets/react.svg b/vite-project/src/assets/react.svg
deleted file mode 100644
index 6c87de9b..00000000
--- a/vite-project/src/assets/react.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/vite-project/src/components/AllItem/AllItemHeader.jsx b/vite-project/src/components/AllItem/AllItemHeader.jsx
new file mode 100644
index 00000000..1a3731bb
--- /dev/null
+++ b/vite-project/src/components/AllItem/AllItemHeader.jsx
@@ -0,0 +1,12 @@
+const AllItemHeader = () => {
+ return (
+
+ 전체 상품
+
+ );
+};
+
+export default AllItemHeader;
diff --git a/vite-project/src/components/AllItem/AllItemList.jsx b/vite-project/src/components/AllItem/AllItemList.jsx
new file mode 100644
index 00000000..ca812674
--- /dev/null
+++ b/vite-project/src/components/AllItem/AllItemList.jsx
@@ -0,0 +1,113 @@
+// components/AllItem/AllItemList.jsx - 반응형 개수 적용
+import { useState, useEffect } from "react";
+import ProductCard from "../BestItem/ProductCard";
+import { getProducts, searchProducts } from "../../api/products";
+import useResponsiveCount from "../../hooks/useResponsiveCount";
+
+const AllItemList = ({
+ sortBy = "recent",
+ searchQuery = "",
+ currentPage = 1,
+ onTotalCountChange,
+}) => {
+ const [products, setProducts] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ // 반응형 훅 사용
+ const { getAllProductCount, getGridClass } = useResponsiveCount();
+ const pageSize = getAllProductCount();
+ const gridClass = getGridClass("all");
+
+ useEffect(() => {
+ const fetchProducts = async () => {
+ try {
+ setLoading(true);
+ setError(null);
+
+ const params = {
+ page: currentPage,
+ pageSize: pageSize, // 🎯 화면 크기별 다른 개수
+ orderBy: sortBy === "latest" ? "recent" : "favorite",
+ };
+
+ let data;
+ if (searchQuery.trim()) {
+ data = await searchProducts(searchQuery.trim(), params);
+ } else {
+ data = await getProducts(params);
+ }
+
+ setProducts(data.list || []);
+
+ if (onTotalCountChange) {
+ onTotalCountChange(data.totalCount || 0);
+ }
+ } catch (err) {
+ setError(err.message);
+ console.error("Products fetch error:", err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchProducts();
+ }, [sortBy, searchQuery, currentPage, pageSize, onTotalCountChange]); // pageSize 의존성 추가
+
+ // 로딩 상태
+ if (loading) {
+ return (
+
+ {/* 🎯 반응형 그리드 클래스와 개수 적용 */}
+
+ {[...Array(pageSize)].map((_, index) => (
+
+ ))}
+
+
+ );
+ }
+
+ // 에러 상태
+ if (error) {
+ return (
+
+
+
상품을 불러오는데 실패했습니다.
+
{error}
+
+
+ );
+ }
+
+ // 빈 상태
+ if (products.length === 0) {
+ return (
+
+
+
+ {searchQuery
+ ? `'${searchQuery}'에 대한 검색 결과가 없습니다.`
+ : "등록된 상품이 없습니다."}
+
+
+
+ );
+ }
+
+ return (
+
+ {/* 🎯 반응형 그리드 + 반응형 개수 */}
+
+ {products.map((product) => (
+
+ ))}
+
+
+ );
+};
+
+export default AllItemList;
diff --git a/vite-project/src/components/AllItem/AllItemRegisterButton.jsx b/vite-project/src/components/AllItem/AllItemRegisterButton.jsx
new file mode 100644
index 00000000..b2db4878
--- /dev/null
+++ b/vite-project/src/components/AllItem/AllItemRegisterButton.jsx
@@ -0,0 +1,20 @@
+import { Link, useLocation } from "react-router-dom";
+
+const AllItemRegisterButton = () => {
+ const location = useLocation();
+
+ return (
+
+ 상품 등록하기
+
+ );
+};
+
+export default AllItemRegisterButton;
diff --git a/vite-project/src/components/AllItem/AllItemSearchBar.jsx b/vite-project/src/components/AllItem/AllItemSearchBar.jsx
new file mode 100644
index 00000000..657e7081
--- /dev/null
+++ b/vite-project/src/components/AllItem/AllItemSearchBar.jsx
@@ -0,0 +1,38 @@
+// src/components/AllItem/AllItemSearchBar.jsx
+import { useState } from "react";
+
+const AllItemSearchBar = ({ onSearch }) => {
+ const [searchValue, setSearchValue] = useState("");
+
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ if (onSearch) {
+ onSearch(searchValue.trim());
+ }
+ };
+
+ const handleKeyPress = (e) => {
+ if (e.key === "Enter") {
+ e.preventDefault();
+ handleSubmit(e);
+ }
+ };
+
+ return (
+
+ );
+};
+
+export default AllItemSearchBar;
diff --git a/vite-project/src/components/AllItem/SortDropDown.jsx b/vite-project/src/components/AllItem/SortDropDown.jsx
new file mode 100644
index 00000000..3e8389a7
--- /dev/null
+++ b/vite-project/src/components/AllItem/SortDropDown.jsx
@@ -0,0 +1,97 @@
+import { useState, useRef, useEffect } from "react";
+
+const SortDropDown = ({ onSortChange, currentSort = "latest" }) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const dropdownRef = useRef(null);
+
+ const sortOptions = [
+ { value: "latest", label: "최신순" },
+ { value: "likes", label: "좋아요순" },
+ ];
+
+ const currentOption = sortOptions.find(
+ (option) => option.value === currentSort
+ );
+
+ // 외부 클릭시 드롭다운 닫기
+ useEffect(() => {
+ const handleClickOutside = (event) => {
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
+ setIsOpen(false);
+ }
+ };
+
+ document.addEventListener("mousedown", handleClickOutside);
+ return () => document.removeEventListener("mousedown", handleClickOutside);
+ }, []);
+
+ const handleSelect = (value) => {
+ onSortChange(value);
+ setIsOpen(false);
+ };
+
+ return (
+
+ {/* 드롭다운 버튼 */}
+
+
+ {/* 드롭다운 메뉴 */}
+ {isOpen && (
+
+
+ {sortOptions.map((option) => (
+
+ ))}
+
+
+ )}
+
+ );
+};
+
+export default SortDropDown;
diff --git a/vite-project/src/components/BestItem/BestItem.jsx b/vite-project/src/components/BestItem/BestItem.jsx
new file mode 100644
index 00000000..f3220839
--- /dev/null
+++ b/vite-project/src/components/BestItem/BestItem.jsx
@@ -0,0 +1,93 @@
+// components/BestItem/BestItem.jsx - 반응형 개수 적용
+import { useState, useEffect } from "react";
+import ProductCard from "./ProductCard";
+import { getBestProducts } from "../../api/products";
+import useResponsiveCount from "../../hooks/useResponsiveCount";
+
+const BestItem = () => {
+ const [bestProducts, setBestProducts] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ // 반응형 훅 사용
+ const { getBestProductCount, getGridClass } = useResponsiveCount();
+ const productCount = getBestProductCount();
+ const gridClass = getGridClass("best");
+
+ useEffect(() => {
+ const fetchBestProducts = async () => {
+ try {
+ setLoading(true);
+ setError(null);
+
+ // 🎯 화면 크기에 따라 다른 개수 요청
+ const data = await getBestProducts(productCount);
+ setBestProducts(data.list || []);
+ } catch (err) {
+ setError(err.message);
+ console.error("Best products fetch error:", err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchBestProducts();
+ }, [productCount]); // productCount가 변경되면 재요청
+
+ if (loading) {
+ return (
+
+
+ 베스트 상품
+
+ {/* 🎯 반응형 그리드 클래스 적용 */}
+
+ {[...Array(productCount)].map((_, index) => (
+
+ ))}
+
+
+ );
+ }
+
+ if (error) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+ 베스트 상품
+
+ {/* 🎯 반응형 그리드 + 반응형 개수 */}
+
+ {bestProducts.map((product) => (
+
+ ))}
+
+
+ );
+};
+
+export default BestItem;
diff --git a/vite-project/src/components/BestItem/ProductCard.jsx b/vite-project/src/components/BestItem/ProductCard.jsx
new file mode 100644
index 00000000..bc4849db
--- /dev/null
+++ b/vite-project/src/components/BestItem/ProductCard.jsx
@@ -0,0 +1,95 @@
+const ProductCard = ({ product }) => {
+ // API 응답 구조에 맞게 데이터 매핑
+ const {
+ name: title, // API에서는 'name', 기존에서는 'title'
+ price,
+ favoriteCount,
+ images, // 배열로 들어옴
+ tags,
+ } = product;
+
+ // 첫 번째 이미지 사용, 안전하게 처리
+ const getImageUrl = () => {
+ if (!images || !Array.isArray(images) || images.length === 0) {
+ return null;
+ }
+ return images[0];
+ };
+
+ const imageUrl = getImageUrl();
+
+ // 가격 포맷 함수
+ const formatPrice = (price) => {
+ return price.toLocaleString() + "원";
+ };
+
+ // 이미지 로드 에러 처리 개선
+ const handleImageError = (e) => {
+ console.log("Image load failed:", imageUrl);
+ e.target.src =
+ "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZjNmNGY2Ii8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtc2l6ZT0iMTgiIGZpbGw9IiM5Y2EzYWYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGR5PSIuM2VtIj5ObyBJbWFnZTwvdGV4dD48L3N2Zz4=";
+ };
+
+ return (
+
+ {/* 상품 이미지 */}
+
+ {imageUrl ? (
+

console.log("Image loaded successfully:", imageUrl)}
+ />
+ ) : (
+
+ 이미지 없음
+
+ )}
+
+
+ {/* 상품 정보 */}
+
+ {/* 상품 제목 */}
+
+ {title}
+
+
+ {/* 가격 */}
+
+ {formatPrice(price)}
+
+
+ {/* 좋아요 */}
+
+
+
{favoriteCount}
+
+
+ {/* 태그들 (있다면 표시) */}
+ {tags && tags.length > 0 && (
+
+ {tags.slice(0, 2).map((tag, index) => (
+
+ {tag}
+
+ ))}
+
+ )}
+
+
+ );
+};
+
+export default ProductCard;
diff --git a/vite-project/src/components/Header/Header.jsx b/vite-project/src/components/Header/Header.jsx
new file mode 100644
index 00000000..c955ac26
--- /dev/null
+++ b/vite-project/src/components/Header/Header.jsx
@@ -0,0 +1,20 @@
+import Logo from "./Logo";
+import Navigation from "./Navigation";
+import Profile from "./Profile";
+
+export default function Header() {
+ return (
+
+ );
+}
diff --git a/vite-project/src/components/Header/Logo.jsx b/vite-project/src/components/Header/Logo.jsx
new file mode 100644
index 00000000..2c3fb725
--- /dev/null
+++ b/vite-project/src/components/Header/Logo.jsx
@@ -0,0 +1,18 @@
+const Logo = () => {
+ return (
+
+ );
+};
+
+export default Logo;
diff --git a/vite-project/src/components/Header/Navigation.jsx b/vite-project/src/components/Header/Navigation.jsx
new file mode 100644
index 00000000..887503af
--- /dev/null
+++ b/vite-project/src/components/Header/Navigation.jsx
@@ -0,0 +1,33 @@
+// components/Header/Navigation.jsx - 간단한 구조
+import { Link, useLocation } from "react-router-dom";
+
+const Navigation = () => {
+ const location = useLocation();
+
+ return (
+
+ );
+};
+
+export default Navigation;
diff --git a/vite-project/src/components/Header/Profile.jsx b/vite-project/src/components/Header/Profile.jsx
new file mode 100644
index 00000000..48a284cc
--- /dev/null
+++ b/vite-project/src/components/Header/Profile.jsx
@@ -0,0 +1,13 @@
+const Profile = () => {
+ return (
+
+ );
+};
+
+export default Profile;
diff --git a/vite-project/src/components/Pagination/Pagination.jsx b/vite-project/src/components/Pagination/Pagination.jsx
new file mode 100644
index 00000000..cd25e55a
--- /dev/null
+++ b/vite-project/src/components/Pagination/Pagination.jsx
@@ -0,0 +1,127 @@
+// components/Pagination/Pagination.jsx
+const Pagination = ({
+ currentPage,
+ totalCount,
+ pageSize = 10,
+ onPageChange,
+}) => {
+ // 총 페이지 수 계산
+ const totalPages = Math.ceil(totalCount / pageSize);
+
+ // 표시할 페이지 번호들 계산 (현재 페이지 기준으로 앞뒤 2개씩)
+ const getVisiblePages = () => {
+ const delta = 2; // 현재 페이지 앞뒤로 보여줄 페이지 수
+ const start = Math.max(1, currentPage - delta);
+ const end = Math.min(totalPages, currentPage + delta);
+
+ const pages = [];
+ for (let i = start; i <= end; i++) {
+ pages.push(i);
+ }
+ return pages;
+ };
+
+ const visiblePages = getVisiblePages();
+
+ // 페이지가 1개 이하면 페이지네이션 숨기기
+ if (totalPages <= 1) return null;
+
+ return (
+
+ {/* 이전 버튼 */}
+
+
+ {/* 첫 번째 페이지 (현재 페이지가 4 이상일 때) */}
+ {currentPage > 3 && (
+ <>
+
+ {currentPage > 4 &&
...}
+ >
+ )}
+
+ {/* 페이지 번호들 */}
+ {visiblePages.map((pageNum) => (
+
+ ))}
+
+ {/* 마지막 페이지 (현재 페이지가 끝에서 3번째 이전일 때) */}
+ {currentPage < totalPages - 2 && (
+ <>
+ {currentPage < totalPages - 3 && (
+
...
+ )}
+
+ >
+ )}
+
+ {/* 다음 버튼 */}
+
+
+ );
+};
+
+export default Pagination;
diff --git a/vite-project/src/hooks/useResponsiveCount.js b/vite-project/src/hooks/useResponsiveCount.js
new file mode 100644
index 00000000..7115cc35
--- /dev/null
+++ b/vite-project/src/hooks/useResponsiveCount.js
@@ -0,0 +1,92 @@
+// hooks/useResponsiveCount.js - 모바일도 2열로 수정
+import { useState, useEffect } from "react";
+
+const useResponsiveCount = () => {
+ const [screenSize, setScreenSize] = useState("desktop");
+
+ useEffect(() => {
+ const updateScreenSize = () => {
+ const width = window.innerWidth;
+
+ if (width < 768) {
+ setScreenSize("mobile");
+ } else if (width < 1024) {
+ setScreenSize("tablet");
+ } else {
+ setScreenSize("desktop");
+ }
+ };
+
+ // 초기 설정
+ updateScreenSize();
+
+ // 윈도우 리사이즈 이벤트 리스너
+ window.addEventListener("resize", updateScreenSize);
+
+ // 클린업
+ return () => window.removeEventListener("resize", updateScreenSize);
+ }, []);
+
+ // 베스트 상품 개수
+ const getBestProductCount = () => {
+ switch (screenSize) {
+ case "mobile":
+ return 1; // 모바일: 1개
+ case "tablet":
+ return 2; // 태블릿: 2개
+ case "desktop":
+ return 4; // 데스크톱: 4개
+ default:
+ return 4;
+ }
+ };
+
+ // 전체 상품 개수 (한 페이지당)
+ const getAllProductCount = () => {
+ switch (screenSize) {
+ case "mobile":
+ return 4; // 모바일: 4개
+ case "tablet":
+ return 6; // 태블릿: 6개
+ case "desktop":
+ return 10; // 데스크톱: 10개
+ default:
+ return 10;
+ }
+ };
+
+ const getGridClass = (type = "all") => {
+ if (type === "best") {
+ switch (screenSize) {
+ case "mobile":
+ return "grid grid-cols-1 gap-4";
+ case "tablet":
+ return "grid grid-cols-2 gap-4";
+ case "desktop":
+ return "grid grid-cols-4 gap-4 lg:gap-6";
+ default:
+ return "grid grid-cols-4 gap-4 lg:gap-6";
+ }
+ } else {
+ switch (screenSize) {
+ case "mobile":
+ return "grid grid-cols-2 gap-4"; // 4개: 2열×2행
+ case "tablet":
+ return "grid grid-cols-3 gap-4"; // 6개: 3열×2행
+ case "desktop":
+ return "grid grid-cols-5 gap-4"; // 10개: 5열×2행
+ default:
+ return "grid grid-cols-5 gap-4";
+ }
+ }
+ };
+
+ return {
+ screenSize,
+ getBestProductCount,
+ getAllProductCount,
+ getGridClass,
+ };
+};
+
+export default useResponsiveCount;
diff --git a/vite-project/src/index.css b/vite-project/src/index.css
index 08a3ac9e..b5c61c95 100644
--- a/vite-project/src/index.css
+++ b/vite-project/src/index.css
@@ -1,68 +1,3 @@
-:root {
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
-
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
-}
-a:hover {
- color: #535bf2;
-}
-
-body {
- margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
-}
-
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
-}
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/vite-project/src/main.jsx b/vite-project/src/main.jsx
index b9a1a6de..e54c61ce 100644
--- a/vite-project/src/main.jsx
+++ b/vite-project/src/main.jsx
@@ -1,10 +1,5 @@
-import { StrictMode } from 'react'
-import { createRoot } from 'react-dom/client'
-import './index.css'
-import App from './App.jsx'
+import { createRoot } from "react-dom/client";
+import "./index.css";
+import App from "./App.jsx";
-createRoot(document.getElementById('root')).render(
-
-
- ,
-)
+createRoot(document.getElementById("root")).render(
);
diff --git a/vite-project/src/pages/additem.jsx b/vite-project/src/pages/additem.jsx
new file mode 100644
index 00000000..77d2c394
--- /dev/null
+++ b/vite-project/src/pages/additem.jsx
@@ -0,0 +1,5 @@
+const AddItemPage = () => {
+ return
AddItemPage
;
+};
+
+export default AddItemPage;
diff --git a/vite-project/src/pages/board.jsx b/vite-project/src/pages/board.jsx
new file mode 100644
index 00000000..3de5ab5f
--- /dev/null
+++ b/vite-project/src/pages/board.jsx
@@ -0,0 +1,5 @@
+const BoardPage = () => {
+ return
BoardPage
;
+};
+
+export default BoardPage;
diff --git a/vite-project/src/pages/market.jsx b/vite-project/src/pages/market.jsx
new file mode 100644
index 00000000..9293dff1
--- /dev/null
+++ b/vite-project/src/pages/market.jsx
@@ -0,0 +1,90 @@
+// App.jsx - 반응형 pageSize 적용
+import { useState, useEffect } from "react";
+import BestItem from "../components/BestItem/BestItem";
+import AllItemHeader from "../components/AllItem/AllItemHeader";
+import AllItemSearchBar from "../components/AllItem/AllItemSearchBar";
+import AllItemRegisterButton from "../components/AllItem/AllItemRegisterButton";
+import SortDropDown from "../components/AllItem/SortDropDown";
+import AllItemList from "../components/AllItem/AllItemList";
+import Pagination from "../components/Pagination/Pagination";
+import useResponsiveCount from "../hooks/useResponsiveCount";
+
+function App() {
+ // 상태 관리
+ const [sortBy, setSortBy] = useState("latest");
+ const [searchQuery, setSearchQuery] = useState("");
+ const [currentPage, setCurrentPage] = useState(1);
+ const [totalCount, setTotalCount] = useState(0);
+
+ // 반응형 훅 사용
+ const { getAllProductCount, screenSize } = useResponsiveCount();
+ const pageSize = getAllProductCount();
+
+ useEffect(() => {
+ setCurrentPage(1);
+ }, [screenSize]);
+
+ // 이벤트 핸들러들
+ const onSearch = (query) => {
+ setSearchQuery(query);
+ setCurrentPage(1);
+ };
+
+ const onSortChange = (newSort) => {
+ setSortBy(newSort);
+ setCurrentPage(1);
+ };
+
+ const onPageChange = (page) => {
+ setCurrentPage(page);
+ };
+
+ const onTotalCountChange = (count) => {
+ setTotalCount(count);
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+ {/* 🎯 화면 크기별 pageSize 적용 */}
+
+
+
+ >
+ );
+}
+
+export default App;
diff --git a/vite-project/tailwind.config.js b/vite-project/tailwind.config.js
new file mode 100644
index 00000000..614c86b4
--- /dev/null
+++ b/vite-project/tailwind.config.js
@@ -0,0 +1,8 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};