update style and setup gh-pages
This commit is contained in:
1
.env
Normal file
1
.env
Normal file
@@ -0,0 +1 @@
|
|||||||
|
REACT_APP_API_URL=https://letterboxd-diary-posters-picker-backend.onrender.com
|
||||||
484
package-lock.json
generated
484
package-lock.json
generated
@@ -28,7 +28,11 @@
|
|||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
|
"sass": "^1.80.3",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"gh-pages": "^6.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@adobe/css-tools": {
|
"node_modules/@adobe/css-tools": {
|
||||||
@@ -4293,6 +4297,279 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@parcel/watcher": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"detect-libc": "^1.0.3",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"micromatch": "^4.0.5",
|
||||||
|
"node-addon-api": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@parcel/watcher-android-arm64": "2.4.1",
|
||||||
|
"@parcel/watcher-darwin-arm64": "2.4.1",
|
||||||
|
"@parcel/watcher-darwin-x64": "2.4.1",
|
||||||
|
"@parcel/watcher-freebsd-x64": "2.4.1",
|
||||||
|
"@parcel/watcher-linux-arm-glibc": "2.4.1",
|
||||||
|
"@parcel/watcher-linux-arm64-glibc": "2.4.1",
|
||||||
|
"@parcel/watcher-linux-arm64-musl": "2.4.1",
|
||||||
|
"@parcel/watcher-linux-x64-glibc": "2.4.1",
|
||||||
|
"@parcel/watcher-linux-x64-musl": "2.4.1",
|
||||||
|
"@parcel/watcher-win32-arm64": "2.4.1",
|
||||||
|
"@parcel/watcher-win32-ia32": "2.4.1",
|
||||||
|
"@parcel/watcher-win32-x64": "2.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-android-arm64": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-darwin-arm64": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-darwin-x64": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-freebsd-x64": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-arm-glibc": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-arm64-glibc": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-arm64-musl": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-x64-glibc": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-linux-x64-musl": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-win32-arm64": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-win32-ia32": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@parcel/watcher-win32-x64": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/parcel"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@pkgjs/parseargs": {
|
"node_modules/@pkgjs/parseargs": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||||
@@ -8271,6 +8548,18 @@
|
|||||||
"npm": "1.2.8000 || >= 1.4.16"
|
"npm": "1.2.8000 || >= 1.4.16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/detect-libc": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"detect-libc": "bin/detect-libc.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/detect-newline": {
|
"node_modules/detect-newline": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
|
||||||
@@ -8541,6 +8830,13 @@
|
|||||||
"integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==",
|
"integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/email-addresses": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/emittery": {
|
"node_modules/emittery": {
|
||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz",
|
||||||
@@ -9879,6 +10175,34 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"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==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"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": {
|
"node_modules/filesize": {
|
||||||
"version": "8.0.7",
|
"version": "8.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz",
|
||||||
@@ -10427,6 +10751,54 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/gh-pages": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-HMXJ8th9u5wRXaZCnLcs/d3oVvCHiZkaP5KQExQljYGwJjQbSPyTdHe/Gc1IvYUR/rWiZLxNobIqfoMHKTKjHQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"async": "^3.2.4",
|
||||||
|
"commander": "^11.0.0",
|
||||||
|
"email-addresses": "^5.0.0",
|
||||||
|
"filenamify": "^4.3.0",
|
||||||
|
"find-cache-dir": "^3.3.1",
|
||||||
|
"fs-extra": "^11.1.1",
|
||||||
|
"globby": "^11.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/commander": {
|
||||||
|
"version": "11.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
|
||||||
|
"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/gh-pages/node_modules/fs-extra": {
|
||||||
|
"version": "11.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
|
||||||
|
"integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.2.0",
|
||||||
|
"jsonfile": "^6.0.1",
|
||||||
|
"universalify": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||||
@@ -11037,6 +11409,12 @@
|
|||||||
"url": "https://opencollective.com/immer"
|
"url": "https://opencollective.com/immer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/immutable": {
|
||||||
|
"version": "4.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
|
||||||
|
"integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/import-fresh": {
|
"node_modules/import-fresh": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||||
@@ -14748,6 +15126,12 @@
|
|||||||
"tslib": "^2.0.3"
|
"tslib": "^2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-addon-api": {
|
||||||
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/node-forge": {
|
"node_modules/node-forge": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||||
@@ -15268,9 +15652,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
@@ -15389,9 +15773,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.41",
|
"version": "8.4.47",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
|
||||||
"integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==",
|
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -15409,8 +15793,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.7",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.0.1",
|
"picocolors": "^1.1.0",
|
||||||
"source-map-js": "^1.2.0"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
@@ -17914,6 +18298,24 @@
|
|||||||
"integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==",
|
"integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==",
|
||||||
"license": "CC0-1.0"
|
"license": "CC0-1.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/sass": {
|
||||||
|
"version": "1.80.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.80.3.tgz",
|
||||||
|
"integrity": "sha512-ptDWyVmDMVielpz/oWy3YP3nfs7LpJTHIJZboMVs8GEC9eUmtZTZhMHlTW98wY4aEorDfjN38+Wr/XjskFWcfA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@parcel/watcher": "^2.4.1",
|
||||||
|
"chokidar": "^4.0.0",
|
||||||
|
"immutable": "^4.0.0",
|
||||||
|
"source-map-js": ">=0.6.2 <2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"sass": "sass.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sass-loader": {
|
"node_modules/sass-loader": {
|
||||||
"version": "12.6.0",
|
"version": "12.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz",
|
||||||
@@ -17952,6 +18354,34 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sass/node_modules/chokidar": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"readdirp": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.16.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sass/node_modules/readdirp": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.16.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sax": {
|
"node_modules/sax": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||||
@@ -18344,9 +18774,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
|
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@@ -18856,6 +19286,19 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"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==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"escape-string-regexp": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/style-loader": {
|
"node_modules/style-loader": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz",
|
||||||
@@ -19127,9 +19570,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.4.10",
|
"version": "3.4.14",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz",
|
||||||
"integrity": "sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==",
|
"integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
@@ -19434,6 +19877,19 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/trim-repeated": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"escape-string-regexp": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tryer": {
|
"node_modules/tryer": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"homepage": "https://hugyouu.github.io/Letterboxd-Diary-Posters-Picker",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.13.3",
|
"@emotion/react": "^11.13.3",
|
||||||
"@emotion/styled": "^11.13.0",
|
"@emotion/styled": "^11.13.0",
|
||||||
@@ -23,13 +24,16 @@
|
|||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
|
"sass": "^1.80.3",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject",
|
||||||
|
"predeploy": "npm run build",
|
||||||
|
"deploy": "gh-pages -d build"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
@@ -48,5 +52,8 @@
|
|||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"gh-pages": "^6.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import "./styles/App.css";
|
import "./styles/App.scss";
|
||||||
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
|
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
|
||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import { PersistGate } from "redux-persist/integration/react";
|
import { PersistGate } from "redux-persist/integration/react";
|
||||||
|
|||||||
@@ -1,239 +1,282 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from "react";
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import {
|
import {
|
||||||
Container, Typography, Card, CardMedia, CardContent,
|
Container,
|
||||||
Button, Checkbox, FormControlLabel, TextField, Dialog, DialogTitle, DialogContent, DialogActions,
|
Typography,
|
||||||
Paper
|
Card,
|
||||||
} from '@material-ui/core';
|
CardMedia,
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
CardContent,
|
||||||
import DeleteIcon from '@material-ui/icons/Delete';
|
Button,
|
||||||
import GetAppIcon from '@material-ui/icons/GetApp';
|
Checkbox,
|
||||||
import ShareIcon from '@material-ui/icons/Share';
|
FormControlLabel,
|
||||||
import EditIcon from '@material-ui/icons/Edit';
|
TextField,
|
||||||
import { removePoster } from '../services/action';
|
Dialog,
|
||||||
|
DialogTitle,
|
||||||
|
DialogContent,
|
||||||
|
DialogActions,
|
||||||
|
Paper,
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
|
import GetAppIcon from "@material-ui/icons/GetApp";
|
||||||
|
import ShareIcon from "@material-ui/icons/Share";
|
||||||
|
import EditIcon from "@material-ui/icons/Edit";
|
||||||
|
import { removePoster } from "../services/action";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
marginTop: theme.spacing(4),
|
marginTop: theme.spacing(4),
|
||||||
marginBottom: theme.spacing(8),
|
marginBottom: theme.spacing(8),
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
},
|
},
|
||||||
posterList: {
|
posterList: {
|
||||||
flex: 2,
|
flex: 2,
|
||||||
marginRight: theme.spacing(2),
|
marginRight: theme.spacing(2),
|
||||||
maxHeight: 'calc(100vh - 200px)',
|
maxHeight: "calc(100vh - 200px)",
|
||||||
overflowY: 'auto',
|
overflowY: "auto",
|
||||||
},
|
},
|
||||||
actionPanel: {
|
actionPanel: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
position: 'sticky',
|
position: "sticky",
|
||||||
top: theme.spacing(4),
|
top: theme.spacing(4),
|
||||||
height: 'fit-content',
|
height: "fit-content",
|
||||||
},
|
},
|
||||||
card: {
|
card: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
marginBottom: theme.spacing(2),
|
marginBottom: theme.spacing(2),
|
||||||
backgroundColor: '#2c3e50',
|
backgroundColor: "#2c3e50",
|
||||||
},
|
},
|
||||||
cardMedia: {
|
cardMedia: {
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
cardContent: {
|
cardContent: {
|
||||||
flex: '1 0 auto',
|
flex: "1 0 auto",
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: theme.spacing(2),
|
gap: theme.spacing(2),
|
||||||
},
|
},
|
||||||
slider: {
|
slider: {
|
||||||
width: '100%',
|
width: "100%",
|
||||||
marginTop: theme.spacing(2),
|
marginTop: theme.spacing(2),
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
width: '100%',
|
width: "100%",
|
||||||
},
|
},
|
||||||
typography: {
|
typography: {
|
||||||
color: '#ecf0f1',
|
color: "#ecf0f1",
|
||||||
},
|
},
|
||||||
formControl: {
|
formControl: {
|
||||||
marginBottom: theme.spacing(2),
|
marginBottom: theme.spacing(2),
|
||||||
},
|
},
|
||||||
checkbox: {
|
checkbox: {
|
||||||
color: '#3498db',
|
color: "#3498db",
|
||||||
},
|
},
|
||||||
paper: {
|
paper: {
|
||||||
padding: theme.spacing(3),
|
padding: theme.spacing(3),
|
||||||
backgroundColor: '#34495e',
|
backgroundColor: "#34495e",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const Cart = () => {
|
const Cart = () => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const selectedPosters = useSelector((state) => {
|
const selectedPosters = useSelector((state) => {
|
||||||
const selections = state.posterSelections;
|
const selections = state.posterSelections;
|
||||||
return Object.entries(selections).flatMap(([movieId, posters]) =>
|
return Object.entries(selections).flatMap(([movieId, posters]) =>
|
||||||
posters.map(posterId => ({ movieId, posterId }))
|
posters.map((posterId) => ({ movieId, posterId }))
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const [selectedForDownload, setSelectedForDownload] = useState(selectedPosters.map(() => true));
|
|
||||||
const [downloadFormat, setDownloadFormat] = useState('zip');
|
|
||||||
const [renameDialogOpen, setRenameDialogOpen] = useState(false);
|
|
||||||
const [currentPosterIndex, setCurrentPosterIndex] = useState(null);
|
|
||||||
const [newPosterName, setNewPosterName] = useState('');
|
|
||||||
|
|
||||||
const handleRemovePoster = (index) => {
|
|
||||||
dispatch(removePoster(selectedPosters[index].movieId, selectedPosters[index].posterId));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDownload = async () => {
|
|
||||||
const postersToDownload = selectedPosters
|
|
||||||
.filter((_, index) => selectedForDownload[index])
|
|
||||||
.map((poster) => ({
|
|
||||||
movieId: poster.movieId,
|
|
||||||
posterId: poster.posterId,
|
|
||||||
movieName: poster.movieName,
|
|
||||||
movieYear: poster.movieYear
|
|
||||||
}));
|
|
||||||
|
|
||||||
console.log('Downloading posters:', postersToDownload);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await axios.post('http://localhost:5000/api/download-posters', {
|
|
||||||
posters: postersToDownload,
|
|
||||||
format: downloadFormat,
|
|
||||||
}, {
|
|
||||||
responseType: 'blob',
|
|
||||||
});
|
|
||||||
|
|
||||||
const blob = new Blob([response.data], { type: response.headers['content-type'] });
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = window.URL.createObjectURL(blob);
|
|
||||||
link.download = `posters.${downloadFormat}`;
|
|
||||||
link.click();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to download posters:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleShare = () => {
|
|
||||||
console.log('Sharing selected posters');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRename = (index) => {
|
|
||||||
setCurrentPosterIndex(index);
|
|
||||||
setNewPosterName(selectedPosters[index].posterId);
|
|
||||||
setRenameDialogOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRenameConfirm = () => {
|
|
||||||
console.log(`Renaming poster ${currentPosterIndex} to ${newPosterName}`);
|
|
||||||
setRenameDialogOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Container className={classes.root}>
|
|
||||||
<div className={classes.posterList}>
|
|
||||||
<Typography variant="h4" gutterBottom className={classes.typography}>Your Cart</Typography>
|
|
||||||
{selectedPosters.map((poster, index) => (
|
|
||||||
<Card key={index} className={classes.card}>
|
|
||||||
<CardMedia
|
|
||||||
className={classes.cardMedia}
|
|
||||||
image={`https://image.tmdb.org/t/p/w500${poster.posterId}`}
|
|
||||||
title={`Poster ${index + 1}`}
|
|
||||||
/>
|
|
||||||
<CardContent className={classes.cardContent}>
|
|
||||||
<Typography variant="h6"
|
|
||||||
className={classes.typography}>{`Movie ID: ${poster.movieId}`}</Typography>
|
|
||||||
<Typography variant="body2"
|
|
||||||
className={classes.typography}>{poster.posterId}</Typography>
|
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Checkbox
|
|
||||||
checked={selectedForDownload[index]}
|
|
||||||
onChange={(e) => {
|
|
||||||
const newSelected = [...selectedForDownload];
|
|
||||||
newSelected[index] = e.target.checked;
|
|
||||||
setSelectedForDownload(newSelected);
|
|
||||||
}}
|
|
||||||
className={classes.checkbox}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Select for download"
|
|
||||||
className={classes.typography}
|
|
||||||
/>
|
|
||||||
<Button startIcon={<DeleteIcon/>} onClick={() => handleRemovePoster(index)}
|
|
||||||
className={classes.typography}>Remove</Button>
|
|
||||||
<Button startIcon={<EditIcon/>} onClick={() => handleRename(index)}
|
|
||||||
className={classes.typography}>Rename</Button>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<Paper className={classes.actionPanel} elevation={3}>
|
|
||||||
<div className={classes.actions}>
|
|
||||||
<Typography gutterBottom>Download Format</Typography>
|
|
||||||
<TextField
|
|
||||||
select
|
|
||||||
value={downloadFormat}
|
|
||||||
onChange={(e) => setDownloadFormat(e.target.value)}
|
|
||||||
SelectProps={{
|
|
||||||
native: true,
|
|
||||||
}}
|
|
||||||
className={classes.formControl}
|
|
||||||
>
|
|
||||||
<option value="zip">ZIP</option>
|
|
||||||
<option value="tar">TAR</option>
|
|
||||||
<option value="7z">7Z</option>
|
|
||||||
</TextField>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
startIcon={<GetAppIcon/>}
|
|
||||||
onClick={handleDownload}
|
|
||||||
disabled={selectedForDownload.every((selected) => !selected)}
|
|
||||||
className={classes.button}
|
|
||||||
>
|
|
||||||
Download Selected
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
color="secondary"
|
|
||||||
startIcon={<ShareIcon/>}
|
|
||||||
onClick={handleShare}
|
|
||||||
className={classes.button}
|
|
||||||
>
|
|
||||||
Share Selection
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Paper>
|
|
||||||
<Dialog open={renameDialogOpen} onClose={() => setRenameDialogOpen(false)}>
|
|
||||||
<DialogTitle>Rename Poster</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
<TextField
|
|
||||||
autoFocus
|
|
||||||
margin="dense"
|
|
||||||
label="New Name"
|
|
||||||
type="text"
|
|
||||||
fullWidth
|
|
||||||
value={newPosterName}
|
|
||||||
onChange={(e) => setNewPosterName(e.target.value)}
|
|
||||||
/>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={() => setRenameDialogOpen(false)} color="primary">
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
<Button onClick={handleRenameConfirm} color="primary">
|
|
||||||
Rename
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
</Container>
|
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const [selectedForDownload, setSelectedForDownload] = useState(
|
||||||
|
selectedPosters.map(() => true)
|
||||||
|
);
|
||||||
|
const [downloadFormat, setDownloadFormat] = useState("zip");
|
||||||
|
const [renameDialogOpen, setRenameDialogOpen] = useState(false);
|
||||||
|
const [currentPosterIndex, setCurrentPosterIndex] = useState(null);
|
||||||
|
const [newPosterName, setNewPosterName] = useState("");
|
||||||
|
|
||||||
|
const handleRemovePoster = (index) => {
|
||||||
|
dispatch(
|
||||||
|
removePoster(
|
||||||
|
selectedPosters[index].movieId,
|
||||||
|
selectedPosters[index].posterId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDownload = async () => {
|
||||||
|
const postersToDownload = selectedPosters
|
||||||
|
.filter((_, index) => selectedForDownload[index])
|
||||||
|
.map((poster) => ({
|
||||||
|
movieId: poster.movieId,
|
||||||
|
posterId: poster.posterId,
|
||||||
|
movieName: poster.movieName,
|
||||||
|
movieYear: poster.movieYear,
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log("Downloading posters:", postersToDownload);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post(
|
||||||
|
"http://localhost:5000/api/download-posters",
|
||||||
|
{
|
||||||
|
posters: postersToDownload,
|
||||||
|
format: downloadFormat,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
responseType: "blob",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const blob = new Blob([response.data], {
|
||||||
|
type: response.headers["content-type"],
|
||||||
|
});
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = window.URL.createObjectURL(blob);
|
||||||
|
link.download = `posters.${downloadFormat}`;
|
||||||
|
link.click();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to download posters:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleShare = () => {
|
||||||
|
console.log("Sharing selected posters");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRename = (index) => {
|
||||||
|
setCurrentPosterIndex(index);
|
||||||
|
setNewPosterName(selectedPosters[index].posterId);
|
||||||
|
setRenameDialogOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRenameConfirm = () => {
|
||||||
|
console.log(`Renaming poster ${currentPosterIndex} to ${newPosterName}`);
|
||||||
|
setRenameDialogOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className="cart-container">
|
||||||
|
<div className="poster-list">
|
||||||
|
<Typography variant="h4" gutterBottom className="cart-title">
|
||||||
|
Your Cart
|
||||||
|
</Typography>
|
||||||
|
{selectedPosters.map((poster, index) => (
|
||||||
|
<Card key={index} className="poster-card">
|
||||||
|
<CardMedia
|
||||||
|
className="poster-media"
|
||||||
|
image={`https://image.tmdb.org/t/p/w500${poster.posterId}`}
|
||||||
|
title={`Poster ${index + 1}`}
|
||||||
|
/>
|
||||||
|
<CardContent className="poster-content">
|
||||||
|
<Typography variant="h6" className="poster-title">
|
||||||
|
{`Movie ID: ${poster.movieId}`}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" className="poster-id">
|
||||||
|
{poster.posterId}
|
||||||
|
</Typography>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={selectedForDownload[index]}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newSelected = [...selectedForDownload];
|
||||||
|
newSelected[index] = e.target.checked;
|
||||||
|
setSelectedForDownload(newSelected);
|
||||||
|
}}
|
||||||
|
className="checkbox"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Select for download"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
startIcon={<DeleteIcon />}
|
||||||
|
onClick={() => handleRemovePoster(index)}
|
||||||
|
className="action-button"
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
startIcon={<EditIcon />}
|
||||||
|
onClick={() => handleRename(index)}
|
||||||
|
className="action-button"
|
||||||
|
>
|
||||||
|
Rename
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Paper className="action-panel" elevation={3}>
|
||||||
|
<div className="action-buttons">
|
||||||
|
<Typography gutterBottom className="action-title">
|
||||||
|
Download Format
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
value={downloadFormat}
|
||||||
|
onChange={(e) => setDownloadFormat(e.target.value)}
|
||||||
|
SelectProps={{
|
||||||
|
native: true,
|
||||||
|
}}
|
||||||
|
className="form-control"
|
||||||
|
>
|
||||||
|
<option value="zip">ZIP</option>
|
||||||
|
<option value="tar">TAR</option>
|
||||||
|
<option value="7z">7Z</option>
|
||||||
|
</TextField>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
startIcon={<GetAppIcon />}
|
||||||
|
onClick={handleDownload}
|
||||||
|
disabled={selectedForDownload.every((selected) => !selected)}
|
||||||
|
className="primary-button"
|
||||||
|
>
|
||||||
|
Download Selected
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="secondary"
|
||||||
|
startIcon={<ShareIcon />}
|
||||||
|
onClick={handleShare}
|
||||||
|
className="secondary-button"
|
||||||
|
>
|
||||||
|
Share Selection
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Paper>
|
||||||
|
<Dialog
|
||||||
|
open={renameDialogOpen}
|
||||||
|
onClose={() => setRenameDialogOpen(false)}
|
||||||
|
className="rename-dialog"
|
||||||
|
>
|
||||||
|
<DialogTitle className="dialog-title">Rename Poster</DialogTitle>
|
||||||
|
<DialogContent className="dialog-content">
|
||||||
|
<TextField
|
||||||
|
autoFocus
|
||||||
|
margin="dense"
|
||||||
|
label="New Name"
|
||||||
|
type="text"
|
||||||
|
fullWidth
|
||||||
|
value={newPosterName}
|
||||||
|
onChange={(e) => setNewPosterName(e.target.value)}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions className="dialog-actions">
|
||||||
|
<Button onClick={() => setRenameDialogOpen(false)} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleRenameConfirm} color="primary">
|
||||||
|
Rename
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Cart;
|
export default Cart;
|
||||||
@@ -17,6 +17,8 @@ import {
|
|||||||
import CheckIcon from "@material-ui/icons/Check";
|
import CheckIcon from "@material-ui/icons/Check";
|
||||||
import NavBar from "./NavBar";
|
import NavBar from "./NavBar";
|
||||||
|
|
||||||
|
const apiUrl = process.env.REACT_APP_API_URL;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
marginTop: theme.spacing(4),
|
marginTop: theme.spacing(4),
|
||||||
@@ -85,14 +87,12 @@ const PosterGallery = ({ movieId }) => {
|
|||||||
(state) => state.posterSelections[movieId] || []
|
(state) => state.posterSelections[movieId] || []
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(movieId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchPosters = async () => {
|
const fetchPosters = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`http://localhost:5000/api/posters/${movieName}/${movieYear}`
|
`${apiUrl}/api/posters/${movieName}/${movieYear}`
|
||||||
);
|
);
|
||||||
setPosters(response.data.posters);
|
setPosters(response.data.posters);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -115,39 +115,39 @@ const PosterGallery = ({ movieId }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Container className={classes.root}>
|
<Container className="poster-gallery">
|
||||||
<Paper elevation={3} className={classes.paper}>
|
<Paper elevation={3} className="content-paper">
|
||||||
<Typography variant="h4" gutterBottom className={classes.title}>
|
<Typography variant="h4" gutterBottom className="title">
|
||||||
Posters for {movieName} ({movieYear})
|
Posters for {movieName} ({movieYear})
|
||||||
</Typography>
|
</Typography>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Box className={classes.loadingContainer}>
|
<Box className="loading-container">
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
{posters.map((poster, index) => (
|
{posters.map((poster, index) => (
|
||||||
<Grid item xs={12} sm={6} md={4} lg={3} key={index}>
|
<Grid item xs={12} sm={6} md={4} lg={3} key={index}>
|
||||||
<Card
|
<Card
|
||||||
className={`${classes.posterCard} ${
|
className={`poster-card ${
|
||||||
selectedPosters.includes(poster.file_path)
|
selectedPosters.includes(poster.file_path)
|
||||||
? classes.selectedPoster
|
? "selected-poster"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handlePosterSelect(poster.file_path)}
|
onClick={() => handlePosterSelect(poster.file_path)}
|
||||||
>
|
>
|
||||||
<CardMedia
|
<CardMedia
|
||||||
className={classes.posterImage}
|
className="poster-image"
|
||||||
image={`https://image.tmdb.org/t/p/w500${poster.file_path}`}
|
image={`https://image.tmdb.org/t/p/w500${poster.file_path}`}
|
||||||
title={`${movieName} poster ${index + 1}`}
|
title={`${movieName} poster ${index + 1}`}
|
||||||
/>
|
/>
|
||||||
{selectedPosters.includes(poster.file_path) && (
|
{selectedPosters.includes(poster.file_path) && (
|
||||||
<CheckIcon className={classes.checkIcon} />
|
<CheckIcon className="check-icon" />
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
</Paper>
|
</Paper>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
LinearProgress,
|
LinearProgress,
|
||||||
Box,
|
Box,
|
||||||
Paper,
|
Paper,
|
||||||
makeStyles,
|
|
||||||
Button,
|
Button,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import Pagination from "@mui/material/Pagination";
|
import Pagination from "@mui/material/Pagination";
|
||||||
@@ -19,127 +18,7 @@ import queryString from "query-string";
|
|||||||
import pulpGif from "../static/images/pulp.gif";
|
import pulpGif from "../static/images/pulp.gif";
|
||||||
import NavBar from "./NavBar";
|
import NavBar from "./NavBar";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const apiUrl = process.env.REACT_APP_API_URL;
|
||||||
root: {
|
|
||||||
marginTop: theme.spacing(4),
|
|
||||||
marginBottom: theme.spacing(8),
|
|
||||||
},
|
|
||||||
paper: {
|
|
||||||
padding: theme.spacing(3),
|
|
||||||
borderRadius: theme.shape.borderRadius,
|
|
||||||
backgroundColor: "#1c1f23",
|
|
||||||
color: "white",
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
marginBottom: theme.spacing(3),
|
|
||||||
},
|
|
||||||
username: {
|
|
||||||
color: "#00A346",
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
},
|
|
||||||
list: {
|
|
||||||
maxHeight: "800px",
|
|
||||||
minHeight: "900px",
|
|
||||||
},
|
|
||||||
listItem: {
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: theme.palette.action.hover,
|
|
||||||
},
|
|
||||||
"&:not(:last-child)": {
|
|
||||||
borderBottom: `1px solid #667788`,
|
|
||||||
paddingTop: theme.spacing(0.5),
|
|
||||||
paddingBottom: theme.spacing(0.5),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
poster: {
|
|
||||||
width: "50px",
|
|
||||||
height: "75px",
|
|
||||||
objectFit: "cover",
|
|
||||||
marginRight: theme.spacing(2),
|
|
||||||
borderRadius: theme.shape.borderRadius,
|
|
||||||
},
|
|
||||||
movieInfo: {
|
|
||||||
flexGrow: 1,
|
|
||||||
},
|
|
||||||
movieTitle: {
|
|
||||||
color: "white",
|
|
||||||
fontFamily: "TiemposTextWeb-Semibold, Georgia, serif",
|
|
||||||
fontSize: "1.38461538rem",
|
|
||||||
fontWeight: "400",
|
|
||||||
|
|
||||||
"&:hover": {
|
|
||||||
color: "var(--primary)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
movieYear: {
|
|
||||||
color: "#667788",
|
|
||||||
},
|
|
||||||
watchedDate: {
|
|
||||||
color: "#667788",
|
|
||||||
textAlign: "center",
|
|
||||||
},
|
|
||||||
watchedDay: {
|
|
||||||
fontSize: "2rem",
|
|
||||||
},
|
|
||||||
refreshButton: {
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
},
|
|
||||||
paginationContainer: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
marginTop: theme.spacing(3),
|
|
||||||
},
|
|
||||||
progressContainer: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
flexDirection: "column",
|
|
||||||
height: "200px",
|
|
||||||
},
|
|
||||||
progressLabel: {
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
color: "white",
|
|
||||||
},
|
|
||||||
noMoviesContainer: {
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
height: "400px",
|
|
||||||
},
|
|
||||||
gifContainer: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
position: "relative",
|
|
||||||
width: "200px",
|
|
||||||
height: "200px",
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
},
|
|
||||||
circleBackground: {
|
|
||||||
position: "absolute",
|
|
||||||
width: "120%",
|
|
||||||
height: "120%",
|
|
||||||
borderRadius: "50%",
|
|
||||||
backgroundColor: "#ffffff",
|
|
||||||
clipPath: "inset(0 0 25% 0)",
|
|
||||||
bottom: "-28%",
|
|
||||||
},
|
|
||||||
gif: {
|
|
||||||
position: "absolute",
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain",
|
|
||||||
},
|
|
||||||
backButton: {
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
backgroundColor: "#00A346",
|
|
||||||
color: "white",
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: "#008036",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const paginationTheme = createTheme({
|
const paginationTheme = createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
@@ -173,7 +52,6 @@ const paginationTheme = createTheme({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const PosterSelector = () => {
|
const PosterSelector = () => {
|
||||||
const classes = useStyles();
|
|
||||||
const [movies, setMovies] = useState([]);
|
const [movies, setMovies] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
@@ -182,20 +60,19 @@ const PosterSelector = () => {
|
|||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const moviesPerPage = 10;
|
const moviesPerPage = 8;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const parsed = queryString.parse(location.search);
|
const parsed = queryString.parse(location.search);
|
||||||
const pageNumber = parsed.page ? parseInt(parsed.page, 10) : 1;
|
const pageNumber = parsed.page ? parseInt(parsed.page, 10) : 1;
|
||||||
setPage(pageNumber);
|
setPage(pageNumber);
|
||||||
|
|
||||||
fetchMovies(pageNumber).then(r => console.log(r));
|
fetchMovies(pageNumber).then((r) => console.log(r));
|
||||||
// fetchUsername();
|
|
||||||
}, [location.search]);
|
}, [location.search]);
|
||||||
|
|
||||||
const fetchUsername = async () => {
|
const fetchUsername = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get("http://localhost:5000/api/username");
|
const response = await axios.get(`${apiUrl}/api/username`);
|
||||||
setUsername(response.data.username);
|
setUsername(response.data.username);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching username:", error);
|
console.error("Error fetching username:", error);
|
||||||
@@ -208,7 +85,7 @@ const PosterSelector = () => {
|
|||||||
setProgress(0);
|
setProgress(0);
|
||||||
|
|
||||||
const response = await axios.get(
|
const response = await axios.get(
|
||||||
`http://localhost:5000/api/movies?page=${pageNumber}&limit=${moviesPerPage}`,
|
`${apiUrl}/api/movies?page=${pageNumber}&limit=${moviesPerPage}`,
|
||||||
{
|
{
|
||||||
onDownloadProgress: (progressEvent) => {
|
onDownloadProgress: (progressEvent) => {
|
||||||
const percentCompleted = Math.round(
|
const percentCompleted = Math.round(
|
||||||
@@ -240,7 +117,7 @@ const PosterSelector = () => {
|
|||||||
|
|
||||||
const handleRefreshFiles = async () => {
|
const handleRefreshFiles = async () => {
|
||||||
try {
|
try {
|
||||||
await axios.delete("http://localhost:5000/api/delete-csv");
|
await axios.delete(`${apiUrl}/api/delete-csv`);
|
||||||
navigate("/");
|
navigate("/");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error deleting CSV file:", error);
|
console.error("Error deleting CSV file:", error);
|
||||||
@@ -267,121 +144,116 @@ const PosterSelector = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Container className={classes.root}>
|
<Container className="poster-selector">
|
||||||
<Paper elevation={3} className={classes.paper}>
|
<Paper elevation={3} className="content-paper">
|
||||||
<Typography variant="h4" gutterBottom className={classes.title}>
|
<Typography variant="h4" className="title">
|
||||||
Your diary
|
Your diary
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{username && (
|
{username && (
|
||||||
<Typography variant="h6" className={classes.username}>
|
<Typography variant="h6" className="username">
|
||||||
Letterboxd User: {username}
|
Letterboxd User: {username}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Box className={classes.progressContainer}>
|
<Box className="progress-container">
|
||||||
<LinearProgress variant="determinate" value={progress} />
|
<LinearProgress />
|
||||||
<Typography className={classes.progressLabel}>
|
<Typography className="progress-label">
|
||||||
Downloading movies...
|
Downloading movies...
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
) : movies.length > 0 ? (
|
) : movies.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<List className={classes.list}>
|
<List className="movies-list">
|
||||||
{movies.map((movie, index) => (
|
{movies.map((movie, index) => (
|
||||||
<ListItem
|
<ListItem
|
||||||
button
|
button
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => handleMovieClick(movie.Name, movie.Year)}
|
onClick={() => handleMovieClick(movie.Name, movie.Year)}
|
||||||
className={classes.listItem}
|
className="movie-item"
|
||||||
>
|
>
|
||||||
<Grid container alignItems="center">
|
<Grid container alignItems="center">
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<img
|
<img
|
||||||
src={
|
src={
|
||||||
`https://image.tmdb.org/t/p/w500${movie.Poster.file_path}` ||
|
`https://image.tmdb.org/t/p/w500${movie.Poster.file_path}` ||
|
||||||
`/api/placeholder/50/75`
|
`/api/placeholder/50/75`
|
||||||
}
|
}
|
||||||
alt={movie.Name}
|
alt={movie.Name}
|
||||||
className={classes.poster}
|
className="movie-poster"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item className={classes.movieInfo}>
|
<Grid item className="movie-info">
|
||||||
<Typography
|
<Typography variant="subtitle1" className="movie-title">
|
||||||
variant="subtitle1"
|
{movie.Name}
|
||||||
className={classes.movieTitle}
|
</Typography>
|
||||||
>
|
<Typography variant="body2" className="movie-year">
|
||||||
{movie.Name}
|
{movie.Year}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography
|
</Grid>
|
||||||
variant="body2"
|
<Grid item>
|
||||||
color="textSecondary"
|
<Box className="watched-date">
|
||||||
className={classes.movieYear}
|
{(() => {
|
||||||
>
|
const { day, month } = formatWatchedDate(
|
||||||
{movie.Year}
|
movie["Watched Date"]
|
||||||
</Typography>
|
);
|
||||||
</Grid>
|
return (
|
||||||
<Grid item>
|
<>
|
||||||
<Box className={classes.watchedDate}>
|
<Typography
|
||||||
{(() => {
|
variant="body2"
|
||||||
const { day, month } = formatWatchedDate(
|
className="watched-day"
|
||||||
movie["Watched Date"]
|
>
|
||||||
);
|
{day}
|
||||||
return (
|
</Typography>
|
||||||
<>
|
<Typography
|
||||||
<Typography
|
variant="body2"
|
||||||
variant="body2"
|
className="watched-month"
|
||||||
className={classes.watchedDay}
|
>
|
||||||
>
|
{month}
|
||||||
{day}
|
</Typography>
|
||||||
</Typography>
|
</>
|
||||||
<Typography
|
);
|
||||||
variant="body2"
|
})()}
|
||||||
className={classes.watchedMonth}
|
</Box>
|
||||||
>
|
</Grid>
|
||||||
{month}
|
</Grid>
|
||||||
</Typography>
|
</ListItem>
|
||||||
</>
|
))}
|
||||||
);
|
</List>
|
||||||
})()}
|
<Box className="pagination-container">
|
||||||
</Box>
|
<ThemeProvider theme={paginationTheme}>
|
||||||
</Grid>
|
<Pagination
|
||||||
</Grid>
|
count={totalPages}
|
||||||
</ListItem>
|
page={page}
|
||||||
))}
|
onChange={handlePageChange}
|
||||||
</List>
|
color="primary"
|
||||||
<Box className={classes.paginationContainer}>
|
|
||||||
<ThemeProvider theme={paginationTheme}>
|
|
||||||
<Pagination
|
|
||||||
count={totalPages}
|
|
||||||
page={page}
|
|
||||||
onChange={handlePageChange}
|
|
||||||
color="primary"
|
|
||||||
/>
|
|
||||||
</ThemeProvider>
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Box className={classes.noMoviesContainer}>
|
|
||||||
<div className={classes.gifContainer}>
|
|
||||||
<div className={classes.circleBackground}></div>
|
|
||||||
<img
|
|
||||||
src={pulpGif}
|
|
||||||
alt="Confused reaction"
|
|
||||||
className={classes.gif}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</ThemeProvider>
|
||||||
<Typography variant="body1" gutterBottom>
|
|
||||||
No movies found in your diary. Please check your Letterboxd
|
|
||||||
username or CSV file.
|
|
||||||
</Typography>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
className={classes.backButton}
|
|
||||||
onClick={handleGoBack}
|
|
||||||
>
|
|
||||||
Go Back
|
|
||||||
</Button>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Box className="no-movies-container">
|
||||||
|
<div className="gif-container">
|
||||||
|
<div className="circle-background"></div>
|
||||||
|
<img
|
||||||
|
src={pulpGif}
|
||||||
|
alt="Confused reaction"
|
||||||
|
className="reaction-gif"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Typography variant="body1" gutterBottom>
|
||||||
|
No movies found in your diary. Please check your Letterboxd
|
||||||
|
username or CSV file.
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
className="back-button"
|
||||||
|
onClick={handleGoBack}
|
||||||
|
>
|
||||||
|
Go Back
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Paper>
|
</Paper>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@@ -7,103 +7,15 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
TextField,
|
TextField,
|
||||||
makeStyles,
|
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import { CloudUploadOutlined } from "@material-ui/icons";
|
import { CloudUploadOutlined } from "@material-ui/icons";
|
||||||
import CloudDoneOutlinedIcon from "@mui/icons-material/CloudDoneOutlined";
|
import CloudDoneOutlinedIcon from "@mui/icons-material/CloudDoneOutlined";
|
||||||
import { useDropzone } from "react-dropzone";
|
import { useDropzone } from "react-dropzone";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const apiUrl = process.env.REACT_APP_API_URL;
|
||||||
root: {
|
|
||||||
padding: theme.spacing(4),
|
|
||||||
backgroundColor: "#14181c",
|
|
||||||
minHeight: "100vh",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
},
|
|
||||||
card: {
|
|
||||||
width: "100%",
|
|
||||||
maxWidth: "600px",
|
|
||||||
backgroundColor: "#1c1f23",
|
|
||||||
borderRadius: theme.shape.borderRadius,
|
|
||||||
boxShadow: theme.shadows[3],
|
|
||||||
padding: theme.spacing(4),
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
marginBottom: theme.spacing(3),
|
|
||||||
fontWeight: "bold",
|
|
||||||
color: "#ffffff",
|
|
||||||
},
|
|
||||||
dropzone: {
|
|
||||||
border: `2px dashed #00A346`,
|
|
||||||
borderRadius: theme.shape.borderRadius,
|
|
||||||
padding: theme.spacing(4),
|
|
||||||
textAlign: "center",
|
|
||||||
cursor: "pointer",
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: "#1f252a",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dropzoneIcon: {
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
color: "#00A346",
|
|
||||||
},
|
|
||||||
dropzoneText: {
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
color: "#ffffff",
|
|
||||||
},
|
|
||||||
progressContainer: {
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
},
|
|
||||||
submitButton: {
|
|
||||||
color: "#fff",
|
|
||||||
fontSize: "0.8rem",
|
|
||||||
fontWeight: "900",
|
|
||||||
textTransform: "uppercase",
|
|
||||||
letterSpacing: "0.04em",
|
|
||||||
lineHeight: "2.8rem",
|
|
||||||
display: "inline-block",
|
|
||||||
cursor: "pointer",
|
|
||||||
padding: "0 1rem",
|
|
||||||
border: "0",
|
|
||||||
borderRadius: "4px",
|
|
||||||
outline: "none",
|
|
||||||
background: "#526e89",
|
|
||||||
transition: "background-color 0.3s ease",
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: "#1caff2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
overviewText: {
|
|
||||||
color: "#456",
|
|
||||||
marginTop: theme.spacing(4),
|
|
||||||
padding: theme.spacing(3),
|
|
||||||
},
|
|
||||||
usernameField: {
|
|
||||||
marginBottom: theme.spacing(3),
|
|
||||||
"& .MuiOutlinedInput-root": {
|
|
||||||
color: "#ffffff",
|
|
||||||
"& fieldset": {
|
|
||||||
borderColor: "#00A346",
|
|
||||||
},
|
|
||||||
"&:hover fieldset": {
|
|
||||||
borderColor: "#00A346",
|
|
||||||
},
|
|
||||||
"&.Mui-focused fieldset": {
|
|
||||||
borderColor: "#1caff2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"& .MuiInputLabel-root": {
|
|
||||||
color: "#ffffff",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const UploadDiary = () => {
|
const UploadDiary = () => {
|
||||||
const classes = useStyles();
|
|
||||||
const [file, setFile] = useState(null);
|
const [file, setFile] = useState(null);
|
||||||
const [uploading, setUploading] = useState(false);
|
const [uploading, setUploading] = useState(false);
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
@@ -112,7 +24,7 @@ const UploadDiary = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkCSVFile = async () => {
|
const checkCSVFile = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get("http://localhost:5000/api/check-csv");
|
const response = await axios.get(`${apiUrl}/api/check-csv`);
|
||||||
if (response.data.fileExists) {
|
if (response.data.fileExists) {
|
||||||
navigate("/PosterSelector");
|
navigate("/PosterSelector");
|
||||||
}
|
}
|
||||||
@@ -136,16 +48,14 @@ const UploadDiary = () => {
|
|||||||
setUploading(true);
|
setUploading(true);
|
||||||
try {
|
try {
|
||||||
if (username) {
|
if (username) {
|
||||||
// Here you would implement the logic to fetch the diary from Letterboxd
|
|
||||||
// For now, we'll just simulate a successful fetch
|
|
||||||
console.log(`Fetching diary for user: ${username}`);
|
console.log(`Fetching diary for user: ${username}`);
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate API call
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
navigate("/PosterSelector");
|
navigate("/PosterSelector");
|
||||||
} else if (file) {
|
} else if (file) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", file);
|
formData.append("file", file);
|
||||||
|
|
||||||
await axios.post("http://localhost:5000/api/upload-csv", formData, {
|
await axios.post(`${apiUrl}/api/upload-csv`, formData, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "multipart/form-data",
|
"Content-Type": "multipart/form-data",
|
||||||
},
|
},
|
||||||
@@ -162,13 +72,13 @@ const UploadDiary = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className={classes.root}>
|
<Container className="upload-diary">
|
||||||
<div className={classes.card}>
|
<div className="upload-card">
|
||||||
<Typography variant="h4" className={classes.title}>
|
<Typography variant="h4" className="title">
|
||||||
Upload Letterboxd Diary
|
Upload Letterboxd Diary
|
||||||
</Typography>
|
</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
className={classes.usernameField}
|
className="username-field"
|
||||||
label="Letterboxd Username"
|
label="Letterboxd Username"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -176,42 +86,33 @@ const UploadDiary = () => {
|
|||||||
onChange={(e) => setUsername(e.target.value)}
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
placeholder="Enter your Letterboxd username"
|
placeholder="Enter your Letterboxd username"
|
||||||
/>
|
/>
|
||||||
<Typography
|
<Typography variant="body2" className="or-text">
|
||||||
variant="body2"
|
|
||||||
style={{ color: "#ffffff", marginBottom: "1rem" }}
|
|
||||||
>
|
|
||||||
Or upload a CSV file:
|
Or upload a CSV file:
|
||||||
</Typography>
|
</Typography>
|
||||||
<div {...getRootProps()} className={classes.dropzone}>
|
<div {...getRootProps()} className="dropzone">
|
||||||
<input {...getInputProps()} />
|
<input {...getInputProps()} />
|
||||||
{file ? (
|
{file ? (
|
||||||
<>
|
<>
|
||||||
<CloudDoneOutlinedIcon
|
<CloudDoneOutlinedIcon className="dropzone-icon" />
|
||||||
className={classes.dropzoneIcon}
|
<Typography variant="h6" className="dropzone-text">
|
||||||
style={{ fontSize: "4rem" }}
|
|
||||||
/>
|
|
||||||
<Typography variant="h6" className={classes.dropzoneText}>
|
|
||||||
Your file has been uploaded: {file.name}
|
Your file has been uploaded: {file.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<CloudUploadOutlined
|
<CloudUploadOutlined className="dropzone-icon" />
|
||||||
className={classes.dropzoneIcon}
|
<Typography variant="h6" className="dropzone-text">
|
||||||
style={{ fontSize: "4rem" }}
|
|
||||||
/>
|
|
||||||
<Typography variant="h6" className={classes.dropzoneText}>
|
|
||||||
Drag and drop a CSV file here or click to select
|
Drag and drop a CSV file here or click to select
|
||||||
</Typography>
|
</Typography>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Grid container justify="center" className={classes.progressContainer}>
|
<Grid container justify="center" className="progress-container">
|
||||||
{uploading ? (
|
{uploading ? (
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
className={classes.submitButton}
|
className="submit-button"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={handleUpload}
|
onClick={handleUpload}
|
||||||
disabled={!username && !file}
|
disabled={!username && !file}
|
||||||
@@ -221,7 +122,7 @@ const UploadDiary = () => {
|
|||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="body1" className={classes.overviewText}>
|
<Typography variant="body1" className="overview-text">
|
||||||
This tool allows you to easily import your Letterboxd diary and select
|
This tool allows you to easily import your Letterboxd diary and select
|
||||||
your favorite movie poster. Follow these simple steps:
|
your favorite movie poster. Follow these simple steps:
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
@use "./scss/uploadDiary";
|
||||||
|
@use "./scss/posterSelector";
|
||||||
|
@use "./scss/posterGallery";
|
||||||
|
@use "./scss/cart";
|
||||||
|
|
||||||
.App {
|
.App {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,7 @@ code {
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
--background: #fff;
|
--background: #fff;
|
||||||
|
--bgComp: #1c1f23;
|
||||||
--foreground: #2c3e50;
|
--foreground: #2c3e50;
|
||||||
--primary: #1caff2;
|
--primary: #1caff2;
|
||||||
--secondary: #000;
|
--secondary: #000;
|
||||||
|
|||||||
166
src/styles/scss/_cart.scss
Normal file
166
src/styles/scss/_cart.scss
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
// Variables
|
||||||
|
$primary-color: #00a346;
|
||||||
|
$secondary-color: #3498db;
|
||||||
|
$background-dark: #2c3e50;
|
||||||
|
$background-light: #34495e;
|
||||||
|
$text-white: #ecf0f1;
|
||||||
|
$text-muted: #95a5a6;
|
||||||
|
$hover-scale: 1.05;
|
||||||
|
$gap-spacing: 1rem;
|
||||||
|
|
||||||
|
.cart-container {
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 4rem;
|
||||||
|
display: flex;
|
||||||
|
gap: $gap-spacing;
|
||||||
|
|
||||||
|
.poster-list {
|
||||||
|
flex: 2;
|
||||||
|
margin-right: 2rem;
|
||||||
|
max-height: calc(100vh - 200px);
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.cart-title {
|
||||||
|
color: $text-white;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poster-card {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
background-color: $background-dark;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.poster-media {
|
||||||
|
width: 120px;
|
||||||
|
height: 180px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poster-content {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 1rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.poster-title {
|
||||||
|
color: $text-white;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poster-id {
|
||||||
|
color: $text-muted;
|
||||||
|
font-size: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poster-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
.action-button {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid $text-muted;
|
||||||
|
color: $text-white;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $background-light;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-panel {
|
||||||
|
flex: 1;
|
||||||
|
position: sticky;
|
||||||
|
top: 2rem;
|
||||||
|
height: fit-content;
|
||||||
|
padding: 1.5rem;
|
||||||
|
background-color: $background-light;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.action-title {
|
||||||
|
color: $text-white;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: $text-white;
|
||||||
|
|
||||||
|
select {
|
||||||
|
background-color: $background-dark;
|
||||||
|
color: $text-white;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 1px solid $text-muted;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
.primary-button,
|
||||||
|
.secondary-button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&.primary-button {
|
||||||
|
background-color: $primary-color;
|
||||||
|
color: $text-white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: darken($primary-color, 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background-color: darken($primary-color, 20%);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.secondary-button {
|
||||||
|
background-color: $secondary-color;
|
||||||
|
color: $text-white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: darken($secondary-color, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/styles/scss/_posterGallery.scss
Normal file
70
src/styles/scss/_posterGallery.scss
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// Variables
|
||||||
|
$primary-color: #00a346;
|
||||||
|
$background-dark: #1c1f23;
|
||||||
|
$text-white: #ffffff;
|
||||||
|
$hover-scale: 1.05;
|
||||||
|
$loading-height: 50vh;
|
||||||
|
|
||||||
|
.poster-gallery {
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
|
||||||
|
.content-paper {
|
||||||
|
padding: 1.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: $background-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: $text-white;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poster-card {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale($hover-scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected-poster {
|
||||||
|
border: 4px solid $primary-color;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poster-image {
|
||||||
|
padding-top: 150%;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.5rem;
|
||||||
|
right: 0.5rem;
|
||||||
|
background-color: $primary-color;
|
||||||
|
color: $text-white;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: $loading-height;
|
||||||
|
}
|
||||||
|
}
|
||||||
192
src/styles/scss/_posterSelector.scss
Normal file
192
src/styles/scss/_posterSelector.scss
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
// Variables
|
||||||
|
$primary-color: #00a346;
|
||||||
|
$secondary-color: #667788;
|
||||||
|
$background-dark: #1c1f23;
|
||||||
|
$text-white: #ffffff;
|
||||||
|
$text-gray: #667788;
|
||||||
|
$border-color: #667788;
|
||||||
|
$hover-color: rgba(102, 119, 136, 0.2);
|
||||||
|
|
||||||
|
.poster-selector {
|
||||||
|
padding: 0 2rem;
|
||||||
|
max-width: 100% !important; // Override MUI Container
|
||||||
|
margin: 2rem auto 4rem !important;
|
||||||
|
|
||||||
|
.content-paper {
|
||||||
|
padding: 1.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: $background-dark !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: $text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
color: $primary-color;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movies-list {
|
||||||
|
max-height: 800px;
|
||||||
|
min-height: 900px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-item {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $hover-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: 1px solid $border-color;
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
padding-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override MUI ListItem styles
|
||||||
|
&.MuiListItem-root {
|
||||||
|
padding: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MuiGrid-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-poster {
|
||||||
|
width: 50px;
|
||||||
|
height: 75px;
|
||||||
|
object-fit: cover;
|
||||||
|
margin-right: 1rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-info {
|
||||||
|
flex-grow: 1;
|
||||||
|
max-width: calc(100% - 110px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-title {
|
||||||
|
color: $text-white;
|
||||||
|
font-family: "TiemposTextWeb-Semibold, Georgia, serif";
|
||||||
|
font-size: 1.38461538rem;
|
||||||
|
font-weight: 400;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.movie-year {
|
||||||
|
color: $text-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.watched-date {
|
||||||
|
color: $text-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.watched-day {
|
||||||
|
font-size: 2rem;
|
||||||
|
line-height: 1;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.watched-month {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
|
||||||
|
// Override MUI Pagination styles
|
||||||
|
.MuiPagination-root {
|
||||||
|
.MuiPaginationItem-root {
|
||||||
|
color: $text-white;
|
||||||
|
|
||||||
|
&.Mui-selected {
|
||||||
|
background-color: $secondary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 200px;
|
||||||
|
|
||||||
|
.MuiLinearProgress-root {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-label {
|
||||||
|
margin-top: 1rem;
|
||||||
|
color: $text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-movies-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gif-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-background {
|
||||||
|
position: absolute;
|
||||||
|
width: 120%;
|
||||||
|
height: 120%;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: $text-white;
|
||||||
|
clip-path: inset(0 0 25% 0);
|
||||||
|
bottom: -28%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reaction-gif {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-button {
|
||||||
|
margin-top: 1rem;
|
||||||
|
background-color: $primary-color !important;
|
||||||
|
color: $text-white !important;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: darken($primary-color, 10%) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
112
src/styles/scss/_uploadDiary.scss
Normal file
112
src/styles/scss/_uploadDiary.scss
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
.upload-diary {
|
||||||
|
padding: 3rem;
|
||||||
|
background-color: #14181c;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.upload-card {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
background-color: #1c1f23;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
padding: 2rem;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username-field {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
|
||||||
|
.MuiOutlinedInput-root {
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border-color: #00a346 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover fieldset {
|
||||||
|
border-color: #00a346 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.Mui-focused fieldset {
|
||||||
|
border-color: #1caff2 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.MuiInputLabel-root {
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.or-text {
|
||||||
|
color: #ffffff;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone {
|
||||||
|
border: 2px dashed #00a346;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #1f252a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone-icon {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: #00a346;
|
||||||
|
font-size: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone-text {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-container {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-button {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 900;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
line-height: 2.8rem;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0 1rem;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
outline: none;
|
||||||
|
background: #526e89;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #1caff2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.7;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.overview-text {
|
||||||
|
color: #456;
|
||||||
|
margin-top: 2rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user