diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..1031301
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,3 @@
+{
+ "recommendations": ["jpoissonnier.vscode-styled-components"]
+}
diff --git a/craco.config.js b/craco.config.js
new file mode 100644
index 0000000..aec2aab
--- /dev/null
+++ b/craco.config.js
@@ -0,0 +1,15 @@
+module.exports = {
+ webpack: {
+ configure: {
+ module: {
+ rules: [
+ {
+ type: "javascript/auto",
+ test: /\.mjs$/,
+ include: /node_modules/,
+ },
+ ],
+ },
+ },
+ },
+};
diff --git a/package-lock.json b/package-lock.json
index 0df0eec..abec8e8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "react-masterclass",
"version": "0.1.0",
"dependencies": {
+ "@craco/craco": "^6.4.2",
"@testing-library/jest-dom": "^5.15.1",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
@@ -16,18 +17,24 @@
"@types/react": "^17.0.36",
"@types/react-dom": "^17.0.11",
"apexcharts": "^3.31.0",
+ "framer-motion": "^5.4.1",
+ "gh-pages": "^3.2.3",
"react": "^17.0.2",
"react-apexcharts": "^1.3.9",
+ "react-beautiful-dnd": "^13.1.0",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
+ "react-hook-form": "^7.20.5",
"react-query": "^3.33.5",
"react-router-dom": "^5.3.0",
"react-scripts": "4.0.3",
+ "recoil": "^0.5.2",
"styled-components": "^5.3.3",
"typescript": "^4.5.2",
"web-vitals": "^1.1.2"
},
"devDependencies": {
+ "@types/react-beautiful-dnd": "^13.1.2",
"@types/react-helmet": "^6.1.4",
"@types/react-router-dom": "^5.3.2",
"@types/styled-components": "^5.1.15"
@@ -1781,6 +1788,27 @@
"node": ">=0.1.95"
}
},
+ "node_modules/@craco/craco": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/@craco/craco/-/craco-6.4.2.tgz",
+ "integrity": "sha512-egIooyvuzKM5dsvWe/U5ISyFpZwLnG9uuTF1fU4s/6b/hE8MvoxyaxKymQKgbtpfOZeH0ebtEP4cbH7xZ4XRbw==",
+ "dependencies": {
+ "cosmiconfig": "^7.0.1",
+ "cross-spawn": "^7.0.0",
+ "lodash": "^4.17.15",
+ "semver": "^7.3.2",
+ "webpack-merge": "^4.2.2"
+ },
+ "bin": {
+ "craco": "bin/craco.js"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "peerDependencies": {
+ "react-scripts": "^4.0.0"
+ }
+ },
"node_modules/@csstools/convert-colors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz",
@@ -3505,7 +3533,6 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
- "dev": true,
"dependencies": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
@@ -3743,6 +3770,15 @@
"csstype": "^3.0.2"
}
},
+ "node_modules/@types/react-beautiful-dnd": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.2.tgz",
+ "integrity": "sha512-+OvPkB8CdE/bGdXKyIhc/Lm2U7UAYCCJgsqmopFmh9gbAudmslkI8eOrPDjg4JhwSE6wytz4a3/wRjKtovHVJg==",
+ "dev": true,
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/react-dom": {
"version": "17.0.11",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
@@ -3760,6 +3796,17 @@
"@types/react": "*"
}
},
+ "node_modules/@types/react-redux": {
+ "version": "7.1.20",
+ "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz",
+ "integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==",
+ "dependencies": {
+ "@types/hoist-non-react-statics": "^3.3.0",
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0",
+ "redux": "^4.0.0"
+ }
+ },
"node_modules/@types/react-router": {
"version": "5.1.17",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz",
@@ -6577,6 +6624,14 @@
"node": ">=6.0.0"
}
},
+ "node_modules/css-box-model": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
+ "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
+ "dependencies": {
+ "tiny-invariant": "^1.0.6"
+ }
+ },
"node_modules/css-color-keywords": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
@@ -7616,6 +7671,11 @@
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
},
+ "node_modules/email-addresses": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
+ "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg=="
+ },
"node_modules/emittery": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz",
@@ -9210,6 +9270,30 @@
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"optional": true
},
+ "node_modules/filename-reserved-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
+ "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/filenamify": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
+ "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
+ "dependencies": {
+ "filename-reserved-regex": "^2.0.0",
+ "strip-outer": "^1.0.1",
+ "trim-repeated": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/filesize": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@@ -9575,6 +9659,43 @@
"node": ">=0.10.0"
}
},
+ "node_modules/framer-motion": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-5.4.1.tgz",
+ "integrity": "sha512-U4hiU3g5RCaZRTtTTOKStXH1jm+8uiIhM46wjIYQ7fWnc5c1cGlAzo238X7AM3WhU//jtqd1l5EHq32x96Eg4g==",
+ "dependencies": {
+ "framesync": "6.0.1",
+ "hey-listen": "^1.0.8",
+ "popmotion": "11.0.3",
+ "style-value-types": "5.0.0",
+ "tslib": "^2.1.0"
+ },
+ "optionalDependencies": {
+ "@emotion/is-prop-valid": "^0.8.2"
+ },
+ "peerDependencies": {
+ "@react-three/fiber": "^7.0.21",
+ "react": ">=16.8 || ^17.0.0",
+ "react-dom": ">=16.8 || ^17.0.0",
+ "three": "^0.135.0"
+ },
+ "peerDependenciesMeta": {
+ "@react-three/fiber": {
+ "optional": true
+ },
+ "three": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/framesync": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz",
+ "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -9735,6 +9856,144 @@
"node": ">=0.10.0"
}
},
+ "node_modules/gh-pages": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.2.3.tgz",
+ "integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==",
+ "dependencies": {
+ "async": "^2.6.1",
+ "commander": "^2.18.0",
+ "email-addresses": "^3.0.1",
+ "filenamify": "^4.3.0",
+ "find-cache-dir": "^3.3.1",
+ "fs-extra": "^8.1.0",
+ "globby": "^6.1.0"
+ },
+ "bin": {
+ "gh-pages": "bin/gh-pages.js",
+ "gh-pages-clean": "bin/gh-pages-clean.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/gh-pages/node_modules/array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "dependencies": {
+ "array-uniq": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gh-pages/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ },
+ "node_modules/gh-pages/node_modules/find-cache-dir": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
+ "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
+ "dependencies": {
+ "commondir": "^1.0.1",
+ "make-dir": "^3.0.2",
+ "pkg-dir": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/avajs/find-cache-dir?sponsor=1"
+ }
+ },
+ "node_modules/gh-pages/node_modules/fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/gh-pages/node_modules/globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+ "dependencies": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gh-pages/node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/gh-pages/node_modules/make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dependencies": {
+ "semver": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/gh-pages/node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gh-pages/node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/gh-pages/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/gh-pages/node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
"node_modules/glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
@@ -9850,6 +10109,11 @@
"node": ">=6"
}
},
+ "node_modules/hamt_plus": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz",
+ "integrity": "sha1-4hwlKWjH4zsg9qGwlM2FeHomVgE="
+ },
"node_modules/handle-thing": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
@@ -10037,6 +10301,11 @@
"resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
"integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
},
+ "node_modules/hey-listen": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
+ "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
+ },
"node_modules/history": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
@@ -13441,6 +13710,11 @@
"node": ">= 0.6"
}
},
+ "node_modules/memoize-one": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
+ "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
+ },
"node_modules/memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
@@ -14843,6 +15117,17 @@
"node": ">=6"
}
},
+ "node_modules/popmotion": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz",
+ "integrity": "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==",
+ "dependencies": {
+ "framesync": "6.0.1",
+ "hey-listen": "^1.0.8",
+ "style-value-types": "5.0.0",
+ "tslib": "^2.1.0"
+ }
+ },
"node_modules/portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -16361,6 +16646,11 @@
"performance-now": "^2.1.0"
}
},
+ "node_modules/raf-schd": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
+ "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ=="
+ },
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -16448,6 +16738,24 @@
"node": ">=10"
}
},
+ "node_modules/react-beautiful-dnd": {
+ "version": "13.1.0",
+ "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz",
+ "integrity": "sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==",
+ "dependencies": {
+ "@babel/runtime": "^7.9.2",
+ "css-box-model": "^1.2.0",
+ "memoize-one": "^5.1.1",
+ "raf-schd": "^4.0.2",
+ "react-redux": "^7.2.0",
+ "redux": "^4.0.4",
+ "use-memo-one": "^1.1.1"
+ },
+ "peerDependencies": {
+ "react": "^16.8.5 || ^17.0.0",
+ "react-dom": "^16.8.5 || ^17.0.0"
+ }
+ },
"node_modules/react-dev-utils": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
@@ -16604,6 +16912,21 @@
"react": ">=16.3.0"
}
},
+ "node_modules/react-hook-form": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.20.5.tgz",
+ "integrity": "sha512-xYeBmQW6oqxDYAYVWIoZYC7tRD6lJBJt9b8Rr1Mv/VhZ+ZUCy2IuXlm2YA9i0/zl0TKKxqBWQOxGEb3qyVIhMg==",
+ "engines": {
+ "node": ">=12.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/react-hook-form"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17"
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -16634,6 +16957,41 @@
}
}
},
+ "node_modules/react-redux": {
+ "version": "7.2.6",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz",
+ "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.15.4",
+ "@types/react-redux": "^7.1.20",
+ "hoist-non-react-statics": "^3.3.2",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.7.2",
+ "react-is": "^17.0.2"
+ },
+ "peerDependencies": {
+ "react": "^16.8.3 || ^17"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-redux/node_modules/@babel/runtime": {
+ "version": "7.16.3",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
+ "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
+ "dependencies": {
+ "regenerator-runtime": "^0.13.4"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@@ -16928,6 +17286,25 @@
"node": ">=8.10.0"
}
},
+ "node_modules/recoil": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.5.2.tgz",
+ "integrity": "sha512-Edibzpu3dbUMLy6QRg73WL8dvMl9Xqhp+kU+f2sJtXxsaXvAlxU/GcnDE8HXPkprXrhHF2e6SZozptNvjNF5fw==",
+ "dependencies": {
+ "hamt_plus": "1.0.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.13.1"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
"node_modules/recursive-readdir": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz",
@@ -16951,6 +17328,14 @@
"node": ">=8"
}
},
+ "node_modules/redux": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz",
+ "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==",
+ "dependencies": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -18950,6 +19335,17 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/strip-outer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+ "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/style-loader": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
@@ -18969,6 +19365,15 @@
"webpack": "^4.0.0 || ^5.0.0"
}
},
+ "node_modules/style-value-types": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz",
+ "integrity": "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==",
+ "dependencies": {
+ "hey-listen": "^1.0.8",
+ "tslib": "^2.1.0"
+ }
+ },
"node_modules/styled-components": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz",
@@ -19746,6 +20151,17 @@
"node": ">=8"
}
},
+ "node_modules/trim-repeated": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+ "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/tryer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
@@ -20184,6 +20600,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/use-memo-one": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz",
+ "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0"
+ }
+ },
"node_modules/util": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
@@ -21348,6 +21772,14 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/webpack-merge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
+ "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==",
+ "dependencies": {
+ "lodash": "^4.17.15"
+ }
+ },
"node_modules/webpack-sources": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
@@ -23332,6 +23764,18 @@
"minimist": "^1.2.0"
}
},
+ "@craco/craco": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/@craco/craco/-/craco-6.4.2.tgz",
+ "integrity": "sha512-egIooyvuzKM5dsvWe/U5ISyFpZwLnG9uuTF1fU4s/6b/hE8MvoxyaxKymQKgbtpfOZeH0ebtEP4cbH7xZ4XRbw==",
+ "requires": {
+ "cosmiconfig": "^7.0.1",
+ "cross-spawn": "^7.0.0",
+ "lodash": "^4.17.15",
+ "semver": "^7.3.2",
+ "webpack-merge": "^4.2.2"
+ }
+ },
"@csstools/convert-colors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz",
@@ -24600,7 +25044,6 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
- "dev": true,
"requires": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
@@ -24800,6 +25243,15 @@
"csstype": "^3.0.2"
}
},
+ "@types/react-beautiful-dnd": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.2.tgz",
+ "integrity": "sha512-+OvPkB8CdE/bGdXKyIhc/Lm2U7UAYCCJgsqmopFmh9gbAudmslkI8eOrPDjg4JhwSE6wytz4a3/wRjKtovHVJg==",
+ "dev": true,
+ "requires": {
+ "@types/react": "*"
+ }
+ },
"@types/react-dom": {
"version": "17.0.11",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
@@ -24817,6 +25269,17 @@
"@types/react": "*"
}
},
+ "@types/react-redux": {
+ "version": "7.1.20",
+ "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz",
+ "integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==",
+ "requires": {
+ "@types/hoist-non-react-statics": "^3.3.0",
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0",
+ "redux": "^4.0.0"
+ }
+ },
"@types/react-router": {
"version": "5.1.17",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz",
@@ -27092,6 +27555,14 @@
"postcss": "^7.0.5"
}
},
+ "css-box-model": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
+ "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
+ "requires": {
+ "tiny-invariant": "^1.0.6"
+ }
+ },
"css-color-keywords": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
@@ -27900,6 +28371,11 @@
}
}
},
+ "email-addresses": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
+ "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg=="
+ },
"emittery": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz",
@@ -29083,6 +29559,21 @@
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"optional": true
},
+ "filename-reserved-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
+ "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik="
+ },
+ "filenamify": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
+ "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
+ "requires": {
+ "filename-reserved-regex": "^2.0.0",
+ "strip-outer": "^1.0.1",
+ "trim-repeated": "^1.0.0"
+ }
+ },
"filesize": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@@ -29366,6 +29857,27 @@
"map-cache": "^0.2.2"
}
},
+ "framer-motion": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-5.4.1.tgz",
+ "integrity": "sha512-U4hiU3g5RCaZRTtTTOKStXH1jm+8uiIhM46wjIYQ7fWnc5c1cGlAzo238X7AM3WhU//jtqd1l5EHq32x96Eg4g==",
+ "requires": {
+ "@emotion/is-prop-valid": "^0.8.2",
+ "framesync": "6.0.1",
+ "hey-listen": "^1.0.8",
+ "popmotion": "11.0.3",
+ "style-value-types": "5.0.0",
+ "tslib": "^2.1.0"
+ }
+ },
+ "framesync": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz",
+ "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==",
+ "requires": {
+ "tslib": "^2.1.0"
+ }
+ },
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -29483,6 +29995,106 @@
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
"integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
},
+ "gh-pages": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.2.3.tgz",
+ "integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==",
+ "requires": {
+ "async": "^2.6.1",
+ "commander": "^2.18.0",
+ "email-addresses": "^3.0.1",
+ "filenamify": "^4.3.0",
+ "find-cache-dir": "^3.3.1",
+ "fs-extra": "^8.1.0",
+ "globby": "^6.1.0"
+ },
+ "dependencies": {
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ },
+ "find-cache-dir": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
+ "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^3.0.2",
+ "pkg-dir": "^4.1.0"
+ }
+ },
+ "fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "requires": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+ "requires": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "requires": {
+ "semver": "^6.0.0"
+ }
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ },
+ "pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "requires": {
+ "find-up": "^4.0.0"
+ }
+ },
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ },
+ "universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
+ }
+ }
+ },
"glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
@@ -29570,6 +30182,11 @@
"pify": "^4.0.1"
}
},
+ "hamt_plus": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz",
+ "integrity": "sha1-4hwlKWjH4zsg9qGwlM2FeHomVgE="
+ },
"handle-thing": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
@@ -29704,6 +30321,11 @@
"resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
"integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
},
+ "hey-listen": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
+ "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
+ },
"history": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
@@ -32253,6 +32875,11 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
+ "memoize-one": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
+ "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
+ },
"memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
@@ -33334,6 +33961,17 @@
"ts-pnp": "^1.1.6"
}
},
+ "popmotion": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz",
+ "integrity": "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==",
+ "requires": {
+ "framesync": "6.0.1",
+ "hey-listen": "^1.0.8",
+ "style-value-types": "5.0.0",
+ "tslib": "^2.1.0"
+ }
+ },
"portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -34576,6 +35214,11 @@
"performance-now": "^2.1.0"
}
},
+ "raf-schd": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
+ "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ=="
+ },
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -34646,6 +35289,20 @@
"whatwg-fetch": "^3.4.1"
}
},
+ "react-beautiful-dnd": {
+ "version": "13.1.0",
+ "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz",
+ "integrity": "sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==",
+ "requires": {
+ "@babel/runtime": "^7.9.2",
+ "css-box-model": "^1.2.0",
+ "memoize-one": "^5.1.1",
+ "raf-schd": "^4.0.2",
+ "react-redux": "^7.2.0",
+ "redux": "^4.0.4",
+ "use-memo-one": "^1.1.1"
+ }
+ },
"react-dev-utils": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
@@ -34770,6 +35427,12 @@
"react-side-effect": "^2.1.0"
}
},
+ "react-hook-form": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.20.5.tgz",
+ "integrity": "sha512-xYeBmQW6oqxDYAYVWIoZYC7tRD6lJBJt9b8Rr1Mv/VhZ+ZUCy2IuXlm2YA9i0/zl0TKKxqBWQOxGEb3qyVIhMg==",
+ "requires": {}
+ },
"react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -34785,6 +35448,29 @@
"match-sorter": "^6.0.2"
}
},
+ "react-redux": {
+ "version": "7.2.6",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz",
+ "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==",
+ "requires": {
+ "@babel/runtime": "^7.15.4",
+ "@types/react-redux": "^7.1.20",
+ "hoist-non-react-statics": "^3.3.2",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.7.2",
+ "react-is": "^17.0.2"
+ },
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.16.3",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz",
+ "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ }
+ }
+ },
"react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@@ -35031,6 +35717,14 @@
"picomatch": "^2.2.1"
}
},
+ "recoil": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.5.2.tgz",
+ "integrity": "sha512-Edibzpu3dbUMLy6QRg73WL8dvMl9Xqhp+kU+f2sJtXxsaXvAlxU/GcnDE8HXPkprXrhHF2e6SZozptNvjNF5fw==",
+ "requires": {
+ "hamt_plus": "1.0.2"
+ }
+ },
"recursive-readdir": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz",
@@ -35048,6 +35742,14 @@
"strip-indent": "^3.0.0"
}
},
+ "redux": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz",
+ "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==",
+ "requires": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
"regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -36648,6 +37350,14 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
},
+ "strip-outer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+ "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "requires": {
+ "escape-string-regexp": "^1.0.2"
+ }
+ },
"style-loader": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
@@ -36657,6 +37367,15 @@
"schema-utils": "^2.7.0"
}
},
+ "style-value-types": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz",
+ "integrity": "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==",
+ "requires": {
+ "hey-listen": "^1.0.8",
+ "tslib": "^2.1.0"
+ }
+ },
"styled-components": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz",
@@ -37244,6 +37963,14 @@
"punycode": "^2.1.1"
}
},
+ "trim-repeated": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+ "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
+ "requires": {
+ "escape-string-regexp": "^1.0.2"
+ }
+ },
"tryer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
@@ -37577,6 +38304,12 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
},
+ "use-memo-one": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz",
+ "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==",
+ "requires": {}
+ },
"util": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
@@ -38746,6 +39479,14 @@
}
}
},
+ "webpack-merge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
+ "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==",
+ "requires": {
+ "lodash": "^4.17.15"
+ }
+ },
"webpack-sources": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
diff --git a/package.json b/package.json
index 8ac911a..cf87862 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@craco/craco": "^6.4.2",
"@testing-library/jest-dom": "^5.15.1",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
@@ -11,22 +12,29 @@
"@types/react": "^17.0.36",
"@types/react-dom": "^17.0.11",
"apexcharts": "^3.31.0",
+ "framer-motion": "^5.4.1",
+ "gh-pages": "^3.2.3",
"react": "^17.0.2",
"react-apexcharts": "^1.3.9",
+ "react-beautiful-dnd": "^13.1.0",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
+ "react-hook-form": "^7.20.5",
"react-query": "^3.33.5",
"react-router-dom": "^5.3.0",
"react-scripts": "4.0.3",
+ "recoil": "^0.5.2",
"styled-components": "^5.3.3",
"typescript": "^4.5.2",
"web-vitals": "^1.1.2"
},
"scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
- "eject": "react-scripts eject"
+ "start": "craco start",
+ "build": "craco build",
+ "test": "craco test",
+ "eject": "react-scripts eject",
+ "deploy": "gh-pages -d build",
+ "predeploy": "npm run build"
},
"eslintConfig": {
"extends": [
@@ -47,8 +55,10 @@
]
},
"devDependencies": {
+ "@types/react-beautiful-dnd": "^13.1.2",
"@types/react-helmet": "^6.1.4",
"@types/react-router-dom": "^5.3.2",
"@types/styled-components": "^5.1.15"
- }
+ },
+ "homepage": "https://gilpop8663.github.io/reactmaster"
}
diff --git a/public/index.html b/public/index.html
index aa069f2..cd1454b 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2,7 +2,10 @@
-
+
- React App
+ Nomflix
diff --git a/src/App.tsx b/src/App.tsx
index 03074c7..6225adb 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,73 +1,36 @@
-import Router from "./Router";
-import { createGlobalStyle } from "styled-components";
-import { ReactQueryDevtools } from "react-query/devtools";
-
-const GlobalStyle = createGlobalStyle`
-@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400&display=swap');
-html, body, div, span, applet, object, iframe,
-h1, h2, h3, h4, h5, h6, p, blockquote, pre,
-a, abbr, acronym, address, big, cite, code,
-del, dfn, em, img, ins, kbd, q, s, samp,
-small, strike, strong, sub, sup, tt, var,
-b, u, i, center,
-dl, dt, dd, ol, ul, li,
-fieldset, form, label, legend,
-table, caption, tbody, tfoot, thead, tr, th, td,
-article, aside, canvas, details, embed,
-figure, figcaption, footer, header, hgroup,
-menu, nav, output, ruby, section, summary,
-time, mark, audio, video {
- margin: 0;
- padding: 0;
- border: 0;
- font-size: 100%;
- font: inherit;
- vertical-align: baseline;
-}
-/* HTML5 display-role reset for older browsers */
-article, aside, details, figcaption, figure,
-footer, header, hgroup, menu, nav, section {
- display: block;
-}
-body {
- line-height: 1;
-}
-ol, ul {
- list-style: none;
-}
-blockquote, q {
- quotes: none;
-}
-blockquote:before, blockquote:after,
-q:before, q:after {
- content: '';
- content: none;
-}
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
-*{
- box-sizing: border-box;
-}
-a{
- text-decoration: none;
- color:inherit;
-}
-
-body{
- font-family: 'Source Sans Pro', sans-serif;
- background-color: ${(props) => props.theme.bgColor};
- color:${(props) => props.theme.textColor}
-}
-`;
+import { Helmet } from "react-helmet";
+import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
+import Header from "./Components/Header";
+import Home from "./Routes/Home";
+import Search from "./Routes/Search";
+// import Search from "./Routes/Search";
+import Tv from "./Routes/Tv";
function App() {
return (
<>
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
>
);
}
diff --git a/src/Components/BannerScreen.tsx b/src/Components/BannerScreen.tsx
new file mode 100644
index 0000000..d98f847
--- /dev/null
+++ b/src/Components/BannerScreen.tsx
@@ -0,0 +1,129 @@
+import { motion } from "framer-motion";
+import { useState } from "react";
+import { useQuery } from "react-query";
+import styled from "styled-components";
+import { getVideoDetail, IGetVideoDetail, IGetVideosProps } from "../api";
+import { makeImageHelper } from "../utils";
+
+const Banner = styled(motion.iframe)<{
+ bgPhoto: string;
+ userWidth: number;
+ over?: boolean;
+}>`
+ background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1)),
+ url(${(props) => props.bgPhoto});
+ background-size: cover;
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ width: 100%;
+ aspect-ratio: 16/9;
+ background-position: center center;
+ z-index: 1;
+`;
+
+const Wrapper = styled.div`
+ flex-direction: column;
+ top: 40vh;
+ display: flex;
+ justify-content: center;
+ align-content: center;
+ position: absolute;
+ padding: 60px;
+ z-index: 0;
+`;
+
+const Title = styled.h2`
+ font-size: 64px;
+ margin-bottom: 20px;
+`;
+
+const Overview = styled.p`
+ font-size: 34px;
+ width: 80%;
+`;
+
+interface IBanner {
+ videoData: IGetVideosProps;
+ isWhat: string;
+}
+
+function BannerScreen({ videoData, isWhat }: IBanner) {
+ const [over, setOver] = useState(false);
+
+ const detailData = useQuery(["video", "detail"], () =>
+ getVideoDetail("movie", videoData.results[0].id + "")
+ );
+ //console.log(detailData.data?.videos.results);
+ const teasearVideo = detailData.data?.videos.results.find(
+ (item) => item.type === "Teaser"
+ );
+ const trailerVideo = detailData.data?.videos.results.find(
+ (item) => item.type === "Trailer"
+ );
+ const openingVideo = detailData.data?.videos.results.find(
+ (item) => item.type === "Opening Credits"
+ );
+
+ const detailVideo = teasearVideo
+ ? teasearVideo
+ : trailerVideo
+ ? trailerVideo
+ : openingVideo;
+ const mouseEnter = (event: any) => {
+ setOver(true);
+ };
+ const mouseLeave = () => {
+ setOver(false);
+ };
+ return (
+ <>
+ {detailVideo ? (
+
+ ) : (
+
+ )}
+ {!over && (
+
+
+ {isWhat === "movie" && videoData.results[0].title}
+ {isWhat === "tv" && videoData.results[0].name}
+
+ {videoData.results[0].overview}
+
+ )}
+ >
+ );
+}
+
+export default BannerScreen;
diff --git a/src/Components/ClickMovie.tsx b/src/Components/ClickMovie.tsx
new file mode 100644
index 0000000..abb0c15
--- /dev/null
+++ b/src/Components/ClickMovie.tsx
@@ -0,0 +1,762 @@
+import {
+ AnimatePresence,
+ motion,
+ useViewportScroll,
+ Variants,
+} from "framer-motion";
+import { useEffect, useState } from "react";
+import { useQuery } from "react-query";
+import { useHistory, useLocation, useRouteMatch } from "react-router-dom";
+import styled from "styled-components";
+import {
+ getSimilarData,
+ getVideoCredit,
+ getVideoDetail,
+ IGetVideoDetail,
+ IMovie,
+ ISimilarProps,
+ IVideoCredit,
+} from "../api";
+import { makeImageHelper } from "../utils";
+
+const Loader = styled.div`
+ width: 100%;
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 48px;
+`;
+
+const Overlay = styled(motion.div)`
+ position: fixed;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.3);
+ opacity: 0;
+`;
+
+const BigMovie = styled(motion.div)`
+ position: absolute;
+ width: 40vw;
+ left: 0;
+ right: 0;
+ margin: 0 auto;
+ overflow: hidden;
+ border-radius: 15px;
+ min-width: 426px;
+ background-color: ${(props) => props.theme.black.veryDark};
+`;
+
+const DisableCover = styled.div<{ isOver: boolean }>`
+ width: 100%;
+ height: 400px;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ margin: 0 auto;
+ z-index: ${(props) => (props.isOver ? 100 : -2)};
+`;
+
+const BigCover = styled(motion.iframe)<{ bgPhoto?: string; userWidth: number }>`
+ background-image: linear-gradient(to top, black, transparent),
+ url(${(props) => props.bgPhoto});
+ background-size: cover;
+ top: 0;
+ right: 0;
+ left: 0;
+ margin: 0 auto;
+ aspect-ratio: 16/9;
+ width: 100%;
+ background-position: center center;
+ height: ${(props) =>
+ props.userWidth > 3840
+ ? 2160
+ : props.userWidth > 2560
+ ? 1440
+ : props.userWidth > 1920
+ ? 1080
+ : props.userWidth > 1280
+ ? 720
+ : props.userWidth > 854
+ ? 480
+ : props.userWidth > 640
+ ? 360
+ : 240};
+
+ border: none;
+`;
+
+const BigContainer = styled(motion.div)`
+ padding: 50px;
+ top: -230px;
+ position: relative;
+`;
+
+const BigTitle = styled.h3`
+ color: ${(props) => props.theme.white.lighter};
+ font-size: 48px;
+ position: relative;
+ margin-bottom: 50px;
+`;
+
+const BigOverview = styled.p`
+ color: ${(props) => props.theme.white.lighter};
+ position: relative;
+ margin-bottom: 100px;
+ font-size: 19px;
+ font-weight: 400;
+ line-height: 25px;
+ width: 80%;
+`;
+
+const DetailGrid = styled.div`
+ display: grid;
+ grid-template-columns: 5fr 2fr;
+`;
+
+const DetailBox = styled.div`
+ display: flex;
+ flex-direction: column;
+`;
+
+const UserBox = styled.div`
+ display: flex;
+ align-items: center;
+ margin-bottom: 60px;
+`;
+
+const PlayCircle = styled.div`
+ width: 40px;
+ margin-left: 10px;
+ height: 40px;
+ border-radius: 20px;
+ border: 2px solid ${(props) => props.theme.white.darker};
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: ${(props) => props.theme.white.lighter};
+ font-size: 18px;
+ font-weight: 100;
+ i {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+`;
+
+const Playbox = styled.div`
+ width: 150px;
+ display: flex;
+ height: 40px;
+ justify-content: center;
+ align-items: center;
+ color: black;
+ font-size: 18px;
+ font-weight: 600;
+ border-radius: 5px;
+ background-color: ${(props) => props.theme.white.lighter};
+ i {
+ margin-right: 10px;
+ }
+`;
+
+const InfoBox = styled.div`
+ display: flex;
+ align-items: flex-start;
+ flex-wrap: wrap;
+ margin-bottom: 20px;
+`;
+
+const InfoSpan = styled.div`
+ font-size: 14px;
+ color: ${(props) => props.theme.white.veryDark};
+`;
+
+const MovieInfoTop = styled.span`
+ color: ${(props) => props.theme.white.darker};
+ margin-left: 5px;
+ font-size: 16px;
+ font-weight: 400;
+`;
+
+const MovieInfo = styled.span`
+ color: ${(props) => props.theme.white.darker};
+ margin-left: 5px;
+ display: flex;
+ line-height: 18px;
+ align-items: center;
+`;
+
+const MoiveAverage = styled.span`
+ font-weight: 600;
+ color: #42c262;
+ font-size: 16px;
+ margin-bottom: 10px;
+`;
+
+const MoreBox = styled.div`
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 20px;
+ grid-template-rows: repeat(3, minmax(100px, 1fr));
+ width: 100%;
+`;
+
+const MoreMovie = styled.div`
+ cursor: pointer;
+ width: 100%;
+ border-radius: 10px;
+
+ background-color: ${(props) => props.theme.black.lighter};
+ color: ${(props) => props.theme.white.darker};
+`;
+const MoreCover = styled.div<{ bgPhoto: string }>`
+ background-image: url(${(props) => props.bgPhoto});
+ background-position: center center;
+ background-size: cover;
+ height: 180px;
+ border-top-left-radius: 10px;
+ border-top-right-radius: 10px;
+ margin-bottom: 10px;
+`;
+
+const MoreInfoBox = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ padding: 15px;
+`;
+
+const MoreInfo = styled.span`
+ display: flex;
+ margin-bottom: 10px;
+ font-size: 14px;
+ align-items: center;
+ line-height: 18px;
+`;
+
+const MoreTitle = styled.span`
+ margin-bottom: 10px;
+ display: flex;
+ font-weight: 600;
+ font-size: 16px;
+ line-height: 20px;
+ color: ${(props) => props.theme.white.lighter};
+`;
+
+interface IClickMovie {
+ bigVideoMatch: { params?: { movieId?: string | null; tvId?: string | null } };
+ videoData: IMovie[];
+ isWhat: string;
+ search?: string;
+ keyword?: string;
+ unqKey: string;
+}
+
+const opacityV: Variants = {
+ normal: {
+ opacity: 1,
+ },
+ entry: {
+ opacity: 0,
+ },
+ exit: {
+ opacity: 0,
+ },
+};
+
+function ClickMovie({
+ bigVideoMatch,
+ isWhat,
+ videoData,
+ search,
+ keyword,
+ unqKey,
+}: IClickMovie) {
+ //console.log(videoData);
+ const history = useHistory();
+ const { scrollY } = useViewportScroll();
+ const [over, setOver] = useState(false);
+ const [clicked, setClicked] = useState(false);
+ useEffect(() => {
+ setClicked(false);
+ }, [clicked]);
+ // console.log(history);
+ const location = useLocation();
+ const movieKeyword: string = new URLSearchParams(location.search).get(
+ "movies"
+ )
+ ? String(new URLSearchParams(location.search).get("movies"))
+ : "";
+
+ const tvKeyword: string = new URLSearchParams(location.search).get("tv")
+ ? String(new URLSearchParams(location.search).get("tv"))
+ : "";
+
+ const searchKeyword = movieKeyword ? movieKeyword : tvKeyword;
+
+ const movieSearch = bigVideoMatch?.params?.movieId
+ ? bigVideoMatch?.params.movieId
+ : searchKeyword;
+
+ // console.log(movieSearch);
+
+ const tvSearch = bigVideoMatch?.params?.tvId
+ ? bigVideoMatch.params.tvId
+ : searchKeyword;
+
+ const isSearch = movieSearch ? movieSearch : tvSearch;
+ // console.log(
+ // `isSearch: ${isSearch}, movieSearch : ${movieSearch}, tvSearch : ${tvSearch}`
+ // );
+ //console.log(isSearch);
+ const backUrl = `${location.pathname}?keyword=${keyword}`;
+ //console.log(location.pathname);
+ // console.log(backUrl);
+ const onOverlayClicked = () => {
+ setOver(false);
+ if (!search) {
+ if (isWhat === "movie") {
+ history.push("/");
+ } else if (isWhat === "tv") {
+ history.push("/tv");
+ }
+ } else {
+ history.push(`${backUrl}`);
+ }
+ //history.push(location);
+ };
+
+ const creditData = useQuery(["video", "credit"], () =>
+ getVideoCredit(isWhat, isSearch)
+ );
+
+ const similarData = useQuery(["video", "similar"], () =>
+ getSimilarData(isWhat, isSearch)
+ );
+
+ //console.log(similarData.data?.results);
+ //console.log(clicked);
+ // const { data } = useQuery(["movies", "video"], () =>
+ // getVideo(bigVideoMatch=.params.movieId)
+ // );
+
+ //console.log(similarMovieData);
+ // console.log(isSearch, creditData.data);
+ //console.log(similarData.data?.results[0].id);
+ // const clickedData =
+ // bigVideoMatch=params.movieId &&
+ // movieData.find((item) => item.id === +bigVideoMatch=params.movieId)
+ // ? movieData.find((item) => item.id === +bigVideoMatch=params.movieId)
+ // : similarData?.data?.results?.find(
+ // (item) => item.id === +bigVideoMatch=params.movieId
+ // );
+ const similarMovieMatch = useRouteMatch<{ movieId: string }>(
+ !search ? `/movies/:movieId` : `undefined`
+ );
+
+ const similarTvMatch = useRouteMatch<{ tvId: string }>(
+ !search ? `/tv/:tvId` : `undefined`
+ );
+
+ const locationTv = {
+ params: {
+ tvId: new URLSearchParams(location.search).get("tv"),
+ },
+ };
+ // console.log(locationTv);
+ const locationMovie = {
+ params: {
+ movieId: new URLSearchParams(location.search).get("movies"),
+ },
+ };
+
+ const similarMatch = similarMovieMatch ? similarMovieMatch : similarTvMatch;
+
+ const detailData = useQuery(["videos", "detail"], () =>
+ getVideoDetail(isWhat, isSearch)
+ );
+ console.log(isSearch);
+ const clickedData = videoData.find((item) => item.id === +isSearch)
+ ? videoData.find((item) => item.id === +isSearch)
+ : detailData.data;
+
+ const teasearVideo = detailData.data?.videos.results.find(
+ (item) => item.type === "Teaser"
+ );
+ const trailerVideo = detailData.data?.videos.results.find(
+ (item) => item.type === "Trailer"
+ );
+
+ const openingVideo = detailData.data?.videos.results.find(
+ (item) => item.type === "Opening Credits"
+ );
+
+ const detailVideo = teasearVideo
+ ? teasearVideo
+ : trailerVideo
+ ? trailerVideo
+ : openingVideo;
+ // console.log(clickedData);
+ const mouseEnter = (event: any) => {
+ setOver(true);
+ };
+ //console.log(similarMatch, similarMovieMatch, similarTvMatch);
+ //console.log(similarMovieMatch, similarMatch);
+ //console.log(similarTvMatch);
+ //console.log(data, isLoading);
+ //console.log(detailData.data);
+ //console.log(similarData.data?.results[0]);
+ //console.log(bigVideoMatch=params.movieId);
+ const onBoxClicked = (id: number) => {
+ setOver(false);
+ setClicked(true);
+ if (!search) {
+ if (isWhat === "movie") {
+ history.push(`/movies/${id}`);
+ } else if (isWhat === "tv") {
+ history.push(`/tv/${id}`);
+ }
+ } else if (search) {
+ if (isWhat === "movie") {
+ history.push(`${location.pathname}?keyword=${keyword}&movies=${id}`);
+ } else if (isWhat === "tv") {
+ history.push(`${location.pathname}?keyword=${keyword}&tv=${id}`);
+ }
+ }
+ };
+
+ // console.log(detailData.data?.videos.results[0].type);
+ //console.log(clickedData?.poster_path);
+ //console.log(clickedData);
+ // console.log("무비ㅏ아이디임", movieId);
+ // console.log(
+ // "시밀러 데이터 :",
+ // similarData.data?.results,
+ // "클릭임:",
+ // clicked,
+ // "시밀러맷치",
+ // similarMatch
+ // );
+ //console.log(clickedData);
+ return (
+ <>
+ {detailData.isLoading ? (
+ Loading...
+ ) : (
+ <>
+
+ {clickedData && (
+
+ )}
+ {clickedData && (
+
+ <>
+ {detailVideo ? (
+
+ ) : (
+
+ )}
+
+
+
+ {isWhat === "movie"
+ ? clickedData.title
+ : clickedData.name}
+
+
+
+
+ 재생
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {clickedData.vote_average
+ ? `${(clickedData.vote_average * 10).toFixed(
+ 0
+ )}% 일치`
+ : ""}
+
+
+ {isWhat === "movie" && clickedData?.release_date
+ ? clickedData?.release_date.slice(0, 4)
+ : clickedData.first_air_date?.slice(0, 4)}
+ 년
+
+
+ {detailData.data?.runtime === 0 ||
+ detailData.data?.runtime === null ||
+ detailData.data?.runtime === undefined
+ ? ""
+ : `${detailData.data?.runtime}분`}
+
+
+
+ {clickedData.overview}
+
+
+ {detailData.data?.genres &&
+ creditData.data?.crew &&
+ creditData.data?.cast && (
+
+
+
+ 장르:
+
+ {detailData.data?.genres?.map((item: any) => (
+
+ {item.name},
+
+ ))}
+
+
+
+
+ 출연진:
+
+
+ {creditData.data?.cast[0]
+ ? `${creditData.data?.cast[0].name},`
+ : ""}
+
+
+ {creditData.data?.cast[1]
+ ? `${creditData.data?.cast[1].name},`
+ : ""}
+
+
+ {creditData.data?.cast[2]
+ ? `${creditData.data?.cast[2].name}`
+ : ""}
+
+
+
+
+ 크리에이터:
+
+
+ {creditData.data?.crew[0]
+ ? `${creditData.data?.crew[0].name},`
+ : ""}
+
+
+ {creditData.data?.crew[1]
+ ? `${creditData.data?.crew[1].name},`
+ : ""}
+
+
+ {creditData.data?.crew[2]
+ ? `${creditData.data?.crew[2].name}`
+ : ""}
+
+
+
+ )}
+
+
+ {similarData?.data?.results && (
+
+ {similarData.data?.results[9] &&
+ Array.from({ length: 9 }, (v, i) => i).map((item) => (
+
+ onBoxClicked(
+ similarData?.data
+ ? similarData?.data?.results[item].id
+ : 0
+ )
+ }
+ >
+ {(similarMatch || search) &&
+ similarData.data?.results && (
+
+ )}
+
+
+ {isWhat === "movie"
+ ? similarData.data?.results[item].title
+ : similarData.data?.results[item].name}
+
+
+ {similarData.data?.results[item].vote_average
+ ? `${(
+ similarData.data?.results[item]
+ .vote_average * 10
+ ).toFixed(0)}%일치`
+ : ""}
+
+
+ {similarData.data?.results[item].overview && (
+
+ {similarData.data?.results[item].overview
+ .length > 200
+ ? `${similarData.data?.results[
+ item
+ ].overview.slice(0, 200)}...`
+ : similarData.data?.results[item]
+ .overview}
+
+ )}
+
+
+ ))}
+
+ )}
+
+ >
+
+ )}
+ )
+
+ <>
+ {similarData.data?.results &&
+ clicked &&
+ (similarMovieMatch ||
+ (locationMovie?.params?.movieId
+ ? locationMovie?.params?.movieId === isSearch
+ : false) ? (
+
+ ) : (
+ similarData.data?.results &&
+ clicked &&
+ (similarTvMatch ||
+ (locationTv?.params?.tvId
+ ? locationTv?.params?.tvId === isSearch
+ : false)) && (
+
+ )
+ ))}
+ >
+ )
+ >
+ )}
+ >
+ );
+}
+
+export default ClickMovie;
diff --git a/src/Components/Footer.tsx b/src/Components/Footer.tsx
new file mode 100644
index 0000000..f16c6c6
--- /dev/null
+++ b/src/Components/Footer.tsx
@@ -0,0 +1,85 @@
+import styled from "styled-components";
+
+const Wrapper = styled.div`
+ width: 100vw;
+ height: 20vh;
+ display: flex;
+ background-color: ${(props) => props.theme.black.darker};
+ flex-direction: column;
+ justify-content: center;
+ align-content: center;
+`;
+
+const Copy = styled.span`
+ text-align: center;
+`;
+
+const Icons = styled.div`
+ margin-top: 15px;
+ display: flex;
+ justify-content: space-between;
+ align-content: center;
+ height: 5vh;
+ padding-left: 45vw;
+ padding-right: 45vw;
+`;
+const Icon = styled.a`
+ display: flex;
+ flex-direction: column;
+ height: 30px;
+ justify-content: center;
+ align-content: center;
+ width: 30px;
+ &:hover {
+ }
+
+ span {
+ text-align: center;
+ }
+ i {
+ display: flex;
+ justify-content: center;
+ align-content: center;
+ }
+`;
+
+const NomarImg = styled.img`
+ height: 20px;
+ display: flex;
+ justify-content: center;
+ align-content: center;
+`;
+
+function Footer() {
+ return (
+
+ © 2021 - Kim Young Gil, All rights reserved.
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default Footer;
diff --git a/src/Components/Header.tsx b/src/Components/Header.tsx
new file mode 100644
index 0000000..ea33498
--- /dev/null
+++ b/src/Components/Header.tsx
@@ -0,0 +1,187 @@
+import {
+ motion,
+ useAnimation,
+ useViewportScroll,
+ Variants,
+} from "framer-motion";
+import { useEffect, useState } from "react";
+import { useForm } from "react-hook-form";
+import { useHistory, useRouteMatch } from "react-router";
+import { Link } from "react-router-dom";
+import styled from "styled-components";
+
+const Nav = styled(motion.div)`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ position: fixed;
+ width: 100%;
+ top: 0;
+ background-color: black;
+ font-size: 14px;
+ padding: 20px 60px;
+ color: white;
+ z-index: 2;
+`;
+
+const Col = styled.div`
+ display: flex;
+ align-items: center;
+`;
+
+const Logo = styled(motion.svg)`
+ margin-right: 50px;
+ width: 95px;
+ height: 25px;
+ fill: ${(props) => props.theme.red};
+
+ path {
+ stroke-width: 6px;
+ stroke: white;
+ }
+`;
+
+const Circle = styled(motion.span)`
+ width: 5px;
+ height: 5px;
+ border-radius: 2.5px;
+ background-color: ${(props) => props.theme.red};
+ position: absolute;
+ bottom: -10px;
+ left: 0;
+ right: 0;
+ margin: 0 auto;
+`;
+
+const Items = styled.ul`
+ display: flex;
+ align-items: center;
+`;
+
+const Item = styled.li`
+ margin-right: 20px;
+ color: ${(props) => props.theme.white.darker};
+ transition: color 0.3s ease-in-out;
+ position: relative;
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ &:hover {
+ color: ${(props) => props.theme.white.lighter};
+ }
+`;
+
+const Search = styled.form`
+ color: white;
+ position: relative;
+ display: flex;
+ align-items: center;
+ svg {
+ height: 25px;
+ }
+`;
+
+const Input = styled(motion.input)`
+ transform-origin: right center;
+ position: absolute;
+ padding: 5px 10px;
+ right: 0;
+ padding-left: 40px;
+ z-index: -1;
+ color: white;
+ font-size: 16px;
+ background-color: transparent;
+ border: 1px solid ${(props) => props.theme.white.lighter};
+`;
+
+const LogoVariants: Variants = {
+ normal: { fillOpacity: 1 },
+ active: { fillOpacity: [0, 1, 0], transition: { repeat: Infinity } },
+};
+
+interface IForm {
+ keyword: string;
+}
+
+function Header() {
+ const { register, handleSubmit } = useForm();
+ const history = useHistory();
+ const [openSearch, setOpenSearch] = useState(false);
+ const homeMatch = useRouteMatch("/");
+ const tvMatch = useRouteMatch("/tv");
+ const navAnimation = useAnimation();
+ // console.log(homeMatch, tvMatch);
+ const { scrollY } = useViewportScroll();
+ const toggleSearch = () => {
+ setOpenSearch((current) => !current);
+ };
+ useEffect(() => {
+ scrollY.onChange(() => {
+ if (scrollY.get() > 80) {
+ navAnimation.start({ backgroundColor: "rgba(0,0,0,1)" });
+ } else {
+ navAnimation.start({ backgroundColor: "rgba(0,0,0,0)" });
+ }
+ });
+ }, [scrollY, navAnimation]);
+ const onValid = (data: IForm) => {
+ //console.log(data);
+ history.push(`/search?keyword=${data.keyword}`);
+ };
+ return (
+
+ );
+}
+
+export default Header;
diff --git a/src/Components/NowMovies.tsx b/src/Components/NowMovies.tsx
new file mode 100644
index 0000000..79f4f3c
--- /dev/null
+++ b/src/Components/NowMovies.tsx
@@ -0,0 +1,429 @@
+import { AnimatePresence, motion, Variants } from "framer-motion";
+import React, { useState } from "react";
+import { useHistory, useLocation, useRouteMatch } from "react-router-dom";
+import styled from "styled-components";
+import { IMovie } from "../api";
+import { makeImageHelper } from "../utils";
+import ClickMovie from "./ClickMovie";
+
+const Slider = styled.div`
+ position: relative;
+ height: 180px;
+ top: -170px;
+ margin-bottom: 70px;
+`;
+
+const Row = styled(motion.div)<{ isFirst: number; hover: boolean }>`
+ display: grid;
+ grid-template-columns: ${(props) =>
+ props.hover === false
+ ? "repeat(6, 1fr) 0.2fr"
+ : "0.2fr repeat(6, 1fr) 0.2fr"};
+ gap: 5px;
+ width: 100%;
+ margin-top: 16px;
+ padding: ${(props) =>
+ props.hover === false ? "0px 0px 0px 65px" : "0px 0px 0px 0px"};
+ position: absolute;
+`;
+
+const Box = styled(motion.div)<{ hover?: boolean; bgPhoto: string }>`
+ background-color: white;
+ height: 180px;
+ font-size: 66px;
+ background-image: ${(props) =>
+ props.bgPhoto === `https://image.tmdb.org/t/p/w500/`
+ ? `url(
+ "https://img.freepik.com/vector-gratis/signo-exclamacion-blanco-circulo-rojo-aislado-sobre-fondo-blanco_120819-332.jpg?size=338&ext=jpg"
+ )`
+ : `url(${props.bgPhoto})`};
+ background-position: center center;
+ background-size: cover;
+ cursor: pointer;
+ &:hover {
+ z-index: 2;
+ }
+ &:first-child {
+ transform-origin: ${(props) =>
+ props.hover ? "center left" : "center left"};
+ }
+ &:nth-child(2) {
+ transform-origin: ${(props) =>
+ props.hover ? "center left" : "center center"};
+ }
+ &:nth-child(6) {
+ transform-origin: ${(props) =>
+ props.hover ? "center center" : "center right"};
+ }
+ &:nth-child(7) {
+ transform-origin: ${(props) =>
+ props.hover ? "center right" : "center center"};
+ }
+`;
+
+const Archive = styled.span`
+ font-size: 32px;
+ font-weight: 600;
+ padding-left: 65px;
+`;
+
+const ArrowBtn = styled(motion.div)`
+ color: white;
+ z-index: 1;
+ width: 65px;
+ height: 185px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: absolute;
+ bottom: -50px;
+ i {
+ position: relative;
+ text-align: center;
+ }
+
+ &:first-child {
+ left: 0;
+ }
+ &:last-child {
+ right: 0;
+ }
+`;
+
+const Info = styled(motion.div)`
+ padding: 10px;
+ background-color: ${(props) => props.theme.black.lighter};
+ position: absolute;
+ width: 100%;
+ bottom: 0;
+ opacity: 0;
+ h4 {
+ font-size: 14px;
+ text-align: center;
+ }
+`;
+
+const ArchiveContainer = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-end;
+`;
+
+const IndexBoxs = styled.div`
+ display: flex;
+ padding-right: 65px;
+`;
+
+const IndexBox = styled(motion.div)<{ index: boolean }>`
+ width: 10px;
+ margin-left: 2px;
+ height: 2px;
+ background-color: ${(props) =>
+ props.index ? props.theme.white.lighter : props.theme.black.lighter};
+`;
+
+const rowVariants: Variants = {
+ hidden: (back: boolean) => ({
+ x: back ? window.outerWidth + 5 : -window.outerWidth - 5,
+ }),
+ visible: { x: 0 },
+ exit: (back: boolean) => ({
+ x: back ? -window.outerWidth - 5 : window.outerWidth + 5,
+ }),
+};
+
+const boxVariants: Variants = {
+ normal: { scale: 1, transition: { type: "tween" } },
+ hover: {
+ scale: 1.3,
+ y: -50,
+ transition: { delay: 0.5, duration: 0.3, type: "tween" },
+ },
+};
+
+const infoVariants: Variants = {
+ hover: {
+ opacity: 1,
+ transition: { delay: 0.5, duration: 0.1, type: "tween" },
+ },
+};
+
+const ArrowVariants: Variants = {
+ btnNormal: {
+ backgroundColor: "rgba(0,0,0,0.5)",
+ fontSize: "20px",
+ color: "rgba(255,255,255,0)",
+ },
+ btnHover: {
+ backgroundColor: "rgba(0, 0, 0, 0.9)",
+ fontSize: "30px",
+ color: "rgba(255,255,255,1)",
+ },
+ exit: {
+ opacity: 0,
+ },
+};
+
+const offset = 6;
+
+interface INowProps {
+ videoData: IMovie[];
+ sliderTitle?: string;
+ search?: string;
+ isWhat: string;
+ unqKey: string;
+}
+
+function NowMovies({
+ videoData,
+ sliderTitle,
+ search,
+ isWhat,
+ unqKey,
+}: INowProps) {
+ const history = useHistory();
+ const location = useLocation();
+ //console.log(pathName);
+ const [leaving, setLeaving] = useState(false);
+ const [rowHover, setRowHover] = useState(false);
+ const rowMouseEnterLeave = () => {
+ setRowHover((prev) => !prev);
+ };
+ const toggleLeaving = () => {
+ setLeaving((prev) => !prev);
+ };
+ const [back, setBack] = useState(false);
+ const [hover, setHover] = useState(false);
+ const [index, setIndex] = useState(0);
+ const totalMovies = videoData.length - 1;
+ const maxIndex = Math.floor(totalMovies / offset) - 1;
+ const decreaseIndex = () => {
+ if (videoData) {
+ if (leaving) return;
+ setBack(false);
+ toggleLeaving();
+
+ setIndex((prev) => (index === 0 ? maxIndex : prev - 1));
+ }
+ };
+ const increaseIndex = () => {
+ if (videoData) {
+ if (leaving) return;
+ setBack(true);
+ toggleLeaving();
+ setHover(true);
+ console.log("맥스인덱스 : ", maxIndex, "인덱스 : ", index);
+ setIndex((prev) => (index === maxIndex ? 0 : prev + 1));
+ }
+ };
+ let keyword = new URLSearchParams(location.search).get("keyword");
+ const onBoxClicked = (id: number) => {
+ //console.log(id);
+ if (!search) {
+ if (isWhat === "movie") {
+ history.push(`/movies/${id}`);
+ } else if (isWhat === "tv") {
+ history.push(`/tv/${id}`);
+ }
+ } else if (search) {
+ if (isWhat === "movie") {
+ history.push(`/search?keyword=${keyword}&movies=${id}`);
+ } else if (isWhat === "tv") {
+ history.push(`/search?keyword=${keyword}&tv=${id}`);
+ }
+ }
+ };
+ // console.log(isSearch);
+ const bigMovieMatch = useRouteMatch<{ movieId?: string }>(
+ !search ? `/movies/:movieId` : "undefined"
+ );
+
+ const bigTvMatch = useRouteMatch<{ tvId?: string }>(
+ !search ? `/tv/:tvId` : "undefined"
+ );
+
+ const locationTv = {
+ params: {
+ tvId: new URLSearchParams(location.search).get("tv"),
+ },
+ };
+ // console.log(locationTv);
+ const locationMovie = {
+ params: {
+ movieId: new URLSearchParams(location.search).get("movies"),
+ },
+ };
+
+ //console.log(locationTv, locationMovie);
+
+ return (
+ <>
+
+
+
+ {sliderTitle}
+
+ {rowHover &&
+ Array.from({ length: maxIndex + 1 }, (v, i) => i).map(
+ (item) => (
+
+ )
+ )}
+
+
+ {hover && (
+
+
+
+ )}
+
+ {hover === true ? (
+
+ ) : null}
+ {videoData
+ .slice(1)
+ .slice(offset * index, offset * index + offset)
+ .map((item) => (
+ onBoxClicked(item.id)}
+ hover={hover}
+ variants={boxVariants}
+ initial="normal"
+ whileHover="hover"
+ transition={{ type: "tween", duration: 0.1 }}
+ bgPhoto={makeImageHelper(
+ item.backdrop_path
+ ? item.backdrop_path
+ : item.poster_path
+ ? item.poster_path
+ : "",
+ "w500"
+ )}
+ key={item.id + unqKey}
+ >
+
+
+ {isWhat === "movie" ? item.title : item.name}
+
+
+
+ ))}
+ {index !== maxIndex ? (
+
+ ) : (
+
+ )}
+
+ (
+
+
+
+ )
+
+
+ {(locationMovie.params.movieId
+ ? locationMovie.params.movieId?.length >= 1
+ : false || bigMovieMatch) &&
+ isWhat === "movie" && (
+
+ )}
+ {(locationTv.params.tvId
+ ? locationTv.params.tvId?.length >= 1
+ : false || bigTvMatch) &&
+ isWhat === "tv" && (
+
+ )}
+ >
+ );
+}
+
+export default React.memo(NowMovies);
diff --git a/src/Router.tsx b/src/Router.tsx
deleted file mode 100644
index 8c86fa2..0000000
--- a/src/Router.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import { BrowserRouter, Switch, Route } from "react-router-dom";
-import Coin from "./Routes/Coin";
-import Coins from "./Routes/Coins";
-
-function Router() {
- return (
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-export default Router;
diff --git a/src/Routes/Chart.tsx b/src/Routes/Chart.tsx
deleted file mode 100644
index 1635057..0000000
--- a/src/Routes/Chart.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import { useQuery } from "react-query";
-import { fetchOHLCInfo } from "../api";
-import ApexChart from "react-apexcharts";
-import styled from "styled-components";
-
-interface ChartProps {
- coinId: string;
-}
-
-interface IHistorical {
- time_open: string;
- time_close: string;
- open: number;
- high: number;
- low: number;
- close: number;
- volume: number;
- market_cap: number;
-}
-
-const Container = styled.div`
- margin-top: 30px;
-`;
-
-function Chart({ coinId }: ChartProps) {
- const { isLoading, data } = useQuery(
- ["ohlc", coinId],
- () => fetchOHLCInfo(coinId),
- {
- refetchInterval: 10000,
- }
- );
- // console.log(
- // data?.map((item) => [item.open, item.high, item.low, item.close])
- // );
- // console.log(data?.map((item) => item.time_close.slice(5, 10)));
- //console.log(data?.map((item) => item.time_close[1]));
- //console.log(data);
- const arr = () =>
- data?.map((item) => {
- let x = item.time_close.slice(5, 10);
- let y = [
- item.open.toFixed(2),
- item.high.toFixed(2),
- item.low.toFixed(2),
- item.close.toFixed(2),
- ];
- //console.log(x);
- return { x: x, y: y };
- });
- // console.log(arr());
- return (
-
- {isLoading ? (
- "Loading Chart ..."
- ) : (
-
- )}
-
- );
-}
-
-export default Chart;
diff --git a/src/Routes/Coin.tsx b/src/Routes/Coin.tsx
deleted file mode 100644
index 2e53017..0000000
--- a/src/Routes/Coin.tsx
+++ /dev/null
@@ -1,296 +0,0 @@
-import { useEffect, useState } from "react";
-import { useQuery } from "react-query";
-import { Helmet } from "react-helmet";
-import {
- Route,
- Switch,
- useLocation,
- useParams,
- useRouteMatch,
-} from "react-router";
-import { Link } from "react-router-dom";
-import styled from "styled-components";
-import { fetchCoinInfo, fetchTickersInfo } from "../api";
-import Chart from "./Chart";
-import Price from "./Price";
-
-interface routeParams {
- coinId: string;
-}
-
-const Container = styled.div`
- padding: 0px 20px;
- max-width: 480px;
- margin: 0 auto;
-`;
-
-const Loading = styled.span`
- text-align: center;
- display: block;
-`;
-
-const Header = styled.header`
- display: flex;
- justify-content: space-between;
- align-items: center;
- height: 15vh;
-`;
-
-const Title = styled.div`
- font-size: 48px;
- color: ${(props) => props.theme.accentColor};
- text-align: center;
-`;
-
-interface RouteState {
- name: string;
-}
-
-interface ICoinInfo {
- id: string;
- name: string;
- symbol: string;
- rank: number;
- is_new: boolean;
- is_active: boolean;
- type: string;
- contract: string;
- platform: string;
- description: string;
- message: string;
- open_source: boolean;
- started_at: string;
- development_status: string;
- hardware_wallet: boolean;
- proof_type: string;
- org_structure: string;
- hash_algorithm: string;
- first_data_at: string;
- last_data_at: string;
-}
-
-interface ITickersInfo {
- id: string;
- name: string;
- symbol: string;
- rank: number;
- circulating_supply: number;
- total_supply: number;
- max_supply: number;
- beta_value: number;
- first_data_at: string;
- last_updated: string;
- quotes: {
- USD: {
- ath_date: string;
- ath_price: number;
- market_cap: number;
- market_cap_change_24h: number;
- percent_change_1h: number;
- percent_change_1y: number;
- percent_change_6h: number;
- percent_change_7d: number;
- percent_change_12h: number;
- percent_change_15m: number;
- percent_change_24h: number;
- percent_change_30d: number;
- percent_change_30m: number;
- percent_from_price_ath: number;
- price: number;
- volume_24h: number;
- volume_24h_change_24h: number;
- };
- };
-}
-
-const ContentContainer = styled.div`
- display: flex;
- flex-direction: column;
- align-items: center;
-`;
-
-const Article = styled.div`
- background-color: ${(props) => props.theme.textColor};
- color: ${(props) => props.theme.bgColor};
- padding: 20px 20px;
- border-radius: 15px;
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 30px;
-`;
-
-const MiniContentDiv = styled.div`
- display: flex;
- align-items: center;
- flex-direction: column;
-`;
-
-const ContentTitle = styled.span`
- font-size: 12px;
- text-align: center;
- margin-bottom: 5px;
-`;
-
-const ContentText = styled.span`
- font-size: 16px;
- text-align: center;
- line-height: 20px;
-`;
-
-const Tab = styled.div`
- width: 100%;
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 10px;
-`;
-
-const Tabs = styled.span<{ isActive: boolean }>`
- text-align: center;
- font-size: 16px;
- padding: 10px;
- background-color: ${(props) => props.theme.textColor};
- color: ${(props) =>
- props.isActive ? props.theme.accentColor : props.theme.bgColor};
- border-radius: 10px;
- a {
- display: block;
- }
-`;
-
-const Home = styled.div`
- text-align: center;
- color: ${(props) => props.theme.bgColor};
- background-color: ${(props) => props.theme.textColor};
- border-radius: 5px;
- padding: 10px;
- right: 200px;
- &:hover {
- color: ${(props) => props.theme.accentColor};
- transition: color 0.2s ease-in-out;
- }
- a {
- display: block;
- }
-`;
-
-function Coin() {
- const { coinId } = useParams();
- const { state } = useLocation();
- const priceMatch = useRouteMatch(`/${coinId}/price`);
- const chartMatch = useRouteMatch(`/${coinId}/chart`);
- const { isLoading: CoinInfoLoading, data: CoinInfoData } =
- useQuery(["coinInfo", coinId], () => fetchCoinInfo(coinId), {
- refetchInterval: 10000,
- });
- const { isLoading: TickersInfoLoading, data: TickersInfoData } =
- useQuery(
- ["tickersInfo", coinId],
- () => fetchTickersInfo(coinId),
- {
- refetchInterval: 10000,
- }
- );
- const loading = CoinInfoLoading || TickersInfoLoading;
- /*
- const [loading, setLoading] = useState(true);
- const [info, setInfo] = useState();
- const [priceInfo, setPriceInfo] = useState();
- console.log(chartMatch);
- useEffect(() => {
- (async () => {
- const infoData = await (
- await fetch(`https://api.coinpaprika.com/v1/coins/${coinId}`)
- ).json();
- const priceData = await (
- await fetch(`https://api.coinpaprika.com/v1/tickers/${coinId}`)
- ).json();
- setInfo(infoData);
- setPriceInfo(priceData);
- setLoading(false);
- // console.log(state);
- // console.log(coinId);
- })();
- }, []);*/
- return (
-
-
-
- {state?.name
- ? state.name
- : loading
- ? "Loading..."
- : CoinInfoData?.name}
-
-
-
-
- Home
-
-
- {state?.name
- ? state.name
- : loading
- ? "Loading..."
- : CoinInfoData?.name}
-
-
-
-
- {loading ? (
- Loading...
- ) : (
-
-
-
- RANK:
- {CoinInfoData?.rank}
-
-
- SYMBOL:
- {CoinInfoData?.symbol}
-
-
- OPEN SOURCE:
-
- {CoinInfoData?.open_source ? "Yes" : "No"}
-
-
-
-
- {CoinInfoData?.description}
-
-
-
- TOTAL SUPPLY:
- {TickersInfoData?.total_supply}
-
-
- MAX SUPPLY:
- {TickersInfoData?.max_supply}
-
-
-
-
- Chart
-
-
- Price
-
-
-
-
-
-
-
-
-
-
-
- )}
-
- );
-}
-
-export default Coin;
diff --git a/src/Routes/Coins.tsx b/src/Routes/Coins.tsx
deleted file mode 100644
index f591d08..0000000
--- a/src/Routes/Coins.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-import { useEffect, useState } from "react";
-import { useQuery } from "react-query";
-import { Link } from "react-router-dom";
-import styled from "styled-components";
-import { fetchCoins } from "../api";
-import { Helmet } from "react-helmet";
-
-const Container = styled.div`
- padding: 0px 20px;
- max-width: 480px;
- margin: 0 auto;
-`;
-
-const Loading = styled.span`
- text-align: center;
- display: block;
-`;
-
-const Header = styled.header`
- display: flex;
- justify-content: center;
- align-items: center;
- height: 15vh;
-`;
-
-const Title = styled.div`
- font-size: 48px;
- color: ${(props) => props.theme.accentColor};
-`;
-
-const Img = styled.img`
- width: 35px;
- height: 35px;
- margin-right: 10px;
-`;
-
-const CoinsList = styled.ul``;
-
-const Coin = styled.li`
- background-color: ${(props) => props.theme.textColor};
- color: ${(props) => props.theme.bgColor};
- margin-bottom: 10px;
- border-radius: 15px;
- a {
- padding: 20px;
- display: flex;
- align-items: center;
- transition: color 0.2s ease-in-out;
- }
- &:hover {
- a {
- color: ${(props) => props.theme.accentColor};
- }
- }
-`;
-
-interface ICoin {
- id: string;
- name: string;
- symbol: string;
- rank: number;
- is_new: boolean;
- is_active: boolean;
- type: string;
-}
-
-function Coins() {
- /*
- const [loading, setLoading] = useState(true);
- const [coins, setCoins] = useState([]);
- useEffect(() => {
- (async () => {
- const response = await fetch("https://api.coinpaprika.com/v1/coins");
- const json = await response.json();
- setCoins(json.slice(0, 100));
- //console.log(json);
- setLoading(false);
- })();
- }, []);*/
- const { isLoading, data } = useQuery("allcoins", fetchCoins);
-
- return (
-
-
- 코인
-
-
- {isLoading ? (
- Loading...
- ) : (
-
- {data?.slice(0, 100).map((item) => (
-
-
-
- {item.name} →
-
-
- ))}
-
- )}
-
- );
-}
-
-export default Coins;
diff --git a/src/Routes/Home.tsx b/src/Routes/Home.tsx
new file mode 100644
index 0000000..c7f4b70
--- /dev/null
+++ b/src/Routes/Home.tsx
@@ -0,0 +1,191 @@
+import { useQuery } from "react-query";
+import { useLocation } from "react-router-dom";
+import styled from "styled-components";
+import {
+ getMoviesPage1,
+ getMoviesPage2,
+ getMoviesPage3,
+ getMoviesPage4,
+ getMoviesPage5,
+ getMoviesPage6,
+ getUpcommingData,
+ IGetVideosProps,
+ IMovie,
+ topRateMoviePage1,
+ topRateMoviePage2,
+ topRateMoviePage3,
+ topRateMoviePage4,
+ topRateMoviePage5,
+ topRateMoviePage6,
+} from "../api";
+import BannerScreen from "../Components/BannerScreen";
+import Footer from "../Components/Footer";
+import NowMovies from "../Components/NowMovies";
+
+const Wrapper = styled.div``;
+
+const Loader = styled.div``;
+
+function Home() {
+ const nowMovieData: IMovie[] = [];
+ const recommendData: IMovie[] = [];
+ const topRateMovies: IMovie[] = [];
+ const recommendData2: IMovie[] = [];
+ const upcommingData: IMovie[] = [];
+ const nowPage1 = useQuery(
+ ["movies", "nowPlayingPage1"],
+ getMoviesPage1
+ );
+ const nowPage2 = useQuery(
+ ["movies", "nowPlayingPage2"],
+ getMoviesPage2
+ );
+ const nowPage3 = useQuery(
+ ["movies", "nowPlayingPage3"],
+ getMoviesPage3
+ );
+ const nowPage4 = useQuery(
+ ["movies", "nowPlayingPage4"],
+ getMoviesPage4
+ );
+ const nowPage5 = useQuery(
+ ["movies", "nowPlayingPage5"],
+ getMoviesPage5
+ );
+ const nowPage6 = useQuery(
+ ["movies", "nowPlayingPage6"],
+ getMoviesPage6
+ );
+
+ const topRatePage1 = useQuery(
+ ["movies", "topRatePage1"],
+ topRateMoviePage1
+ );
+
+ const topRatePage2 = useQuery(
+ ["movies", "topRatePage2"],
+ topRateMoviePage2
+ );
+
+ const topRatePage3 = useQuery(
+ ["movies", "topRatePage3"],
+ topRateMoviePage3
+ );
+
+ const topRatePage4 = useQuery(
+ ["movies", "topRatePage4"],
+ topRateMoviePage4
+ );
+
+ const topRatePage5 = useQuery(
+ ["movies", "topRatePage5"],
+ topRateMoviePage5
+ );
+
+ const topRatePage6 = useQuery(
+ ["movies", "topRatePage6"],
+ topRateMoviePage6
+ );
+
+ const upcommingPage1 = useQuery(
+ ["movies", "upcomming1"],
+ () => getUpcommingData(1)
+ );
+ const upcommingPage2 = useQuery(
+ ["movies", "upcomming2"],
+ () => getUpcommingData(2)
+ );
+ const upcommingPage3 = useQuery(
+ ["movies", "upcomming3"],
+ () => getUpcommingData(3)
+ );
+
+ //console.log(nowPage1);
+ nowPage1?.data?.results.map((item) => nowMovieData.push(item));
+ nowPage2?.data?.results.map((item) => nowMovieData.push(item));
+ nowPage3?.data?.results.map((item) => nowMovieData.push(item));
+
+ nowPage4?.data?.results.map((item) => recommendData.push(item));
+ nowPage5?.data?.results.map((item) => recommendData.push(item));
+ nowPage6?.data?.results.map((item) => recommendData.push(item));
+
+ topRatePage1?.data?.results.map((item) => topRateMovies.push(item));
+ topRatePage2?.data?.results.map((item) => topRateMovies.push(item));
+ topRatePage3?.data?.results.map((item) => topRateMovies.push(item));
+
+ topRatePage4?.data?.results.map((item) => recommendData2.push(item));
+ topRatePage5?.data?.results.map((item) => recommendData2.push(item));
+ topRatePage6?.data?.results.map((item) => recommendData2.push(item));
+
+ upcommingPage1.data?.results.map((item) => upcommingData.push(item));
+ upcommingPage2.data?.results.map((item) => upcommingData.push(item));
+ upcommingPage3.data?.results.map((item) => upcommingData.push(item));
+ // console.log(clickedMovie);
+ //console.log(index, "인뎃으");
+ //console.log(nowMovieData, isLoading);
+
+ const location = useLocation();
+
+ return (
+
+ {upcommingData.length < 58 ? (
+ Loading...
+ ) : (
+ <>
+ {nowPage1.data?.results[0] && (
+
+ )}
+
+ {nowMovieData && (
+
+ )}
+ {topRateMovies && (
+
+ )}
+ {recommendData && (
+
+ )}
+ {recommendData2 && (
+
+ )}
+ {upcommingData && (
+
+ )}
+
+ >
+ )}
+
+ );
+}
+
+export default Home;
diff --git a/src/Routes/Price.tsx b/src/Routes/Price.tsx
deleted file mode 100644
index 1aedfc9..0000000
--- a/src/Routes/Price.tsx
+++ /dev/null
@@ -1,188 +0,0 @@
-import { useQuery } from "react-query";
-import styled, { keyframes } from "styled-components";
-import { fetchTickersInfo } from "../api";
-
-interface ICoin {
- coinId: string;
-}
-
-interface ICoinInfo {
- id: string;
- name: string;
- symbol: string;
- rank: number;
- is_new: boolean;
- is_active: boolean;
- type: string;
- contract: string;
- platform: string;
- description: string;
- message: string;
- open_source: boolean;
- started_at: string;
- development_status: string;
- hardware_wallet: boolean;
- proof_type: string;
- org_structure: string;
- hash_algorithm: string;
- first_data_at: string;
- last_data_at: string;
-}
-
-interface ITickersInfo {
- id: string;
- name: string;
- symbol: string;
- rank: number;
- circulating_supply: number;
- total_supply: number;
- max_supply: number;
- beta_value: number;
- first_data_at: string;
- last_updated: string;
- quotes: {
- USD: {
- ath_date: string;
- ath_price: number;
- market_cap: number;
- market_cap_change_24h: number;
- percent_change_1h: number;
- percent_change_1y: number;
- percent_change_6h: number;
- percent_change_7d: number;
- percent_change_12h: number;
- percent_change_15m: number;
- percent_change_24h: number;
- percent_change_30d: number;
- percent_change_30m: number;
- percent_from_price_ath: number;
- price: number;
- volume_24h: number;
- volume_24h_change_24h: number;
- };
- };
-}
-
-const centerAni = keyframes`
- 0%{
- opacity:0;
- }50%{
-
- opacity:0.5;
- }100%{
-
- opacity:1;
- }
-`;
-
-const ContainerDiv = styled.div`
- width: 100%;
-`;
-
-const Container = styled.div`
- width: 100%;
-`;
-const Tags = styled.div`
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 100%;
- background-color: ${(props) => props.theme.textColor};
- color: ${(props) => props.theme.bgColor};
- padding: 10px 15px;
- margin-top: 10px;
- border-radius: 15px;
- animation: ${centerAni} 0.5s ease-in-out;
- &:first-child {
- margin-top: 30px;
- }
-`;
-
-const TagTitle = styled.span`
- font-size: 12px;
-`;
-const TagContent = styled.span<{ isMinus: boolean }>`
- color: ${(props) =>
- props.isMinus ? props.theme.plusColor : props.theme.minusColor};
- font-size: 18px;
-`;
-
-function Price({ coinId }: ICoin) {
- const { isLoading, data } = useQuery(
- ["price", coinId],
- () => fetchTickersInfo(coinId),
- {
- refetchInterval: 10000,
- }
- );
- return (
-
- {isLoading ? (
- "Loading Price..."
- ) : (
-
-
- Current Prices :
- {`$${data?.quotes.USD.price.toFixed(3)}`}
-
-
- Percent Change 12 Hours :
- {`${data?.quotes.USD.percent_change_12h}%`}
-
-
- Percent Change 24 Hourss :
- {`${data?.quotes.USD.percent_change_24h}%`}
-
-
- Percent Change 7 days :
- {`${data?.quotes.USD.percent_change_7d}%`}
-
-
- Volume Change 24hours :
- {`$${data?.quotes.USD.volume_24h_change_24h}`}
-
-
- Maximum Price :
- {`$${data?.quotes.USD.ath_price.toFixed(3)}`}
-
-
- Maximum Price Date :
- {`${data?.quotes.USD.ath_date.slice(
- 0,
- 10
- )}`}
-
-
- )}
-
- );
-}
-
-export default Price;
diff --git a/src/Routes/Search.tsx b/src/Routes/Search.tsx
new file mode 100644
index 0000000..4bc5eef
--- /dev/null
+++ b/src/Routes/Search.tsx
@@ -0,0 +1,89 @@
+import { useQuery } from "react-query";
+import { useLocation } from "react-router";
+import { getSearchVideo, ISearchMovie } from "../api";
+import styled from "styled-components";
+import NowMovies from "../Components/NowMovies";
+import { useEffect } from "react";
+import Footer from "../Components/Footer";
+
+const Wrapper = styled.div`
+ padding-top: 500px;
+`;
+
+const Loader = styled.div`
+ font-size: 48px;
+ color: ${(props) => props.theme.white.lighter};
+ display: flex;
+ justify-content: center;
+ align-items: center;
+`;
+
+function Search() {
+ const location = useLocation();
+ //console.log("로케이션 : ", location);
+ useEffect(() => {}, [location]);
+ const keyword: any = location.search
+ ? new URLSearchParams(location.search).get("keyword")
+ : "";
+ const word: string = keyword
+ ?.toString()
+ .trim()
+ ?.replace(/,/g, " ")
+ .split(" ")
+ .map((item: string) => item.trim().split(" "))
+ .join("+");
+
+ const searchData = useQuery(
+ ["movies", "search"],
+ () => getSearchVideo("tv", word),
+ { refetchInterval: 100 }
+ );
+
+ const searchData2 = useQuery(
+ ["movies", "search2"],
+ () => getSearchVideo("movie", word),
+ { refetchInterval: 500 }
+ );
+
+ //console.log(location);
+ //console.log(pramas);
+ //console.log(location);
+ // console.log(keyword);
+
+ //console.log(location);
+ //console.log(location);
+ //console.log(searchData);
+ return (
+
+ {!searchData.data?.results[0] && !searchData2.data?.results[0] ? (
+ 검색한 결과가 없습니다
+ ) : (
+ <>
+ {searchData.data?.results[0] && (
+
+ )}
+ {searchData2.data?.results[0] && (
+
+ )}
+
+ >
+ )}
+
+ );
+}
+
+export default Search;
diff --git a/src/Routes/Tv.tsx b/src/Routes/Tv.tsx
new file mode 100644
index 0000000..07748dd
--- /dev/null
+++ b/src/Routes/Tv.tsx
@@ -0,0 +1,132 @@
+import { useQuery } from "react-query";
+import { useLocation } from "react-router-dom";
+import styled from "styled-components";
+import {
+ getAiringTodayTvData,
+ getPopularTvData,
+ getTopRatedTvData,
+ getTvOnAir,
+ IGetVideosProps,
+ IMovie,
+} from "../api";
+import BannerScreen from "../Components/BannerScreen";
+import Footer from "../Components/Footer";
+import NowMovies from "../Components/NowMovies";
+
+const Wrapper = styled.div``;
+
+const Loader = styled.div``;
+
+function Tv() {
+ const topRatedData: IMovie[] = [];
+ const onAirData: IMovie[] = [];
+ const popularData: IMovie[] = [];
+ const aringTodayData: IMovie[] = [];
+ const location = useLocation();
+ const onAirPage1 = useQuery(["Tv", "onAir1"], () =>
+ getTvOnAir(1)
+ );
+ const onAirPage2 = useQuery(["Tv", "onAir2"], () =>
+ getTvOnAir(2)
+ );
+ const onAirPage3 = useQuery(["Tv", "onAir3"], () =>
+ getTvOnAir(3)
+ );
+ const topRatedPage1 = useQuery(["tv", "topRated1"], () =>
+ getTopRatedTvData(1)
+ );
+ const topRatedPage2 = useQuery(["tv", "topRated2"], () =>
+ getTopRatedTvData(2)
+ );
+ const topRatedPage3 = useQuery(["tv", "topRated3"], () =>
+ getTopRatedTvData(3)
+ );
+ const popularPage1 = useQuery(["tv", "popular1"], () =>
+ getPopularTvData(1)
+ );
+ const popularPage2 = useQuery(["tv", "popular2"], () =>
+ getPopularTvData(1)
+ );
+ const popularPage3 = useQuery(["tv", "popular3"], () =>
+ getPopularTvData(1)
+ );
+
+ const airingTodayPage1 = useQuery(["tv", "airing1"], () =>
+ getAiringTodayTvData(1)
+ );
+ const airingTodayPage2 = useQuery(["tv", "airing3"], () =>
+ getAiringTodayTvData(2)
+ );
+ const airingTodayPage3 = useQuery(["tv", "airing2"], () =>
+ getAiringTodayTvData(3)
+ );
+
+ onAirPage1?.data?.results.map((item) => onAirData.push(item));
+ onAirPage2?.data?.results.map((item) => onAirData.push(item));
+ onAirPage3?.data?.results.map((item) => onAirData.push(item));
+
+ topRatedPage1?.data?.results.map((item) => topRatedData.push(item));
+ topRatedPage2?.data?.results.map((item) => topRatedData.push(item));
+ topRatedPage3.data?.results.map((item) => topRatedData.push(item));
+
+ popularPage1.data?.results.map((item) => popularData.push(item));
+ popularPage2.data?.results.map((item) => popularData.push(item));
+ popularPage3.data?.results.map((item) => popularData.push(item));
+
+ airingTodayPage1.data?.results.map((item) => aringTodayData.push(item));
+ airingTodayPage2.data?.results.map((item) => aringTodayData.push(item));
+ airingTodayPage3.data?.results.map((item) => aringTodayData.push(item));
+
+ return (
+
+ {aringTodayData.length < 58 ? (
+ Loading...
+ ) : (
+ <>
+ {topRatedPage1.data?.results[1] && (
+
+ )}
+ {onAirData && (
+
+ )}
+ {topRatedData && (
+
+ )}
+ {popularData && (
+
+ )}
+ {aringTodayData && (
+
+ )}
+
+ >
+ )}
+
+ );
+}
+
+export default Tv;
diff --git a/src/api.ts b/src/api.ts
index 0f43c8c..e3fe3d6 100644
--- a/src/api.ts
+++ b/src/api.ts
@@ -1,25 +1,280 @@
-const BASE_URL = "https://api.coinpaprika.com/v1";
+const API_KEY = "8ada0ba81365b222c17dc83dc8b3e61d";
+const BASE_URL = "https://api.themoviedb.org/3";
-export function fetchCoins() {
- return fetch(`${BASE_URL}/coins`).then((response) => response.json());
+export interface IMovie {
+ adult?: boolean;
+ backdrop_path: string;
+ genre_ids: number[];
+ id: number;
+ original_language: string;
+ original_title?: string;
+ overview: string;
+ popularity: number;
+ poster_path: string;
+ release_date?: string;
+ title?: string;
+ video: boolean;
+ vote_average: number;
+ vote_count: number;
+ name?: string;
+ first_air_date?: string;
}
-export function fetchCoinInfo(coinId: string) {
- return fetch(`${BASE_URL}/coins/${coinId}`).then((response) =>
- response.json()
- );
+export interface IGetVideosProps {
+ dates?: {
+ maximum: string;
+ minimum: string;
+ };
+ page: number;
+ results: IMovie[];
+ total_pages: number;
+ total_results: number;
}
-export function fetchTickersInfo(coinId: string) {
- return fetch(`${BASE_URL}/tickers/${coinId}`).then((response) =>
- response.json()
- );
+export interface IGetVideoDetail {
+ data: object;
+ name?: string;
+ first_air_date?: string;
+ origin_country?: string[];
+ original_name?: string;
+ dataUpdatedAt: number;
+ errorUpdatedAt: number;
+ failureCount: number;
+ adult: boolean;
+ backdrop_path: string;
+ budget: number;
+ genres: [
+ {
+ id: number;
+ name: string;
+ }
+ ];
+ id: number;
+ imdb_id: string;
+ original_language: string;
+ original_title: string;
+ overview: string;
+ popularity: number;
+ poster_path: string;
+ release_date: string;
+ revenue: number;
+ runtime: number;
+ tagline: string;
+ title: string;
+ vote_average: number;
+ vote_count: number;
+ videos: {
+ results: [
+ {
+ id: string;
+ iso_639_1: string;
+ iso_3166_1: string;
+ key: string;
+ name: string;
+ official: boolean;
+ published_at: string;
+ site: string;
+ size: number;
+ type: string;
+ }
+ ];
+ };
}
-export function fetchOHLCInfo(coinId: string) {
- const endDate = Math.floor(Date.now() / 1000);
- const startDate = endDate - 60 * 60 * 24 * 14;
+export interface IVideoCredit {
+ cast: ICast[];
+ crew: ICrew[];
+ id: number;
+}
+
+interface ICast {
+ adult: boolean;
+ cast_id: number;
+ character: string;
+ credit_id: string;
+ gender: number;
+ id: number;
+ known_for_department: string;
+ name: string;
+ order: number;
+ original_name: string;
+ popularity: number;
+ profile_path: string;
+}
+
+interface ICrew {
+ adult: boolean;
+ credit_id: string;
+ department: string;
+ gender: number;
+ id: number;
+ job: string;
+ known_for_department: string;
+ name: string;
+ original_name: string;
+ popularity: number;
+ profile_path: string;
+}
+
+export interface ISimilarProps {
+ page: number;
+ results: IMovie[];
+ total_pages: number;
+ total_results: number;
+}
+
+export interface ISearchMovie {
+ page: number;
+ results: IMovie[];
+ total_pages: number;
+ total_results: number;
+}
+
+export interface ITvProps {
+ backdrop_path: string;
+ first_air_date: string;
+ genre_ids: number[];
+ id: number;
+ name: string;
+ origin_country: string[];
+ original_language: string;
+ original_name: string;
+ overview: string;
+ popularity: number;
+ poster_path: string;
+ vote_average: number;
+ vote_count: number;
+}
+
+export interface IGetTvProps {
+ page: number;
+ results: ITvProps[];
+ total_pages: number;
+ total_results: number;
+}
+export function getMoviesPage1() {
+ return fetch(
+ `${BASE_URL}/movie/now_playing?api_key=${API_KEY}&language=en-US&page=1`
+ ).then((response) => response.json());
+}
+
+export function getMoviesPage2() {
+ return fetch(
+ `${BASE_URL}/movie/now_playing?api_key=${API_KEY}&language=en-US&page=3`
+ ).then((response) => response.json());
+}
+
+export function getMoviesPage3() {
+ return fetch(
+ `${BASE_URL}/movie/now_playing?api_key=${API_KEY}&language=en-US&page=5`
+ ).then((response) => response.json());
+}
+
+export function getMoviesPage4() {
+ return fetch(
+ `${BASE_URL}/movie/now_playing?api_key=${API_KEY}&language=en-US&page=10`
+ ).then((response) => response.json());
+}
+
+export function getMoviesPage5() {
+ return fetch(
+ `${BASE_URL}/movie/now_playing?api_key=${API_KEY}&language=en-US&page=12`
+ ).then((response) => response.json());
+}
+
+export function getMoviesPage6() {
+ return fetch(
+ `${BASE_URL}/movie/now_playing?api_key=${API_KEY}&language=en-US&page=14`
+ ).then((response) => response.json());
+}
+
+export function topRateMoviePage1() {
+ return fetch(
+ `${BASE_URL}/movie/top_rated?api_key=${API_KEY}&language=en-US&page=1`
+ ).then((response) => response.json());
+}
+export function topRateMoviePage2() {
+ return fetch(
+ `${BASE_URL}/movie/top_rated?api_key=${API_KEY}&language=en-US&page=3`
+ ).then((response) => response.json());
+}
+export function topRateMoviePage3() {
+ return fetch(
+ `${BASE_URL}/movie/top_rated?api_key=${API_KEY}&language=en-US&page=5`
+ ).then((response) => response.json());
+}
+
+export function topRateMoviePage4() {
+ return fetch(
+ `${BASE_URL}/movie/top_rated?api_key=${API_KEY}&language=en-US&page=7`
+ ).then((response) => response.json());
+}
+export function topRateMoviePage5() {
+ return fetch(
+ `${BASE_URL}/movie/top_rated?api_key=${API_KEY}&language=en-US&page=9`
+ ).then((response) => response.json());
+}
+export function topRateMoviePage6() {
+ return fetch(
+ `${BASE_URL}/movie/top_rated?api_key=${API_KEY}&language=en-US&page=11`
+ ).then((response) => response.json());
+}
+
+export function getVideoDetail(format: string, id: string) {
+ return fetch(
+ `${BASE_URL}/${format}/${id}?api_key=${API_KEY}&language=en-US&append_to_response=videos`
+ ).then((response) => response.json());
+}
+
+export function getVideoCredit(format: string, id: string) {
+ return fetch(
+ `${BASE_URL}/${format}/${id}/credits?api_key=${API_KEY}&language=en-US`
+ ).then((response) => response.json());
+}
+
+export function getSearchVideo(format: string, id: string) {
+ return fetch(
+ `${BASE_URL}/search/${format}?api_key=${API_KEY}&query=${id}&page=1`
+ ).then((response) => response.json());
+}
+
+export function getTvOnAir(page: number) {
+ return fetch(
+ `${BASE_URL}/tv/on_the_air?api_key=${API_KEY}&language=en-US&page=${page}`
+ ).then((response) => response.json());
+}
+
+export function getSimilarData(format: string, id: string) {
+ return fetch(
+ `
+ ${BASE_URL}/${format}/${id}/similar?api_key=${API_KEY}&language=en-US&page=1`
+ ).then((response) => response.json());
+}
+
+export function getUpcommingData(page: number) {
+ return fetch(
+ `
+ ${BASE_URL}/movie/upcoming?api_key=${API_KEY}&language=en-US&page=${page}`
+ ).then((response) => response.json());
+}
+
+export function getTopRatedTvData(page: number) {
+ return fetch(
+ `
+ ${BASE_URL}/tv/top_rated?api_key=${API_KEY}&language=en-US&page=${page}`
+ ).then((response) => response.json());
+}
+
+export function getPopularTvData(page: number) {
+ return fetch(
+ `
+ ${BASE_URL}/tv/popular?api_key=${API_KEY}&language=en-US&page=${page}`
+ ).then((response) => response.json());
+}
+
+export function getAiringTodayTvData(page: number) {
return fetch(
- `${BASE_URL}/coins/${coinId}/ohlcv/historical?start=${startDate}&end=${endDate}`
+ `
+ ${BASE_URL}/tv/airing_today?api_key=${API_KEY}&language=en-US&page=${page}`
).then((response) => response.json());
}
diff --git a/src/atoms.ts b/src/atoms.ts
new file mode 100644
index 0000000..d732f83
--- /dev/null
+++ b/src/atoms.ts
@@ -0,0 +1 @@
+import { atom } from "recoil";
diff --git a/src/index.tsx b/src/index.tsx
index c6c1c70..f5f6b1b 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,19 +1,86 @@
import React from "react";
import ReactDOM from "react-dom";
import { QueryClient, QueryClientProvider } from "react-query";
-import { ThemeProvider } from "styled-components";
+import { BrowserRouter } from "react-router-dom";
+import { RecoilRoot } from "recoil";
+import { createGlobalStyle, ThemeProvider } from "styled-components";
import App from "./App";
import { theme } from "./theme";
const queryClient = new QueryClient();
+const GlobalStyle = createGlobalStyle`
+@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400&display=swap');
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+body {
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+*{
+ box-sizing: border-box;
+}
+a{
+ text-decoration: none;
+ color:inherit;
+}
+
+body{
+ font-family: 'Source Sans Pro', sans-serif;
+ background-color: black;
+ color: ${(props) => props.theme.white.darker};
+}
+`;
+
ReactDOM.render(
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
,
document.getElementById("root")
);
diff --git a/src/styled.d.ts b/src/styled.d.ts
index 452018c..5a4a027 100644
--- a/src/styled.d.ts
+++ b/src/styled.d.ts
@@ -4,10 +4,16 @@ import "styled-components";
// and extend them!
declare module "styled-components" {
export interface DefaultTheme {
- bgColor: string;
- textColor: string;
- accentColor: string;
- plusColor: string;
- minusColor: string;
+ red: string;
+ black: {
+ veryDark: string;
+ darker: string;
+ lighter: string;
+ };
+ white: {
+ darker: string;
+ lighter: string;
+ veryDark: string;
+ };
}
}
diff --git a/src/theme.ts b/src/theme.ts
index fe97910..9b954e4 100644
--- a/src/theme.ts
+++ b/src/theme.ts
@@ -1,9 +1,15 @@
import { DefaultTheme } from "styled-components";
export const theme: DefaultTheme = {
- bgColor: "#7f8fa6",
- textColor: "#353b48",
- accentColor: "#e1b12c",
- plusColor: "#A4F0A4",
- minusColor: "#FE1F1F",
+ red: "#E51013",
+ black: {
+ veryDark: "#141414",
+ darker: "#181818",
+ lighter: "#2F2F2F",
+ },
+ white: {
+ lighter: "#fff",
+ darker: "#e5e5e5",
+ veryDark: "#616161",
+ },
};
diff --git a/src/utils.ts b/src/utils.ts
new file mode 100644
index 0000000..fcbd388
--- /dev/null
+++ b/src/utils.ts
@@ -0,0 +1,3 @@
+export function makeImageHelper(id: string, format?: string) {
+ return `https://image.tmdb.org/t/p/${format ? format : "original"}/${id}`;
+}