diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..af46c32 --- /dev/null +++ b/.babelrc @@ -0,0 +1,19 @@ +{ + "presets": ["@babel/preset-env", "@babel/preset-react"], + "plugins": [ + [ + "@babel/plugin-transform-runtime", + { + "regenerator": true + } + ], + [ + "babel-plugin-styled-components", + { + "ssr": true, + "displayName": true, + "pure": true + } + ] + ] +} diff --git a/.gitignore b/.gitignore index 5638686..1c42bc2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ # misc .DS_Store +.env .env.local .env.development.local .env.test.local @@ -41,4 +42,7 @@ psd thumb sketch +### next.js ### +.next + # End of https://www.toptal.com/developers/gitignore/api/react \ No newline at end of file diff --git a/README.md b/README.md index e45b7c5..5779c79 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # 프로젝트 이름 및 소개 -![fd web 로고](./src/assets/images/FD_Web.png)

+![fd web 로고](./public/assets/images/FD_Web.png)

FD Web : FRIDAY의 대표 홈페이지 제작 (링크: https://www.fridayproject.co.kr/)

## ⏰ 개발 기간 diff --git a/package-lock.json b/package-lock.json index 24a9280..d74e88d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1034,22 +1034,110 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.6.tgz", - "integrity": "sha512-8uRHk9ZmRSnWqUgyae249EJZ94b0yAGLBIqzZzl+0iEdbno55Pmlt/32JZsHwXD9k/uZj18Aqqk35wBX4CBTXA==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.0.tgz", + "integrity": "sha512-ReY6pxwSzEU0b3r2/T/VhqMKg/AkceBT19X0UptA3/tYi5Pe2eXgEUH+NNMC5nok6c6XQz5tyVTUpuezRfSMSg==", "requires": { "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "babel-plugin-polyfill-corejs2": "^0.3.1", - "babel-plugin-polyfill-corejs3": "^0.5.2", - "babel-plugin-polyfill-regenerator": "^0.3.1", + "@babel/helper-plugin-utils": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", "semver": "^6.3.0" }, "dependencies": { + "@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==" + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + } + }, + "browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "requires": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + } + }, + "caniuse-lite": { + "version": "1.0.30001462", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001462.tgz", + "integrity": "sha512-PDd20WuOBPiasZ7KbFnmQRyuLE7cFXW2PVd7dmALzbkUXEP46upAuCDm9eY9vho8fgNMGmbAX92QBZHzcnWIqw==" + }, + "core-js-compat": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.29.0.tgz", + "integrity": "sha512-ScMn3uZNAFhK2DGoEfErguoiAHhV2Ju+oJo/jK08p7B3f3UhocUrCCkTvnZaiS+edl5nlIoiBXKcwMc6elv4KQ==", + "requires": { + "browserslist": "^4.21.5" + } + }, + "electron-to-chromium": { + "version": "1.4.322", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.322.tgz", + "integrity": "sha512-KovjizNC9XB7dno/2GjxX8VS0SlfPpCjtyoKft+bCO+UfD8bFy16hY4Sh9s0h9BDxbRH2U0zX5VBjpM1LTcNlg==" + }, + "node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } } } }, @@ -2125,6 +2213,89 @@ } } }, + "@next/env": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.2.3.tgz", + "integrity": "sha512-FN50r/E+b8wuqyRjmGaqvqNDuWBWYWQiigfZ50KnSFH0f+AMQQyaZl+Zm2+CIpKk0fL9QxhLxOpTVA3xFHgFow==" + }, + "@next/swc-android-arm-eabi": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.2.3.tgz", + "integrity": "sha512-mykdVaAXX/gm+eFO2kPeVjnOCKwanJ9mV2U0lsUGLrEdMUifPUjiXKc6qFAIs08PvmTMOLMNnUxqhGsJlWGKSw==", + "optional": true + }, + "@next/swc-android-arm64": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.2.3.tgz", + "integrity": "sha512-8XwHPpA12gdIFtope+n9xCtJZM3U4gH4vVTpUwJ2w1kfxFmCpwQ4xmeGSkR67uOg80yRMuF0h9V1ueo05sws5w==", + "optional": true + }, + "@next/swc-darwin-arm64": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.2.3.tgz", + "integrity": "sha512-TXOubiFdLpMfMtaRu1K5d1I9ipKbW5iS2BNbu8zJhoqrhk3Kp7aRKTxqFfWrbliAHhWVE/3fQZUYZOWSXVQi1w==", + "optional": true + }, + "@next/swc-darwin-x64": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.2.3.tgz", + "integrity": "sha512-GZctkN6bJbpjlFiS5pylgB2pifHvgkqLAPumJzxnxkf7kqNm6rOGuNjsROvOWVWXmKhrzQkREO/WPS2aWsr/yw==", + "optional": true + }, + "@next/swc-freebsd-x64": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.2.3.tgz", + "integrity": "sha512-rK6GpmMt/mU6MPuav0/M7hJ/3t8HbKPCELw/Uqhi4732xoq2hJ2zbo2FkYs56y6w0KiXrIp4IOwNB9K8L/q62g==", + "optional": true + }, + "@next/swc-linux-arm-gnueabihf": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.2.3.tgz", + "integrity": "sha512-yeiCp/Odt1UJ4KUE89XkeaaboIDiVFqKP4esvoLKGJ0fcqJXMofj4ad3tuQxAMs3F+qqrz9MclqhAHkex1aPZA==", + "optional": true + }, + "@next/swc-linux-arm64-gnu": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.2.3.tgz", + "integrity": "sha512-/miIopDOUsuNlvjBjTipvoyjjaxgkOuvlz+cIbbPcm1eFvzX2ltSfgMgty15GuOiR8Hub4FeTSiq3g2dmCkzGA==", + "optional": true + }, + "@next/swc-linux-arm64-musl": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.2.3.tgz", + "integrity": "sha512-sujxFDhMMDjqhruup8LLGV/y+nCPi6nm5DlFoThMJFvaaKr/imhkXuk8uCTq4YJDbtRxnjydFv2y8laBSJVC2g==", + "optional": true + }, + "@next/swc-linux-x64-gnu": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.2.3.tgz", + "integrity": "sha512-w5MyxPknVvC9LVnMenAYMXMx4KxPwXuJRMQFvY71uXg68n7cvcas85U5zkdrbmuZ+JvsO5SIG8k36/6X3nUhmQ==", + "optional": true + }, + "@next/swc-linux-x64-musl": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.2.3.tgz", + "integrity": "sha512-CTeelh8OzSOVqpzMFMFnVRJIFAFQoTsI9RmVJWW/92S4xfECGcOzgsX37CZ8K982WHRzKU7exeh7vYdG/Eh4CA==", + "optional": true + }, + "@next/swc-win32-arm64-msvc": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.2.3.tgz", + "integrity": "sha512-7N1KBQP5mo4xf52cFCHgMjzbc9jizIlkTepe9tMa2WFvEIlKDfdt38QYcr9mbtny17yuaIw02FXOVEytGzqdOQ==", + "optional": true + }, + "@next/swc-win32-ia32-msvc": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.2.3.tgz", + "integrity": "sha512-LzWD5pTSipUXTEMRjtxES/NBYktuZdo7xExJqGDMnZU8WOI+v9mQzsmQgZS/q02eIv78JOCSemqVVKZBGCgUvA==", + "optional": true + }, + "@next/swc-win32-x64-msvc": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.2.3.tgz", + "integrity": "sha512-aLG2MaFs4y7IwaMTosz2r4mVbqRyCnMoFqOcmfTi7/mAS+G4IMH0vJp4oLdbshqiVoiVuKrAfqtXj55/m7Qu1Q==", + "optional": true + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2370,6 +2541,14 @@ "loader-utils": "^2.0.0" } }, + "@swc/helpers": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", + "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "requires": { + "tslib": "^2.4.0" + } + }, "@testing-library/dom": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.16.0.tgz", @@ -3345,6 +3524,28 @@ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.2.tgz", "integrity": "sha512-LVAaGp/wkkgYJcjmHsoKx4juT1aQvJyPcW09MLCjVTh3V2cc6PnyempiLMNH5iMdfIX/zdbjUx2KDjMLCTdPeA==" }, + "axios": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz", + "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + }, + "dependencies": { + "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==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, "axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -3848,6 +4049,11 @@ "source-map": "~0.6.0" } }, + "client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -6035,14 +6241,6 @@ "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==" }, - "history": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", - "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", - "requires": { - "@babel/runtime": "^7.7.6" - } - }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -7876,6 +8074,47 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "next": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/next/-/next-13.2.3.tgz", + "integrity": "sha512-nKFJC6upCPN7DWRx4+0S/1PIOT7vNlCT157w9AzbXEgKy6zkiPKEt5YyRUsRZkmpEqBVrGgOqNfwecTociyg+w==", + "requires": { + "@next/env": "13.2.3", + "@next/swc-android-arm-eabi": "13.2.3", + "@next/swc-android-arm64": "13.2.3", + "@next/swc-darwin-arm64": "13.2.3", + "@next/swc-darwin-x64": "13.2.3", + "@next/swc-freebsd-x64": "13.2.3", + "@next/swc-linux-arm-gnueabihf": "13.2.3", + "@next/swc-linux-arm64-gnu": "13.2.3", + "@next/swc-linux-arm64-musl": "13.2.3", + "@next/swc-linux-x64-gnu": "13.2.3", + "@next/swc-linux-x64-musl": "13.2.3", + "@next/swc-win32-arm64-msvc": "13.2.3", + "@next/swc-win32-ia32-msvc": "13.2.3", + "@next/swc-win32-x64-msvc": "13.2.3", + "@swc/helpers": "0.4.14", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.1.1" + }, + "dependencies": { + "caniuse-lite": { + "version": "1.0.30001462", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001462.tgz", + "integrity": "sha512-PDd20WuOBPiasZ7KbFnmQRyuLE7cFXW2PVd7dmALzbkUXEP46upAuCDm9eY9vho8fgNMGmbAX92QBZHzcnWIqw==" + } + } + }, + "next-images": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/next-images/-/next-images-1.8.4.tgz", + "integrity": "sha512-E6JV+aMxeUCh8A+cwn1xgmlh/zINSW4JC/XLNbM+PWQd5LBdfB+m1IDCAfNnGOKMo96kzw+4LsKxnX/Kldw78Q==", + "requires": { + "file-loader": "^6.2.0", + "url-loader": "^4.1.0" + } + }, "no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -10492,6 +10731,11 @@ } } }, + "prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==" + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -10547,6 +10791,11 @@ } } }, + "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==" + }, "psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -10773,28 +11022,19 @@ } } }, + "react-notion": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/react-notion/-/react-notion-0.10.0.tgz", + "integrity": "sha512-i5lVAxzSs7GnTpIbKtivPQWxGZiKCO5xmCmMJyn6F91y8X1IIJqnypkK+31F2acb1l1Qd8Yv0ktuvXwz9g49NQ==", + "requires": { + "prismjs": "^1.21.0" + } + }, "react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" }, - "react-router": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz", - "integrity": "sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==", - "requires": { - "history": "^5.2.0" - } - }, - "react-router-dom": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.3.0.tgz", - "integrity": "sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==", - "requires": { - "history": "^5.2.0", - "react-router": "6.3.0" - } - }, "react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -11722,6 +11962,14 @@ } } }, + "styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "requires": { + "client-only": "0.0.1" + } + }, "stylehacks": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.0.tgz", @@ -12228,6 +12476,16 @@ "punycode": "^2.1.0" } }, + "url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "requires": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index f28c62c..64fb376 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,13 @@ "@testing-library/react": "^13.2.0", "@testing-library/user-event": "^13.5.0", "animate.css": "^4.1.1", + "axios": "^1.3.4", + "babel-plugin-styled-components": "^2.0.7", "eslint-config-prettier": "^8.5.0", "framer-motion": "^9.0.3", "install": "^0.13.0", + "next": "^13.2.3", + "next-images": "^1.8.4", "npm": "^8.13.2", "polished": "^4.2.2", "prop-types": "^15.8.1", @@ -23,7 +27,7 @@ "react-dom": "^18.1.0", "react-lottie": "^1.2.3", "react-material-ui-carousel": "^3.4.2", - "react-router-dom": "^6.3.0", + "react-notion": "^0.10.0", "react-scripts": "5.0.1", "react-slick": "^0.29.0", "recoil": "^0.7.4", @@ -33,10 +37,10 @@ "web-vitals": "^2.1.4" }, "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" + "dev": "next", + "start": "next start", + "build": "next build", + "export": "next export" }, "eslintConfig": { "extends": [ @@ -56,5 +60,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "@babel/plugin-transform-runtime": "^7.21.0" } } diff --git a/pages/_app.js b/pages/_app.js new file mode 100644 index 0000000..5993001 --- /dev/null +++ b/pages/_app.js @@ -0,0 +1,28 @@ +import React from 'react'; +import GlobalStyle from '../src/styles/GlobalStyle'; +import { RecoilRoot } from 'recoil'; +import { ThemeProvider } from 'styled-components'; +import { AnimatePresence } from 'framer-motion'; + +const theme = { + primaryColor: '#01baae', + secondaryColor: '#000', + TitleFont: 'TimesNewRomanPSMT', +}; + +export default function MyApp({ Component, pageProps }) { + return ( + +
+ + + + + + + + +
+
+ ); +} diff --git a/pages/_document.js b/pages/_document.js new file mode 100644 index 0000000..6877981 --- /dev/null +++ b/pages/_document.js @@ -0,0 +1,43 @@ +import React from 'react'; +import Document, { Html, Head, Main, NextScript } from 'next/document'; +import { ServerStyleSheet } from 'styled-components'; + +class MyDocument extends Document { + static async getInitialProps(ctx) { + const sheet = new ServerStyleSheet(); + const originalRenderPage = ctx.renderPage; + try { + ctx.renderPage = () => + originalRenderPage({ + enhanceApp: App => props => sheet.collectStyles(), + }); + + const initialProps = await Document.getInitialProps(ctx); + return { + ...initialProps, + styles: ( + <> + {initialProps.styles} + {sheet.getStyleElement()} + + ), + }; + } finally { + sheet.seal(); + } + } + + render() { + return ( + + + +
+ + + + ); + } +} + +export default MyDocument; diff --git a/pages/blog.js b/pages/blog.js new file mode 100644 index 0000000..a677e33 --- /dev/null +++ b/pages/blog.js @@ -0,0 +1,77 @@ +import React from 'react'; +import { useSetRecoilState } from 'recoil'; +import { menuAtom } from '../src/recoil/atom'; +import AnimatedPage from '../src/components/template/AnimatedPage'; +import { getBlogItems } from '../src/data/source/NotionApi'; +import BlogList from '../src/components/blog/BlogList'; +import styled from 'styled-components'; +import ScrollToTopButton from '../src/components/ScrollToTopButton'; +import { useRouter } from 'next/router'; + +const TitleContainer = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + height: 100px; + margin: 10vw 0; +`; + +const StyledH1 = styled.div` + font-size: 10vw; + text-align: center; + line-height: 1; +`; + +const BackgroundText = styled.div` + opacity: 0.4; + filter: blur(10px); + font-family: SegoeUISymbol; + font-size: 10vw; + text-align: center; + color: #f1efef; + @media only screen and (max-width: 800px) { + filter: blur(4px); + } +`; + +const Text = styled.div` + background-color: rgba(0, 122, 114, 0.86); + padding: 1.3rem 1rem; + font-size: 40px; + margin-bottom: 3rem; + text-align: center; +`; + +const Blog = () => { + const router = useRouter(); + const setMenu = useSetRecoilState(menuAtom); + const [blogItems, setBlogItems] = React.useState([]); + + React.useEffect(() => { + getBlogItems() + .then(data => { + setBlogItems(data); + }) + .catch(err => { + alert('포스트를 불러오는데 실패했습니다.'); + router.push('/'); + }); + }, []); + + return ( + + {setMenu(1)} + + Friday + VALUABLE + + Friday Blog + + + + ); +}; + +export default Blog; diff --git a/src/pages/Contact.js b/pages/contact.js similarity index 92% rename from src/pages/Contact.js rename to pages/contact.js index f9dd2c9..ce64017 100644 --- a/src/pages/Contact.js +++ b/pages/contact.js @@ -1,11 +1,12 @@ import React from 'react'; import styled, { css } from 'styled-components'; -import { menuAtom } from '../recoil/atom'; +import { menuAtom } from '../src/recoil/atom'; import { useSetRecoilState } from 'recoil'; -import mailIcon from '../assets/images/icons/gmail.png'; -import kakaoIcon from '../assets/images/icons/kakao.png'; -import instagramIcon from '../assets/images/icons/instagram.png'; -import AnimatedPage from '../components/template/AnimatedPage'; +import AnimatedPage from '../src/components/template/AnimatedPage'; + +const mailIcon = "/assets/images/icons/gmail.png"; +const kakaoIcon = "/assets/images/icons/kakao.png"; +const instagramIcon = "/assets/images/icons/instagram.png"; const GradientBackground = styled.div` width: 100%; diff --git a/src/pages/Main.js b/pages/index.js similarity index 65% rename from src/pages/Main.js rename to pages/index.js index 822d0a7..11edd5a 100644 --- a/src/pages/Main.js +++ b/pages/index.js @@ -1,15 +1,15 @@ import React from 'react'; import { useSetRecoilState } from 'recoil'; import Lottie from 'react-lottie'; -import FridayAnimation from '../lottie/friday.json'; -import ProjectIntro from '../components/main/ProjectIntro'; -import PhilosophyText from '../components/main/PhilosophyText'; +import ProjectIntro from '../src/components/main/ProjectIntro'; +import PhilosophyText from '../src/components/main/PhilosophyText'; import styled from 'styled-components'; -import MainTop from '../components/main/MainTop'; -import Review from '../components/main/Review'; -import JoinFriday from '../components/JoinFriday'; -import { menuAtom } from '../recoil/atom'; -import AnimatedPage from '../components/template/AnimatedPage'; +import MainTop from '../src/components/main/MainTop'; +import Review from '../src/components/main/Review'; +import JoinFriday from '../src/components/JoinFriday'; +import { menuAtom } from '../src/recoil/atom'; +import AnimatedPage from '../src/components/template/AnimatedPage'; +import FridayAnimation from '../public/assets/lottie/friday.json'; const GradientContainer = styled.div` padding: 5vh 0; diff --git a/pages/post.js b/pages/post.js new file mode 100644 index 0000000..7601c75 --- /dev/null +++ b/pages/post.js @@ -0,0 +1,55 @@ +import React, { useEffect, useState } from 'react'; +import { useSetRecoilState } from 'recoil'; +import { useRouter } from 'next/router'; +import { getNotionPost } from '../src/data/source/NotionApi'; +import AnimatedPage from '../src/components/template/AnimatedPage'; +import ScrollToTopButton from '../src/components/ScrollToTopButton'; +import { menuAtom } from '../src/recoil/atom'; +import { NotionRenderer } from 'react-notion'; +import styled from 'styled-components'; + +import 'react-notion/src/styles.css'; +import 'prismjs/themes/prism-tomorrow.css'; + +const Container = styled.div` + width: 100%; + background-color: #fffcfa; + min-height: 100vh; + padding: 3rem 0; +`; + +const Post = () => { + const setMenu = useSetRecoilState(menuAtom); + + const router = useRouter(); + const { id } = router.query; + + const [notionData, setNotionData] = useState({}); + + useEffect(() => { + if (id) { + getNotionPost(id) + .then(data => { + setNotionData(data); + }) + .catch(err => { + alert('포스트를 불러오는데 실패했습니다.'); + router.push('/blog'); + }); + } + }, [id]); + + return ( + + + {setMenu(1)} + {Object.keys(notionData).length && } + + + + + + ); +}; + +export default Post; diff --git a/src/pages/Project.js b/pages/project.js similarity index 90% rename from src/pages/Project.js rename to pages/project.js index 7aeb636..3b9e029 100644 --- a/src/pages/Project.js +++ b/pages/project.js @@ -1,14 +1,14 @@ import React from 'react'; import { useRecoilState, useSetRecoilState } from 'recoil'; -import { menuAtom } from '../recoil/atom'; -import { prjState, visibleState } from '../recoil/atom'; +import { menuAtom } from '../src/recoil/atom'; +import { prjState, visibleState } from '../src/recoil/atom'; import styled from 'styled-components'; -import Icons from '../components/Icons'; -import card from '../components/project/Card'; -import Modal from '../components/project/Modal'; -import Projects from '../components/project/Projects'; -import JoinFriday from '../components/JoinFriday'; -import AnimatedPage from '../components/template/AnimatedPage'; +import Icons from '../src/components/Icons'; +import card from '../src/components/project/Card'; +import Modal from '../src/components/project/Modal'; +import Projects from '../src/components/project/Projects'; +import JoinFriday from '../src/components/JoinFriday'; +import AnimatedPage from '../src/components/template/AnimatedPage'; const TitleContainer = styled.div` display: flex; diff --git a/pages/recruit.js b/pages/recruit.js new file mode 100644 index 0000000..4024f4e --- /dev/null +++ b/pages/recruit.js @@ -0,0 +1,23 @@ +import React from 'react'; +import TitleBackgroundCard from '../src/components/recruit/TitleBackgroundCard'; +import ProcessCard from '../src/components/recruit/ProcessCard'; +import RecruitAreaCard from '../src/components/recruit/RecruitAreaCard'; +import FAQCard from '../src/components/recruit/FAQCard'; +import { menuAtom } from '../src/recoil/atom'; +import { useSetRecoilState } from 'recoil'; +import AnimatedPage from '../src/components/template/AnimatedPage'; + +function Recruit() { + const setMenu = useSetRecoilState(menuAtom); + return ( + + {setMenu(1)} + + + + + + ); +} + +export default Recruit; diff --git a/src/assets/fonts/SegoeUI.TTF b/public/assets/fonts/SegoeUI.TTF similarity index 100% rename from src/assets/fonts/SegoeUI.TTF rename to public/assets/fonts/SegoeUI.TTF diff --git a/src/assets/fonts/SegoeUI.eot b/public/assets/fonts/SegoeUI.eot similarity index 100% rename from src/assets/fonts/SegoeUI.eot rename to public/assets/fonts/SegoeUI.eot diff --git a/src/assets/fonts/SegoeUI.woff b/public/assets/fonts/SegoeUI.woff similarity index 100% rename from src/assets/fonts/SegoeUI.woff rename to public/assets/fonts/SegoeUI.woff diff --git a/src/assets/fonts/SegoeUI.woff2 b/public/assets/fonts/SegoeUI.woff2 similarity index 100% rename from src/assets/fonts/SegoeUI.woff2 rename to public/assets/fonts/SegoeUI.woff2 diff --git a/src/assets/fonts/TimesNewRomanMTStd.eot b/public/assets/fonts/TimesNewRomanMTStd.eot similarity index 100% rename from src/assets/fonts/TimesNewRomanMTStd.eot rename to public/assets/fonts/TimesNewRomanMTStd.eot diff --git a/src/assets/fonts/TimesNewRomanMTStd.ttf b/public/assets/fonts/TimesNewRomanMTStd.ttf similarity index 100% rename from src/assets/fonts/TimesNewRomanMTStd.ttf rename to public/assets/fonts/TimesNewRomanMTStd.ttf diff --git a/src/assets/fonts/TimesNewRomanMTStd.woff b/public/assets/fonts/TimesNewRomanMTStd.woff similarity index 100% rename from src/assets/fonts/TimesNewRomanMTStd.woff rename to public/assets/fonts/TimesNewRomanMTStd.woff diff --git a/src/assets/fonts/TimesNewRomanMTStd.woff2 b/public/assets/fonts/TimesNewRomanMTStd.woff2 similarity index 100% rename from src/assets/fonts/TimesNewRomanMTStd.woff2 rename to public/assets/fonts/TimesNewRomanMTStd.woff2 diff --git a/src/assets/fonts/TimesNewRomanPSMT.ttf b/public/assets/fonts/TimesNewRomanPSMT.ttf similarity index 100% rename from src/assets/fonts/TimesNewRomanPSMT.ttf rename to public/assets/fonts/TimesNewRomanPSMT.ttf diff --git a/public/assets/fonts/TossFaceFontMac.ttf b/public/assets/fonts/TossFaceFontMac.ttf new file mode 100644 index 0000000..03b3b6a Binary files /dev/null and b/public/assets/fonts/TossFaceFontMac.ttf differ diff --git a/src/assets/images/FD_Web.png b/public/assets/images/FD_Web.png similarity index 100% rename from src/assets/images/FD_Web.png rename to public/assets/images/FD_Web.png diff --git a/src/assets/images/Friday.jpg b/public/assets/images/Friday.jpg similarity index 100% rename from src/assets/images/Friday.jpg rename to public/assets/images/Friday.jpg diff --git a/src/assets/images/Friday2.jpg b/public/assets/images/Friday2.jpg similarity index 100% rename from src/assets/images/Friday2.jpg rename to public/assets/images/Friday2.jpg diff --git a/src/assets/images/aos.png b/public/assets/images/aos.png similarity index 100% rename from src/assets/images/aos.png rename to public/assets/images/aos.png diff --git a/src/assets/images/comento.png b/public/assets/images/comento.png similarity index 100% rename from src/assets/images/comento.png rename to public/assets/images/comento.png diff --git a/src/assets/images/deliverN.png b/public/assets/images/deliverN.png similarity index 100% rename from src/assets/images/deliverN.png rename to public/assets/images/deliverN.png diff --git a/src/assets/images/icons/gmail.png b/public/assets/images/icons/gmail.png similarity index 100% rename from src/assets/images/icons/gmail.png rename to public/assets/images/icons/gmail.png diff --git a/src/assets/images/icons/instagram.png b/public/assets/images/icons/instagram.png similarity index 100% rename from src/assets/images/icons/instagram.png rename to public/assets/images/icons/instagram.png diff --git a/src/assets/images/icons/kakao.png b/public/assets/images/icons/kakao.png similarity index 100% rename from src/assets/images/icons/kakao.png rename to public/assets/images/icons/kakao.png diff --git a/src/assets/images/ios.png b/public/assets/images/ios.png similarity index 100% rename from src/assets/images/ios.png rename to public/assets/images/ios.png diff --git a/src/assets/images/job/android.png b/public/assets/images/job/android.png similarity index 100% rename from src/assets/images/job/android.png rename to public/assets/images/job/android.png diff --git a/src/assets/images/job/be.jpg b/public/assets/images/job/be.jpg similarity index 100% rename from src/assets/images/job/be.jpg rename to public/assets/images/job/be.jpg diff --git a/src/assets/images/job/design.jpg b/public/assets/images/job/design.jpg similarity index 100% rename from src/assets/images/job/design.jpg rename to public/assets/images/job/design.jpg diff --git a/src/assets/images/job/fe.jpg b/public/assets/images/job/fe.jpg similarity index 100% rename from src/assets/images/job/fe.jpg rename to public/assets/images/job/fe.jpg diff --git a/src/assets/images/job/ios.jpg b/public/assets/images/job/ios.jpg similarity index 100% rename from src/assets/images/job/ios.jpg rename to public/assets/images/job/ios.jpg diff --git a/src/assets/images/job/mobile.jpeg b/public/assets/images/job/mobile.jpeg similarity index 100% rename from src/assets/images/job/mobile.jpeg rename to public/assets/images/job/mobile.jpeg diff --git a/src/assets/images/job/pm.jpg b/public/assets/images/job/pm.jpg similarity index 100% rename from src/assets/images/job/pm.jpg rename to public/assets/images/job/pm.jpg diff --git a/src/assets/images/momTimer.png b/public/assets/images/momTimer.png similarity index 100% rename from src/assets/images/momTimer.png rename to public/assets/images/momTimer.png diff --git a/src/assets/images/nalo.png b/public/assets/images/nalo.png similarity index 100% rename from src/assets/images/nalo.png rename to public/assets/images/nalo.png diff --git a/src/assets/images/ootd.png b/public/assets/images/ootd.png similarity index 100% rename from src/assets/images/ootd.png rename to public/assets/images/ootd.png diff --git a/src/assets/images/planDial.png b/public/assets/images/planDial.png similarity index 100% rename from src/assets/images/planDial.png rename to public/assets/images/planDial.png diff --git a/src/assets/images/promise.png b/public/assets/images/promise.png similarity index 100% rename from src/assets/images/promise.png rename to public/assets/images/promise.png diff --git a/src/assets/images/recruitBackground.png b/public/assets/images/recruitBackground.png similarity index 100% rename from src/assets/images/recruitBackground.png rename to public/assets/images/recruitBackground.png diff --git a/src/assets/images/remoa.png b/public/assets/images/remoa.png similarity index 100% rename from src/assets/images/remoa.png rename to public/assets/images/remoa.png diff --git a/src/assets/images/review/jinyoung.jpg b/public/assets/images/review/jinyoung.jpg similarity index 100% rename from src/assets/images/review/jinyoung.jpg rename to public/assets/images/review/jinyoung.jpg diff --git a/src/assets/images/review/mina.jpg b/public/assets/images/review/mina.jpg similarity index 100% rename from src/assets/images/review/mina.jpg rename to public/assets/images/review/mina.jpg diff --git a/src/assets/images/review/seonghwan.jpg b/public/assets/images/review/seonghwan.jpg similarity index 100% rename from src/assets/images/review/seonghwan.jpg rename to public/assets/images/review/seonghwan.jpg diff --git a/src/assets/images/review/wonhee.jpg b/public/assets/images/review/wonhee.jpg similarity index 100% rename from src/assets/images/review/wonhee.jpg rename to public/assets/images/review/wonhee.jpg diff --git a/src/assets/images/texti.png b/public/assets/images/texti.png similarity index 100% rename from src/assets/images/texti.png rename to public/assets/images/texti.png diff --git a/src/assets/images/tunnel.jpg b/public/assets/images/tunnel.jpg similarity index 100% rename from src/assets/images/tunnel.jpg rename to public/assets/images/tunnel.jpg diff --git a/src/lottie/friday.json b/public/assets/lottie/friday.json similarity index 100% rename from src/lottie/friday.json rename to public/assets/lottie/friday.json diff --git a/src/lottie/scroll.json b/public/assets/lottie/scroll.json similarity index 100% rename from src/lottie/scroll.json rename to public/assets/lottie/scroll.json diff --git a/src/assets/videos/tunnel.mp4 b/public/assets/videos/tunnel.mp4 similarity index 100% rename from src/assets/videos/tunnel.mp4 rename to public/assets/videos/tunnel.mp4 diff --git a/src/App.js b/src/App.js deleted file mode 100644 index 017759f..0000000 --- a/src/App.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { useRoutes, useLocation } from 'react-router-dom'; -import { AnimatePresence } from 'framer-motion'; - -import Main from './pages/Main'; -import Project from './pages/Project'; -import Recruit from './pages/Recruit'; -import Contact from './pages/Contact'; - -function App() { - const location = useLocation(); - const element = useRoutes([ - { - path: '/', - element:
, - }, - { - path: '/project', - element: , - }, - { - path: '/recruit', - element: , - }, - { - path: '/contact', - element: , - }, - ]); - - if (!element) return null; - - return {React.cloneElement(element, { key: location.pathname })}; -} - -export default App; diff --git a/src/components/Button.js b/src/components/Button.js index 5ab5988..6b1a06f 100644 --- a/src/components/Button.js +++ b/src/components/Button.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import styled, { css } from 'styled-components'; import { lighten, darken } from 'polished'; +import MyLink from '../components/MyLink'; Button.propTypes = { color: PropTypes.string, @@ -17,7 +18,7 @@ Button.defaultProps = { border: false, }; -const StyledButton = styled.a` +const StyledButton = styled.span` ${props => { const COLOR = props.color; const BACKGROUND_COLOR = props.backgroundColor; @@ -59,7 +60,10 @@ const StyledButton = styled.a` }} `; -function Button({ children, ...rest }) { +function Button({ children, href, ...rest }) { + if (href) { + children = ({children}); + } return {children}; } diff --git a/src/components/Footer.js b/src/components/Footer.js index f0f8b74..8592ec9 100644 --- a/src/components/Footer.js +++ b/src/components/Footer.js @@ -3,6 +3,7 @@ import styled from 'styled-components'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faGithub, faInstagram } from '@fortawesome/free-brands-svg-icons'; import PageMenuList from './PageMenuList'; +import Link from 'next/link'; const GradientFooter = styled.div` width: 100%; @@ -56,12 +57,12 @@ export default function Footer() { - + - - + + - + Copyright © Friday. All Rights Reserved. diff --git a/src/components/Header.js b/src/components/Header.js index 5ced9d3..58008a9 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -6,7 +6,7 @@ import { throttle } from 'lodash'; import ModalMenu from './main/ModalMenu'; import MyLink from '../components/MyLink'; import PageMenuList from './PageMenuList'; -import { motion } from 'framer-motion' +import { motion } from 'framer-motion'; const FixedHeader = styled(motion.div)` height: 4rem; @@ -20,7 +20,7 @@ const FixedHeader = styled(motion.div)` top: 0; z-index: 3; justify-content: space-between; - background-color: rgba(255, 255, 255, 0.2); + background-color: ${props => props.isBlack ? 'rgba(0, 0, 0, 0.3)' : 'rgba(255, 255, 255, 0.2)'}; -webkit-backdrop-filter: blur(1rem); backdrop-filter: blur(1rem); `; @@ -67,7 +67,7 @@ const PageListContainer = styled.div` } `; -function Header() { +function Header({ blackHeader }) { const [menu, setMenu] = useRecoilState(menuAtom); const [isScrollingDown, setIsScrollingDown] = React.useState(false); @@ -108,8 +108,8 @@ function Header() { return ( <> - - + + FRIDAY diff --git a/src/components/Icons.js b/src/components/Icons.js index 42e7c3c..090c6d6 100644 --- a/src/components/Icons.js +++ b/src/components/Icons.js @@ -1,12 +1,12 @@ -import comentoIcon from '../assets/images/comento.png'; -import planDialIcon from '../assets/images/planDial.png'; -import fridayIcon from '../assets/images/FD_Web.png'; -import momTimer from '../assets/images/momTimer.png'; -import promise from '../assets/images/promise.png'; -import texti from '../assets/images/texti.png'; -import ootd from '../assets/images/ootd.png'; -import remoa from '../assets/images/remoa.png'; -import deliverN from '../assets/images/deliverN.png'; +const comentoIcon = '/assets/images/comento.png'; +const planDialIcon = '/assets/images/planDial.png'; +const fridayIcon = '/assets/images/FD_Web.png'; +const momTimer = '/assets/images/momTimer.png'; +const promise = '/assets/images/promise.png'; +const texti = '/assets/images/texti.png'; +const ootd = '/assets/images/ootd.png'; +const remoa = '/assets/images/remoa.png'; +const deliverN = '/assets/images/deliverN.png'; const Icons = [ { diff --git a/src/components/MyLink.js b/src/components/MyLink.js index 62e54a9..aedeb55 100644 --- a/src/components/MyLink.js +++ b/src/components/MyLink.js @@ -1,27 +1,12 @@ import React from 'react'; -import PropTypes from 'prop-types'; import styled, { css } from 'styled-components'; -import { Link } from 'react-router-dom'; - -MyLink.propTypes = { - color: PropTypes.string, - navigation: PropTypes.bool, - fontSize: PropTypes.number, - hoverColor: PropTypes.string, -}; - -MyLink.defaultProps = { - color: 'white', - navigation: true, - fontSize: '1.5rem', - hoverColor: '#01B9AD', -}; +import Link from 'next/link'; const StyledLink = styled(Link)` ${props => { - const COLOR = props.color; - const FONT_SIZE = props.fontSize; - const HOVER_COLOR = props.hoverColor; + const COLOR = props.color ?? 'white'; + const FONT_SIZE = props.fontSize ?? '1.5rem'; + const HOVER_COLOR = props.hoverColor ?? '#01B9AD'; return css` color: ${COLOR}; font-size: ${FONT_SIZE}; @@ -35,8 +20,8 @@ const StyledLink = styled(Link)` }} `; -function MyLink({ children, ...args }) { - return {children}; +function MyLink({ children, to, ...args }) { + return {children}; } export default MyLink; diff --git a/src/components/PageMenuList.js b/src/components/PageMenuList.js index 90e8df1..82318c3 100644 --- a/src/components/PageMenuList.js +++ b/src/components/PageMenuList.js @@ -36,6 +36,11 @@ const PageMenuList = ({fontSize = "1.3rem"}) => { CONTACT + + + BLOG + + ); }; diff --git a/src/components/ScrollAnimation.js b/src/components/ScrollAnimation.js index b4140d1..455e878 100644 --- a/src/components/ScrollAnimation.js +++ b/src/components/ScrollAnimation.js @@ -1,7 +1,8 @@ import React from 'react'; -import { AnimationOnScroll } from 'react-animation-on-scroll'; +// import { AnimationOnScroll } from 'react-animation-on-scroll'; import 'animate.css/animate.min.css'; -export default function ScrollAnimation({ ...settings }) { - return ; +export default function ScrollAnimation({ children, ...settings }) { + // return ; + return
{children}
; } diff --git a/src/components/ScrollToTop.js b/src/components/ScrollToTop.js index 20168ff..eb2eba2 100644 --- a/src/components/ScrollToTop.js +++ b/src/components/ScrollToTop.js @@ -1,8 +1,8 @@ import { useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; +import { useRouter } from 'next/router'; export default function ScrollToTop({ delay = 0 }) { - const { pathname } = useLocation(); + const { pathname } = useRouter(); useEffect(() => { setTimeout(() => window.scrollTo(0, 0), delay); diff --git a/src/components/ScrollToTopButton.js b/src/components/ScrollToTopButton.js new file mode 100644 index 0000000..0fc82c5 --- /dev/null +++ b/src/components/ScrollToTopButton.js @@ -0,0 +1,48 @@ +import React from 'react'; +import styled from 'styled-components'; + +const TopButton = styled.button` + position: fixed; + cursor: pointer; + right: 5%; + bottom: 5%; + z-index: 1; + background-color: rgba(255, 255, 255, 0.8); + -webkit-backdrop-filter: blur(1rem); + backdrop-filter: blur(1rem); + border-radius: 50%; + border: none; + width: 70px; + height: 70px; +`; + +const TopIcon = styled.div` + border: solid #01b9ad; + border-width: 0 5px 5px 0; + display: inline-block; + padding: 5px; + transform: rotate(225deg); + -webkit-transform: rotate(225deg); +`; + +const TopText = styled.div` + font-size: 1rem; + font-weight: bold; + color: #01b9ad; +`; + +export default function ScrollToTopButton() { + const scrollToTop = () => { + window.scrollTo({ + top: 0, + behavior: 'smooth', + }); + }; + + return ( + + + TOP + + ); +} diff --git a/src/components/blog/BlogItem.js b/src/components/blog/BlogItem.js new file mode 100644 index 0000000..9ffcace --- /dev/null +++ b/src/components/blog/BlogItem.js @@ -0,0 +1,123 @@ +import React from 'react'; +import styled from 'styled-components'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faUser, faClock, faPenNib } from '@fortawesome/free-solid-svg-icons'; +import Router from 'next/router'; + +const BlogItemLayout = styled.div` + width: 90vw; + border-radius: 1.5rem; + background-color: rgba(255, 255, 255, 0.2); + padding: 1.5rem 1.5rem 2rem 1.5rem; + display: grid; + grid-template-columns: 4.5rem auto; + grid-template-rows: 1fr 1fr 1.2fr; + gap: 0px 20px; + cursor: pointer; + transition: all 0.2s ease-in-out; + + &:hover { + background-color: rgba(255, 255, 255, 0.35); + width: 93vw; + } +`; + +const ThumbnailArea = styled.div` + font-family: 'TossFace', 'SegoeUISymbol', sans-serif; + font-size: 4rem; + line-height: 1.2; + grid-row-start: 1; + grid-row-end: 3; +`; + +const TitleArea = styled.div` + font-family: 'SegoeUISymbol', sans-serif; + font-size: min(1.5rem, 5vw); + font-weight: bold; + line-height: min(calc(1.5rem + 10px), 5.5vw); + align-self: center; +`; + +const TagArea = styled.div` + display: flex; + flex-wrap: wrap; +`; + +const Tag = styled.span` + font-family: SegoeUISymbol; + font-size: 15px; + border-radius: 5px; + padding-right: 10px; + font-weight: 600; + text-shadow: #01baae 0 0 10px; + align-self: center; +`; + +const InfoArea = styled.div` + display: flex; + flex-wrap: wrap; + gap: 5px 20px; + align-self: end; + font-family: 'SegoeUISymbol', sans-serif; + font-size: 15px; + color: #cccccc; +`; + +const Info = styled.span` + display: inline-flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: 5px; + flex-direction: row; + line-height: 1; +`; + +export default function BlogItem({ blogItem }) { + let authorData = ''; + + if (blogItem.author) { + authorData = blogItem.author; + if (authorData.email) { + authorData += `(${authorData.email})`; + } + } + + return ( + + Router.push({ + pathname: '/post', + query: { id: blogItem.id }, + }) + } + > + {blogItem.icon ?? ''} + {blogItem.title ?? ''} + {blogItem.tags ? blogItem.tags.map((item, index) => #{item}) : ''} +
+ + + + {authorData} + + + + {dateToText(blogItem.createdAt) ?? ''} + + + + {dateToText(blogItem.EditedAt) ?? ''} + + +
+ ); +} + +function dateToText(date) { + if (!date) return null; + const year = date.getFullYear(); + const month = date.getMonth() + 1; + const day = date.getDate(); + return `${year}년 ${month}월 ${day}일`; +} diff --git a/src/components/blog/BlogList.js b/src/components/blog/BlogList.js new file mode 100644 index 0000000..571fa2c --- /dev/null +++ b/src/components/blog/BlogList.js @@ -0,0 +1,31 @@ +import React from 'react'; +import BlogItem from './BlogItem'; +import styled from 'styled-components'; +import { motion, AnimatePresence } from 'framer-motion'; + +const BlogListLayout = styled(motion.div)` + display: flex; + flex-direction: column; + align-items: center; + margin: 7vw 0px; + min-height: 100vh; + gap: 30px 0px; +`; + +export default function BlogList({ blogItems }) { + const animationParams = { + initial: { opacity: 0, y: -10 }, + animate: { opacity: 1, y: 0 }, + transition: { duration: 0.3, ease: 'easeOut' }, + }; + + return ( + + {blogItems.map((item, index) => ( + + + + ))} + + ); +} diff --git a/src/components/main/MainTop.js b/src/components/main/MainTop.js index 50f80fc..7f4e326 100644 --- a/src/components/main/MainTop.js +++ b/src/components/main/MainTop.js @@ -3,7 +3,7 @@ import styled from 'styled-components'; import MainVideo from './MainVideo'; import Button from '../Button'; import Lottie from 'react-lottie'; -import Scroll from '../../lottie/scroll.json'; +import Scroll from '../../../public/assets/lottie/scroll.json'; import MyLink from '../../components/MyLink'; const TopContainer = styled.div` diff --git a/src/components/main/MainVideo.js b/src/components/main/MainVideo.js index 1b1bd78..cc51528 100644 --- a/src/components/main/MainVideo.js +++ b/src/components/main/MainVideo.js @@ -1,7 +1,8 @@ import React from 'react'; import styled from 'styled-components'; -import Video from '../../assets/videos/tunnel.mp4'; -import Thumbnail from '../../assets/images/tunnel.jpg'; + +const Thumbnail = '/assets/images/tunnel.jpg'; +const Video = '/assets/videos/tunnel.mp4'; const FullVideos = styled.div` height: 100vh; diff --git a/src/components/main/ModalMenu.js b/src/components/main/ModalMenu.js index 7a679bd..8a169dd 100644 --- a/src/components/main/ModalMenu.js +++ b/src/components/main/ModalMenu.js @@ -58,6 +58,9 @@ function ModalMenu({ isVisible }) { CONTACT + + BLOG + )} diff --git a/src/components/main/ProjectIntro.js b/src/components/main/ProjectIntro.js index 75512e2..c2b43f8 100644 --- a/src/components/main/ProjectIntro.js +++ b/src/components/main/ProjectIntro.js @@ -44,7 +44,7 @@ function ProjectIntro() { infinite: true, speed: 400, slidesToShow: 5, - slidesToScroll: 2, + slidesToScroll: 1, arrows: false, autoplay: true, autoplaySpeed: 2000, diff --git a/src/components/main/Review.js b/src/components/main/Review.js index 3ca7388..43310d4 100644 --- a/src/components/main/Review.js +++ b/src/components/main/Review.js @@ -1,10 +1,11 @@ import React from 'react'; import styled, { css } from 'styled-components'; import ScrollAnimation from '../ScrollAnimation'; -import minaImg from '../../assets/images/review/mina.jpg'; -import wonheeImg from '../../assets/images/review/wonhee.jpg'; -import seonghwanImg from '../../assets/images/review/seonghwan.jpg'; -import jinyoungImg from '../../assets/images/review/jinyoung.jpg'; + +const minaImg = "/assets/images/review/mina.jpg"; +const wonheeImg = "/assets/images/review/wonhee.jpg"; +const seonghwanImg = "/assets/images/review/seonghwan.jpg"; +const jinyoungImg = "/assets/images/review/jinyoung.jpg"; const Positioner = styled.div` width: 100%; diff --git a/src/components/project/Modal.js b/src/components/project/Modal.js index 112832f..adf5281 100644 --- a/src/components/project/Modal.js +++ b/src/components/project/Modal.js @@ -6,6 +6,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faXmark, faLink } from '@fortawesome/free-solid-svg-icons'; import { motion, AnimatePresence } from 'framer-motion'; import { faGithub } from '@fortawesome/free-brands-svg-icons'; +import Link from 'next/link'; const ModalStyle = styled(motion.div)` background-color: rgba(255, 255, 255, 0.5); @@ -68,7 +69,7 @@ const Text = styled.div` } `; -const Link = styled.a` +const LinkComp = styled(Link)` font-size: 25px; font-weight: 800px; text-decoration: none; @@ -154,16 +155,16 @@ function Modal({ ...rest }) { {rest.content.title} {rest.content.git ? ( - + - + ) : ( '' )} {rest.content.site ? ( - + - + ) : ( '' )} @@ -177,16 +178,16 @@ function Modal({ ...rest }) { {rest.content.aos ? ( - - - + + + ) : ( '' )} {rest.content.ios ? ( - - - + + + ) : ( '' )} diff --git a/src/components/recruit/FAQ.js b/src/components/recruit/FAQ.js index a8304a9..4a22723 100644 --- a/src/components/recruit/FAQ.js +++ b/src/components/recruit/FAQ.js @@ -29,7 +29,7 @@ const FaqTitleContainer = styled.div` gap: 10px; `; -const QuestionTitle = styled.p` +const QuestionTitle = styled.div` font-weight: bold; font-size: 22px; display: flex; diff --git a/src/components/recruit/RecruitAreaCard.js b/src/components/recruit/RecruitAreaCard.js index 0a3f5b5..60780b9 100644 --- a/src/components/recruit/RecruitAreaCard.js +++ b/src/components/recruit/RecruitAreaCard.js @@ -2,11 +2,12 @@ import React, { useState } from 'react'; import styled from 'styled-components'; import * as Text from './Text'; import * as Job from './JobExplain'; -import designImg from '../../assets/images/job/design.jpg'; -import MobileImg from '../../assets/images/job/mobile.jpeg'; -import FrontEndImg from '../../assets/images/job/fe.jpg'; -import BackEndImg from '../../assets/images/job/be.jpg'; -import PmImg from '../../assets/images/job/pm.jpg'; + +const designImg = '/assets/images/job/design.jpg'; +const MobileImg = '/assets/images/job/mobile.jpeg'; +const FrontEndImg = '/assets/images/job/fe.jpg'; +const BackEndImg = '/assets/images/job/be.jpg'; +const PmImg = '/assets/images/job/pm.jpg'; const RecruitLayout = styled.div` display: flex; diff --git a/src/components/recruit/TitleBackgroundCard.js b/src/components/recruit/TitleBackgroundCard.js index 79f2ef8..6519967 100644 --- a/src/components/recruit/TitleBackgroundCard.js +++ b/src/components/recruit/TitleBackgroundCard.js @@ -1,8 +1,9 @@ import React from 'react'; import styled from 'styled-components'; -import BackgroundImage from '../../assets/images/recruitBackground.png'; import Button from '../../components/Button'; +const BackgroundImage = "/assets/images/recruitBackground.png"; + const TitleContainer = styled.div` background-image: url(${BackgroundImage}); background-size: cover; diff --git a/src/components/template/AnimatedPage.js b/src/components/template/AnimatedPage.js index 41047e6..07725fd 100644 --- a/src/components/template/AnimatedPage.js +++ b/src/components/template/AnimatedPage.js @@ -5,7 +5,7 @@ import Header from '../Header'; import Footer from '../Footer'; import { isMobile } from 'react-device-detect'; -const AnimatedPage = ({ children }) => { +const AnimatedPage = ({ children, blackHeader = false }) => { const innerContent = ( <> @@ -16,7 +16,7 @@ const AnimatedPage = ({ children }) => { return ( <> -
+
{isMobile ? ( innerContent ) : ( diff --git a/src/data/model/BlogPostSummary.js b/src/data/model/BlogPostSummary.js new file mode 100644 index 0000000..a4cb10d --- /dev/null +++ b/src/data/model/BlogPostSummary.js @@ -0,0 +1,25 @@ +export default class BlogPostSummary { + constructor({ id, title, author, email, icon, tags, createdAt, EditedAt }) { + this.id = id; + this.title = title; + this.author = author; + this.email = email; + this.icon = icon; + this.tags = tags; + this.createdAt = createdAt; + this.EditedAt = EditedAt; + } + + static fromRawData(rawData) { + return new BlogPostSummary({ + id: rawData.id, + title: rawData.properties.제목.title[0].text.content, + author: rawData.properties.작성자.created_by.name, + email: rawData.properties.작성자.created_by.person.email, + icon: rawData.icon.emoji, + tags: rawData.properties.태그.multi_select.map((tag) => tag.name), + createdAt: new Date(rawData.created_time), + EditedAt: new Date(rawData.last_edited_time), + }); + } +} diff --git a/src/data/source/NotionApi.js b/src/data/source/NotionApi.js new file mode 100644 index 0000000..95b3977 --- /dev/null +++ b/src/data/source/NotionApi.js @@ -0,0 +1,43 @@ +import axios from 'axios'; +import BlogPostSummary from '../model/BlogPostSummary'; + +const notionKey = process.env.NEXT_PUBLIC_NOTION_KEY; +const notionDatabaseKey = process.env.NEXT_PUBLIC_NOTION_DATABASE_KEY; + +const commonHeaders = { + headers: { + Authorization: `Bearer ${notionKey}`, + 'Notion-Version': '2022-06-28', + }, +}; + +export async function getBlogItems() { + try { + const result = await axios.post( + `/databases/${notionDatabaseKey}/query`, + { + page_size: 100, + sorts: [ + { + property: '작성 일시', + direction: 'descending', + }, + ], + }, + commonHeaders + ); + + return result.data.results.map(item => BlogPostSummary.fromRawData(item)); + } catch (error) { + throw new Error(error); + } +} + +export async function getNotionPost(id) { + try { + const result = await axios.get(`/page/${id}`); + return result.data; + } catch (error) { + throw new Error(error); + } +} diff --git a/src/index.js b/src/index.js deleted file mode 100644 index aa15a37..0000000 --- a/src/index.js +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; -import GlobalStyle from './styles/GlobalStyle'; -import { BrowserRouter } from 'react-router-dom'; -import { RecoilRoot } from 'recoil'; -import { ThemeProvider } from 'styled-components'; - -const theme = { - primaryColor: '#01baae', - secondaryColor: '#000', - TitleFont: 'TimesNewRomanPSMT', -}; - -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/pages/Recruit.js b/src/pages/Recruit.js deleted file mode 100644 index 2e2d2f5..0000000 --- a/src/pages/Recruit.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import TitleBackgroundCard from '../components/recruit/TitleBackgroundCard'; -import ProcessCard from '../components/recruit/ProcessCard'; -import RecruitAreaCard from '../components/recruit/RecruitAreaCard'; -import FAQCard from '../components/recruit/FAQCard'; -import { menuAtom } from '../recoil/atom'; -import { useSetRecoilState } from 'recoil'; -import AnimatedPage from '../components/template/AnimatedPage'; - -function Recruit() { - const setMenu = useSetRecoilState(menuAtom); - return ( - - {setMenu(1)} - - - - - - ); -} - -export default Recruit; diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js deleted file mode 100644 index 5253d3a..0000000 --- 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 8f2609b..0000000 --- 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/src/styles/GlobalStyle.js b/src/styles/GlobalStyle.js index da29e3c..ca3fb51 100644 --- a/src/styles/GlobalStyle.js +++ b/src/styles/GlobalStyle.js @@ -1,12 +1,14 @@ import { createGlobalStyle } from 'styled-components'; -import SegoeTTF from '../assets/fonts/SegoeUI.TTF'; -import SegoeEot from '../assets/fonts/SegoeUI.eot'; -import SegoeWoff from '../assets/fonts/SegoeUI.woff'; -import SegoeWoff2 from '../assets/fonts/SegoeUI.woff2'; -import TimesTTF from '../assets/fonts/TimesNewRomanMTStd.ttf'; -import TimesEot from '../assets/fonts/TimesNewRomanMTStd.eot'; -import TimesWoff from '../assets/fonts/TimesNewRomanMTStd.woff'; -import TimesWoff2 from '../assets/fonts/TimesNewRomanMTStd.woff2'; + +const SegoeTTF = '/assets/fonts/SegoeUI.TTF'; +const SegoeEot = '/assets/fonts/SegoeUI.eot'; +const SegoeWoff = '/assets/fonts/SegoeUI.woff'; +const SegoeWoff2 = '/assets/fonts/SegoeUI.woff2'; +const TimesTTF = '/assets/fonts/TimesNewRomanMTStd.ttf'; +const TimesEot = '/assets/fonts/TimesNewRomanMTStd.eot'; +const TimesWoff = '/assets/fonts/TimesNewRomanMTStd.woff'; +const TimesWoff2 = '/assets/fonts/TimesNewRomanMTStd.woff2'; +const TossFace = '/assets/fonts/TossFaceFontMac.ttf'; const GlobalStyle = createGlobalStyle` *, *::before, *::after { @@ -28,6 +30,10 @@ const GlobalStyle = createGlobalStyle` url(${TimesWoff2}) format('woff2'), url(${TimesEot}+'?#iefix') format('embedded-opentype'); } +@font-face { + font-family: 'TossFace'; + src: url(${TossFace}) format('truetype'); + } body { max-width:100%;