From 925b3cb9040850d144f4efae24787e9dd4fa9612 Mon Sep 17 00:00:00 2001 From: Paul Hughes Date: Sun, 23 Feb 2025 19:22:05 +0000 Subject: [PATCH] Create Repository --- .prettierrc.json | 4 + README.md | 36 + eslint.config.js | 28 + index.html | 13 + package-lock.json | 2719 +++++++++++++++++ package.json | 38 + public/error-image.jpg | Bin 0 -> 19157 bytes public/favicon.ico | Bin 0 -> 15406 bytes results.json | 76 + src/App.css | 18 + src/App.tsx | 19 + .../BookmarkButton/bookmarkbutton.module.css | 5 + src/components/BookmarkButton/index.tsx | 29 + .../FullMovieCard/fullmoviecard.module.css | 32 + src/components/FullMovieCard/index.tsx | 39 + src/components/Loading/index.tsx | 20 + src/components/Loading/loading.module.css | 12 + src/components/Moogle/index.tsx | 18 + src/components/Moogle/moogle.module.css | 29 + src/components/MovieCard/index.tsx | 44 + src/components/MovieCard/moviecard.module.css | 37 + src/components/MovieModal/index.tsx | 85 + .../MovieModal/moviemodal.module.css | 28 + src/components/NoResults/index.tsx | 22 + src/components/NoResults/noresults.module.css | 14 + src/components/Pagination/index.tsx | 69 + .../Pagination/pagination.module.css | 8 + src/components/SearchForm/index.tsx | 49 + .../SearchForm/searchform.module.css | 24 + src/components/SearchResults/index.tsx | 79 + .../SearchResults/searchresults.module.css | 31 + src/context/BookmarkContext.tsx | 56 + src/main.tsx | 16 + src/pages/ErrorPage/errorpage.module.css | 12 + src/pages/ErrorPage/index.tsx | 17 + src/pages/HomePage/homepage.module.css | 8 + src/pages/HomePage/index.tsx | 15 + src/pages/ResultsPage/index.tsx | 75 + src/pages/ResultsPage/resultspage.module.css | 7 + src/types/types.ts | 53 + src/vite-env.d.ts | 1 + testapi.sh | 1 + tsconfig.app.json | 30 + tsconfig.json | 7 + tsconfig.node.json | 24 + vite.config.ts | 12 + 46 files changed, 3959 insertions(+) create mode 100644 .prettierrc.json create mode 100644 README.md create mode 100644 eslint.config.js create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/error-image.jpg create mode 100755 public/favicon.ico create mode 100644 results.json create mode 100644 src/App.css create mode 100644 src/App.tsx create mode 100644 src/components/BookmarkButton/bookmarkbutton.module.css create mode 100644 src/components/BookmarkButton/index.tsx create mode 100644 src/components/FullMovieCard/fullmoviecard.module.css create mode 100644 src/components/FullMovieCard/index.tsx create mode 100644 src/components/Loading/index.tsx create mode 100644 src/components/Loading/loading.module.css create mode 100644 src/components/Moogle/index.tsx create mode 100644 src/components/Moogle/moogle.module.css create mode 100644 src/components/MovieCard/index.tsx create mode 100644 src/components/MovieCard/moviecard.module.css create mode 100644 src/components/MovieModal/index.tsx create mode 100644 src/components/MovieModal/moviemodal.module.css create mode 100644 src/components/NoResults/index.tsx create mode 100644 src/components/NoResults/noresults.module.css create mode 100644 src/components/Pagination/index.tsx create mode 100644 src/components/Pagination/pagination.module.css create mode 100644 src/components/SearchForm/index.tsx create mode 100644 src/components/SearchForm/searchform.module.css create mode 100644 src/components/SearchResults/index.tsx create mode 100644 src/components/SearchResults/searchresults.module.css create mode 100644 src/context/BookmarkContext.tsx create mode 100644 src/main.tsx create mode 100644 src/pages/ErrorPage/errorpage.module.css create mode 100644 src/pages/ErrorPage/index.tsx create mode 100644 src/pages/HomePage/homepage.module.css create mode 100644 src/pages/HomePage/index.tsx create mode 100644 src/pages/ResultsPage/index.tsx create mode 100644 src/pages/ResultsPage/resultspage.module.css create mode 100644 src/types/types.ts create mode 100644 src/vite-env.d.ts create mode 100755 testapi.sh create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..2e929b7 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "tabWidth": 2, + "singleQuote": false +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..d1b5de9 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# 3PL Technical Assessment + +Movie Search Site + +## Information + +Built with ReactJS and Typescript using create vite@latest + +## Hosting Locally + +### Clone the repository + +``` +git clone https://git.paulus.casa/Paulus/tech-assessment-3pl.git && cd tech-assessment-3pl +``` + +### Install dependencies + +``` +npm install +``` + +### Create .env file with API address and your API Key + +The file should look like this. You must prefix the key and address with VITE\_ due to the configuration of the project. + +``` +VITE_APIKEY=yourkey +VITE_APIADDRESS=http://www.omdbapi.com/ +``` + +### Host Locally + +``` +npm run dev +``` diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..79a552e --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,28 @@ +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import tseslint from "typescript-eslint"; + +export default tseslint.config( + { ignores: ["dist"] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ["**/*.{ts,tsx}"], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + }, + }, +); diff --git a/index.html b/index.html new file mode 100644 index 0000000..44f007c --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Moogle | Google for your movies! + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b8deebf --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2719 @@ +{ + "name": "vite-typescript-test", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vite-typescript-test", + "version": "0.0.0", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@mui/icons-material": "^6.4.5", + "@mui/material": "^6.4.5", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-loader-spinner": "^6.1.6", + "react-router-dom": "^7.1.5" + }, + "devDependencies": { + "@eslint/js": "^9.19.0", + "@types/node": "^22.13.4", + "@types/react": "^19.0.8", + "@types/react-dom": "^19.0.3", + "@vitejs/plugin-react-swc": "^3.5.0", + "eslint": "^9.19.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.18", + "globals": "^15.14.0", + "prettier": "3.5.1", + "typescript": "~5.7.2", + "typescript-eslint": "^8.22.0", + "vite": "^6.1.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.9", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.9", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.9" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.9", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.26.9", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.9", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.26.9", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.1", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "license": "MIT" + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.24.2", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.12.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.21.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.7", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.12.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "6.4.5", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "6.4.5", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^6.4.5", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "6.4.5", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/core-downloads-tracker": "^6.4.5", + "@mui/system": "^6.4.3", + "@mui/types": "^7.2.21", + "@mui/utils": "^6.4.3", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^19.0.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^6.4.3", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "6.4.3", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/utils": "^6.4.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "6.4.3", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "6.4.3", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/private-theming": "^6.4.3", + "@mui/styled-engine": "^6.4.3", + "@mui/types": "^7.2.21", + "@mui/utils": "^6.4.3", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.21", + "license": "MIT", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "6.4.3", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/types": "^7.2.21", + "@types/prop-types": "^15.7.14", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.8", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@swc/core": { + "version": "1.10.18", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.17" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.10.18", + "@swc/core-darwin-x64": "1.10.18", + "@swc/core-linux-arm-gnueabihf": "1.10.18", + "@swc/core-linux-arm64-gnu": "1.10.18", + "@swc/core-linux-arm64-musl": "1.10.18", + "@swc/core-linux-x64-gnu": "1.10.18", + "@swc/core-linux-x64-musl": "1.10.18", + "@swc/core-win32-arm64-msvc": "1.10.18", + "@swc/core-win32-ia32-msvc": "1.10.18", + "@swc/core-win32-x64-msvc": "1.10.18" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.10.18", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.17", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.13.5", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.0.10", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.0.4", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/stylis": { + "version": "4.2.5", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/type-utils": "8.24.1", + "@typescript-eslint/utils": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/typescript-estree": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.24.1", + "@typescript-eslint/utils": "8.24.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.24.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/visitor-keys": "8.24.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.24.1", + "@typescript-eslint/types": "8.24.1", + "@typescript-eslint/typescript-estree": "8.24.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.24.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc/core": "^1.10.15" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelize": { + "version": "1.0.1", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.24.2", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.2", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "9.21.0", + "@eslint/plugin-kit": "^0.2.7", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.19", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.0", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.15.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/ignore": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.8", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.49", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.5.1", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "19.0.0", + "license": "MIT" + }, + "node_modules/react-loader-spinner": { + "version": "6.1.6", + "license": "MIT", + "dependencies": { + "react-is": "^18.2.0", + "styled-components": "^6.1.2" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-loader-spinner/node_modules/react-is": { + "version": "18.3.1", + "license": "MIT" + }, + "node_modules/react-router": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "react-router": "7.2.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.10", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.34.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.34.8", + "@rollup/rollup-android-arm64": "4.34.8", + "@rollup/rollup-darwin-arm64": "4.34.8", + "@rollup/rollup-darwin-x64": "4.34.8", + "@rollup/rollup-freebsd-arm64": "4.34.8", + "@rollup/rollup-freebsd-x64": "4.34.8", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", + "@rollup/rollup-linux-arm-musleabihf": "4.34.8", + "@rollup/rollup-linux-arm64-gnu": "4.34.8", + "@rollup/rollup-linux-arm64-musl": "4.34.8", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", + "@rollup/rollup-linux-riscv64-gnu": "4.34.8", + "@rollup/rollup-linux-s390x-gnu": "4.34.8", + "@rollup/rollup-linux-x64-gnu": "4.34.8", + "@rollup/rollup-linux-x64-musl": "4.34.8", + "@rollup/rollup-win32-arm64-msvc": "4.34.8", + "@rollup/rollup-win32-ia32-msvc": "4.34.8", + "@rollup/rollup-win32-x64-msvc": "4.34.8", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.7.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "license": "MIT" + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-components": { + "version": "6.1.15", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.49", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/styled-components/node_modules/@emotion/memoize": { + "version": "0.8.1", + "license": "MIT" + }, + "node_modules/styled-components/node_modules/@emotion/unitless": { + "version": "0.8.1", + "license": "MIT" + }, + "node_modules/styled-components/node_modules/stylis": { + "version": "4.3.2", + "license": "MIT" + }, + "node_modules/stylis": { + "version": "4.2.0", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "license": "0BSD" + }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "license": "ISC" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.7.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.24.1", + "@typescript-eslint/parser": "8.24.1", + "@typescript-eslint/utils": "8.24.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "6.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.24.2", + "postcss": "^8.5.2", + "rollup": "^4.30.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/postcss": { + "version": "8.5.3", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yaml": { + "version": "2.7.0", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b67e77a --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "vite-typescript-test", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview", + "prettify": "prettier --write ." + }, + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@mui/icons-material": "^6.4.5", + "@mui/material": "^6.4.5", + "react-loader-spinner": "^6.1.6", + "react-router-dom": "^7.1.5", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@eslint/js": "^9.19.0", + "@types/node": "^22.13.4", + "@types/react": "^19.0.8", + "@types/react-dom": "^19.0.3", + "@vitejs/plugin-react-swc": "^3.5.0", + "eslint": "^9.19.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.18", + "globals": "^15.14.0", + "prettier": "3.5.1", + "typescript": "~5.7.2", + "typescript-eslint": "^8.22.0", + "vite": "^6.1.0" + } +} diff --git a/public/error-image.jpg b/public/error-image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf5d7a4828c82dedcd13a291b9d90bc365b2b81b GIT binary patch literal 19157 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 literal 0 HcmV?d00001 diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100755 index 0000000000000000000000000000000000000000..ade39514c9a8279fcaeec0ae4b4c5b581f15314a GIT binary patch literal 15406 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 K2L7)#@IL_fG~Fry literal 0 HcmV?d00001 diff --git a/results.json b/results.json new file mode 100644 index 0000000..e774ecb --- /dev/null +++ b/results.json @@ -0,0 +1,76 @@ +{ + "Search": [ + { + "Title": "Inception", + "Year": "2010", + "imdbID": "tt1375666", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_SX300.jpg" + }, + { + "Title": "Inception: The Cobol Job", + "Year": "2010", + "imdbID": "tt5295894", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BMjE0NGIwM2EtZjQxZi00ZTE5LWExN2MtNDBlMjY1ZmZkYjU3XkEyXkFqcGdeQXVyNjMwNzk3Mjk@._V1_SX300.jpg" + }, + { + "Title": "The Crack: Inception", + "Year": "2019", + "imdbID": "tt6793710", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BZTc4MDliNjAtYmU4YS00NmQzLWEwNjktYTQ2MGFjNDc5MDhlXkEyXkFqcGc@._V1_SX300.jpg" + }, + { + "Title": "Inception: Jump Right Into the Action", + "Year": "2010", + "imdbID": "tt5295990", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BZGFjOTRiYjgtYjEzMS00ZjQ2LTkzY2YtOGQ0NDI2NTVjOGFmXkEyXkFqcGdeQXVyNDQ5MDYzMTk@._V1_SX300.jpg" + }, + { + "Title": "Inception: Motion Comics", + "Year": "2010–", + "imdbID": "tt1790736", + "Type": "series", + "Poster": "https://m.media-amazon.com/images/M/MV5BNGRkYzkzZmEtY2YwYi00ZTlmLTgyMTctODE0NTNhNTVkZGIxXkEyXkFqcGdeQXVyNjE4MDMwMjk@._V1_SX300.jpg" + }, + { + "Title": "Inception", + "Year": "2014", + "imdbID": "tt7321322", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BOTY3OGFlNTktYTJiZi00ZWMxLTk4MjQtNmJiODkxYThiNjg4XkEyXkFqcGc@._V1_SX300.jpg" + }, + { + "Title": "Madness Inception", + "Year": "2022", + "imdbID": "tt29258696", + "Type": "movie", + "Poster": "N/A" + }, + { + "Title": "Inception: 4Movie Premiere Special", + "Year": "2010", + "imdbID": "tt1686778", + "Type": "movie", + "Poster": "N/A" + }, + { + "Title": "Cyberalien: Inception", + "Year": "2017", + "imdbID": "tt7926130", + "Type": "movie", + "Poster": "N/A" + }, + { + "Title": "WWA: The Inception", + "Year": "2001", + "imdbID": "tt0311992", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BNTEyNGJjMTMtZjZhZC00ODFkLWIyYzktN2JjMTcwMmY5MDJlXkEyXkFqcGdeQXVyNDkwMzY5NjQ@._V1_SX300.jpg" + } + ], + "totalResults": "38", + "Response": "True" +} diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..cd7e4cc --- /dev/null +++ b/src/App.css @@ -0,0 +1,18 @@ +body { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +#root { + max-width: 1400px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +@media screen and (max-width: 600px) { + #root { + padding: 0; + } +} diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..3fa8bd8 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,19 @@ +import { Routes, Route } from "react-router-dom"; + +import HomePage from "@/pages/HomePage"; +import ResultsPage from "@/pages/ResultsPage"; +import ErrorPage from "@/pages/ErrorPage"; + +import "@/App.css"; + +function App() { + return ( + + } /> + } /> + } /> + + ); +} + +export default App; diff --git a/src/components/BookmarkButton/bookmarkbutton.module.css b/src/components/BookmarkButton/bookmarkbutton.module.css new file mode 100644 index 0000000..6a9b43e --- /dev/null +++ b/src/components/BookmarkButton/bookmarkbutton.module.css @@ -0,0 +1,5 @@ +.bookmarkbutton { + position: absolute; + top: 1%; + left: 1%; +} diff --git a/src/components/BookmarkButton/index.tsx b/src/components/BookmarkButton/index.tsx new file mode 100644 index 0000000..27f9116 --- /dev/null +++ b/src/components/BookmarkButton/index.tsx @@ -0,0 +1,29 @@ +import BookmarkIcon from "@mui/icons-material/Bookmark"; +import BookmarkBorderIcon from "@mui/icons-material/BookmarkBorder"; + +import { Search } from "@/types/types"; +import { useBookmarksContext } from "@/context/BookmarkContext"; + +import classes from "./bookmarkbutton.module.css"; + +interface BookmarkButtonProps { + movie: Search; +} + +const BookmarkButton = ({ movie }: BookmarkButtonProps) => { + const { toggleBookmark, isBookmark } = useBookmarksContext(); + + return ( +
{ + toggleBookmark(movie); + }} + > + {" "} + {isBookmark(movie) ? : } +
+ ); +}; + +export default BookmarkButton; diff --git a/src/components/FullMovieCard/fullmoviecard.module.css b/src/components/FullMovieCard/fullmoviecard.module.css new file mode 100644 index 0000000..1df0a6d --- /dev/null +++ b/src/components/FullMovieCard/fullmoviecard.module.css @@ -0,0 +1,32 @@ +.imgcontainer { + display: flex; + justify-content: center; + align-items: center; + height: 45%; +} + +.image { + height: 100%; + max-width: 80%; + aspect-ratio: auto; + margin: 0 auto 2rem; +} + +.subheading { + font-size: 1.1rem; + line-height: 1.3rem; + min-height: 2.6rem; + margin: 0.5rem auto; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-align: center; +} + +.year { + font-size: 1rem; + text-align: center; +} diff --git a/src/components/FullMovieCard/index.tsx b/src/components/FullMovieCard/index.tsx new file mode 100644 index 0000000..18afe56 --- /dev/null +++ b/src/components/FullMovieCard/index.tsx @@ -0,0 +1,39 @@ +import { MovieDetails, Search } from "@/types/types"; +import BookmarkButton from "@/components/BookmarkButton"; + +import classes from "./fullmoviecard.module.css"; + +interface FullMovieCardProps { + movie: MovieDetails; + searchResult: Search; + handleImageError: (event: React.SyntheticEvent) => void; +} + +const FullMovieCard = ({ + movie, + handleImageError, + searchResult, +}: FullMovieCardProps) => { + return ( + <> + +
+ ) => { + handleImageError(e); + }} + alt={`${movie.Title} Poster`} + /> +
+

{movie.Title}

+

Year: {movie.Year}

+

Directed By: {movie.Director}

+

Plot: {movie.Plot}

+

IMDB Rating: {movie.imdbRating}

+ + ); +}; + +export default FullMovieCard; diff --git a/src/components/Loading/index.tsx b/src/components/Loading/index.tsx new file mode 100644 index 0000000..0759fa0 --- /dev/null +++ b/src/components/Loading/index.tsx @@ -0,0 +1,20 @@ +import { RotatingLines } from "react-loader-spinner"; + +import classes from "./loading.module.css"; + +const Loading = () => { + return ( +
+ +

Loading...........

+
+ ); +}; + +export default Loading; diff --git a/src/components/Loading/loading.module.css b/src/components/Loading/loading.module.css new file mode 100644 index 0000000..39e92ab --- /dev/null +++ b/src/components/Loading/loading.module.css @@ -0,0 +1,12 @@ +.container { + height: 100%; + display: flex; + flex-direction: column; + gap: 2rem; + align-items: center; + justify-content: center; +} + +.text { + font-size: 2rem; +} diff --git a/src/components/Moogle/index.tsx b/src/components/Moogle/index.tsx new file mode 100644 index 0000000..5c38049 --- /dev/null +++ b/src/components/Moogle/index.tsx @@ -0,0 +1,18 @@ +import classes from "./moogle.module.css"; + +const Moogle = () => { + return ( +

+ + M + o + o + g + l + e + +

+ ); +}; + +export default Moogle; diff --git a/src/components/Moogle/moogle.module.css b/src/components/Moogle/moogle.module.css new file mode 100644 index 0000000..8e9ec70 --- /dev/null +++ b/src/components/Moogle/moogle.module.css @@ -0,0 +1,29 @@ +.title { + text-wrap: nowrap; + font-size: 4rem; + margin: 0.25rem; +} + +.link { + text-decoration: none; +} + +.green { + color: green; +} + +.yellow { + color: yellow; +} + +.purple { + color: purple; +} + +.orange { + color: orange; +} + +.blue { + color: blue; +} diff --git a/src/components/MovieCard/index.tsx b/src/components/MovieCard/index.tsx new file mode 100644 index 0000000..f2220f0 --- /dev/null +++ b/src/components/MovieCard/index.tsx @@ -0,0 +1,44 @@ +import { Search } from "@/types/types"; +import BookmarkButton from "@/components/BookmarkButton"; + +import classes from "./moviecard.module.css"; + +interface MovieCardProps { + movie: Search; + openHandler: (arg: string | undefined, arg2: Search) => void; + handleImageError: (event: React.SyntheticEvent) => void; +} + +const MovieCard = ({ + movie, + openHandler, + handleImageError, +}: MovieCardProps) => { + return ( + <> + +
+ ) => { + handleImageError(e); + }} + alt={`${movie.Title} Poster`} + /> +
+

{movie.Year}

+

{movie.Title}

+ + + ); +}; + +export default MovieCard; diff --git a/src/components/MovieCard/moviecard.module.css b/src/components/MovieCard/moviecard.module.css new file mode 100644 index 0000000..6f90c26 --- /dev/null +++ b/src/components/MovieCard/moviecard.module.css @@ -0,0 +1,37 @@ +.imgcontainer { + display: flex; + justify-content: center; + align-items: center; + height: 65%; +} + +.image { + height: 100%; + max-width: 80%; + aspect-ratio: auto; + margin: 0 auto; +} + +.subheading { + font-size: 1.1rem; + line-height: 1.3rem; + min-height: 2.6rem; + margin: 0.5rem auto; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-align: center; +} + +.year { + font-size: 1rem; + text-align: center; +} + +.button { + padding: 0.25rem 2rem; + border-radius: 10px; +} diff --git a/src/components/MovieModal/index.tsx b/src/components/MovieModal/index.tsx new file mode 100644 index 0000000..4b4ead5 --- /dev/null +++ b/src/components/MovieModal/index.tsx @@ -0,0 +1,85 @@ +import Modal from "@mui/material/Modal"; +import CloseIcon from "@mui/icons-material/Close"; +import { useState, useEffect } from "react"; +import { useLocation } from "react-router-dom"; + +import Loading from "@/components/Loading"; +import { MovieDetails, Search } from "@/types/types"; +import FullMovieCard from "@/components/FullMovieCard"; + +import classes from "./moviemodal.module.css"; + +interface MovieModalProps { + id: string | undefined; + open: boolean; + searchResult: Search | undefined; + closeHandler: () => void; + handleImageError: (event: React.SyntheticEvent) => void; +} + +type MovieResult = MovieDetails | null; + +const MovieModal = ({ + open, + closeHandler, + id, + handleImageError, + searchResult, +}: MovieModalProps) => { + const APIADDRESS = import.meta.env.VITE_APIADDRESS; + const APIKEY = import.meta.env.VITE_APIKEY; + + const [movieResult, setMovieResult] = useState(null); + + async function handleGetMovieResult() { + const endpoint = `${APIADDRESS}?i=${id}&apikey=${APIKEY}`; + + const reply = await fetch(`${endpoint}`); + const data = await reply.json(); + setMovieResult(data); + } + + const location = useLocation(); + + useEffect(() => { + handleGetMovieResult(); + }, [location, id]); + + return ( + <> + +
+
+ + { + movieResult === null ? ( + + ) : movieResult?.imdbID !== id ? ( + + ) : searchResult !== undefined ? ( + + ) : ( + <> + ) //I know here that the movie will display + } +
+
+
+ + ); +}; + +export default MovieModal; diff --git a/src/components/MovieModal/moviemodal.module.css b/src/components/MovieModal/moviemodal.module.css new file mode 100644 index 0000000..24555ab --- /dev/null +++ b/src/components/MovieModal/moviemodal.module.css @@ -0,0 +1,28 @@ +.modal { + width: 100vw; + height: 100vh; + display: flex; + justify-content: center; + align-items: center; + background-color: #000000a6; +} + +.container { + position: relative; + border: 2px solid #000000; + padding: 1rem; + border-radius: 10px; + width: clamp(350px, 75%, 1200px); + height: clamp(350px, 75%, 1200px); + background: #ffffff; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.closebutton { + position: absolute; + top: 1%; + right: 1%; +} diff --git a/src/components/NoResults/index.tsx b/src/components/NoResults/index.tsx new file mode 100644 index 0000000..6f36919 --- /dev/null +++ b/src/components/NoResults/index.tsx @@ -0,0 +1,22 @@ +import Moogle from "@/components/Moogle"; +import SearchForm from "@/components/SearchForm"; + +import classes from "./noresults.module.css"; + +interface NoResultsProps { + searchQuery: string | undefined; +} + +const NoResults = ({ searchQuery }: NoResultsProps) => { + return ( +
+ +

+ No results for {`${searchQuery}`} were found! +

+ +
+ ); +}; + +export default NoResults; diff --git a/src/components/NoResults/noresults.module.css b/src/components/NoResults/noresults.module.css new file mode 100644 index 0000000..0400065 --- /dev/null +++ b/src/components/NoResults/noresults.module.css @@ -0,0 +1,14 @@ +.container { + height: 90vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 1rem; +} + +.text { + margin: 0rem; + padding: 0.5rem; + font-size: 1.5rem; +} diff --git a/src/components/Pagination/index.tsx b/src/components/Pagination/index.tsx new file mode 100644 index 0000000..6bb753a --- /dev/null +++ b/src/components/Pagination/index.tsx @@ -0,0 +1,69 @@ +import classes from "./pagination.module.css"; + +interface PaginationProps { + searchQuery: string | undefined; + page: string | undefined; + maxResults: string; +} + +const Pagination = ({ searchQuery, page, maxResults }: PaginationProps) => { + const pageToNumber = (Page: PaginationProps["page"]): number => { + if (Page === undefined) { + return 1; + } else { + return parseInt(Page); + } + }; + + // According to API docs the highest value is 100 + const getPages = ( + page: PaginationProps["page"], + maxResults: PaginationProps["maxResults"], + ): number[] => { + const pageNumber = pageToNumber(page); + const pageNumbers: number[] = []; + const maxPageNumber = pageToNumber(maxResults) / 10; + + let startPage = pageNumber - 2; + + if (startPage < 3) { + startPage = 1; + } + + if (startPage > 98) { + startPage = 98; + } + + if (startPage > maxPageNumber - 4) { + startPage = Math.max(1, maxPageNumber - 4); + } + + for (let i = 0; i < 5; i++) { + if (startPage + i <= maxPageNumber) { + pageNumbers.push(startPage + i); + } + } + + return pageNumbers; + }; + + const pages = getPages(page, maxResults); + + return ( +
+ {pages.map((num) => { + return ( + + {num} + + ); + })} +
+ ); +}; + +export default Pagination; diff --git a/src/components/Pagination/pagination.module.css b/src/components/Pagination/pagination.module.css new file mode 100644 index 0000000..ca76622 --- /dev/null +++ b/src/components/Pagination/pagination.module.css @@ -0,0 +1,8 @@ +.container { + padding: 2rem 0; +} + +.link { + font-size: 1.2rem; + padding: 0 1rem; +} diff --git a/src/components/SearchForm/index.tsx b/src/components/SearchForm/index.tsx new file mode 100644 index 0000000..215d3a0 --- /dev/null +++ b/src/components/SearchForm/index.tsx @@ -0,0 +1,49 @@ +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; + +import classes from "./searchform.module.css"; + +interface SearchFormProps { + layout: string; +} + +const SearchForm = ({ layout }: SearchFormProps) => { + const navigate = useNavigate(); + const [search, setSearch] = useState(""); + + function handleChange(event: React.FormEvent) { + const element = event.currentTarget as HTMLInputElement; + const value = element.value; + setSearch(value); + } + + async function handleSubmit(event: React.FormEvent) { + event.preventDefault(); + const redirect = `/results/${search}`; + navigate(redirect); + } + + return ( +
+
handleSubmit(event)} + > + + +
+
+ ); +}; + +export default SearchForm; diff --git a/src/components/SearchForm/searchform.module.css b/src/components/SearchForm/searchform.module.css new file mode 100644 index 0000000..8516e4c --- /dev/null +++ b/src/components/SearchForm/searchform.module.css @@ -0,0 +1,24 @@ +.form { + display: flex; + align-items: center; + justify-content: center; + gap: 2rem; + padding: 0.5rem 2rem; + flex-direction: column; +} + +.horizontal { + flex-direction: row; +} + +.input { + font-size: 1.5rem; + border-radius: 10px; + padding: 0.5rem; +} + +.button { + font-size: 1.2rem; + padding: 0.5rem 2rem; + border-radius: 0.5rem; +} diff --git a/src/components/SearchResults/index.tsx b/src/components/SearchResults/index.tsx new file mode 100644 index 0000000..6cfa86a --- /dev/null +++ b/src/components/SearchResults/index.tsx @@ -0,0 +1,79 @@ +import MovieCard from "@/components/MovieCard"; +import { Search, ResultsApi } from "@/types/types"; +import Pagination from "@/components/Pagination"; +import Moogle from "@/components/Moogle"; +import SearchForm from "@/components/SearchForm"; +import MovieModal from "@/components/MovieModal"; + +import classes from "./searchresults.module.css"; + +interface SearchResultsProps { + results: ResultsApi; + id: string | undefined; + searchQuery: string | undefined; + page: string | undefined; + open: boolean; + movieSelected: Search | undefined; + openHandler: (arg: string | undefined, arg2: Search) => void; + closeHandler: () => void; +} + +const SearchResults = ({ + results, + searchQuery, + page, + open, + openHandler, + closeHandler, + id, + movieSelected, +}: SearchResultsProps) => { + const handleImageError = (event: React.SyntheticEvent) => { + const element = event.currentTarget as HTMLImageElement; + element.src = "/error-image.jpg"; + }; + + return ( + <> +
+ + +
+
+

+ Search Results for {`\"${searchQuery}\"`} +

+
+ {results.Search.map((element: Search, index: number) => { + return ( +
+ +
+ ); + })} +
+ + +
+ + ); +}; + +export default SearchResults; diff --git a/src/components/SearchResults/searchresults.module.css b/src/components/SearchResults/searchresults.module.css new file mode 100644 index 0000000..0370524 --- /dev/null +++ b/src/components/SearchResults/searchresults.module.css @@ -0,0 +1,31 @@ +.topbar { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + gap: 6rem; +} + +.title { + font-size: 2rem; +} + +.container { + padding: 1rem; +} + +.subcontainer { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + max-width: 1000px; + margin: 0 auto; + gap: 2rem; +} + +.moviecontainer { + position: relative; + height: 40vh; + background: #fff2cc; + padding: 1rem; + border: 1px solid black; +} diff --git a/src/context/BookmarkContext.tsx b/src/context/BookmarkContext.tsx new file mode 100644 index 0000000..8324d36 --- /dev/null +++ b/src/context/BookmarkContext.tsx @@ -0,0 +1,56 @@ +import { + createContext, + useState, + useContext, + ReactNode, +} from "react"; + +import { Search } from "@/types/types"; + +type BookmarkContextType = { + bookmarks: Search[]; + toggleBookmark: (item: Search) => void; + isBookmark: (movie: Search) => boolean; +}; + +type BookmarkProviderProps = { + children: ReactNode; +}; + +const BookmarkContext = createContext( + undefined, +); + +const BookmarkContextProvider = ({ children }: BookmarkProviderProps) => { + const [bookmarks, setBookmarks] = useState(() => { + return JSON.parse(localStorage.getItem("Bookmarks") || "[]"); + }); + + const toggleBookmark = (movie: Search) => { + const newBookmarks = isBookmark(movie) + ? bookmarks.filter((item) => item.imdbID !== movie.imdbID) + : [...bookmarks, movie]; + setBookmarks(newBookmarks); + localStorage.setItem("Bookmarks", JSON.stringify(newBookmarks)); + }; + + const isBookmark = (movie: Search) => { + return bookmarks.some((item) => item.imdbID === movie.imdbID); + }; + + return ( + + {children} + + ); +}; + +export default BookmarkContextProvider; + +export const useBookmarksContext = () => { + const context = useContext(BookmarkContext); + if (!context) { + throw new Error("No Provider for useBookmarks"); + } + return context; +}; diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..3c3f3a9 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,16 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { BrowserRouter } from "react-router-dom"; + +import BookmarkContextProvider from "@/context/BookmarkContext"; +import App from "@/App.tsx"; + +createRoot(document.getElementById("root")!).render( + + + + + + + , +); diff --git a/src/pages/ErrorPage/errorpage.module.css b/src/pages/ErrorPage/errorpage.module.css new file mode 100644 index 0000000..8b31cda --- /dev/null +++ b/src/pages/ErrorPage/errorpage.module.css @@ -0,0 +1,12 @@ +.container { + height: 90vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 1rem; +} + +.text { + font-size: 2rem; +} diff --git a/src/pages/ErrorPage/index.tsx b/src/pages/ErrorPage/index.tsx new file mode 100644 index 0000000..e6aff46 --- /dev/null +++ b/src/pages/ErrorPage/index.tsx @@ -0,0 +1,17 @@ +import Moogle from "@/components/Moogle"; +import SearchForm from "@/components/SearchForm"; + +import classes from "./errorpage.module.css"; + +const ErrorPage = () => { + return ( +
+ +
404
+
This Page Does Not Exist
+ +
+ ); +}; + +export default ErrorPage; diff --git a/src/pages/HomePage/homepage.module.css b/src/pages/HomePage/homepage.module.css new file mode 100644 index 0000000..20a3acd --- /dev/null +++ b/src/pages/HomePage/homepage.module.css @@ -0,0 +1,8 @@ +.container { + height: 90vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 1rem; +} diff --git a/src/pages/HomePage/index.tsx b/src/pages/HomePage/index.tsx new file mode 100644 index 0000000..e045a7b --- /dev/null +++ b/src/pages/HomePage/index.tsx @@ -0,0 +1,15 @@ +import Moogle from "@/components/Moogle"; +import SearchForm from "@/components/SearchForm"; + +import classes from "./homepage.module.css"; + +const HomePage = () => { + return ( +
+ + +
+ ); +}; + +export default HomePage; diff --git a/src/pages/ResultsPage/index.tsx b/src/pages/ResultsPage/index.tsx new file mode 100644 index 0000000..56635f6 --- /dev/null +++ b/src/pages/ResultsPage/index.tsx @@ -0,0 +1,75 @@ +import { useParams, useLocation } from "react-router-dom"; +import { useEffect, useState } from "react"; + +import { ResultsApi, Search } from "@/types/types"; +import Loading from "@/components/Loading"; +import NoResults from "@/components/NoResults"; +import SearchResults from "@/components/SearchResults"; + +import classes from "./resultspage.module.css"; + +type Results = ResultsApi | undefined; + +const ResultsPage = () => { + const APIADDRESS = import.meta.env.VITE_APIADDRESS; + const APIKEY = import.meta.env.VITE_APIKEY; + + //Data for API Call and Result + const { search, page } = useParams(); + const [results, setResults] = useState(); + const location = useLocation(); + + //Handlers for Movie Modal Opening and Closing + const [open, setOpen] = useState(false); + const [id, setId] = useState(""); + const [movieSelected, setMovieSelected] = useState(); + + const handleOpen = (ID: string | undefined, movie: Search) => { + setOpen(true); + setId(ID); + setMovieSelected(movie); + }; + const handleClose = () => setOpen(false); + + async function handleGetResults() { + let endpoint: string = ""; + + if (page === "0" || page === undefined) { + //default is 1 anyway but just in case someone wants to change parameters + endpoint = `${APIADDRESS}?s=${search}&apikey=${APIKEY}`; + } else { + endpoint = `${APIADDRESS}?s=${search}&page=${page}&apikey=${APIKEY}`; + } + + const reply = await fetch(`${endpoint}`); + const data = await reply.json(); + setResults(data); + } + + useEffect(() => { + handleGetResults(); + }, [location]); + + return ( +
+ {results === undefined ? ( + + ) : results.Response === "False" ? ( + + ) : ( + + )} +
+ ); +}; + +export default ResultsPage; diff --git a/src/pages/ResultsPage/resultspage.module.css b/src/pages/ResultsPage/resultspage.module.css new file mode 100644 index 0000000..133e080 --- /dev/null +++ b/src/pages/ResultsPage/resultspage.module.css @@ -0,0 +1,7 @@ +.container { + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} diff --git a/src/types/types.ts b/src/types/types.ts new file mode 100644 index 0000000..e7f70e6 --- /dev/null +++ b/src/types/types.ts @@ -0,0 +1,53 @@ +/* --- Thanks to "https://quicktype.io" --- */ + +export interface ResultsApi { + Search: Search[]; + totalResults: string; + Response: string; +} + +export interface Search { + Title: string; + Year: string; + imdbID: string; + Type: Type; + Poster: string; +} + +export enum Type { + Movie = "movie", + Series = "series", +} + +export interface MovieDetails { + Title: string; + Year: string; + Rated: string; + Released: string; + Runtime: string; + Genre: string; + Director: string; + Writer: string; + Actors: string; + Plot: string; + Language: string; + Country: string; + Awards: string; + Poster: string; + Ratings: Rating[]; + Metascore: string; + imdbRating: string; + imdbVotes: string; + imdbID: string; + Type: string; + DVD: string; + BoxOffice: string; + Production: string; + Website: string; + Response: string; +} + +export interface Rating { + Source: string; + Value: string; +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/testapi.sh b/testapi.sh new file mode 100755 index 0000000..324967b --- /dev/null +++ b/testapi.sh @@ -0,0 +1 @@ +curl -X GET 'http://omdbapi.com/?s=inception&apikey=APIKEY' >> "results.json" \ No newline at end of file diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..6b2e117 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..db0becc --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..a975b44 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; +import path from "path"; + +export default defineConfig({ + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + plugins: [react()], +});