diff --git a/README copy.md b/README copy.md deleted file mode 100644 index fd3b758d..00000000 --- a/README copy.md +++ /dev/null @@ -1,12 +0,0 @@ -# React + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-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 and enable type-aware lint rules. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/README.md b/README.md index fe7375db..fd3b758d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,12 @@ -# πŸ–₯️ Mission-FE-Zero100 -FE Zero100 λ―Έμ…˜μ„ μœ„ν•œ λ ˆν¬μ§€ν† λ¦¬μž…λ‹ˆλ‹€. +# React + Vite +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. -### 🎯 λ―Έμ…˜ μš”κ΅¬μ‚¬ν•­ -1. λ―Έμ…˜ μ§„ν–‰ 방법을 κΌ­ 읽고 μ§„ν–‰ν•΄μ£Όμ„Έμš” - [λ―Έμ…˜ μ§„ν–‰ 방법](https://www.notion.so/46dbd9440a4f4d5e97228011dff70f5a?pvs=21) +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-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 and enable type-aware lint rules. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/package-lock.json b/package-lock.json index 11534e8c..99bd3068 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,18 +9,21 @@ "version": "0.0.0", "dependencies": { "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-router-dom": "^7.4.1", + "styled-components": "^6.1.16" }, "devDependencies": { "@eslint/js": "^9.21.0", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", - "eslint": "^9.23.0", + "eslint": "^9.21.0", + "eslint-config-prettier": "^10.1.1", + "eslint-plugin-prettier": "^5.2.5", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.19", "globals": "^15.15.0", - "prettier": "^3.5.3", "vite": "^6.2.3" } }, @@ -320,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.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", @@ -1015,6 +1039,19 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@pkgr/core": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.0.tgz", + "integrity": "sha512-vsJDAkYR6qCPu+ioGScGiMYR7LvZYIXh/dlQeviqoTWNCVfKTLYD/LkNWH4Mxsv2a5vpIRc77FN5DnmK1eBggQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.37.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.37.0.tgz", @@ -1340,6 +1377,12 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", @@ -1374,6 +1417,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.3.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", @@ -1518,6 +1567,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.30001707", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz", @@ -1590,6 +1648,15 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1605,11 +1672,30 @@ "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-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": { @@ -1769,6 +1855,50 @@ } } }, + "node_modules/eslint-config-prettier": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.1.tgz", + "integrity": "sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.5.tgz", + "integrity": "sha512-IKKP8R87pJyMl7WWamLgPkloB16dagPIdd2FjBDbyRYPKo93wS/NbCOPh6gH+ieNLC+XZrhJt/kWj0PS/DFdmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.10.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react-hooks": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", @@ -1893,6 +2023,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2234,7 +2371,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", @@ -2350,7 +2486,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/postcss": { @@ -2382,6 +2517,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", @@ -2398,6 +2539,7 @@ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -2408,6 +2550,19 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -2449,6 +2604,46 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.4.1.tgz", + "integrity": "sha512-Vmizn9ZNzxfh3cumddqv3kLOKvc7AskUT0dC1prTabhiEi0U4A33LmkDOJ79tXaeSqCqMBXBU/ySX88W85+EUg==", + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.4.1.tgz", + "integrity": "sha512-L3/4tig0Lvs6m6THK0HRV4eHUdpx0dlJasgCxXKnavwhh4tKYgpuZk75HRYNoRKDyDWi9QgzGXsQ1oQSBlWpAA==", + "license": "MIT", + "dependencies": { + "react-router": "7.4.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2522,6 +2717,18 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "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", @@ -2549,7 +2756,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" @@ -2568,6 +2774,68 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/styled-components": { + "version": "6.1.16", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.16.tgz", + "integrity": "sha512-KpWB6ORAWGmbWM10cDJfEV6sXc/uVkkkQV3SLwTNQ/E/PqWgNHIoMSLh1Lnk2FkB9+JHK7uuMq1i+9ArxDD7iQ==", + "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", @@ -2581,6 +2849,42 @@ "node": ">=8" } }, + "node_modules/synckit": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.10.3.tgz", + "integrity": "sha512-R1urvuyiTaWfeCggqEvpDJwAlDVdsT9NM+IP//Tk2x7qHCkSvBk/fwFgw/TLAHzZlrAnnazMcRw0ZD8HlYFTEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/synckit/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "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", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 155d21de..4003de36 100644 --- a/package.json +++ b/package.json @@ -12,18 +12,21 @@ }, "dependencies": { "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-router-dom": "^7.4.1", + "styled-components": "^6.1.16" }, "devDependencies": { "@eslint/js": "^9.21.0", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", - "eslint": "^9.23.0", + "eslint": "^9.21.0", + "eslint-config-prettier": "^10.1.1", + "eslint-plugin-prettier": "^5.2.5", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.19", "globals": "^15.15.0", - "prettier": "^3.5.3", "vite": "^6.2.3" } } diff --git a/src/App.css b/src/App.css index b9d355df..b9073274 100644 --- a/src/App.css +++ b/src/App.css @@ -1,42 +1,160 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; +/* src/App.css */ +body { + font-family: Arial, sans-serif; /* 폰트 λ³€κ²½ */ + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + margin: 0; + background-color: #fff; } -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; +.app-container { + max-width: 600px; + width: 100%; + padding: 20px; } -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); + +h1 { + font-size: 2.5rem; + font-weight: bold; + margin-bottom: 10px; + text-align: left; +} + +h2 { + font-size: 1.5rem; + font-weight: bold; + margin-bottom: 10px; + text-align: left; +} + +/* μž…λ ₯μ°½ */ +.input-container { + margin-bottom: 10px; +} + +.input-container input { + width: 100%; + padding: 8px; + font-size: 1rem; + border: 2px solid #333; /* μž…λ ₯창만 ꡡ은 ν…Œλ‘λ¦¬ */ + border-radius: 0; + box-sizing: border-box; +} + +/* Add λ²„νŠΌ */ +.add-button-container { + margin-bottom: 20px; +} + + +.add-button-container button:hover { + background-color: #333; +} + +/* ν•„ν„° λ²„νŠΌ */ +.filter-buttons { + display: flex; + justify-content: center; /* 쀑앙 μ •λ ¬ */ + gap: 10px; + margin-bottom: 20px; +} + +.filter-buttons button { + flex: 1; /* λ™μΌν•œ 폭 */ + padding: 8px 12px; + font-size: 1rem; + background-color: #fff; + color: #000; + border: 1px solid #333; /* 얇은 ν…Œλ‘λ¦¬ */ + border-radius: 0; + cursor: pointer; +} + +.filter-buttons button:hover { + background-color: #f0f0f0; } -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); + +/* 남은 μž‘μ—… 수 */ +.tasks-remaining { + font-size: 1.5rem; + font-weight: bold; + margin-bottom: 10px; + text-align: left; } -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } +/* μž‘μ—… λͺ©λ‘ */ +.task-list { + margin-top: 10px; } -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } +.task-item { + margin-bottom: 20px; } -.card { - padding: 2em; +.task-row { + display: flex; + align-items: center; + margin-bottom: 5px; } -.read-the-docs { - color: #888; +.task-row input[type="checkbox"] { + width: 20px; + height: 20px; + margin-right: 10px; + border: 2px solid #333; + border-radius: 0; + appearance: none; + cursor: pointer; } + +.task-row input[type="checkbox"]:checked { + background-color: #000; + border-color: #000; + position: relative; +} + +.task-row input[type="checkbox"]:checked::after { + content: "βœ”"; + color: #fff; + font-size: 14px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.task-row .task-name { + font-size: 1rem; +} + +.task-actions { + display: flex; + gap: 10px; +} + +.task-actions button { + flex: 1; + padding: 5px 10px; + font-size: 0.9rem; + background-color: #fff; + color: #000; + border: 1px solid #333; + border-radius: 0; + cursor: pointer; +} + +.task-actions button:hover { + background-color: #f0f0f0; +} + +.task-actions .button-delete { + background-color: #ff0000; + color: #fff; + +} + +.task-actions .button-delete:hover { + background-color: #e60000; +} \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index de1492e4..1e9e2172 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,8 +1,9 @@ -import React, { useState } from "react"; -import TextComponent from "@/component/TextComponent"; -import ButtonComponent from "@/component/ButtonComponent"; -import CheckboxComponent from "@/component/CheckboxComponent"; -import InputComponent from "@/component/InputComponent"; +import Header from "@/component/Header"; +import AddTodo from "@/component/AddTodo"; +import Category from "@/component/Category"; +import TodoList from "@/component/TodoList"; + +import "./App.css"; function App() { const [tasks, setTasks] = useState([ @@ -44,48 +45,33 @@ function App() { return true; }); + const activeTaskCount = tasks.filter(task => !task.completed).length; + + + + return ( -
-

- -

-

- -

-
- setInputValue(e.target.value)} - /> - -
-
- setFilter("all")} /> - setFilter("active")} /> - setFilter("completed")} /> -
-
- -
- +
+
+ + +
); } diff --git a/src/component/AddTodo.jsx b/src/component/AddTodo.jsx new file mode 100644 index 00000000..4207b6b0 --- /dev/null +++ b/src/component/AddTodo.jsx @@ -0,0 +1,18 @@ +import InputComponent from "./InputComponent"; +import ButtonComponent from "./ButtonComponent"; + +function AddTodo({ inputValue, setInputValue, addTask }) { + return ( +
+
+ setInputValue(e.target.value)} + /> +
+ +
+ ); +} + +export default AddTodo; \ No newline at end of file diff --git a/src/component/ButtonComponent.jsx b/src/component/ButtonComponent.jsx index e972d833..701db591 100644 --- a/src/component/ButtonComponent.jsx +++ b/src/component/ButtonComponent.jsx @@ -1,7 +1,12 @@ -import React from "react"; +function ButtonComponent({ label, onClick, type }) { + + const buttonClass = type === "add" ? "add-button-container" : ""; -function ButtonComponent({ label, onClick }) { - return ; + return ( + + ); } export default ButtonComponent; \ No newline at end of file diff --git a/src/component/Category.jsx b/src/component/Category.jsx new file mode 100644 index 00000000..b0f252d7 --- /dev/null +++ b/src/component/Category.jsx @@ -0,0 +1,14 @@ + +import ButtonComponent from "./ButtonComponent"; + +function Category({ setFilter }) { + return ( +
+ setFilter("all")} /> + setFilter("active")} /> + setFilter("completed")} /> +
+ ); +} + +export default Category; \ No newline at end of file diff --git a/src/component/CheckboxComponent.jsx b/src/component/CheckboxComponent.jsx index 5473e91f..39f3c143 100644 --- a/src/component/CheckboxComponent.jsx +++ b/src/component/CheckboxComponent.jsx @@ -1,5 +1,3 @@ -import React from "react"; - function CheckboxComponent({ isChecked, onChange }) { return ; } diff --git a/src/component/Header.jsx b/src/component/Header.jsx new file mode 100644 index 00000000..03a3575a --- /dev/null +++ b/src/component/Header.jsx @@ -0,0 +1,12 @@ +import TextComponent from "./TextComponent"; + +function Header() { + return ( +
+ + +
+ ); +} + +export default Header; \ No newline at end of file diff --git a/src/component/InputComponent.jsx b/src/component/InputComponent.jsx index 7bcac583..6bfbe0dc 100644 --- a/src/component/InputComponent.jsx +++ b/src/component/InputComponent.jsx @@ -1,5 +1,3 @@ -import React from "react"; - function InputComponent({ value, onChange, placeholder }) { return ; } diff --git a/src/component/TextComponent.jsx b/src/component/TextComponent.jsx index 35eaaf68..ade087e7 100644 --- a/src/component/TextComponent.jsx +++ b/src/component/TextComponent.jsx @@ -1,7 +1,11 @@ -import React from "react"; +function TextComponent({ text, type }) { + + const style = { + fontSize: type === "title" ? "2rem" : "1.5rem", + fontWeight: type === "title" ? "bold" : "normal", + }; -function TextComponent({ text }) { - return {text}; + return {text}; } export default TextComponent; \ No newline at end of file diff --git a/src/component/TodoComponent.jsx b/src/component/TodoComponent.jsx new file mode 100644 index 00000000..f4135263 --- /dev/null +++ b/src/component/TodoComponent.jsx @@ -0,0 +1,31 @@ +// src/components/Todo.jsx +import CheckboxComponent from "./CheckboxComponent"; +import ButtonComponent from "./ButtonComponent"; + +function Todo({ task, index, toggleTask, editTask, deleteTask }) { + return ( +
+
+ toggleTask(index)} + /> + {task.name} +
+
+ editTask(index, prompt("Edit task:", task.name))} + /> + deleteTask(index)} + /> +
+
+ ); +} + +export default Todo; diff --git a/src/component/TodoList.jsx b/src/component/TodoList.jsx new file mode 100644 index 00000000..38ac15bd --- /dev/null +++ b/src/component/TodoList.jsx @@ -0,0 +1,21 @@ +function TodoList({ filteredTasks, toggleTask, editTask, deleteTask, activeTaskCount }) { + return ( +
+
+ +
+
+ {filteredTasks.map((task, index) => ( + + ))} +
+
+ ); +} diff --git a/src/index.css b/src/index.css index 08a3ac9e..e69de29b 100644 --- a/src/index.css +++ b/src/index.css @@ -1,68 +0,0 @@ -:root { - font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/vite.config.js b/vite.config.js index 24a4b461..0891f5f1 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,4 +1,4 @@ -import react from "@vitejs/plugin-react"; + import react from "@vitejs/plugin-react"; import { resolve } from "node:path"; import { defineConfig } from "vite"; @@ -12,6 +12,7 @@ export default defineConfig({ }, }, server: { + port: 3000, }, build: {