diff --git a/README.md b/README.md index 58beeaccd..e69de29bb 100644 --- a/README.md +++ b/README.md @@ -1,70 +0,0 @@ -# Getting Started with Create React App - -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). - -## Available Scripts - -In the project directory, you can run: - -### `npm start` - -Runs the app in the development mode.\ -Open [http://localhost:3000](http://localhost:3000) to view it in your browser. - -The page will reload when you make changes.\ -You may also see any lint errors in the console. - -### `npm test` - -Launches the test runner in the interactive watch mode.\ -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. - -### `npm run build` - -Builds the app for production to the `build` folder.\ -It correctly bundles React in production mode and optimizes the build for the best performance. - -The build is minified and the filenames include the hashes.\ -Your app is ready to be deployed! - -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. - -### `npm run eject` - -**Note: this is a one-way operation. Once you `eject`, you can't go back!** - -If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. - -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. - -You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). - -### Code Splitting - -This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) - -### Analyzing the Bundle Size - -This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) - -### Making a Progressive Web App - -This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) - -### Advanced Configuration - -This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) - -### Deployment - -This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) - -### `npm run build` fails to minify - -This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) diff --git a/package-lock.json b/package-lock.json index a1e590ee6..48f3936d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,10 +11,22 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/jest": "^29.5.12", + "@types/node": "^20.12.12", + "@types/react": "^18.3.2", + "@types/react-dom": "^18.3.0", + "axios": "^1.6.8", + "path-browserify": "^1.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.22.3", "react-scripts": "5.0.1", + "styled-components": "^6.1.8", + "typescript": "^5.4.5", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -630,9 +642,17 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, "engines": { "node": ">=6.9.0" }, @@ -1875,6 +1895,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -2270,6 +2301,24 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", + "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", + "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==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -3241,6 +3290,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz", + "integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -4046,9 +4103,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.4.tgz", - "integrity": "sha512-PhglGmhWeD46FYOVLt3X7TiWjzwuVGW9wG/4qocPevXMjCmrIc5b6db9WjeGE4QYVpUAWMDv3v0IiBwObY289A==", + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -4297,9 +4354,12 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "node_modules/@types/node": { - "version": "20.5.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz", - "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==" + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -4332,19 +4392,18 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/react": { - "version": "18.2.21", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", - "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", + "version": "18.3.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.2.tgz", + "integrity": "sha512-Btgg89dAnqD4vV7R3hlwOxgqobUQKgx3MmrQRi0yYbs/P0ym8XozIAlkqVilPqHQwXs4e9Tf63rrCgl58BcO4w==", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", - "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", "dependencies": { "@types/react": "*" } @@ -4362,11 +4421,6 @@ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, "node_modules/@types/semver": { "version": "7.5.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", @@ -4412,6 +4466,11 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" }, + "node_modules/@types/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw==" + }, "node_modules/@types/testing-library__jest-dom": { "version": "5.14.9", "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", @@ -5285,6 +5344,29 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -5826,6 +5908,14 @@ "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==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -5838,9 +5928,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001528", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001528.tgz", - "integrity": "sha512-0Db4yyjR9QMNlsxh+kKWzQtkyflkG/snYheSzkjmvdEtEXB1+jt7A2HmSEiO6XIJPIbo92lHNGNySvE5pZcs5Q==", + "version": "1.0.30001609", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz", + "integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==", "funding": [ { "type": "opencollective", @@ -6261,6 +6351,14 @@ "postcss": "^8.4" } }, + "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==", + "engines": { + "node": ">=4" + } + }, "node_modules/css-declaration-sorter": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", @@ -6442,6 +6540,16 @@ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" }, + "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==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/css-tree": { "version": "1.0.0-alpha.37", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", @@ -8294,9 +8402,9 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -12879,6 +12987,11 @@ "tslib": "^2.0.3" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -13085,9 +13198,9 @@ } }, "node_modules/postcss": { - "version": "8.4.29", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", - "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -14375,6 +14488,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -14671,6 +14789,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.22.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz", + "integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==", + "dependencies": { + "@remix-run/router": "1.15.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.22.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz", + "integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==", + "dependencies": { + "@remix-run/router": "1.15.3", + "react-router": "6.22.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -15485,6 +15633,11 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "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==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -15980,6 +16133,38 @@ "webpack": "^5.0.0" } }, + "node_modules/styled-components": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.8.tgz", + "integrity": "sha512-PQ6Dn+QxlWyEGCKDS71NGsXoVLKfE1c3vApkvDYS5KAK+V8fNWGhbSUEo9Gg2iaID2tjLXegEW3bZDUGpofRWw==", + "dependencies": { + "@emotion/is-prop-valid": "1.2.1", + "@emotion/unitless": "0.8.0", + "@types/stylis": "4.2.0", + "css-to-react-native": "3.2.0", + "csstype": "3.1.2", + "postcss": "8.4.31", + "shallowequal": "1.1.0", + "stylis": "4.3.1", + "tslib": "2.5.0" + }, + "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/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, "node_modules/stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", @@ -15995,6 +16180,11 @@ "postcss": "^8.2.15" } }, + "node_modules/stylis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", + "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" + }, "node_modules/sucrase": { "version": "3.34.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", @@ -16624,16 +16814,15 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "peer": true, + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { @@ -16655,6 +16844,11 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", diff --git a/package.json b/package.json index 7ff0d6b58..ee371f84e 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,18 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/jest": "^29.5.12", + "@types/node": "^20.12.12", + "@types/react": "^18.3.2", + "@types/react-dom": "^18.3.0", + "axios": "^1.6.8", + "path-browserify": "^1.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.22.3", "react-scripts": "5.0.1", + "styled-components": "^6.1.8", + "typescript": "^5.4.5", "web-vitals": "^2.1.4" }, "scripts": { @@ -34,5 +43,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11" } } diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index a11777cc4..000000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/index.html b/public/index.html index aa069f27c..62c81d2c5 100644 --- a/public/index.html +++ b/public/index.html @@ -1,5 +1,5 @@ - + @@ -24,7 +24,7 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - React App + 판다 마켓 diff --git a/public/logo192.png b/public/logo192.png deleted file mode 100644 index fc44b0a37..000000000 Binary files a/public/logo192.png and /dev/null differ diff --git a/public/logo512.png b/public/logo512.png deleted file mode 100644 index a4e47a654..000000000 Binary files a/public/logo512.png and /dev/null differ diff --git a/public/manifest.json b/public/manifest.json deleted file mode 100644 index 080d6c77a..000000000 --- a/public/manifest.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "short_name": "React App", - "name": "Create React App Sample", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/public/robots.txt b/public/robots.txt deleted file mode 100644 index e9e57dc4d..000000000 --- a/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 74b5e0534..000000000 --- a/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/App.js b/src/App.js deleted file mode 100644 index 378457572..000000000 --- a/src/App.js +++ /dev/null @@ -1,25 +0,0 @@ -import logo from './logo.svg'; -import './App.css'; - -function App() { - return ( -
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
-
- ); -} - -export default App; diff --git a/src/App.test.js b/src/App.test.js deleted file mode 100644 index 1f03afeec..000000000 --- a/src/App.test.js +++ /dev/null @@ -1,8 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 000000000..2c5e86a57 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; +import Products from "./pages/Products"; +import AddItem from "./pages/AddItem"; +import ProductsDetail from "./pages/ProductsDetail"; +function App() { + //Products 주소는 /items지만 메인 페이지가 없어서 *로 잠깐 대체 + return ( + + + } /> + } /> + } /> + } /> + + + ); +} + +export default App; diff --git a/src/components/CommentInput.tsx b/src/components/CommentInput.tsx new file mode 100644 index 000000000..5751bc657 --- /dev/null +++ b/src/components/CommentInput.tsx @@ -0,0 +1,92 @@ +import React, { useState, ChangeEvent } from "react"; +import styled from "styled-components"; + +interface RegisterButtonProps { + isEnabled: boolean; +} + +function CommentInput(): JSX.Element { + const [comment, setComment] = useState(""); + + const handleInputChange = (event: ChangeEvent): void => { + setComment(event.target.value); + }; + + const isCommentValid = comment.trim() !== ""; + return ( +
+ 문의하기 + + 등록 +
+ ); +} +export default CommentInput; + +const Section = styled.div` + width: 1200px; + margin: 0 auto; + @media (max-width: 1199px) { + width: 696px; + } + @media (max-width: 767px) { + width: 344px; + } +`; +const Text = styled.p` + font-family: "Pretendard"; + font-style: normal; + font-weight: 600; + font-size: 16px; + line-height: 19px; + color: #111827; + margin: 40px 0 0 0; +`; +const InputArea = styled.textarea` + display: flex; + flex-direction: row; + align-items: flex-start; + padding: 16px 24px; + gap: 10px; + width: 100%; + height: 104px; + background: #f3f4f6; + border-radius: 12px; + border: none; + margin: 10px 0; + &::placeholder { + font-family: "Pretendard"; + font-style: normal; + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #9ca3af; + @media (max-width: 767px) { + font-size: 14px; + } + } +`; +const RegisterButton = styled.button` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 12px 23px; + gap: 10px; + width: 74px; + height: 42px; + border-radius: 8px; + margin: 0 0 0 auto; + border: none; + font-family: "Pretendard"; + font-style: normal; + font-weight: 600; + font-size: 16px; + color: #ffffff; + background-color: ${({ isEnabled }) => (isEnabled ? "#3692FF" : "#9ca3af")}; + cursor: ${({ isEnabled }) => (isEnabled ? "pointer" : "not-allowed")}; +`; diff --git a/src/components/CommentList.tsx b/src/components/CommentList.tsx new file mode 100644 index 000000000..889890bb4 --- /dev/null +++ b/src/components/CommentList.tsx @@ -0,0 +1,166 @@ +import { useParams } from "react-router-dom"; +import React, { useEffect, useState } from "react"; +import styled from "styled-components"; +import axios from "axios"; +import noneComments from "../images/noneComments.svg"; +import dots from "../images/3dots.svg"; + +interface Comment { + id: number; + content: string; + image: string; + nickname: string; + updatedAt: string; +} + +function CommentList() { + const [comments, setComments] = useState([]); + const { productId } = useParams<{ productId: string }>(); + const numericProductId = parseInt(productId || "", 10); + + const getComments = async (productId: number) => { + try { + const response = await axios.get( + `https://panda-market-api.vercel.app/products/${productId}/comments` + ); + return response.data; + } catch (error) { + console.log(error); + } + }; + + useEffect(() => { + if (!numericProductId || isNaN(numericProductId)) { + console.error("상품 ID가 유효하지 않습니다."); + return; + } + + const fetchComments = async () => { + try { + const data = await getComments(numericProductId); + setComments(data.list); + console.log(data); + } catch (error) { + console.error("댓글을 불러오는 데 실패했습니다:", error); + } + }; + + fetchComments(); + }, [numericProductId]); + + return ( + <> + {!comments || comments.length === 0 ? ( + + 댓글이 없습니다. + 아직 문의가 없습니다 + + ) : ( + <> + + {comments.map((comment, id) => ( +
+
+ {comment.content} + +
+ + + + {comment.nickname} + {comment.updatedAt} + + + +
+ ))} +
+ + )} + + ); +} +export default CommentList; + +const NoneCommentsContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + width: 1200px; + margin: 0 auto; + @media (max-width: 1199px) { + width: 696px; + } + @media (max-width: 767px) { + width: 344px; + } +`; +const NoneCommentsText = styled.p` + font-family: "Pretendard"; + font-style: normal; + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #9ca3af; + margin: 30px 0 0px; +`; +const CommentListContainer = styled.div` + display: flex; + flex-direction: column; + align-items: flex-start; + width: 1200px; + margin: 0 auto; + @media (max-width: 1199px) { + width: 696px; + } + @media (max-width: 767px) { + width: 344px; + } +`; +const Content = styled.p` + font-family: "Pretendard"; + font-style: normal; + font-weight: 400; + font-size: 16px; + line-height: 140%; + color: #1f2937; + margin: 20px 0; +`; +const ProfileContainer = styled.div` + display: flex; +`; +const ProfileImage = styled.img` + width: 40px; + height: 40px; + margin-right: 20px; +`; +const NickNameContainer = styled.div` + display: flex; + flex-direction: column; + gap: 5px; +`; +const NickName = styled.p` + font-family: "Pretendard"; + font-style: normal; + font-weight: 400; + font-size: 14px; + line-height: 17px; + color: #4b5563; +`; +const UpDatedAt = styled.p` + font-family: "Pretendard"; + font-style: normal; + font-weight: 400; + font-size: 12px; + line-height: 14px; + color: #9ca3af; +`; +const Divider = styled.div` + width: 100%; + height: 1px; + background-color: #e5e7eb; + margin: 16px 0; +`; +const Dots = styled.img` + margin: 0 10px 0 auto; +`; diff --git a/src/components/FileInput.tsx b/src/components/FileInput.tsx new file mode 100644 index 000000000..0374e3335 --- /dev/null +++ b/src/components/FileInput.tsx @@ -0,0 +1,141 @@ +import React, { useEffect, useRef, useState, ChangeEvent } from "react"; +import styled from "styled-components"; +import X from "../images/ic_X.svg"; +import plus from "../images/ic_plus.svg"; + +interface FileInputProps { + name: string; + value: File | null; + initialPreview?: string; + onChange: (name: string, nextName: File | null) => void; +} +function FileInput({ name, value, initialPreview, onChange }: FileInputProps) { + const [preview, setPreview] = useState(initialPreview); + const inputRef = useRef(null); + + const handleChange = (e: ChangeEvent) => { + const files = e.target.files; + if (!files || files.length === 0) { + // 파일이 없거나 파일 배열의 길이가 0인 경우 + return; + } + const nextValue = files[0]; // 첫 번째 파일만을 선택 + onChange(name, nextValue); + }; + + const handleClearClick = () => { + const inputNode = inputRef.current; + if (!inputNode) return; + + inputNode.value = ""; + onChange(name, null); + }; + + useEffect(() => { + if (!value) return; + const nextPreview = URL.createObjectURL(value); + setPreview(nextPreview); + + return () => { + setPreview(initialPreview); + URL.revokeObjectURL(nextPreview); + }; + }, [value, initialPreview]); + + return ( + + + + + 이미지 등록 + + + <> + {value && 이미지 등록} + {value && } + + + + ); +} + +export default FileInput; + +const Container = styled.div` + display: flex; + gap: 20px; +`; +const Container1 = styled.div` + display: flex; + position: relative; +`; +const ImageRegister = styled.input` + width: 282px; + height: 282px; + background-color: #f3f4f6; + cursor: pointer; + opacity: 0; + @media (max-width: 1199px) { + width: 162px; + height: 162px; + } +`; + +const Image = styled.img` + box-sizing: border-box; + width: 282px; + height: 282px; + border: none; + border-radius: 12px; + @media (max-width: 1199px) { + width: 162px; + height: 162px; + } +`; +const Delete = styled.img` + position: absolute; + top: 10px; + right: 10px; +`; +const InputText = styled.p` + position: absolute; + margin: -110px 102px; + z-index: 1; + font-family: "Pretendard"; + font-style: normal; + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #9ca3af; + width: 100px; + @media (max-width: 1199px) { + margin: -60px 45px; + } +`; +const Plus = styled.img` + position: absolute; + margin: 100px -170px; + z-index: 1; + @media (max-width: 1199px) { +\ + margin: 50px -105px; + } +`; +const InputWrapper = styled.div` + position: relative; + width: 282px; + height: 282px; + margin: 10px 0; + background: #f3f4f6; + border-radius: 12px; + border: none; + @media (max-width: 1199px) { + width: 162px; + height: 162px; + } +`; diff --git a/src/components/Header.tsx b/src/components/Header.tsx new file mode 100644 index 000000000..3aaec6c3b --- /dev/null +++ b/src/components/Header.tsx @@ -0,0 +1,92 @@ +import styled from "styled-components"; +import React from "react"; +import Logo from "../images/logo.svg"; +import { Link } from "react-router-dom"; +function Header() { + return ( + + + + 판다마켓 로고 + + + + 로그인 + + ); +} +const HeaderContainer = styled.div` + box-sizing: border-box; + position: sticky; + width: 100%; + height: 70px; + left: 0px; + top: 0px; + display: flex; + background: #ffffff; + border-bottom: 1px solid #dfdfdf; + align-items: center; + z-index: 2; +`; +const MenuContainer = styled.div` + margin-left: 200px; + display: flex; + gap: 30px; + align-items: center; + @media (max-width: 1199px) { + margin-left: 24px; + } +`; +const FreeBoard = styled.a` + font-family: "Pretendard"; + font-style: normal; + font-weight: 700; + font-size: 18px; + line-height: 21px; + display: flex; + align-items: center; + text-align: center; + color: #4b5563; +`; +const StyledLink = styled(Link)` + text-decoration: none; +`; +const UsedMarket = styled.a` + font-family: "Pretendard"; + font-style: normal; + font-weight: 700; + font-size: 18px; + line-height: 21px; + display: flex; + align-items: center; + text-align: center; + color: #3692ff; +`; +const Login = styled.a` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + width: 88px; + height: 42px; + margin: 0 200px 0 auto; + background: #3692ff; + border-radius: 8px; + font-family: "Pretendard"; + font-style: normal; + font-weight: 600; + font-size: 16px; + line-height: 19px; + display: flex; + align-items: center; + color: #ffffff; + @media (max-width: 1199px) { + margin: 0 24px 0 auto; + } +`; +export default Header; diff --git a/src/components/TagInput.tsx b/src/components/TagInput.tsx new file mode 100644 index 000000000..d67871f2f --- /dev/null +++ b/src/components/TagInput.tsx @@ -0,0 +1,129 @@ +import React, { useState } from "react"; +import styled from "styled-components"; +import DeleteIcon from "../images/ic_X_gray.svg"; + +interface TagInputProps { + tags: string[]; + setTags: React.Dispatch>; + setIsTagsEmpty?: React.Dispatch> | undefined; + placeholder?: string; +} +const TagInput = ({ + tags, + setTags, + setIsTagsEmpty, + placeholder, +}: TagInputProps) => { + const [inputValue, setInputValue] = useState(""); + + const handleInputChange = (e: React.ChangeEvent) => { + setInputValue(e.target.value); + }; + + const handleInputKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && inputValue.trim() !== "") { + setTags([...tags, inputValue.trim()]); + e.preventDefault(); + setInputValue(""); + if (setIsTagsEmpty) { + setIsTagsEmpty(false); + } + } + }; + + const handleTagDelete = (index: any) => { + const newTags = [...tags]; + newTags.splice(index, 1); + setTags(newTags); + if (setIsTagsEmpty) { + setIsTagsEmpty(newTags.length === 0); + } + }; + + return ( + + + + {tags.map((tag) => ( + + {tag} + handleTagDelete(`tag-${tag}`)}> + + + + ))} + + + ); +}; + +const InputTagContainer = styled.div` + display: flex; + flex-direction: column; + align-items: flex-start; +`; + +const InputTag = styled.input` + width: 100%; + height: 56px; + background: #f3f4f6; + border-radius: 12px; + padding: 0px 25px; + border: none; + &::placeholder { + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #9ca3af; + } +`; + +const TagList = styled.div` + display: flex; + flex-wrap: wrap; + margin-top: 10px; + gap: 10px; +`; + +const TagItem = styled.div` + display: flex; + align-items: center; + padding: 12px 12px 12px 16px; + background: #f9fafb; + border-radius: 26px; + font-family: "Pretendard"; + font-style: normal; + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #1f2937; +`; + +const TagText = styled.span` + font-size: 16px; + font-weight: 400; + line-height: 24px; +`; + +const DeleteButton = styled.button` + background-color: transparent; + color: #ccc; + border: none; + cursor: pointer; + margin-left: 5px; +`; + +const CloseIcon = styled.img` + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; +`; +export default TagInput; diff --git a/src/declarations.d.ts b/src/declarations.d.ts new file mode 100644 index 000000000..a4c7cc1fb --- /dev/null +++ b/src/declarations.d.ts @@ -0,0 +1,5 @@ +// declarations.d.ts +declare module "*.svg" { + const content: any; + export default content; +} diff --git a/src/images/3dots.svg b/src/images/3dots.svg new file mode 100644 index 000000000..51b03fba0 --- /dev/null +++ b/src/images/3dots.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/arrow_down.svg b/src/images/arrow_down.svg new file mode 100644 index 000000000..8308690fd --- /dev/null +++ b/src/images/arrow_down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/bottom-banner-img.png b/src/images/bottom-banner-img.png new file mode 100644 index 000000000..420452ae4 Binary files /dev/null and b/src/images/bottom-banner-img.png differ diff --git a/src/images/eyeoff.svg b/src/images/eyeoff.svg new file mode 100644 index 000000000..45ad62321 --- /dev/null +++ b/src/images/eyeoff.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/eyeon.svg b/src/images/eyeon.svg new file mode 100644 index 000000000..35a75305e --- /dev/null +++ b/src/images/eyeon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/heart.svg b/src/images/heart.svg new file mode 100644 index 000000000..cad016c13 --- /dev/null +++ b/src/images/heart.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/ic_X.svg b/src/images/ic_X.svg new file mode 100644 index 000000000..1e0d50959 --- /dev/null +++ b/src/images/ic_X.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/ic_X_gray.svg b/src/images/ic_X_gray.svg new file mode 100644 index 000000000..047044dcb --- /dev/null +++ b/src/images/ic_X_gray.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/images/ic_plus.svg b/src/images/ic_plus.svg new file mode 100644 index 000000000..5bb9abf55 --- /dev/null +++ b/src/images/ic_plus.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/images/logo.svg b/src/images/logo.svg new file mode 100644 index 000000000..ba9c9386b --- /dev/null +++ b/src/images/logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/images/noneComments.svg b/src/images/noneComments.svg new file mode 100644 index 000000000..7e8de7b28 --- /dev/null +++ b/src/images/noneComments.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/images/productImg.png b/src/images/productImg.png new file mode 100644 index 000000000..3024aa0b2 Binary files /dev/null and b/src/images/productImg.png differ diff --git a/src/images/search.svg b/src/images/search.svg new file mode 100644 index 000000000..52241e6d8 --- /dev/null +++ b/src/images/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/section1.png b/src/images/section1.png new file mode 100644 index 000000000..0341dd622 Binary files /dev/null and b/src/images/section1.png differ diff --git a/src/images/section2.png b/src/images/section2.png new file mode 100644 index 000000000..adfaa67c1 Binary files /dev/null and b/src/images/section2.png differ diff --git a/src/images/section3.png b/src/images/section3.png new file mode 100644 index 000000000..782d345d3 Binary files /dev/null and b/src/images/section3.png differ diff --git a/src/images/social/facebook-logo.svg b/src/images/social/facebook-logo.svg new file mode 100644 index 000000000..8491c2f83 --- /dev/null +++ b/src/images/social/facebook-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/social/google-logo.svg b/src/images/social/google-logo.svg new file mode 100644 index 000000000..84cf7136a --- /dev/null +++ b/src/images/social/google-logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/images/social/instagram-logo.svg b/src/images/social/instagram-logo.svg new file mode 100644 index 000000000..c83306f84 --- /dev/null +++ b/src/images/social/instagram-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/social/kakao-logo.svg b/src/images/social/kakao-logo.svg new file mode 100644 index 000000000..854ddda5e --- /dev/null +++ b/src/images/social/kakao-logo.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/images/social/twitter-logo.svg b/src/images/social/twitter-logo.svg new file mode 100644 index 000000000..14a6069a1 --- /dev/null +++ b/src/images/social/twitter-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/social/youtube-logo.svg b/src/images/social/youtube-logo.svg new file mode 100644 index 000000000..5fcc0ff34 --- /dev/null +++ b/src/images/social/youtube-logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/images/text-logo.svg b/src/images/text-logo.svg new file mode 100644 index 000000000..f52d0bf9c --- /dev/null +++ b/src/images/text-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/images/top-banner-img.png b/src/images/top-banner-img.png new file mode 100644 index 000000000..becdedd7c Binary files /dev/null and b/src/images/top-banner-img.png differ diff --git a/src/images/turnback.svg b/src/images/turnback.svg new file mode 100644 index 000000000..a00369598 --- /dev/null +++ b/src/images/turnback.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/index.js b/src/index.js deleted file mode 100644 index d563c0fb1..000000000 --- a/src/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; - -const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - - - -); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(); diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 000000000..ae53ced64 --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,23 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; + +// 루트 DOM 요소를 찾습니다. 타입스크립트에서는 이 요소가 null이 아니도록 명시적으로 확인해야 합니다. +const rootElement = document.getElementById("root"); + +// 만약 rootElement가 null이라면, 오류를 발생시킵니다. 이는 타입스크립트에서 런타임 오류를 방지하기 위함입니다. +if (!rootElement) { + throw new Error( + "루트 요소를 찾을 수 없습니다. index.html에
가 있는지 확인하세요." + ); +} + +// createRoot에 rootElement를 전달합니다. +const root = ReactDOM.createRoot(rootElement); + +// ReactDOM의 render 메서드를 사용하여 App 컴포넌트를 렌더링합니다. +root.render( + + + +); diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9dfc1c058..000000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/pages/AddItem.tsx b/src/pages/AddItem.tsx new file mode 100644 index 000000000..cbe552612 --- /dev/null +++ b/src/pages/AddItem.tsx @@ -0,0 +1,222 @@ +import React, { useState, useEffect, useCallback, ChangeEvent } from "react"; +import styled, { createGlobalStyle } from "styled-components"; +import Header from "../components/Header"; +import FileInput from "../components/FileInput"; +import TagInput from "../components/TagInput"; + +// 글로벌 스타일 정의 +const GlobalStyle = createGlobalStyle` + * { + box-sizing: border-box; + } + + body { + font-family: "Pretendard"; + font-style: normal; + } +`; + +// AddItem 컴포넌트 +function AddItem(): JSX.Element { + // 상태 타입 정의 + interface Values { + title: string; + content: string; + imgFile: File | null; + price: string; + tag: string; + } + + const [values, setValues] = useState({ + title: "", + content: "", + imgFile: null, + price: "", + tag: "", + }); + + const [tags, setTags] = useState([]); + const [isValid, setIsValid] = useState(false); + + // handleChange 함수의 타입 정의 + const handleChange = (name: string, value: string | File | null) => { + setValues((prevValues) => ({ + ...prevValues, + [name]: value, + })); + }; + + // handleInputChange 함수의 타입 정의 + const handleInputChange = ( + e: ChangeEvent | ChangeEvent + ) => { + const { name, value } = e.target; + handleChange(name, value); + }; + + // 입력 값 검증 함수 + const validateInputs = useCallback(() => { + const isValid = + values.title.trim() !== "" && + values.content.trim() !== "" && + values.price.trim() !== "" && + tags.length > 0; + + setIsValid(isValid); + }, [values, tags]); + + // 입력 값 검증 함수 호출 + useEffect(() => { + validateInputs(); + }, [values, validateInputs]); + + // 제출 함수 + const handleSubmit = () => { + console.log("submit"); + }; + + return ( + <> + +
+
+ + 상품 등록하기 + + 등록 + + + 상품 이미지 + + 상품명 + + 상품 소개 + + 판매 가격 + + 태그 + +
+ + ); +} + +export default AddItem; + +const Section = styled.div` + width: 1200px; + margin: 30px auto; + @media (max-width: 1199px) { + width: 100%; + padding: 0 24px; + } +`; +const TopSection = styled.div` + display: flex; + width: 100%; +`; +const RegisterText = styled.h1` + font-weight: 700; + font-size: 28px; + line-height: 33px; + display: flex; + align-items: center; + color: #1f2937; +`; +const RegisterButton = styled.button` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 12px 20px; + gap: 10px; + width: 88px; + height: 42px; + background-color: ${(props) => (props.disabled ? "#9ca3af" : "#3692ff")}; + border-radius: 8px; + border: none; + font-weight: 600; + font-size: 16px; + line-height: 19px; + color: #ffffff; + margin: 0 0 0 auto; +`; +const Text = styled.p` + font-weight: 700; + font-size: 18px; + line-height: 21px; + display: flex; + align-items: center; + color: #1f2937; + margin: 20px 0; +`; + +const ProductName = styled.input` + width: 100%; + height: 56px; + background: #f3f4f6; + border-radius: 12px; + padding: 0px 25px; + border: none; + &::placeholder { + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #9ca3af; + } +`; + +const ProductInfo = styled.textarea` + width: 100%; + height: 200px; + background: #f3f4f6; + border-radius: 12px; + padding: 20px 25px; + position: relative; + border: none; + &::placeholder { + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #9ca3af; + } +`; +const Price = styled.input` + width: 100%; + height: 56px; + background: #f3f4f6; + border-radius: 12px; + padding: 0px 25px; + border: none; + &::placeholder { + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #9ca3af; + } +`; diff --git a/src/pages/Products.tsx b/src/pages/Products.tsx new file mode 100644 index 000000000..37286b111 --- /dev/null +++ b/src/pages/Products.tsx @@ -0,0 +1,347 @@ +import styled from "styled-components"; +import React, { useEffect, useState } from "react"; +import axios from "axios"; +import { useNavigate } from "react-router"; +import "../products.css"; +import heart from "../images/heart.svg"; +import search from "../images/search.svg"; +import arrowDown from "../images/arrow_down.svg"; +import Header from "../components/Header"; + +interface Product { + id: number; + name: string; + images: string; + price: number; + favoriteCount: number; + createdAt: string; +} +interface OptionsContainerProps { + isOpen: boolean; +} + +function Products() { + const [products, setProducts] = useState([]); + const [bestProducts, setBestProducts] = useState([]); + const [order, setOrder] = useState("recent"); + const [isOpen, setIsOpen] = useState(false); + const page = 1; + const pageSize = 10; + + const navigate = useNavigate(); + + useEffect(() => { + const fetchProducts = async () => { + try { + const response = await axios.get( + `https://panda-market-api.vercel.app/products?page=${page}&pageSize=${pageSize}&orderBy=${order}`, + { + headers: { + "Content-Type": "application/json", + }, + } + ); + const data = response.data as { list: Product[] }; + if (data && data.list) { + const sortedData = data.list.sort( + (a, b) => b.favoriteCount - a.favoriteCount + ); + setBestProducts(sortedData.slice(0, 4)); + + const sortedProducts = data.list.slice().sort((a, b) => { + if (order === "recent") { + return ( + new Date(b.createdAt).getTime() - + new Date(a.createdAt).getTime() + ); + } else if (order === "favorite") { + return b.favoriteCount - a.favoriteCount; + } + return 0; + }); + setProducts(sortedProducts); + } else { + alert("에러가 발생했습니다."); + } + } catch (error) { + console.error(error); + } + }; + fetchProducts(); + }, [order]); + + const handleOrderChange = (selectedOrder: string) => { + setOrder(selectedOrder); + setIsOpen(false); // Close dropdown after selecting an option + }; + + const handleProductClick = (productId: number) => { + navigate(`/items/${productId}`); + }; + + return ( + <> +
+ + 베스트 상품 + + {bestProducts && + bestProducts.map((product) => ( + handleProductClick(product.id)} + > + + {product.name} + {product.price}원 + + + {product.favoriteCount} + + + ))} + +
+ 전체 상품 + + + 검색 + + + navigate("/additem")}> + 상품 등록하기 + + + setIsOpen(!isOpen)}> + {order === "recent" ? "최신순" : "좋아요순"} + + + + + + + + +
+ + {products && + products.map((product) => ( + handleProductClick(product.id)} + > + + {product.name} + {product.price}원 + + + {product.favoriteCount} + + + ))} + +
+ + ); +} + +const Container = styled.div` + box-sizing: border-box; + width: 1200px; + margin: 0 auto; +`; +const BestSectionTitle = styled.p` + font-family: "Pretendard"; + font-style: normal; + font-weight: 700; + font-size: 20px; + line-height: 140%; + display: flex; + align-items: center; + letter-spacing: 0.02em; + color: #111827; + margin-top: 20px; +`; +const SectionTitle = styled.p` + font-family: "Pretendard"; + font-style: normal; + font-weight: 700; + font-size: 20px; + line-height: 140%; + display: flex; + align-items: center; + letter-spacing: 0.02em; + color: #111827; +`; +const BestProductContainer = styled.div` + display: flex; + gap: 1rem; + margin-top: 20px; +`; +const BestProductItem = styled.div``; +const BestProductImage = styled.img` + width: 282px; + height: 282px; + border-radius: 16px; +`; +const ProductImage = styled.img` + width: 221px; + height: 221px; + border-radius: 16px; +`; +const ProductName = styled.p` + font-family: "Pretendard"; + font-style: normal; + font-weight: 500; + font-size: 14px; + line-height: 17px; + color: #1f2937; +`; +const ProductPrice = styled.p` + font-family: "Pretendard"; + font-style: normal; + font-weight: 700; + font-size: 16px; + line-height: 19px; + color: #1f2937; +`; +const ProductLikes = styled.div` + font-family: "Pretendard"; + font-style: normal; + font-weight: 500; + font-size: 12px; + line-height: 14px; + color: #4b5563; +`; +const ProductContainer = styled.div` + gap: 1rem; + display: flex; + width: 1200px; + flex-wrap: wrap; +`; +const ProductItem = styled.div` + width: 221px; +`; +const Heart = styled.img` + margin-right: 10px; +`; +const Search = styled.div` + display: flex; +`; +const ProductRegister = styled.a` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + padding: 12px 23px; + gap: 10px; + height: 42px; + background: #3692ff; + border-radius: 8px; + font-family: "Pretendard"; + font-style: normal; + font-weight: 600; + font-size: 16px; + line-height: 19px; + color: #ffffff; + cursor: pointer; +`; + +const CustomSelect = styled.div` + position: relative; + display: inline-block; +`; + +const SelectButton = styled.div` + display: flex; + align-items: flex-start; + padding: 12px 0px; + gap: 10px; + width: 130px; + height: 42px; + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 12px; + font-family: "Pretendard"; + font-style: normal; + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #1f2937; +`; + +const OptionsContainer = styled.div` + display: ${(props) => (props.isOpen ? "block" : "none")}; + position: absolute; + z-index: 1; + width: 130px; + height: 84px; + background: #ffffff; + border-width: 1px 1px 0px 1px; + border-style: solid; + border-color: #e5e7eb; + border-radius: 12px 12px 12px 12px; + font-family: "Pretendard"; + font-style: normal; + font-weight: 400; + font-size: 16px; + color: #1f2937; +`; + +const Option = styled.div` + padding: 10px; + cursor: pointer; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 130px; + height: 42px; + border-bottom: 1px solid #ccc; + &:hover { + background-color: #ddd; + } +`; +const Tools = styled.div` + display: flex; + gap: 20px; + margin: 0 30px 0 auto; +`; +const SearchInput = styled.input` + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 9px 20px 9px 46px; + gap: 10px; + border: none; + width: 325px; + height: 42px; + background: #f3f4f6; + border-radius: 12px; +`; +const Arrow = styled.img` + width: 24px; + margin: -2px 0px 0 0px; +`; +const Order = styled.div` + margin: 0 0px 0 20px; + width: 60px; +`; +export default Products; diff --git a/src/pages/ProductsDetail.tsx b/src/pages/ProductsDetail.tsx new file mode 100644 index 000000000..ff4f2b687 --- /dev/null +++ b/src/pages/ProductsDetail.tsx @@ -0,0 +1,269 @@ +import { useParams } from "react-router-dom"; +import React, { useEffect, useState } from "react"; +import styled from "styled-components"; +import axios from "axios"; +import Header from "../components/Header"; +import heart from "../images/heart.svg"; +import dots from "../images/3dots.svg"; +import turnback from "../images/turnback.svg"; +import { createGlobalStyle } from "styled-components"; +import CommentInput from "../components/CommentInput"; +import CommentList from "../components/CommentList"; +import { Link } from "react-router-dom"; + +interface Product { + id: number; + name: string; + images: string; + price: number; + description: string; + tags: string[]; + favoriteCount: number; +} +const GlobalStyle = createGlobalStyle` + * { + box-sizing: border-box; + } + + body { + font-family: "Pretendard"; + font-style: normal; + } +`; + +function ProductsDetail() { + const { productId } = useParams<{ productId: string }>(); + const numericProductId = parseInt(productId || "", 10); + const [product, setProduct] = useState(null); + + const getProductById = async (productId: number) => { + try { + const response = await axios.get( + `https://panda-market-api.vercel.app/products/${productId}` + ); + return response.data; + } catch (error) { + console.error(error); + } + }; + + useEffect(() => { + const fetchProduct = async () => { + if (!numericProductId || isNaN(numericProductId)) { + console.error("상품 ID가 유효하지 않습니다."); + return; + } + + try { + const data = await getProductById(numericProductId); + setProduct(data); + } catch (error) { + console.error("상품 정보를 불러오는 데 실패했습니다:", error); + } + }; + + fetchProduct(); + }, [numericProductId]); + + return ( + <> + +
+ + + {product ? ( + <> + + + {product.name} + + {product.price}원 + + 상품 소개 + {product.description} + 상품 태그 + + {product.tags.map((tag) => ( + + #{tag} + + ))} + + + + {product.favoriteCount} + + + + ) : ( +
로딩 중...
+ )} +
+ + + + + 목록으로 돌아가기 + 목록으로 돌아가기 + + +
+ + ); +} + +export default ProductsDetail; + +const Container = styled.div` + position: relative; + width: 1200px; + margin: 20px auto; + @media (max-width: 1199px) { + width: 696px; + } + @media (max-width: 767px) { + width: 344px; + } +`; +const ProductContainer = styled.div` + display: flex; + gap: 24px; + @media (max-width: 767px) { + flex-direction: column; + } +`; +const ProductInfo = styled.div` + display: flex; + flex-direction: column; + width: 690px; + @media (max-width: 767px) { + width: 344px; + } +`; +const ProductImage = styled.img` + width: 486px; + height: 486px; + border-radius: 16px; + @media (max-width: 1199px) { + width: 340px; + height: 340px; + } +`; +const ProductName = styled.p` + font-weight: 600; + font-size: 24px; + line-height: 29px; + color: #1f2937; + @media (max-width: 1199px) { + font-size: 20px; + } + @media (max-width: 767px) { + font-size: 16px; + } +`; +const ProductPrice = styled.p` + font-weight: 600; + font-size: 40px; + line-height: 48px; + color: #1f2937; + margin: 24px 0; + @media (max-width: 1199px) { + font-size: 32px; + } + @media (max-width: 767px) { + font-size: 24px; + } +`; +const DescriptionTitle = styled.p` + font-weight: 500; + font-size: 14px; + line-height: 17px; + color: #4b5563; +`; +const Description = styled.p` + font-weight: 400; + font-size: 16px; + line-height: 140%; + color: #1f2937; + margin: 10px 0 30px; +`; +const ProductLikes = styled.div` + font-weight: 500; + font-size: 16px; + line-height: 19px; + color: #4b5563; + display: flex; + align-items: center; + padding: 4px 12px; + gap: 10px; + width: 87px; + height: 40px; + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 35px; + margin: auto 0 0 0; +`; +const Dots = styled.img` + position: absolute; + margin: 0 0 0 680px; + @media (max-width: 1199px) { + margin: 0 0 0 330px; + } + @media (max-width: 767px) { + margin: 0 0 0 330px; + } +`; + +const Heart = styled.img` + margin-right: 5px; + width: 26px; + height: 26px; +`; +const Divider = styled.div` + width: 100%; + height: 1px; + background-color: #e5e7eb; + margin-bottom: 16px; +`; +const BackButton = styled.div` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + gap: 10px; + width: 240px; + height: 48px; + background: #3692ff; + border-radius: 40px; + font-weight: 600; + font-size: 18px; + line-height: 24px; + text-align: center; + color: #ffffff; + margin: 24px auto; +`; +const StyledLink = styled(Link)` + text-decoration: none; +`; +const TagList = styled.div` + display: flex; + flex-wrap: wrap; + margin-top: 10px; + margin-bottom: 10px; + gap: 10px; +`; +const TagItem = styled.div` + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 6px 16px; + gap: 10px; + background: #f3f4f6; + border-radius: 26px; +`; +const TagText = styled.p` + font-weight: 400; + font-size: 16px; + line-height: 24px; + color: #1f2937; +`; diff --git a/src/products.css b/src/products.css new file mode 100644 index 000000000..96ba8a33d --- /dev/null +++ b/src/products.css @@ -0,0 +1,5 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js deleted file mode 100644 index 5253d3ad9..000000000 --- a/src/reportWebVitals.js +++ /dev/null @@ -1,13 +0,0 @@ -const reportWebVitals = onPerfEntry => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/src/setupTests.js b/src/setupTests.js deleted file mode 100644 index 8f2609b7b..000000000 --- a/src/setupTests.js +++ /dev/null @@ -1,5 +0,0 @@ -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom'; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..a89f6b783 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,110 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es5" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "jsx": "react" /* Specify what JSX code is generated. */, + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": ["src", "declarations.d.ts"] +}