diff --git a/package-lock.json b/package-lock.json index c27bbe4e..ac756890 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,19 +7,29 @@ "": { "name": "react-messenger-19th", "version": "0.1.0", + "license": "ISC", "dependencies": { "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", "@types/node": "^16.18.91", - "@types/react": "^18.2.69", "@types/react-dom": "^18.2.22", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.47", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.26.2", "react-scripts": "5.0.1", "typescript": "^4.9.5", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "@types/react": "^18.3.9", + "file-loader": "^6.2.0", + "tailwindcss": "^3.4.13", + "webpack": "^5.95.0", + "webpack-cli": "^5.1.4" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2288,6 +2298,16 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "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", @@ -3338,6 +3358,15 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz", + "integrity": "sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==", + "license": "MIT", + "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", @@ -4059,15 +4088,6 @@ "@types/json-schema": "*" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -4210,12 +4230,12 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, "node_modules/@types/react": { - "version": "18.2.69", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.69.tgz", - "integrity": "sha512-W1HOMUWY/1Yyw0ba5TkCV+oqynRjG7BnteBB+B7JmAK7iw3l2SW+VGOxL+akPweix6jk2NNJtyJKpn4TkpfK3Q==", + "version": "18.3.9", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.9.tgz", + "integrity": "sha512-+BpAVyTpJkNWWSSnaLBk6ePpHLOGJKnEQNbINNovPWzvEUyAe3e+/d494QdEh71RekM/qV7lw6jzf1HGrJyAtQ==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, @@ -4240,11 +4260,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.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" - }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -4678,6 +4693,53 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -4737,10 +4799,11 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", "peerDependencies": { "acorn": "^8" } @@ -5145,9 +5208,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.19", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", - "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", "funding": [ { "type": "opencollective", @@ -5162,12 +5225,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001599", + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -5634,9 +5698,9 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "funding": [ { "type": "opencollective", @@ -5651,11 +5715,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -5762,9 +5827,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001600", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", - "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", + "version": "1.0.30001664", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz", + "integrity": "sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==", "funding": [ { "type": "opencollective", @@ -5778,7 +5843,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/case-sensitive-paths-webpack-plugin": { "version": "2.4.0", @@ -5904,6 +5970,21 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -7018,9 +7099,10 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.715", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.715.tgz", - "integrity": "sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==" + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz", + "integrity": "sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==", + "license": "ISC" }, "node_modules/emittery": { "version": "0.8.1", @@ -7055,9 +7137,10 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", - "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -7074,6 +7157,19 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/envinfo": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -7270,9 +7366,10 @@ } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -8140,6 +8237,16 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -8182,6 +8289,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" @@ -8304,6 +8412,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -9342,6 +9460,16 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/ipaddr.js": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", @@ -9636,6 +9764,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -9813,6 +9954,16 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -12619,9 +12770,10 @@ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -13092,9 +13244,10 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -13258,9 +13411,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "funding": [ { "type": "opencollective", @@ -13275,10 +13428,11 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -14686,9 +14840,10 @@ } }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, @@ -14835,15 +14990,16 @@ } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.1" } }, "node_modules/react-error-overlay": { @@ -14864,6 +15020,38 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.2.tgz", + "integrity": "sha512-tvN1iuT03kHgOFnLPfLJ8V95eijteveqdOSk+srqfePtQvqCExB8eHOYnlilbOcyJyKnYkr1vJvf7YqotAJu1A==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.19.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.2.tgz", + "integrity": "sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.19.2", + "react-router": "6.26.2" + }, + "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", @@ -14968,6 +15156,19 @@ "node": ">=8.10.0" } }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/recursive-readdir": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", @@ -15480,9 +15681,10 @@ } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } @@ -15719,6 +15921,19 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -15805,9 +16020,10 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "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==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -16491,9 +16707,10 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "node_modules/tailwindcss": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", - "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.13.tgz", + "integrity": "sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==", + "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -16503,7 +16720,7 @@ "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.19.1", + "jiti": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -17044,9 +17261,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "funding": [ { "type": "opencollective", @@ -17061,9 +17278,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -17217,20 +17435,20 @@ } }, "node_modules/webpack": { - "version": "5.91.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", - "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", + "version": "5.95.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz", + "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==", + "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", + "acorn-import-attributes": "^1.9.5", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.16.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -17262,6 +17480,62 @@ } } }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/webpack-dev-middleware": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", @@ -17495,6 +17769,21 @@ "node": ">=10.13.0" } }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", @@ -17675,6 +17964,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index ea335d36..d4fa6cb6 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,12 @@ "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", "@types/node": "^16.18.91", - "@types/react": "^18.2.69", "@types/react-dom": "^18.2.22", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.47", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.26.2", "react-scripts": "5.0.1", "typescript": "^4.9.5", "web-vitals": "^2.1.4" @@ -39,5 +41,17 @@ "last 1 firefox version", "last 1 safari version" ] - } + }, + "devDependencies": { + "@types/react": "^18.3.9", + "file-loader": "^6.2.0", + "tailwindcss": "^3.4.13", + "webpack": "^5.95.0", + "webpack-cli": "^5.1.4" + }, + "description": "안녕하세요 🙌🏻 20기 프론트 운영진 김동혁입니다. 이번 미션에서는 드디어 투두리스트에서 벗어나 새로운 프로젝트인 **messenger** 만들기를 진행합니다.", + "main": "tailwind.config.js", + "keywords": [], + "author": "", + "license": "ISC" } diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index a11777cc..00000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/htmlStyle.css b/public/htmlStyle.css new file mode 100644 index 00000000..06ece866 --- /dev/null +++ b/public/htmlStyle.css @@ -0,0 +1,23 @@ +html, +body { + height: 100%; + width: 100%; + margin: 0; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + font-family: 'AppleSDGothicNeo', sans-serif; +} + +#root { + width: 100%; + max-width: 375px; + height: 100%; + max-height: 812px; + border-radius: 20px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + display: flex; + flex-direction: column; + overflow: hidden; +} \ No newline at end of file diff --git a/public/index.html b/public/index.html index aa069f27..999564d1 100644 --- a/public/index.html +++ b/public/index.html @@ -1,43 +1,19 @@ - - - - - - - - - - - React App - - - -
- - - + \ No newline at end of file diff --git a/public/logo192.png b/public/logo192.png deleted file mode 100644 index fc44b0a3..00000000 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 a4e47a65..00000000 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 080d6c77..00000000 --- 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 e9e57dc4..00000000 --- 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 74b5e053..00000000 --- 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.tsx b/src/App.tsx index 5381007b..4c707e02 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,8 +1,19 @@ +import React from 'react'; +import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; +import ChatRoom from '../src/pages/chatRoom'; +import ChatListRoom from './pages/chatListRoom'; +import FriendListRoom from './pages/friendListRoom'; + function App() { return ( -
-

20기 프론트엔드 파이팅!!! 디자인과 사이좋게 지내요~~~

-
+ + + {/* 기본 경로: FriendListRoom => 친구 목록 */} + } /> + } /> + } /> + + ); } diff --git a/src/assets/addFriendIcon.svg b/src/assets/addFriendIcon.svg new file mode 100644 index 00000000..a2b02eab --- /dev/null +++ b/src/assets/addFriendIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/angryImoIcon.svg b/src/assets/angryImoIcon.svg new file mode 100644 index 00000000..3b692db2 --- /dev/null +++ b/src/assets/angryImoIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/backArrowImg.svg b/src/assets/backArrowImg.svg new file mode 100644 index 00000000..383ab793 --- /dev/null +++ b/src/assets/backArrowImg.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/badImoIcon.svg b/src/assets/badImoIcon.svg new file mode 100644 index 00000000..e69de29b diff --git a/src/assets/battery.svg b/src/assets/battery.svg new file mode 100644 index 00000000..01beff5d --- /dev/null +++ b/src/assets/battery.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/assets/chatIcon.svg b/src/assets/chatIcon.svg new file mode 100644 index 00000000..94863493 --- /dev/null +++ b/src/assets/chatIcon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/chatIcon_on.svg b/src/assets/chatIcon_on.svg new file mode 100644 index 00000000..fc2897e5 --- /dev/null +++ b/src/assets/chatIcon_on.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/chatMoreIcon.svg b/src/assets/chatMoreIcon.svg new file mode 100644 index 00000000..81233267 --- /dev/null +++ b/src/assets/chatMoreIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/defaultProfileImg.svg b/src/assets/defaultProfileImg.svg new file mode 100644 index 00000000..5d953bce --- /dev/null +++ b/src/assets/defaultProfileImg.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/etcIcon.svg b/src/assets/etcIcon.svg new file mode 100644 index 00000000..9e977292 --- /dev/null +++ b/src/assets/etcIcon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/friendIcon.svg b/src/assets/friendIcon.svg new file mode 100644 index 00000000..56d37a0e --- /dev/null +++ b/src/assets/friendIcon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/friendIcon_on.svg b/src/assets/friendIcon_on.svg new file mode 100644 index 00000000..aed4633e --- /dev/null +++ b/src/assets/friendIcon_on.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/giftIcon.svg b/src/assets/giftIcon.svg new file mode 100644 index 00000000..4adbc6cc --- /dev/null +++ b/src/assets/giftIcon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/glassesIcon.svg b/src/assets/glassesIcon.svg new file mode 100644 index 00000000..7153750d --- /dev/null +++ b/src/assets/glassesIcon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/goodImoIcon.svg b/src/assets/goodImoIcon.svg new file mode 100644 index 00000000..fd191122 --- /dev/null +++ b/src/assets/goodImoIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/happyImoIcon.svg b/src/assets/happyImoIcon.svg new file mode 100644 index 00000000..4cd2a859 --- /dev/null +++ b/src/assets/happyImoIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/heartImoIcon.svg b/src/assets/heartImoIcon.svg new file mode 100644 index 00000000..695dfbff --- /dev/null +++ b/src/assets/heartImoIcon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/morePointImg.svg b/src/assets/morePointImg.svg new file mode 100644 index 00000000..0e50923c --- /dev/null +++ b/src/assets/morePointImg.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/myProfileImg.svg b/src/assets/myProfileImg.svg new file mode 100644 index 00000000..c98be5c7 --- /dev/null +++ b/src/assets/myProfileImg.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/networkImg.svg b/src/assets/networkImg.svg new file mode 100644 index 00000000..ddea4e75 --- /dev/null +++ b/src/assets/networkImg.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/openChatIcon.svg b/src/assets/openChatIcon.svg new file mode 100644 index 00000000..242d0c2a --- /dev/null +++ b/src/assets/openChatIcon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/plusButtonImg.svg b/src/assets/plusButtonImg.svg new file mode 100644 index 00000000..5a3cd268 --- /dev/null +++ b/src/assets/plusButtonImg.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/searchIcon.svg b/src/assets/searchIcon.svg new file mode 100644 index 00000000..7153750d --- /dev/null +++ b/src/assets/searchIcon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/settingIcon.svg b/src/assets/settingIcon.svg new file mode 100644 index 00000000..6805ab58 --- /dev/null +++ b/src/assets/settingIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/shopIcon.svg b/src/assets/shopIcon.svg new file mode 100644 index 00000000..54a9db8d --- /dev/null +++ b/src/assets/shopIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/smileIcon.svg b/src/assets/smileIcon.svg new file mode 100644 index 00000000..24c707db --- /dev/null +++ b/src/assets/smileIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/wifiImg.svg b/src/assets/wifiImg.svg new file mode 100644 index 00000000..e6c4572a --- /dev/null +++ b/src/assets/wifiImg.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/bottomViewList.tsx b/src/components/bottomViewList.tsx new file mode 100644 index 00000000..66dd3ab8 --- /dev/null +++ b/src/components/bottomViewList.tsx @@ -0,0 +1,41 @@ +import React, { useState } from 'react'; +import { Link, useLocation } from 'react-router-dom'; + +const BottomViewList: React.FC = () => { + const location = useLocation(); + const [selectedIcon, setSelectedIcon] = useState(location.pathname); + // useLocation으로 초기 경로 가져와 현재 선택된 아이콘 저장 + + const handleTabClick = (icon: string) => { + setSelectedIcon(icon); + }; + + return ( +
+ handleTabClick('/')}> + Friend + + handleTabClick('/chatListRoom')}> + ChatRoom + + OpenChat + Etc +
+ ); +}; + +export default BottomViewList; diff --git a/src/components/chatHeader.tsx b/src/components/chatHeader.tsx new file mode 100644 index 00000000..bdb605c0 --- /dev/null +++ b/src/components/chatHeader.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; + +const ChatHeader: React.FC = () => { + const navigate = useNavigate(); + + const handleBackClick = () => { + navigate('/chatListRoom'); // chatListRoom 경로로 이동 + }; + + return ( +
+ {/* 왼쪽 뒤로가기 버튼 */} +
+ backArrowImg +
+ + {/* 중앙 이름 */} +
+ 김나나 +
+ + {/* 오른쪽 더보기 버튼 */} +
+ morePointImg +
+
+ ); +}; + +export default ChatHeader; diff --git a/src/components/chatRoomList.tsx b/src/components/chatRoomList.tsx new file mode 100644 index 00000000..5536be2e --- /dev/null +++ b/src/components/chatRoomList.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import messagesData from '../data/chatData.json'; +import userData from '../data/userData.json'; + +interface ChatRoomProps { + userId: number; +} + +const ChatRoomList: React.FC = ({ userId }) => { + const navigate = useNavigate(); + + // 해당 userId에 맞는 채팅방 데이터를 찾기 + const chatRoom = messagesData.messages.filter(message => message.senderId === userId); + + // 가장 최근 메시지 가져오기 + const latestMessage = chatRoom[chatRoom.length - 1]; // 가장 최근 메시지 + + // userId에 맞는 사용자 이름 찾기 + const user = userData.find(user => user.id === userId); + const userName = user ? user.name : `사용자 ${userId}`; // 사용자 이름이 없으면 기본 이름 사용 + + // 클릭 시 해당 사용자의 ChatRoom으로 라우팅 + const handleClick = () => { + navigate(`/chatRoom/${userId}`); + }; + + return ( +
+ {/* 프로필 이미지 */} + profile + + {/* 이름과 메시지 */} +
+
{userName}
+
{latestMessage ? latestMessage.message : "메시지가 없습니다."}
+
+ + {/* 날짜 */} +
+ {latestMessage ? latestMessage.timestamp.split(' ')[0] : "날짜 없음"} +
+
+ ); +}; + +export default ChatRoomList; diff --git a/src/components/dateDivider.tsx b/src/components/dateDivider.tsx new file mode 100644 index 00000000..6a8ebd8c --- /dev/null +++ b/src/components/dateDivider.tsx @@ -0,0 +1,34 @@ +// DateDivider 컴포넌트에 전달되는 props 타입 정의 +type DateDividerProps = { + date: string; // date prop을 문자열로 받을 수 있도록 설정 +}; + +// 요일을 구하는 함수 +const getDayOfWeek = (dateString: string): string => { + const daysOfWeek = ['일', '월', '화', '수', '목', '금', '토']; + const date = new Date(dateString); // dateString을 Date 객체로 변환 + const dayOfWeek = date.getDay(); // 요일을 숫자로 가져옴 (0: 일요일, 1: 월요일, ... 6: 토요일) + return daysOfWeek[dayOfWeek]; // 숫자에 해당하는 요일 반환 +}; + +// DateDivider 컴포넌트: 날짜 구분자를 표시 +const DateDivider: React.FC = ({ date }) => { + const dayOfWeek = getDayOfWeek(date); // 요일 계산 + + return ( +
+ {/* 왼쪽 선 */} +
+ + {/* 날짜와 요일 텍스트 */} + + {date} {dayOfWeek}요일 + + + {/* 오른쪽 선 */} +
+
+ ); +}; + +export default DateDivider; diff --git a/src/components/myMessageBox.tsx b/src/components/myMessageBox.tsx new file mode 100644 index 00000000..3b3e272e --- /dev/null +++ b/src/components/myMessageBox.tsx @@ -0,0 +1,22 @@ +// MyMessageBox 컴포넌트에 전달되는 props 타입 정의 +type MyMessageBoxProps = { + message: string; + timestamp: string; +}; + +// MyMessageBox 컴포넌트: 사용자가 보낸 메시지 표시 +const MyMessageBox: React.FC = ({ message, timestamp }) => { + return ( +
+ {/* 타임스탬프 */} + {timestamp} + + {/* 메시지 박스 */} +
+

{message}

+
+
+ ); +}; + +export default MyMessageBox; diff --git a/src/components/navBar.tsx b/src/components/navBar.tsx new file mode 100644 index 00000000..837d49f8 --- /dev/null +++ b/src/components/navBar.tsx @@ -0,0 +1,46 @@ +import React, { useState, useEffect } from 'react'; + +const NavBar: React.FC = () => { + const [time, setTime] = useState(""); + + // 시간 업데이트 함수 + const updateTime = () => { + const currentTime = new Date(); + let hours = currentTime.getHours(); // H + const minutes = currentTime.getMinutes().toString().padStart(2, '0'); // 분 + + // 12시간 형식으로 변환 + hours = hours % 12; + hours = hours ? hours : 12; // 0시를 12시로 변환 + + const newTime = `${hours.toString().padStart(2, '0')}:${minutes}`; + setTime(newTime); // 시간 초기화 + }; + + // 1분마다 시간 업데이트 + useEffect(() => { + updateTime(); // 첫 랜더링시 호출 + const intervalId = setInterval(updateTime, 60000); // 1분마다 업데이트 + + return () => clearInterval(intervalId); + // 컴포넌트가 언마운트될 때 인터벌 제거.. 사실 자세히 모르겠음 다시 공부해보자 + }, []); + + return ( +
+ {/* 시간 표시 */} +
+ {time} +
+ + {/* 우측 아이콘 표시 */} +
+ Network + WiFi + Battery +
+
+ ); +}; + +export default NavBar; diff --git a/src/components/otherMessageBox.tsx b/src/components/otherMessageBox.tsx new file mode 100644 index 00000000..3a95a10f --- /dev/null +++ b/src/components/otherMessageBox.tsx @@ -0,0 +1,27 @@ +// OtherMessageBox 컴포넌트에 전달되는 props 타입 정의 +type OtherMessageBoxProps = { + message: string; + timestamp: string; +}; + +// OtherMessageBox 컴포넌트: 상대방이 보낸 메시지 표시 +const OtherMessageBox: React.FC = ({ message, timestamp }) => { + return ( +
+ + {/* 메시지 박스 */} +
+

+ {message} +

+
+ + {/* 시간 표시 */} + + {timestamp} + +
+ ); +}; + +export default OtherMessageBox; diff --git a/src/components/plusButton.tsx b/src/components/plusButton.tsx new file mode 100644 index 00000000..14189f23 --- /dev/null +++ b/src/components/plusButton.tsx @@ -0,0 +1,9 @@ +const PlusButton: React.FC = () => { + return ( + + ); +}; + +export default PlusButton; \ No newline at end of file diff --git a/src/components/profileButton.tsx b/src/components/profileButton.tsx new file mode 100644 index 00000000..9b57fdce --- /dev/null +++ b/src/components/profileButton.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +interface ProfileButtonProps { + toggleUserId: () => void; +} + +const ProfileButton: React.FC = ({ toggleUserId }) => { + return ( + + ); +}; + +export default ProfileButton; diff --git a/src/data/chatData.json b/src/data/chatData.json new file mode 100644 index 00000000..a0ecf5bf --- /dev/null +++ b/src/data/chatData.json @@ -0,0 +1,28 @@ +{ + "messages": [ + { + "messageId": 1, + "senderId": 1, + "message": "나나야 우리 낼 모임 누구누구 온댔지?", + "timestamp": "2024.09.11 오후 9:47" + }, + { + "messageId": 2, + "senderId": 2, + "message": "나랑 너랑 미미랑 오랜지랑 루비님이랑 로로님이랑 디디랑 음 그리고 또 누구였더라", + "timestamp": "2024.09.11 오후 9:47" + }, + { + "messageId": 3, + "senderId": 2, + "message": "선우야 나 드디어 생일이다~", + "timestamp": "2024.09.12 오후 9:47" + }, + { + "messageId": 4, + "senderId": 1, + "message": "생일 축하해 ㅎㅎ", + "timestamp": "2024.09.12 오후 9:48" + } + ] +} diff --git a/src/data/userData.json b/src/data/userData.json new file mode 100644 index 00000000..58701087 --- /dev/null +++ b/src/data/userData.json @@ -0,0 +1,37 @@ +[ + { + "id": 1, + "name": "선우", + "birthday": "1990-11-01" + }, + { + "id": 2, + "name": "문현준", + "birthday": "1990-11-02" + }, + { + "id": 3, + "name": "이상혁", + "birthday": "1991-11-02" + }, + { + "id": 4, + "name": "최우제", + "birthday": "1990-11-03" + }, + { + "id": 5, + "name": "이민형", + "birthday": "1990-11-03" + }, + { + "id": 6, + "name": "류민석", + "birthday": "1990-11-04" + }, + { + "id": 7, + "name": "김나나", + "birthday": "1990-11-04" + } +] diff --git a/src/index.css b/src/index.css deleted file mode 100644 index ec2585e8..00000000 --- a/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/src/index.tsx b/src/index.tsx index d10be77d..3b193169 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,6 +1,5 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; -import './index.css'; import App from './App'; const root = ReactDOM.createRoot( diff --git a/src/pages/chatListRoom.tsx b/src/pages/chatListRoom.tsx new file mode 100644 index 00000000..3659828d --- /dev/null +++ b/src/pages/chatListRoom.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import NavBar from '../components/navBar'; +import BottomViewList from '../components/bottomViewList'; +import ChatRoomList from '../components/chatRoomList'; + +const ChatListRoom: React.FC = () => { + const userIds = [1]; // 목록에 랜더링할 사용자 ID + + return ( +
+ + +
+
+ 채팅 +
+
+ search + moreChat + setting +
+
+ +
+ {userIds.map(userId => ( + + ))} +
+ + +
+ ); +}; + +export default ChatListRoom; diff --git a/src/pages/chatRoom.tsx b/src/pages/chatRoom.tsx new file mode 100644 index 00000000..c0784b47 --- /dev/null +++ b/src/pages/chatRoom.tsx @@ -0,0 +1,169 @@ +import React, { useState, useEffect, useRef } from 'react'; +import NavBar from '../components/navBar'; +import DateDivider from '../components/dateDivider'; +import MyMessageBox from '../components/myMessageBox'; +import OtherMessageBox from '../components/otherMessageBox'; +import PlusButton from '../components/plusButton'; +import ChatHeader from '../components/chatHeader'; +import messagesData from '../data/chatData.json'; +import ProfileButton from '../components/profileButton'; + +// Message 타입 정의 : 타입 스크립트 쓰니까 편하네요!!! +type Message = { + messageId: number; + // 메세지 아이디를 따로 저장해두면 좋을 것 같아서 일단 넣어줬습니다! 습관 비스무리한.. + senderId: number; + // 사용자 전환 시 메세지 디자인도 변경도 변경됩니다. 이를 위해 senderId를 넣어줬습니다! + message: string; + // 메세지 내용은 string으로 저장했습니다! + timestamp: string; + // 일단 시간을 데이터로 저장하기 위해 string으로 저장했습니다! +}; + +const ChatRoom: React.FC = () => { + // 현재 사용자 ID 상태 (기본값: 1) + const [userId, setUserId] = useState(1); + + // 메시지 데이터 상태 (초기값: 빈 배열) + const [messages, setMessages] = useState([]); + + // 컴포넌트 첫 랜더링시 JSON 데이터를 상태에 설정함 + useEffect(() => { + const storedMessages = localStorage.getItem('ChatData'); + if (storedMessages) { + setMessages(JSON.parse(storedMessages)); + } else { + setMessages(messagesData.messages); // JSON에서 초기 데이터 설정 + } + }, []); + + // 버튼 클릭 시 사용자 ID 변경 + const toggleUserId = () => { + setUserId(userId === 1 ? 2 : 1); + }; + + // 입력된 메시지 상태 (메시지 입력값 저장) + const [inputMessage, setInputMessage] = useState(""); + + // 메시지 입력 시 마다 호출됨 (input 값 변화 추적) + const handleInputChange = (e: React.ChangeEvent) => { + setInputMessage(e.target.value); + // 인풋의 value를 그대로 추적해서 inputMessage 상태에 담습니다! + }; + + // 스크롤을 적용을 위한 useRef. DOM 조작에는 Ref가 제일 효율적이라고 하네요! + const messageScrollRef = useRef(null); + + // 메시지 전송 시 스크롤 하단 이동 + const scrollToBottom = () => { + messageScrollRef.current?.scrollIntoView({ behavior: "smooth" }); + }; + + // 메시지 추가 시 (전송 시) 스크롤 하단 이동 함수 실행 + useEffect(() => { + scrollToBottom(); + }, [messages]); + + // 로컬 스토리지에 메세지 업로드 + const updateLocalStorage = (newMessages: Message[]) => { + localStorage.setItem('ChatData', JSON.stringify(newMessages)); + }; + + // Enter 키 입력 시 메시지를 상태에 추가함 (사실 전송의 기능을 수행합니다!) + const sendMessage = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' && inputMessage.trim()) { + // 현재 시간을 타임스탬프로 저장 + const now = new Date(); + const newTimestamp = `${formatDate(now)}`; // 날짜와 시간 저장 + + // 입력된 메세지 기반으로 새 메세지를 생성합니다! + const newMessage: Message = { + messageId: messages.length + 1, // 메시지 ID는 기존 메시지 수에 +1 + senderId: userId, // 현재 사용자 ID를 저장함 + message: inputMessage, // 입력된 메시지 내용 저장 + timestamp: newTimestamp, // 현재 시간 + }; + + // 기존 메시지에 새 메시지 추가 + const updatedMessages = [...messages, newMessage]; + setMessages(updatedMessages); + + // 메세지 업로드 -> 잘 동작을 안함.. 해결하기ㅠㅠ + updateLocalStorage(updatedMessages); + + // 입력창 초기화.. 까먹을뻔 + setInputMessage(""); + } + }; + + // 이전 메시지의 날짜를 추적할 변수 (컴포넌트 외부에서 관리) + let previousDate = ""; + + // 날짜를 yyyy.MM.dd 형식으로 변환하는 함수 + const formatDate = (date: Date) => { + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); // 2자리 월 + const day = date.getDate().toString().padStart(2, '0'); // 2자리 일 + return `${year}.${month}.${day}`; + }; + + return ( +
+ + + + {/* 채팅 메세지 메인 Body */ } +
+ {/* 메시지 리스트 순회하면서 각각 렌더링 */} + {messages.map((message) => { + const currentDate = message.timestamp.split(' ')[0]; // 날짜 부분만 추출 + const showDateDivider = currentDate !== previousDate; // 날짜가 다르면 DateDivider 렌더링 + previousDate = currentDate; // 이전 날짜 업데이트 + + return ( +
+ {/* 날짜 구분자 (현재 날짜와 이전 메시지 날짜가 다를 때만 렌더링) */} + {showDateDivider && } + + {/* senderId와 userId 동일 여부에 따라 메시지 박스를 렌더링 */} + {message.senderId === userId ? ( + + ) : ( +
{/* 좌측에 프로필, 우측에 메시지 박스 배치 */} + {/* 상대방 메시지일 때 좌측에 프로필 렌더링 */} + + + {/* 메시지 박스 */} + +
+ )} +
+ ); + + })} + {/* 스크롤 하단 이동을 위한 빈 태그 '타겟 요소'. */} +
+
+ + {/* 하단 입력 영역, 그림자가 안나타남 */} +
+ + {/* 좌측의 추가 버튼 */} + + + {/* 메시지 입력 영역 (Enter 키 입력 시 메시지 등록) */} + +
+
+ ); +}; + +export default ChatRoom; diff --git a/src/pages/friendListRoom.tsx b/src/pages/friendListRoom.tsx new file mode 100644 index 00000000..74a8fd98 --- /dev/null +++ b/src/pages/friendListRoom.tsx @@ -0,0 +1,97 @@ +import React, { useEffect, useState } from 'react'; +import NavBar from '../components/navBar'; +import BottomViewList from '../components/bottomViewList'; +import userData from '../data/userData.json'; // 사용자 데이터 JSON 파일 + +const FriendListRoom: React.FC = () => { + // 사용자 ID 상태 (기본값: 1) + const [userId] = useState(1); + + // 사용자 프로필 상태 + const [userProfile, setUserProfile] = useState<{ id: number, name: string } | null>(null); + + // 생일인 친구 목록 상태 + const [birthdayFriends, setBirthdayFriends] = useState<{ id: number, name: string }[]>([]); + + // 친구 목록 상태 + const [friends, setFriends] = useState<{ id: number, name: string }[]>([]); + + // 컴포넌트가 처음 렌더링될 때 사용자 데이터를 불러오는 useEffect + useEffect(() => { + // 사용자 데이터에서 현재 사용자 ID에 해당하는 프로필 찾기 + const profile = userData.find(user => user.id === userId); + if (profile) { + setUserProfile(profile); // 프로필 상태 업데이트 + } + + // 오늘 날짜 가져오기 + const today = new Date(); + const todayString = `${today.getMonth() + 1}-${today.getDate()}`; // MM-DD 형식으로 변환 + + // 생일인 친구 목록과 친구 목록 설정 + const birthdayFriendsList = userData.filter(friend => { + const friendBirthday = new Date(friend.birthday); + const friendBirthdayString = `${friendBirthday.getMonth() + 1}-${friendBirthday.getDate()}`; + return friendBirthdayString === todayString; // 생일이 오늘인 친구 필터링 + }); + + const friendsList = userData.filter(friend => friend.id !== userId); // 현재 사용자를 제외한 친구 목록 + + setBirthdayFriends(birthdayFriendsList); // 생일인 친구 목록 상태 업데이트 + setFriends(friendsList); // 친구 목록 상태 업데이트 + }, [userId]); // userId가 변경될 때마다 다시 실행 + + return ( +
+ +
+
+

친구

+
+ Search + Add Friend + Settings +
+
+ + {/* 본인 프로필 */} + {userProfile && ( // 사용자 프로필이 있을 경우에만 렌더링 +
+ My Profile + {userProfile.name} +
+ )} + + {/* 생일인 친구 */} + {birthdayFriends.length > 0 && ( // 생일인 친구가 있을 경우에만 렌더링 +
+
생일인 친구
+ {birthdayFriends.map(friend => ( +
+
+ Friend +

{friend.name}

+
+ Gift +
+ ))} +
+ )} + + {/* 친구 목록 */} +
+
친구 {friends.length}
+ {friends.map(friend => ( +
+ Friend +

{friend.name}

+
+ ))} +
+
+ +
+ ); +}; + +export default FriendListRoom; diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 00000000..d8e66d95 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,26 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + mode: 'jit', + content: [ + './src/**/*.{js,jsx,ts,tsx}', + './public/index.html', + ], + theme: { + extend: { + fontFamily: { + appleSD: ['AppleSDGothicNeo', 'sans-serif'], + }, + colors: { + mainYellow: 'rgba(239, 213, 70, 1)', + paleYellow: 'rgba(255, 252, 223, 1)', + grey50: 'rgba(249, 250, 251, 1)', + grey100: 'rgba(242, 244, 246, 1)', + grey200: 'rgba(229, 232, 235, 1)', + grey400: 'rgba(176, 184, 193, 1)', + grey800: 'rgba(51, 61, 75, 1)', + mainFont: 'rgba(51, 61, 75, 1)', + } + }, + }, + plugins: [], +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..87dcb34e --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,10 @@ +module.exports = { + module: { + rules: [ + { + test: /\.svg$/, + use: 'file-loader', + }, + ], + }, +};