diff --git a/README.md b/README.md index 7059a962..ff04d6a7 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,182 @@ -# React + Vite -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +``` +16-Sprint-Mission +├─ eslint.config.js +├─ index.html +├─ package-lock.json +├─ package.json +├─ public +│ ├─ images +│ │ ├─ icon_google.png +│ │ ├─ icon_kakao.png +│ │ ├─ icon_password_invisible.png +│ │ ├─ icon_password_visible.png +│ │ ├─ icon_profile.png +│ │ ├─ ic_arrow_down.png +│ │ ├─ ic_back.png +│ │ ├─ ic_facebook.png +│ │ ├─ ic_instagram.png +│ │ ├─ ic_kebab.png +│ │ ├─ ic_nextPageClick_active.png +│ │ ├─ ic_nextPageClick_inactive.png +│ │ ├─ ic_plus.png +│ │ ├─ ic_prevPageClick_active.png +│ │ ├─ ic_prevPageClick_inactive.png +│ │ ├─ ic_search.png +│ │ ├─ ic_sort.png +│ │ ├─ ic_twitter.png +│ │ ├─ ic_X.png +│ │ ├─ ic_youtube.png +│ │ ├─ img_comment_none.png +│ │ ├─ img_favorite_inactive.png +│ │ ├─ Img_home_01 +│ │ │ ├─ Img_home_01@0.5x.png +│ │ │ ├─ Img_home_01@1.5x.png +│ │ │ ├─ Img_home_01@1x.png +│ │ │ └─ Img_home_01@2x.png +│ │ ├─ Img_home_02 +│ │ │ ├─ Img_home_02@0.5x.png +│ │ │ ├─ Img_home_02@1.5x.png +│ │ │ ├─ Img_home_02@1x.png +│ │ │ └─ Img_home_02@2x.png +│ │ ├─ Img_home_03 +│ │ │ ├─ Img_home_03@0.5x.png +│ │ │ ├─ Img_home_03@1.5x.png +│ │ │ ├─ Img_home_03@1x.png +│ │ │ └─ Img_home_03@2x.png +│ │ ├─ Img_home_bottom +│ │ │ ├─ Img_home_bottom@0.5x.png +│ │ │ ├─ Img_home_bottom@1.5x.png +│ │ │ ├─ Img_home_bottom@1x.png +│ │ │ └─ Img_home_bottom@2x.png +│ │ ├─ Img_home_top +│ │ │ ├─ Img_home_top@0.5x.png +│ │ │ ├─ Img_home_top@1.5x.png +│ │ │ ├─ Img_home_top@1x.png +│ │ │ └─ Img_home_top@2x.png +│ │ ├─ img_items_default_md.png +│ │ ├─ Img_logo.png +│ │ └─ Img_openGraph.png +│ └─ _redirects +├─ README.md +├─ src +│ ├─ App.jsx +│ ├─ common.css +│ ├─ components +│ │ ├─ comments +│ │ │ ├─ CommentCard.jsx +│ │ │ ├─ CommentCard.module.css +│ │ │ ├─ CommentEditForm.jsx +│ │ │ ├─ CommentEditForm.module.css +│ │ │ ├─ CommentRequireForm.jsx +│ │ │ ├─ CommentRequireForm.module.css +│ │ │ ├─ CommentsContainer.jsx +│ │ │ ├─ CommentsContainer.module.css +│ │ │ ├─ CommentView.jsx +│ │ │ └─ CommentView.module.css +│ │ ├─ common +│ │ │ ├─ AuthField +│ │ │ │ ├─ AuthField.jsx +│ │ │ │ └─ AuthField.module.css +│ │ │ ├─ Button +│ │ │ ├─ ItemCard +│ │ │ │ ├─ ItemCard.jsx +│ │ │ │ └─ ItemCard.module.css +│ │ │ ├─ ItemCardSkeleton +│ │ │ │ ├─ ItemCardSkeleton.jsx +│ │ │ │ └─ ItemCardSkeleton.module.css +│ │ │ ├─ ItemsContainer +│ │ │ │ ├─ ItemsContainer.jsx +│ │ │ │ └─ ItemsContainer.module.css +│ │ │ ├─ KebabMenu +│ │ │ │ ├─ KebabMenu.jsx +│ │ │ │ └─ KebabMenu.module.css +│ │ │ ├─ Pagination +│ │ │ │ ├─ Pagination.jsx +│ │ │ │ ├─ Pagination.module.css +│ │ │ │ ├─ PaginationButton.jsx +│ │ │ │ └─ PaginationButton.module.css +│ │ │ ├─ PaginationButton +│ │ │ ├─ SearchInput +│ │ │ │ ├─ SearchInput.jsx +│ │ │ │ └─ SearchInput.module.css +│ │ │ └─ SelectDropdown +│ │ │ ├─ SelectDropdown.jsx +│ │ │ └─ SelectDropdown.module.css +│ │ └─ layout +│ │ ├─ LogoHeader +│ │ │ ├─ LogoHeader.jsx +│ │ │ └─ LogoHeader.module.css +│ │ ├─ Nav +│ │ │ ├─ Nav.jsx +│ │ │ └─ Nav.module.css +│ │ └─ profileCard +│ │ ├─ ProfileCard.jsx +│ │ └─ ProfileCard.module.css +│ ├─ constants +│ ├─ contexts +│ │ └─ LoginContext.jsx +│ ├─ fonts +│ │ └─ rokafsansmedium-normal.woff +│ ├─ hooks +│ │ ├─ useAsync.jsx +│ │ ├─ useFormFields.jsx +│ │ ├─ usePageSizeByBreakPoint.jsx +│ │ ├─ usePaginationByOffset.jsx +│ │ ├─ useScreenBreakpoint.jsx +│ │ └─ useSearchQueryString.jsx +│ ├─ main.jsx +│ ├─ pages +│ │ ├─ AddItemPage +│ │ │ ├─ AddItemPage.jsx +│ │ │ └─ AddItemPage.module.css +│ │ ├─ AuthPage +│ │ │ ├─ fieldsConfig.js +│ │ │ ├─ FormAuth.css +│ │ │ ├─ LoginPage.jsx +│ │ │ ├─ sections +│ │ │ │ ├─ SocialLogin.jsx +│ │ │ │ └─ SocialLogin.module.css +│ │ │ └─ SignupPage.jsx +│ │ ├─ BoardPage +│ │ │ └─ BoardPage.jsx +│ │ ├─ FaqPage +│ │ │ └─ FaqPage.jsx +│ │ ├─ HomePage +│ │ │ ├─ Banner.css +│ │ │ ├─ BannerBottom.css +│ │ │ ├─ Card.css +│ │ │ ├─ Cards.css +│ │ │ ├─ Footer.css +│ │ │ ├─ Home.css +│ │ │ ├─ HomePage.jsx +│ │ │ └─ Main.css +│ │ ├─ ItemDetailsPage +│ │ │ ├─ ItemDetailsPage.jsx +│ │ │ ├─ ItemDetailsPage.module.css +│ │ │ └─ sections +│ │ │ ├─ ItemComments.jsx +│ │ │ ├─ ItemComments.module.css +│ │ │ ├─ ItemDetailsSection.jsx +│ │ │ └─ ItemDetailsSection.module.css +│ │ ├─ ItemsPage +│ │ │ ├─ ItemsPage.css +│ │ │ ├─ ItemsPage.jsx +│ │ │ └─ sections +│ │ │ ├─ BestItemsSection.jsx +│ │ │ ├─ CurrentItemsSection +│ │ │ │ ├─ ItemsSearchHeader.jsx +│ │ │ │ └─ ItemsSearchHeader.module.css +│ │ │ ├─ CurrentItemsSection.jsx +│ │ │ └─ ItemsSection.module.css +│ │ └─ PrivacyPage +│ │ └─ PrivacyPage.jsx +│ ├─ reset.css +│ └─ utils +│ ├─ api.js +│ ├─ debounce.js +│ ├─ formatPrice.js +│ └─ validators.js +└─ vite.config.js -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh - -## Expanding the ESLint configuration - -If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. +``` \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 80568c27..72d9de22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "react-dom": "^19.0.0", "react-responsive": "^10.0.1", "react-router": "^7.5.3", - "react-router-dom": "^7.5.3" + "react-router-dom": "^7.5.3", + "styled-components": "^6.1.18" }, "devDependencies": { "@eslint/js": "^9.22.0", @@ -322,6 +323,27 @@ "node": ">=6.9.0" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.3", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", @@ -1376,6 +1398,12 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/stylis": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", + "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", + "license": "MIT" + }, "node_modules/@vitejs/plugin-react": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.4.1.tgz", @@ -1520,6 +1548,15 @@ "node": ">=6" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001715", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz", @@ -1616,17 +1653,36 @@ "node": ">= 8" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, "node_modules/css-mediaquery": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz", "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==", "license": "BSD" }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, "license": "MIT" }, "node_modules/debug": { @@ -2292,7 +2348,6 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -2417,7 +2472,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -2462,6 +2516,12 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2665,6 +2725,12 @@ "integrity": "sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==", "license": "MIT" }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2692,7 +2758,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -2711,6 +2776,68 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/styled-components": { + "version": "6.1.18", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.18.tgz", + "integrity": "sha512-Mvf3gJFzZCkhjY2Y/Fx9z1m3dxbza0uI9H1CbNZm/jSHCojzJhQ0R7bByrlFJINnMzz/gPulpoFFGymNwrsMcw==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.49", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/stylis": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2741,6 +2868,12 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, "node_modules/turbo-stream": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", diff --git a/package.json b/package.json index 4796bcc1..8b7645a6 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "react-dom": "^19.0.0", "react-responsive": "^10.0.1", "react-router": "^7.5.3", - "react-router-dom": "^7.5.3" + "react-router-dom": "^7.5.3", + "styled-components": "^6.1.18" }, "devDependencies": { "@eslint/js": "^9.22.0", diff --git a/public/images/ic_X.png b/public/images/ic_X.png new file mode 100644 index 00000000..ce355240 Binary files /dev/null and b/public/images/ic_X.png differ diff --git a/public/images/ic_back.png b/public/images/ic_back.png new file mode 100644 index 00000000..6671f152 Binary files /dev/null and b/public/images/ic_back.png differ diff --git a/public/images/ic_kebab.png b/public/images/ic_kebab.png new file mode 100644 index 00000000..b390f973 Binary files /dev/null and b/public/images/ic_kebab.png differ diff --git a/public/images/ic_plus.png b/public/images/ic_plus.png new file mode 100644 index 00000000..5cd8fc68 Binary files /dev/null and b/public/images/ic_plus.png differ diff --git a/public/images/icon_password_invisible.png b/public/images/icon_password_invisible.png index 69a949ba..57e303f5 100644 Binary files a/public/images/icon_password_invisible.png and b/public/images/icon_password_invisible.png differ diff --git a/public/images/icon_password_visible.png b/public/images/icon_password_visible.png index e8a0fba8..5263589a 100644 Binary files a/public/images/icon_password_visible.png and b/public/images/icon_password_visible.png differ diff --git a/public/images/img_comment_none.png b/public/images/img_comment_none.png new file mode 100644 index 00000000..115ee43c Binary files /dev/null and b/public/images/img_comment_none.png differ diff --git a/src/App.jsx b/src/App.jsx index eb06a0fd..11120814 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,29 +1,35 @@ -import { BrowserRouter, Routes, Route } from 'react-router-dom'; -import Home from './pages/Home/Home'; -import Login from './pages/Auth/Login'; -import Signup from './pages/Auth/Signup'; -import Items from './pages/Items/Items'; -import Privacy from './pages/Privacy/Privacy'; -import Faq from './pages/Faq/Faq'; -import AddItem from './pages/AddItem/AddItem'; -import { LoginStateProvider } from './contexts/LoginStateContext'; -import Board from './pages/Board/Board'; +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import { LoginProvider } from "./contexts/LoginContext"; +import HomePage from "./pages/HomePage/HomePage"; +import LoginPage from "./pages/AuthPage/LoginPage"; +import SignupPage from "./pages/AuthPage/SignupPage"; +import ItemsPage from "./pages/ItemsPage/ItemsPage"; +import AddItemPage from "./pages/AddItemPage/AddItemPage"; +import PrivacyPage from "./pages/PrivacyPage/PrivacyPage"; +import FaqPage from "./pages/FaqPage/FaqPage"; +import BoardPage from "./pages/BoardPage/BoardPage"; +import ItemDetailsPage from "./pages/ItemDetailsPage/ItemDetailsPage"; function App() { return ( - + - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + + } /> + + } /> + } /> + + } /> + } /> + } /> + } /> + + } /> + } /> - + ); } diff --git a/src/apis/api.js b/src/apis/api.js deleted file mode 100644 index 3eddfee7..00000000 --- a/src/apis/api.js +++ /dev/null @@ -1,22 +0,0 @@ -const BASE_URL = 'https://panda-market-api.vercel.app'; - -export const getItems = async ({ - offset, - pageSize, - orderBy = 'recent', - keyword = '', -}) => { - //pc: 10개, 태블릿: 6개, 모바일: 4개 - //offset이 11이면 : page는? pc: 2, 태블릿: 2, 모바일: 3 - //offset이 8이면 : page는? pc: 1, 태블릿: 2, 모바일: 2 - - const page = Math.ceil(offset / pageSize); - const query = `page=${page}&pageSize=${pageSize}&orderBy=${orderBy}&keyword=${keyword}`; - - const response = await fetch(`${BASE_URL}/products?${query}`); - if (!response.ok) { - throw new Error('품목을 불러오지 못했습니다.'); - } - const body = await response.json(); - return body; -}; diff --git a/src/common.css b/src/common.css index 7971659d..788eaa17 100644 --- a/src/common.css +++ b/src/common.css @@ -34,6 +34,7 @@ body { font-weight: 600; font-family: 'Pretendard'; border: none; + cursor: pointer; } .button-style:hover { @@ -42,6 +43,7 @@ body { .button-style:disabled { background-color: var(--color-gray400); + cursor: auto; } @font-face { diff --git a/src/components/ItemDetails/ItemDescription.jsx b/src/components/ItemDetails/ItemDescription.jsx new file mode 100644 index 00000000..5a78b1f2 --- /dev/null +++ b/src/components/ItemDetails/ItemDescription.jsx @@ -0,0 +1,26 @@ +import styles from "./ItemDescription.module.css"; + +const ItemDescription = ({ description, tags = [] }) => { + return ( +
+
+

상품 소개

+ {description} +
+
+

상품 태그

+
+ {tags.map((tag) => { + return ( +
+ {`#${tag}`} +
+ ); + })} +
+
+
+ ); +}; + +export default ItemDescription; diff --git a/src/components/ItemDetails/ItemDescription.module.css b/src/components/ItemDetails/ItemDescription.module.css new file mode 100644 index 00000000..cffe8920 --- /dev/null +++ b/src/components/ItemDetails/ItemDescription.module.css @@ -0,0 +1,50 @@ + +.description-container { + display: flex; + flex-direction: column; + gap: 24px; + margin-bottom: var(--description-margin-bottom); +} + +.subtitle-container { + display: flex; + flex-direction: column; + gap: var(--subtitle-gap); +} + +.subtitle { + font-weight: 600; + font-size: 16px; + line-height: 26px; +} + +.description { + font-weight: 400; + font-size: 16px; + line-height: 26px; +} + +.tag-container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 8px; +} + +.tag { + border-radius: 26px; + padding: 5px 16px; + background-color: var(--color-gray200); + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; + font-weight: 400; + font-size: 16px; + line-height: 26px; + cursor: pointer; +} + +.tag:hover { + background-color: var(--color-gray300); +} diff --git a/src/components/ItemDetails/ItemMetaData.jsx b/src/components/ItemDetails/ItemMetaData.jsx new file mode 100644 index 00000000..1d08bbe0 --- /dev/null +++ b/src/components/ItemDetails/ItemMetaData.jsx @@ -0,0 +1,15 @@ +import styles from "./ItemMetaData.module.css"; +import ProfileCard from "../layout/ProfileCard/ProfileCard"; +import FavoriteButton from "../common/FavoriteButton/FavoriteButton"; + +const ItemMetaData = ({ ownerNickname, updatedAt, favoriteCount }) => { + return ( +
+ +
+ +
+ ); +}; + +export default ItemMetaData; diff --git a/src/components/ItemDetails/ItemMetaData.module.css b/src/components/ItemDetails/ItemMetaData.module.css new file mode 100644 index 00000000..ed1a38c4 --- /dev/null +++ b/src/components/ItemDetails/ItemMetaData.module.css @@ -0,0 +1,27 @@ +.metadata-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + gap: 16px; +} + +.nickname { + font-weight: 500; + font-size: 14px; + line-height: 24px; + color: var(--color-gray600); +} + +.updatedAt { + font-weight: 400; + font-size: 14px; + line-height: 24px; + color: var(--color-gray400); +} + +.vertical-line-box { + flex-grow: 1; + height: 34px; + border-right: 1px solid var(--color-gray300); +} \ No newline at end of file diff --git a/src/components/ItemDetails/ItemTitleHeader.jsx b/src/components/ItemDetails/ItemTitleHeader.jsx new file mode 100644 index 00000000..60e930da --- /dev/null +++ b/src/components/ItemDetails/ItemTitleHeader.jsx @@ -0,0 +1,16 @@ +import KebabMenu from "../common/KebabMenu/KebabMenu"; +import styles from "./ItemTitleHeader.module.css"; + +const ItemTitleHeader = ({ name, price, id, menuItems }) => { + return ( +
+
+

{name}

+ {price} +
+ +
+ ); +}; + +export default ItemTitleHeader; diff --git a/src/components/ItemDetails/ItemTitleHeader.module.css b/src/components/ItemDetails/ItemTitleHeader.module.css new file mode 100644 index 00000000..a026d0e0 --- /dev/null +++ b/src/components/ItemDetails/ItemTitleHeader.module.css @@ -0,0 +1,30 @@ +.header-container { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items:start; + padding-bottom: 16px; + border-bottom: 1px solid var(--color-gray300); + margin-bottom: 24px; +} + +.title-container { + display: flex; + flex-direction: column; + gap: 16px; + width: 100%; +} + +.title { + font-weight: 600; + font-size: 24px; + line-height: 32px; + color: var(--color-gray800); +} + +.price { + font-weight: 600; + font-size: 40px; + line-height: 100%; + color: var(--color-gray800); +} \ No newline at end of file diff --git a/src/components/comments/CommentCard.jsx b/src/components/comments/CommentCard.jsx new file mode 100644 index 00000000..375f8904 --- /dev/null +++ b/src/components/comments/CommentCard.jsx @@ -0,0 +1,61 @@ +import { useState } from "react"; +import styles from "./CommentCard.module.css"; +import CommentEditForm from "./CommentEditForm"; +import CommentView from "./CommentView"; + +const CommentCard = ({ comment }) => { + const [isEditing, setIsEditing] = useState(false); + const [zIndex, setZIndex] = useState(0); + const handleEditClick = (e) => { + e.preventDefault(); + setIsEditing(true); + }; + + const handleDeleteClick = (e) => { + e.preventDefault(); + }; + + const handleSubmitEdit = (e) => { + e.preventDefault(); + setIsEditing(false); + }; + + const handleCancelEdit = (e) => { + e.preventDefault(); + setIsEditing(false); + }; + + const handleKebabOpen = () => { + setZIndex(1); + }; + + const handleKebabClose = () => { + setZIndex(0); + }; + + const containerStyle = { + zIndex: zIndex, + }; + + return ( +
+ {isEditing ? ( + + ) : ( + + )} +
+ ); +}; + +export default CommentCard; diff --git a/src/pages/Home/Home.css b/src/components/comments/CommentCard.module.css similarity index 100% rename from src/pages/Home/Home.css rename to src/components/comments/CommentCard.module.css diff --git a/src/components/comments/CommentEditForm.jsx b/src/components/comments/CommentEditForm.jsx new file mode 100644 index 00000000..e0e150e9 --- /dev/null +++ b/src/components/comments/CommentEditForm.jsx @@ -0,0 +1,48 @@ +import styles from "./CommentEditForm.module.css"; +import { useState } from "react"; +import ProfileCard from "../layout/ProfileCard/ProfileCard"; + +const INQUIRE_PLACEHOLDER = + "개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다."; + +const CommentEditForm = ({ comment, onSubmit, onCancel }) => { + const [inquireText, setInquireText] = useState(comment?.content); + + const handleInquireTextChange = (e) => { + setInquireText(e.target.value); + }; + + return ( +
+