diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 8a2637a9..00000000 --- a/.editorconfig +++ /dev/null @@ -1,9 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 2 -charset = utf-8 -end_of_line = lf -trim_trailing_whitespace = true -insert_final_newline = true \ No newline at end of file diff --git a/.env.sample b/.env.sample index 1902044a..d80f32bb 100644 --- a/.env.sample +++ b/.env.sample @@ -1,3 +1 @@ -NEXT_PUBLIC_FIREBASE_API= -NEXT_PUBLIC_FIREBASE_APP= NEXT_POKEMONTCG_API_KEY= \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 848ae3e4..16687407 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,12 +1,23 @@ { "parser": "@typescript-eslint/parser", - "plugins": ["prettier", "@typescript-eslint/eslint-plugin"], + "plugins": ["prettier", "@typescript-eslint/eslint-plugin", "import"], "extends": [ "next/core-web-vitals", "plugin:@typescript-eslint/recommended", "plugin:@tanstack/eslint-plugin-query/recommended", + "plugin:jsx-a11y/strict", "prettier" ], + "settings": { + "import/parsers": { + "@typescript-eslint-parser": [".ts", ".tsx"] + }, + "import/resolver": { + "typescript": { + "alwaysTryTypes": true + } + } + }, "rules": { "prettier/prettier": "error", "camelcase": "off", @@ -35,6 +46,34 @@ "specialLink": ["hrefLeft", "hrefRight"], "aspects": ["invalidHref", "preferButton"] } + ], + "jsx-a11y/media-has-caption": "off", + "import/order": [ + "error", + { + "groups": [ + "builtin", + "external", + "internal", + ["parent", "sibling"], + "object", + "type", + "index" + ], + "pathGroups": [ + { + "pattern": "{react,react-dom/**}", + "group": "external", + "position": "before" + } + ], + "pathGroupsExcludedImportTypes": ["react"], + "newlines-between": "always", + "alphabetize": { + "order": "asc", + "caseInsensitive": true + } + } ] }, "overrides": [ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d584fe26..5cedeac4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,10 @@ jobs: run: pnpm install - name: Check types - run: pnpm type-check + run: pnpm type - name: Check linting run: pnpm lint + + - name: Check style + run: pnpm style diff --git a/.stylelintrc b/.stylelintrc new file mode 100644 index 00000000..1fa076c4 --- /dev/null +++ b/.stylelintrc @@ -0,0 +1,12 @@ +{ + "extends": [ + "stylelint-config-standard-scss", + "stylelint-config-prettier-scss" + ], + "rules": { + "selector-class-pattern": null, + "keyframes-name-pattern": null, + "no-descending-specificity": null, + "scss/percent-placeholder-pattern": null + } +} diff --git a/README.md b/README.md index e704dfb1..c76602e2 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ -

PokéRef is a Pokémon encyclopedia built with Next JS, Typescript and Styled-Components and uses data from PokéAPI and Smogon

+

PokéRef is a Pokémon encyclopedia built with Next JS, Typescript and Scss modules and uses data from PokéAPI, Smogon and PokémonTCG

You'll find a ton of information on every pokémon, moves, abilities, items and a lot more

Live version @@ -57,8 +57,9 @@ ✅404 page ✅Responsive -🛠Check how the login with a provider works -🛠Second type select in the list of pokémon in a type page +🛠Implement Radix UI to create reusable components +🛠Second type select in the list of pokémon in a type page +🛠Change login provider 🔜Contest section in a move's page @@ -82,13 +83,13 @@ git clone https://github.com/thibaudbrault/PokeRef.git

Install the dependencies

```bash -npm install +pnpm install ```

Start the server

```bash -npm run dev +pnpm dev ```

Enjoy 😃

@@ -102,14 +103,15 @@ I chose to use PokéAPI because there are a lot of tutorials to start from, the

Story of this project

-- Started by using vanilla JS + Sass to learn how to fetch data from an API in vanilla JS -- Quickly moved to React JS + Sass to learn React by working on a big project -- Moved to React JS + Styled-Components to learn a new way to write CSS. It was a good move for me because I really like Styled-Components because it has the advantages of Sass, is easily importable / exportable between files and supports theming. +- Started by using vanilla JS + Scss to learn how to fetch data from an API in vanilla JS +- Quickly moved to React JS + Scss to learn React by working on a big project +- Moved to React JS + Styled-Components to learn a new way to write CSS. It was a good move for me because I really like Styled-Components because it has the advantages of Scss, is easily importable / exportable between files and supports theming. - Added React-Query to fetch data. It's a great library that makes it easy to manage caching, fetching, loading and error handling for every data fetch. - Finally moved to Next JS (instead of CRA) + Styled-Components to learn to use Next JS. I chose to use Next JS to benefit from the image optimization given by the component because the app has a lot of images to render and every optimization is welcome. I also chose it to benefit from the Static-Site generation. - Upgraded to Next 13. There were some problems that made the transition to using the app folder instead of the pages one not possible, but I benefited from the changes to the component (it no longer creates spans) and the component (it no longer need to have an anchor tag inside). - Added React-Table and converted all my tables to benefit from virtualization, sorting and filtering for every column making it easier to find the desired information. - Added Firebase for authentication and saving a user's caught pokémon with data stored in Firestore. +- Changed all the structure folder and moved from Styled-Components to Scss modules.

Problems encountered (ordered from the oldest to the most recent)

@@ -120,6 +122,7 @@ I chose to use PokéAPI because there are a lot of tutorials to start from, the - Implementing React-Query. I had to learn how to modify my custom hooks to make it work with React-Query and how to import the data from the hooks. It took me some time to make the transition works, but I don't regret it because my code is more readable (mainly the part where I import my hooks, but also the way I handle the loading state to return an animation while the data is being fetched) and it's an easy way to cache data. - Moving from CRA to Next. The main problem I had was learning to use dynamic routing and when I understood it the migration became easier. It still took me some time because I had to move all my files in other folders, change the paths in imports, implement the component along with a width and height, correct some problems with the images (the creation of multiple spans wrapping the image that was solved by using next/future/image before moving to Next 13) and a few other problems with the component (the fact that it can't have multiple children, that it needs to have a 'href' instead of the 'to' used in react-router to give the path and that you need to put an anchor tag inside the Link and use passHref). - Converting all the files to Typescript and declare all the types. +- Make my components fully reusable.

Contents

@@ -137,8 +140,10 @@ I chose to use PokéAPI because there are a lot of tutorials to start from, the - - - -- +- - +- +-

Acknowledgements

@@ -170,4 +175,5 @@ A big thanks also to the PokeAPI team for creating such a huge, detailed and ver

License

-MIT + diff --git a/next.config.js b/next.config.js index b9862b66..088cbbf6 100644 --- a/next.config.js +++ b/next.config.js @@ -9,9 +9,6 @@ const withPWA = require("next-pwa")({ }) const nextConfig = withPWA({ - compiler: { - styledComponents: true - }, eslint: { ignoreDuringBuilds: true }, diff --git a/package.json b/package.json index 55e5d266..d5c1a02b 100644 --- a/package.json +++ b/package.json @@ -13,24 +13,33 @@ "scripts": { "dev": "next dev -p 3005", "build": "next build", + "start": "next start", "test": "playwright test", "test:headed": "playwright test --headed", "postbuild": "next-sitemap", - "start": "next start", - "type-check": "tsc --noEmit", - "lint": "eslint --ignore-path .gitignore \"src/**/*.+(ts|js|tsx)\" --fix", - "format": "prettier --ignore-path .gitignore \"src/**/*.+(ts|js|tsx)\" --write", + "type": "tsc --noEmit", + "lint": "eslint --ignore-path .gitignore \"src/**/*.+(ts|js|tsx)\"", + "lint:fix": "eslint --ignore-path .gitignore \"src/**/*.+(ts|js|tsx)\" --fix", + "format": "prettier --ignore-path .gitignore \"src/**/*.+(ts|js|tsx)\"", + "format:fix": "prettier --ignore-path .gitignore \"src/**/*.+(ts|js|tsx)\" --write", + "style": "stylelint \"src/**/*.scss\"", + "style:fix": "stylelint \"src/**/*.scss\" --fix", "postinstall": "husky install" }, "dependencies": { - "@hookform/resolvers": "2.9.10", + "@hookform/resolvers": "3.1.1", "@meronex/icons": "4.0.0", + "@radix-ui/react-label": "2.0.2", + "@radix-ui/react-navigation-menu": "1.1.3", + "@radix-ui/react-separator": "1.0.3", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-tabs": "1.0.4", "@tanstack/match-sorter-utils": "8.7.6", "@tanstack/react-query": "4.29.7", "@tanstack/react-query-devtools": "4.29.7", "@tanstack/react-table": "8.7.9", "axios": "^1.4.0", - "firebase": "9.22.0", + "class-variance-authority": "0.6.1", "fuse.js": "6.6.2", "hamburger-react": "2.5.0", "next": "13.4.3", @@ -49,7 +58,7 @@ "react-select": "5.7.0", "react-tooltip": "5.13.1", "react-virtual": "2.10.4", - "styled-components": "6.0.0-rc.3", + "sass": "1.63.4", "yup": "1.2.0" }, "devDependencies": { @@ -59,24 +68,30 @@ "@types/react": "18.0.25", "@types/react-dom": "18.0.9", "@types/react-modal": "3.13.1", - "@types/styled-components": "5.1.26", - "@typescript-eslint/eslint-plugin": "5.43.0", - "@typescript-eslint/parser": "5.43.0", + "@typescript-eslint/eslint-plugin": "6.0.0", + "@typescript-eslint/parser": "6.0.0", "eslint": "8.27.0", "eslint-config-next": "13.0.3", "eslint-config-prettier": "8.5.0", "eslint-import-resolver-typescript": "3.5.2", "eslint-plugin-import": "2.26.0", - "eslint-plugin-prettier": "4.2.1", + "eslint-plugin-jsx-a11y": "6.7.1", + "eslint-plugin-prettier": "5.0.0", "husky": "8.0.2", "lint-staged": "13.2.2", - "prettier": "2.7.1", - "typescript": "4.8.4" + "prettier": "3.0.0", + "stylelint": "15.9.0", + "stylelint-config-prettier-scss": "1.0.0", + "stylelint-config-standard-scss": "10.0.0", + "typescript": "5.1.3" }, "lint-staged": { "./src/**/*.{ts,js,jsx,tsx}": [ - "pnpm lint", - "pnpm format" + "pnpm lint:fix", + "pnpm format:fix" + ], + "./src/**/*.scss": [ + "pnpm style:fix" ] } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c2e2dd8d..707b4b54 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,11 +6,26 @@ settings: dependencies: '@hookform/resolvers': - specifier: 2.9.10 - version: 2.9.10(react-hook-form@7.43.9) + specifier: 3.1.1 + version: 3.1.1(react-hook-form@7.43.9) '@meronex/icons': specifier: 4.0.0 version: 4.0.0(react@18.2.0) + '@radix-ui/react-label': + specifier: 2.0.2 + version: 2.0.2(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-navigation-menu': + specifier: 1.1.3 + version: 1.1.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-separator': + specifier: 1.0.3 + version: 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': + specifier: 1.0.2 + version: 1.0.2(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-tabs': + specifier: 1.0.4 + version: 1.0.4(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) '@tanstack/match-sorter-utils': specifier: 8.7.6 version: 8.7.6 @@ -26,9 +41,9 @@ dependencies: axios: specifier: ^1.4.0 version: 1.4.0 - firebase: - specifier: 9.22.0 - version: 9.22.0 + class-variance-authority: + specifier: 0.6.1 + version: 0.6.1 fuse.js: specifier: 6.6.2 version: 6.6.2 @@ -37,16 +52,16 @@ dependencies: version: 2.5.0(react@18.2.0) next: specifier: 13.4.3 - version: 13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0) + version: 13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0)(sass@1.63.4) next-plausible: specifier: 3.7.2 version: 3.7.2(next@13.4.3)(react-dom@18.2.0)(react@18.2.0) next-pwa: specifier: 5.6.0 - version: 5.6.0(@babel/core@7.22.5)(next@13.4.3)(webpack@5.87.0) + version: 5.6.0(@babel/core@7.22.5)(next@13.4.3)(webpack@5.88.0) next-sitemap: specifier: 4.1.3 - version: 4.1.3(@next/env@13.4.5)(next@13.4.3) + version: 4.1.3(@next/env@13.4.7)(next@13.4.3) nextjs-progressbar: specifier: 0.0.16 version: 0.0.16(next@13.4.3)(react@18.2.0) @@ -83,9 +98,9 @@ dependencies: react-virtual: specifier: 2.10.4 version: 2.10.4(react@18.2.0) - styled-components: - specifier: 6.0.0-rc.3 - version: 6.0.0-rc.3(react-dom@18.2.0)(react@18.2.0) + sass: + specifier: 1.63.4 + version: 1.63.4 yup: specifier: 1.2.0 version: 1.2.0 @@ -109,21 +124,18 @@ devDependencies: '@types/react-modal': specifier: 3.13.1 version: 3.13.1 - '@types/styled-components': - specifier: 5.1.26 - version: 5.1.26 '@typescript-eslint/eslint-plugin': - specifier: 5.43.0 - version: 5.43.0(@typescript-eslint/parser@5.43.0)(eslint@8.27.0)(typescript@4.8.4) + specifier: 6.0.0 + version: 6.0.0(@typescript-eslint/parser@6.0.0)(eslint@8.27.0)(typescript@5.1.3) '@typescript-eslint/parser': - specifier: 5.43.0 - version: 5.43.0(eslint@8.27.0)(typescript@4.8.4) + specifier: 6.0.0 + version: 6.0.0(eslint@8.27.0)(typescript@5.1.3) eslint: specifier: 8.27.0 version: 8.27.0 eslint-config-next: specifier: 13.0.3 - version: 13.0.3(eslint@8.27.0)(typescript@4.8.4) + version: 13.0.3(eslint@8.27.0)(typescript@5.1.3) eslint-config-prettier: specifier: 8.5.0 version: 8.5.0(eslint@8.27.0) @@ -132,10 +144,13 @@ devDependencies: version: 3.5.2(eslint-plugin-import@2.26.0)(eslint@8.27.0) eslint-plugin-import: specifier: 2.26.0 - version: 2.26.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-typescript@3.5.2)(eslint@8.27.0) + version: 2.26.0(@typescript-eslint/parser@6.0.0)(eslint-import-resolver-typescript@3.5.2)(eslint@8.27.0) + eslint-plugin-jsx-a11y: + specifier: 6.7.1 + version: 6.7.1(eslint@8.27.0) eslint-plugin-prettier: - specifier: 4.2.1 - version: 4.2.1(eslint-config-prettier@8.5.0)(eslint@8.27.0)(prettier@2.7.1) + specifier: 5.0.0 + version: 5.0.0(eslint-config-prettier@8.5.0)(eslint@8.27.0)(prettier@3.0.0) husky: specifier: 8.0.2 version: 8.0.2 @@ -143,11 +158,20 @@ devDependencies: specifier: 13.2.2 version: 13.2.2 prettier: - specifier: 2.7.1 - version: 2.7.1 + specifier: 3.0.0 + version: 3.0.0 + stylelint: + specifier: 15.9.0 + version: 15.9.0 + stylelint-config-prettier-scss: + specifier: 1.0.0 + version: 1.0.0(stylelint@15.9.0) + stylelint-config-standard-scss: + specifier: 10.0.0 + version: 10.0.0(postcss@8.4.24)(stylelint@15.9.0) typescript: - specifier: 4.8.4 - version: 4.8.4 + specifier: 5.1.3 + version: 5.1.3 packages: @@ -171,32 +195,11 @@ packages: leven: 3.1.0 dev: false - /@babel/cli@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-N5d7MjzwsQ2wppwjhrsicVDhJSqF9labEP/swYiHhio4Ca2XjEehpgPmerjnLQl7BPE59BLud0PTWGYwqFl/cQ==} - engines: {node: '>=6.9.0'} - hasBin: true - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@jridgewell/trace-mapping': 0.3.18 - commander: 4.1.1 - convert-source-map: 1.9.0 - fs-readdir-recursive: 1.1.0 - glob: 7.2.3 - make-dir: 2.1.0 - slash: 2.0.0 - optionalDependencies: - '@nicolo-ribaudo/chokidar-2': 2.1.8-no-fsevents.3 - chokidar: 3.5.3 - dev: false - /@babel/code-frame@7.22.5: resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.22.5 - dev: false /@babel/compat-data@7.22.5: resolution: {integrity: sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==} @@ -432,7 +435,6 @@ packages: /@babel/helper-validator-identifier@7.22.5: resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-validator-option@7.22.5: resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} @@ -469,7 +471,6 @@ packages: '@babel/helper-validator-identifier': 7.22.5 chalk: 2.4.2 js-tokens: 4.0.0 - dev: false /@babel/parser@7.22.5: resolution: {integrity: sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==} @@ -501,43 +502,6 @@ packages: '@babel/plugin-transform-optional-chaining': 7.22.5(@babel/core@7.22.5) dev: false - /@babel/plugin-external-helpers@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-ngnNEWxmykPk82mH4ajZT0qTztr3Je6hrMuKAslZVM8G1YZTENJSYwrIGtt6KOtznug3exmAtF4so/nPqJuA4A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: false - - /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.22.5): - resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.22.5(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.22.5 - transitivePeerDependencies: - - supports-color - dev: false - - /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.22.5): - resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/compat-data': 7.22.5 - '@babel/core': 7.22.5 - '@babel/helper-compilation-targets': 7.22.5(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.5) - '@babel/plugin-transform-parameters': 7.22.5(@babel/core@7.22.5) - dev: false - /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.5): resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} @@ -642,16 +606,6 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: false - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.5): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: @@ -726,16 +680,6 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: false - /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.22.5): resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} @@ -1188,51 +1132,6 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-react-display-name@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: false - - /@babel/plugin-transform-react-jsx-development@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/plugin-transform-react-jsx': 7.22.5(@babel/core@7.22.5) - dev: false - - /@babel/plugin-transform-react-jsx@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-rog5gZaVbUip5iWDMTYbVM15XQq+RkUKhET/IHR6oizR+JEoN6CAfTTuHcK4vwUyzca30qqHqEpzBOnaRMWYMA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-module-imports': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.22.5) - '@babel/types': 7.22.5 - dev: false - - /@babel/plugin-transform-react-pure-annotations@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - dev: false - /@babel/plugin-transform-regenerator@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==} engines: {node: '>=6.9.0'} @@ -1305,21 +1204,6 @@ packages: '@babel/helper-plugin-utils': 7.22.5 dev: false - /@babel/plugin-transform-typescript@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-SMubA9S7Cb5sGSFFUlqxyClTA9zWJ8qGQrppNUm05LtFuN1ELRFNndkix4zUJrC9F+YivWwa1dHMSyo0e0N9dA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.22.5(@babel/core@7.22.5) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.22.5) - transitivePeerDependencies: - - supports-color - dev: false - /@babel/plugin-transform-unicode-escapes@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==} engines: {node: '>=6.9.0'} @@ -1467,37 +1351,6 @@ packages: esutils: 2.0.3 dev: false - /@babel/preset-react@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-M+Is3WikOpEJHgR385HbuCITPTaPRaNkibTEa9oiofmJvIsrceb4yp9RL9Kb+TE8LznmeyZqpP+Lopwcx59xPQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.22.5 - '@babel/plugin-transform-react-display-name': 7.22.5(@babel/core@7.22.5) - '@babel/plugin-transform-react-jsx': 7.22.5(@babel/core@7.22.5) - '@babel/plugin-transform-react-jsx-development': 7.22.5(@babel/core@7.22.5) - '@babel/plugin-transform-react-pure-annotations': 7.22.5(@babel/core@7.22.5) - dev: false - - /@babel/preset-typescript@7.22.5(@babel/core@7.22.5): - resolution: {integrity: sha512-YbPaal9LxztSGhmndR46FmAbkJ/1fAsw293tSU+I5E5h+cnJ3d4GTwyUgGYmOXJYdGA+uNePle4qbaRzj2NISQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.22.5 - '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.22.5) - '@babel/plugin-transform-modules-commonjs': 7.22.5(@babel/core@7.22.5) - '@babel/plugin-transform-typescript': 7.22.5(@babel/core@7.22.5) - transitivePeerDependencies: - - supports-color - dev: false - /@babel/regjsgen@0.8.0: resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} dev: false @@ -1548,6 +1401,40 @@ packages: resolution: {integrity: sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ==} dev: false + /@csstools/css-parser-algorithms@2.2.0(@csstools/css-tokenizer@2.1.1): + resolution: {integrity: sha512-9BoQ/jSrPq4vv3b9jjLW+PNNv56KlDH5JMx5yASSNrCtvq70FCNZUjXRvbCeR9hYj9ZyhURtqpU/RFIgg6kiOw==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + '@csstools/css-tokenizer': ^2.1.1 + dependencies: + '@csstools/css-tokenizer': 2.1.1 + dev: true + + /@csstools/css-tokenizer@2.1.1: + resolution: {integrity: sha512-GbrTj2Z8MCTUv+52GE0RbFGM527xuXZ0Xa5g0Z+YN573uveS4G0qi6WNOMyz3yrFM/jaILTTwJ0+umx81EzqfA==} + engines: {node: ^14 || ^16 || >=18} + dev: true + + /@csstools/media-query-list-parser@2.1.1(@csstools/css-parser-algorithms@2.2.0)(@csstools/css-tokenizer@2.1.1): + resolution: {integrity: sha512-pUjtFbaKbiFNjJo8pprrIaXLvQvWIlwPiFnRI4sEnc4F0NIGTOsw8kaJSR3CmZAKEvV8QYckovgAnWQC0bgLLQ==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + '@csstools/css-parser-algorithms': ^2.2.0 + '@csstools/css-tokenizer': ^2.1.1 + dependencies: + '@csstools/css-parser-algorithms': 2.2.0(@csstools/css-tokenizer@2.1.1) + '@csstools/css-tokenizer': 2.1.1 + dev: true + + /@csstools/selector-specificity@2.2.0(postcss-selector-parser@6.0.13): + resolution: {integrity: sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss-selector-parser: ^6.0.10 + dependencies: + postcss-selector-parser: 6.0.13 + dev: true + /@emotion/babel-plugin@11.11.0: resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} dependencies: @@ -1637,6 +1524,21 @@ packages: resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==} dev: false + /@eslint-community/eslint-utils@4.4.0(eslint@8.27.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.27.0 + eslint-visitor-keys: 3.4.1 + dev: true + + /@eslint-community/regexpp@4.5.1: + resolution: {integrity: sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + /@eslint/eslintrc@1.4.1: resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1654,598 +1556,117 @@ packages: - supports-color dev: true - /@firebase/analytics-compat@0.2.6(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10): - resolution: {integrity: sha512-4MqpVLFkGK7NJf/5wPEEP7ePBJatwYpyjgJ+wQHQGHfzaCDgntOnl9rL2vbVGGKCnRqWtZDIWhctB86UWXaX2Q==} - peerDependencies: - '@firebase/app-compat': 0.x - dependencies: - '@firebase/analytics': 0.10.0(@firebase/app@0.9.10) - '@firebase/analytics-types': 0.8.0 - '@firebase/app-compat': 0.2.10 - '@firebase/component': 0.6.4 - '@firebase/util': 1.9.3 - tslib: 2.5.3 - transitivePeerDependencies: - - '@firebase/app' + /@floating-ui/core@1.3.0: + resolution: {integrity: sha512-vX1WVAdPjZg9DkDkC+zEx/tKtnST6/qcNpwcjeBgco3XRNHz5PUA+ivi/yr6G3o0kMR60uKBJcfOdfzOFI7PMQ==} dev: false - /@firebase/analytics-types@0.8.0: - resolution: {integrity: sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw==} + /@floating-ui/dom@1.3.0: + resolution: {integrity: sha512-qIAwejE3r6NeA107u4ELDKkH8+VtgRKdXqtSPaKflL2S2V+doyN+Wt9s5oHKXPDo4E8TaVXaHT3+6BbagH31xw==} + dependencies: + '@floating-ui/core': 1.3.0 dev: false - /@firebase/analytics@0.10.0(@firebase/app@0.9.10): - resolution: {integrity: sha512-Locv8gAqx0e+GX/0SI3dzmBY5e9kjVDtD+3zCFLJ0tH2hJwuCAiL+5WkHuxKj92rqQj/rvkBUCfA1ewlX2hehg==} + /@hookform/resolvers@3.1.1(react-hook-form@7.43.9): + resolution: {integrity: sha512-tS16bAUkqjITNSvbJuO1x7MXbn7Oe8ZziDTJdA9mMvsoYthnOOiznOTGBYwbdlYBgU+tgpI/BtTU3paRbCuSlg==} peerDependencies: - '@firebase/app': 0.x + react-hook-form: ^7.0.0 dependencies: - '@firebase/app': 0.9.10 - '@firebase/component': 0.6.4 - '@firebase/installations': 0.6.4(@firebase/app@0.9.10) - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - tslib: 2.5.3 + react-hook-form: 7.43.9(react@18.2.0) dev: false - /@firebase/app-check-compat@0.3.6(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10): - resolution: {integrity: sha512-azHAeHi9igoaIo04E6Yfuc7aIbWoWuBXuqjyYyWbeCc8Zz/NfJvIAgmXugN4LdxsHJ7XGlZTvwJ6YaYROdSa7A==} - peerDependencies: - '@firebase/app-compat': 0.x + /@humanwhocodes/config-array@0.11.10: + resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} + engines: {node: '>=10.10.0'} dependencies: - '@firebase/app-check': 0.7.0(@firebase/app@0.9.10) - '@firebase/app-check-types': 0.5.0 - '@firebase/app-compat': 0.2.10 - '@firebase/component': 0.6.4 - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - tslib: 2.5.3 + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 transitivePeerDependencies: - - '@firebase/app' - dev: false + - supports-color + dev: true - /@firebase/app-check-interop-types@0.2.0: - resolution: {integrity: sha512-+3PQIeX6/eiVK+x/yg8r6xTNR97fN7MahFDm+jiQmDjcyvSefoGuTTNQuuMScGyx3vYUBeZn+Cp9kC0yY/9uxQ==} - dev: false + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true - /@firebase/app-check-types@0.5.0: - resolution: {integrity: sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ==} - dev: false + /@humanwhocodes/object-schema@1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + dev: true - /@firebase/app-check@0.7.0(@firebase/app@0.9.10): - resolution: {integrity: sha512-y0raLJpEtiL+wonfInFMaSfBV/EDvr356ZHMWbpr5F7fR0/I3cC0h7U6SKpKhrbSHJ0fOYIe0xbih20KTlpcnA==} - peerDependencies: - '@firebase/app': 0.x + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} dependencies: - '@firebase/app': 0.9.10 - '@firebase/component': 0.6.4 - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - tslib: 2.5.3 + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.18 dev: false - /@firebase/app-compat@0.2.10: - resolution: {integrity: sha512-kulrAW9JKkWeLeXKYjipCh60MmZcRC626NYpNWKxnjZ3YsVk6vgMuM+BHvhHQVp0fgfOq3hMNp5tyhlAB1Q1EQ==} - dependencies: - '@firebase/app': 0.9.10 - '@firebase/component': 0.6.4 - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - tslib: 2.5.3 + /@jridgewell/resolve-uri@3.1.0: + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} dev: false - /@firebase/app-types@0.9.0: - resolution: {integrity: sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==} + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} dev: false - /@firebase/app@0.9.10: - resolution: {integrity: sha512-2aLHuPLrjgxds95e2JpuAb29pBGArihHwjdJBUKtJnSxxEdwxAsGuXzSrOrmzYXlAwxUTZkOD6Cbl/dfTTwhKA==} + /@jridgewell/source-map@0.3.3: + resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} dependencies: - '@firebase/component': 0.6.4 - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - idb: 7.1.1 - tslib: 2.5.3 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.18 dev: false - /@firebase/auth-compat@0.4.2(@firebase/app-compat@0.2.10)(@firebase/app-types@0.9.0)(@firebase/app@0.9.10): - resolution: {integrity: sha512-Q30e77DWXFmXEt5dg5JbqEDpjw9y3/PcP9LslDPR7fARmAOTIY9MM6HXzm9KC+dlrKH/+p6l8g9ifJiam9mc4A==} - peerDependencies: - '@firebase/app-compat': 0.x - dependencies: - '@firebase/app-compat': 0.2.10 - '@firebase/auth': 0.23.2(@firebase/app@0.9.10) - '@firebase/auth-types': 0.12.0(@firebase/app-types@0.9.0)(@firebase/util@1.9.3) - '@firebase/component': 0.6.4 - '@firebase/util': 1.9.3 - node-fetch: 2.6.7 - tslib: 2.5.3 - transitivePeerDependencies: - - '@firebase/app' - - '@firebase/app-types' - - encoding + /@jridgewell/sourcemap-codec@1.4.14: + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} dev: false - /@firebase/auth-interop-types@0.2.1: - resolution: {integrity: sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==} + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} dev: false - /@firebase/auth-types@0.12.0(@firebase/app-types@0.9.0)(@firebase/util@1.9.3): - resolution: {integrity: sha512-pPwaZt+SPOshK8xNoiQlK5XIrS97kFYc3Rc7xmy373QsOJ9MmqXxLaYssP5Kcds4wd2qK//amx/c+A8O2fVeZA==} - peerDependencies: - '@firebase/app-types': 0.x - '@firebase/util': 1.x + /@jridgewell/trace-mapping@0.3.18: + resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} dependencies: - '@firebase/app-types': 0.9.0 - '@firebase/util': 1.9.3 + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 dev: false - /@firebase/auth@0.23.2(@firebase/app@0.9.10): - resolution: {integrity: sha512-dM9iJ0R6tI1JczuGSxXmQbXAgtYie0K4WvKcuyuSTCu9V8eEDiz4tfa1sO3txsfvwg7nOY3AjoCyMYEdqZ8hdg==} + /@meronex/icons@4.0.0(react@18.2.0): + resolution: {integrity: sha512-WnoxUT02qawZSvsoPSwe7YOqOk0APysIHugiD3dYdc/QNeoigN4PD8mmmtmZFKlv8/Z7eERub0BmPkWcJ1BI+w==} peerDependencies: - '@firebase/app': 0.x - dependencies: - '@firebase/app': 0.9.10 - '@firebase/component': 0.6.4 - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - node-fetch: 2.6.7 - tslib: 2.5.3 - transitivePeerDependencies: - - encoding - dev: false - - /@firebase/component@0.6.4: - resolution: {integrity: sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==} + react: '*' dependencies: - '@firebase/util': 1.9.3 - tslib: 2.5.3 + camelcase: 5.3.1 + ncp: 2.0.0 + react: 18.2.0 dev: false - /@firebase/database-compat@0.3.4: - resolution: {integrity: sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg==} - dependencies: - '@firebase/component': 0.6.4 - '@firebase/database': 0.14.4 - '@firebase/database-types': 0.10.4 - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - tslib: 2.5.3 + /@next/env@13.4.3: + resolution: {integrity: sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ==} dev: false - /@firebase/database-types@0.10.4: - resolution: {integrity: sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ==} - dependencies: - '@firebase/app-types': 0.9.0 - '@firebase/util': 1.9.3 + /@next/env@13.4.7: + resolution: {integrity: sha512-ZlbiFulnwiFsW9UV1ku1OvX/oyIPLtMk9p/nnvDSwI0s7vSoZdRtxXNsaO+ZXrLv/pMbXVGq4lL8TbY9iuGmVw==} dev: false - /@firebase/database@0.14.4: - resolution: {integrity: sha512-+Ea/IKGwh42jwdjCyzTmeZeLM3oy1h0mFPsTy6OqCWzcu/KFqRAr5Tt1HRCOBlNOdbh84JPZC47WLU18n2VbxQ==} + /@next/eslint-plugin-next@13.0.3: + resolution: {integrity: sha512-slmTAHNKDyc7jhx4VF8lFbmOPWJ3PShtUUWpb6x9+ga59CyOxgP6AdcDhxfapnWYACKe/TwYiaveufu7LqXgZg==} dependencies: - '@firebase/auth-interop-types': 0.2.1 - '@firebase/component': 0.6.4 - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - faye-websocket: 0.11.4 - tslib: 2.5.3 - dev: false + glob: 7.1.7 + dev: true - /@firebase/firestore-compat@0.3.9(@firebase/app-compat@0.2.10)(@firebase/app-types@0.9.0)(@firebase/app@0.9.10): - resolution: {integrity: sha512-u4fGeuaDaMnAPp20PAm6vrhktVGCtfmC3iup5ymMkOUNIqbuQ/+WLL3zUlJi+Ytl4hX0vVNg4UQEh4vfMorc4Q==} - peerDependencies: - '@firebase/app-compat': 0.x - dependencies: - '@firebase/app-compat': 0.2.10 - '@firebase/component': 0.6.4 - '@firebase/firestore': 3.12.0(@firebase/app@0.9.10) - '@firebase/firestore-types': 2.5.1(@firebase/app-types@0.9.0)(@firebase/util@1.9.3) - '@firebase/util': 1.9.3 - tslib: 2.5.3 - transitivePeerDependencies: - - '@firebase/app' - - '@firebase/app-types' - - encoding + /@next/swc-darwin-arm64@13.4.3: + resolution: {integrity: sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true dev: false - - /@firebase/firestore-types@2.5.1(@firebase/app-types@0.9.0)(@firebase/util@1.9.3): - resolution: {integrity: sha512-xG0CA6EMfYo8YeUxC8FeDzf6W3FX1cLlcAGBYV6Cku12sZRI81oWcu61RSKM66K6kUENP+78Qm8mvroBcm1whw==} - peerDependencies: - '@firebase/app-types': 0.x - '@firebase/util': 1.x - dependencies: - '@firebase/app-types': 0.9.0 - '@firebase/util': 1.9.3 - dev: false - - /@firebase/firestore@3.12.0(@firebase/app@0.9.10): - resolution: {integrity: sha512-mZdwIJBOIAdkaykqZqMYQZldSH19gf7u1Y77UVxh4igm1zaG8ZiGE8qYVXQ/vGc+BvvUZ8OpnqLI5Z0JSJtDIg==} - engines: {node: '>=10.10.0'} - peerDependencies: - '@firebase/app': 0.x - dependencies: - '@firebase/app': 0.9.10 - '@firebase/component': 0.6.4 - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - '@firebase/webchannel-wrapper': 0.10.0 - '@grpc/grpc-js': 1.7.3 - '@grpc/proto-loader': 0.6.13 - node-fetch: 2.6.7 - tslib: 2.5.3 - transitivePeerDependencies: - - encoding - dev: false - - /@firebase/functions-compat@0.3.4(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10): - resolution: {integrity: sha512-kxVxTGyLV1MBR3sp3mI+eQ6JBqz0G5bk310F8eX4HzDFk4xjk5xY0KdHktMH+edM2xs1BOg0vwvvsAHczIjB+w==} - peerDependencies: - '@firebase/app-compat': 0.x - dependencies: - '@firebase/app-compat': 0.2.10 - '@firebase/component': 0.6.4 - '@firebase/functions': 0.9.4(@firebase/app@0.9.10) - '@firebase/functions-types': 0.6.0 - '@firebase/util': 1.9.3 - tslib: 2.5.3 - transitivePeerDependencies: - - '@firebase/app' - - encoding - dev: false - - /@firebase/functions-types@0.6.0: - resolution: {integrity: sha512-hfEw5VJtgWXIRf92ImLkgENqpL6IWpYaXVYiRkFY1jJ9+6tIhWM7IzzwbevwIIud/jaxKVdRzD7QBWfPmkwCYw==} - dev: false - - /@firebase/functions@0.9.4(@firebase/app@0.9.10): - resolution: {integrity: sha512-3H2qh6U+q+nepO5Hds+Ddl6J0pS+zisuBLqqQMRBHv9XpWfu0PnDHklNmE8rZ+ccTEXvBj6zjkPfdxt6NisvlQ==} - peerDependencies: - '@firebase/app': 0.x - dependencies: - '@firebase/app': 0.9.10 - '@firebase/app-check-interop-types': 0.2.0 - '@firebase/auth-interop-types': 0.2.1 - '@firebase/component': 0.6.4 - '@firebase/messaging-interop-types': 0.2.0 - '@firebase/util': 1.9.3 - node-fetch: 2.6.7 - tslib: 2.5.3 - transitivePeerDependencies: - - encoding - dev: false - - /@firebase/installations-compat@0.2.4(@firebase/app-compat@0.2.10)(@firebase/app-types@0.9.0)(@firebase/app@0.9.10): - resolution: {integrity: sha512-LI9dYjp0aT9Njkn9U4JRrDqQ6KXeAmFbRC0E7jI7+hxl5YmRWysq5qgQl22hcWpTk+cm3es66d/apoDU/A9n6Q==} - peerDependencies: - '@firebase/app-compat': 0.x - dependencies: - '@firebase/app-compat': 0.2.10 - '@firebase/component': 0.6.4 - '@firebase/installations': 0.6.4(@firebase/app@0.9.10) - '@firebase/installations-types': 0.5.0(@firebase/app-types@0.9.0) - '@firebase/util': 1.9.3 - tslib: 2.5.3 - transitivePeerDependencies: - - '@firebase/app' - - '@firebase/app-types' - dev: false - - /@firebase/installations-types@0.5.0(@firebase/app-types@0.9.0): - resolution: {integrity: sha512-9DP+RGfzoI2jH7gY4SlzqvZ+hr7gYzPODrbzVD82Y12kScZ6ZpRg/i3j6rleto8vTFC8n6Len4560FnV1w2IRg==} - peerDependencies: - '@firebase/app-types': 0.x - dependencies: - '@firebase/app-types': 0.9.0 - dev: false - - /@firebase/installations@0.6.4(@firebase/app@0.9.10): - resolution: {integrity: sha512-u5y88rtsp7NYkCHC3ElbFBrPtieUybZluXyzl7+4BsIz4sqb4vSAuwHEUgCgCeaQhvsnxDEU6icly8U9zsJigA==} - peerDependencies: - '@firebase/app': 0.x - dependencies: - '@firebase/app': 0.9.10 - '@firebase/component': 0.6.4 - '@firebase/util': 1.9.3 - idb: 7.0.1 - tslib: 2.5.3 - dev: false - - /@firebase/logger@0.4.0: - resolution: {integrity: sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==} - dependencies: - tslib: 2.5.3 - dev: false - - /@firebase/messaging-compat@0.2.4(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10): - resolution: {integrity: sha512-lyFjeUhIsPRYDPNIkYX1LcZMpoVbBWXX4rPl7c/rqc7G+EUea7IEtSt4MxTvh6fDfPuzLn7+FZADfscC+tNMfg==} - peerDependencies: - '@firebase/app-compat': 0.x - dependencies: - '@firebase/app-compat': 0.2.10 - '@firebase/component': 0.6.4 - '@firebase/messaging': 0.12.4(@firebase/app@0.9.10) - '@firebase/util': 1.9.3 - tslib: 2.5.3 - transitivePeerDependencies: - - '@firebase/app' - dev: false - - /@firebase/messaging-interop-types@0.2.0: - resolution: {integrity: sha512-ujA8dcRuVeBixGR9CtegfpU4YmZf3Lt7QYkcj693FFannwNuZgfAYaTmbJ40dtjB81SAu6tbFPL9YLNT15KmOQ==} - dev: false - - /@firebase/messaging@0.12.4(@firebase/app@0.9.10): - resolution: {integrity: sha512-6JLZct6zUaex4g7HI3QbzeUrg9xcnmDAPTWpkoMpd/GoSVWH98zDoWXMGrcvHeCAIsLpFMe4MPoZkJbrPhaASw==} - peerDependencies: - '@firebase/app': 0.x - dependencies: - '@firebase/app': 0.9.10 - '@firebase/component': 0.6.4 - '@firebase/installations': 0.6.4(@firebase/app@0.9.10) - '@firebase/messaging-interop-types': 0.2.0 - '@firebase/util': 1.9.3 - idb: 7.0.1 - tslib: 2.5.3 - dev: false - - /@firebase/performance-compat@0.2.4(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10): - resolution: {integrity: sha512-nnHUb8uP9G8islzcld/k6Bg5RhX62VpbAb/Anj7IXs/hp32Eb2LqFPZK4sy3pKkBUO5wcrlRWQa6wKOxqlUqsg==} - peerDependencies: - '@firebase/app-compat': 0.x - dependencies: - '@firebase/app-compat': 0.2.10 - '@firebase/component': 0.6.4 - '@firebase/logger': 0.4.0 - '@firebase/performance': 0.6.4(@firebase/app@0.9.10) - '@firebase/performance-types': 0.2.0 - '@firebase/util': 1.9.3 - tslib: 2.5.3 - transitivePeerDependencies: - - '@firebase/app' - dev: false - - /@firebase/performance-types@0.2.0: - resolution: {integrity: sha512-kYrbr8e/CYr1KLrLYZZt2noNnf+pRwDq2KK9Au9jHrBMnb0/C9X9yWSXmZkFt4UIdsQknBq8uBB7fsybZdOBTA==} - dev: false - - /@firebase/performance@0.6.4(@firebase/app@0.9.10): - resolution: {integrity: sha512-HfTn/bd8mfy/61vEqaBelNiNnvAbUtME2S25A67Nb34zVuCSCRIX4SseXY6zBnOFj3oLisaEqhVcJmVPAej67g==} - peerDependencies: - '@firebase/app': 0.x - dependencies: - '@firebase/app': 0.9.10 - '@firebase/component': 0.6.4 - '@firebase/installations': 0.6.4(@firebase/app@0.9.10) - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - tslib: 2.5.3 - dev: false - - /@firebase/remote-config-compat@0.2.4(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10): - resolution: {integrity: sha512-FKiki53jZirrDFkBHglB3C07j5wBpitAaj8kLME6g8Mx+aq7u9P7qfmuSRytiOItADhWUj7O1JIv7n9q87SuwA==} - peerDependencies: - '@firebase/app-compat': 0.x - dependencies: - '@firebase/app-compat': 0.2.10 - '@firebase/component': 0.6.4 - '@firebase/logger': 0.4.0 - '@firebase/remote-config': 0.4.4(@firebase/app@0.9.10) - '@firebase/remote-config-types': 0.3.0 - '@firebase/util': 1.9.3 - tslib: 2.5.3 - transitivePeerDependencies: - - '@firebase/app' - dev: false - - /@firebase/remote-config-types@0.3.0: - resolution: {integrity: sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA==} - dev: false - - /@firebase/remote-config@0.4.4(@firebase/app@0.9.10): - resolution: {integrity: sha512-x1ioTHGX8ZwDSTOVp8PBLv2/wfwKzb4pxi0gFezS5GCJwbLlloUH4YYZHHS83IPxnua8b6l0IXUaWd0RgbWwzQ==} - peerDependencies: - '@firebase/app': 0.x - dependencies: - '@firebase/app': 0.9.10 - '@firebase/component': 0.6.4 - '@firebase/installations': 0.6.4(@firebase/app@0.9.10) - '@firebase/logger': 0.4.0 - '@firebase/util': 1.9.3 - tslib: 2.5.3 - dev: false - - /@firebase/storage-compat@0.3.2(@firebase/app-compat@0.2.10)(@firebase/app-types@0.9.0)(@firebase/app@0.9.10): - resolution: {integrity: sha512-wvsXlLa9DVOMQJckbDNhXKKxRNNewyUhhbXev3t8kSgoCotd1v3MmqhKKz93ePhDnhHnDs7bYHy+Qa8dRY6BXw==} - peerDependencies: - '@firebase/app-compat': 0.x - dependencies: - '@firebase/app-compat': 0.2.10 - '@firebase/component': 0.6.4 - '@firebase/storage': 0.11.2(@firebase/app@0.9.10) - '@firebase/storage-types': 0.8.0(@firebase/app-types@0.9.0)(@firebase/util@1.9.3) - '@firebase/util': 1.9.3 - tslib: 2.5.3 - transitivePeerDependencies: - - '@firebase/app' - - '@firebase/app-types' - - encoding - dev: false - - /@firebase/storage-types@0.8.0(@firebase/app-types@0.9.0)(@firebase/util@1.9.3): - resolution: {integrity: sha512-isRHcGrTs9kITJC0AVehHfpraWFui39MPaU7Eo8QfWlqW7YPymBmRgjDrlOgFdURh6Cdeg07zmkLP5tzTKRSpg==} - peerDependencies: - '@firebase/app-types': 0.x - '@firebase/util': 1.x - dependencies: - '@firebase/app-types': 0.9.0 - '@firebase/util': 1.9.3 - dev: false - - /@firebase/storage@0.11.2(@firebase/app@0.9.10): - resolution: {integrity: sha512-CtvoFaBI4hGXlXbaCHf8humajkbXhs39Nbh6MbNxtwJiCqxPy9iH3D3CCfXAvP0QvAAwmJUTK3+z9a++Kc4nkA==} - peerDependencies: - '@firebase/app': 0.x - dependencies: - '@firebase/app': 0.9.10 - '@firebase/component': 0.6.4 - '@firebase/util': 1.9.3 - node-fetch: 2.6.7 - tslib: 2.5.3 - transitivePeerDependencies: - - encoding - dev: false - - /@firebase/util@1.9.3: - resolution: {integrity: sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==} - dependencies: - tslib: 2.5.3 - dev: false - - /@firebase/webchannel-wrapper@0.10.0: - resolution: {integrity: sha512-2I8y+vJVrPfPFJrnRGpao1Qc2Gu7wmYoo5ed2s5zK/DUGgcyY1Yr/xC0YdnKM4pi7rG3HqwW9ehAKUXoTMLdoA==} - dev: false - - /@floating-ui/core@1.3.0: - resolution: {integrity: sha512-vX1WVAdPjZg9DkDkC+zEx/tKtnST6/qcNpwcjeBgco3XRNHz5PUA+ivi/yr6G3o0kMR60uKBJcfOdfzOFI7PMQ==} - dev: false - - /@floating-ui/dom@1.3.0: - resolution: {integrity: sha512-qIAwejE3r6NeA107u4ELDKkH8+VtgRKdXqtSPaKflL2S2V+doyN+Wt9s5oHKXPDo4E8TaVXaHT3+6BbagH31xw==} - dependencies: - '@floating-ui/core': 1.3.0 - dev: false - - /@grpc/grpc-js@1.7.3: - resolution: {integrity: sha512-H9l79u4kJ2PVSxUNA08HMYAnUBLj9v6KjYQ7SQ71hOZcEXhShE/y5iQCesP8+6/Ik/7i2O0a10bPquIcYfufog==} - engines: {node: ^8.13.0 || >=10.10.0} - dependencies: - '@grpc/proto-loader': 0.7.7 - '@types/node': 20.3.1 - dev: false - - /@grpc/proto-loader@0.6.13: - resolution: {integrity: sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g==} - engines: {node: '>=6'} - hasBin: true - dependencies: - '@types/long': 4.0.2 - lodash.camelcase: 4.3.0 - long: 4.0.0 - protobufjs: 6.11.3 - yargs: 16.2.0 - dev: false - - /@grpc/proto-loader@0.7.7: - resolution: {integrity: sha512-1TIeXOi8TuSCQprPItwoMymZXxWT0CPxUhkrkeCUH+D8U7QDwQ6b7SUz2MaLuWM2llT+J/TVFLmQI5KtML3BhQ==} - engines: {node: '>=6'} - hasBin: true - dependencies: - '@types/long': 4.0.2 - lodash.camelcase: 4.3.0 - long: 4.0.0 - protobufjs: 7.2.3 - yargs: 17.7.2 - dev: false - - /@hookform/resolvers@2.9.10(react-hook-form@7.43.9): - resolution: {integrity: sha512-JIL1DgJIlH9yuxcNGtyhsWX/PgNltz+5Gr6+8SX9fhXc/hPbEIk6wPI82nhgvp3uUb6ZfAM5mqg/x7KR7NAb+A==} - peerDependencies: - react-hook-form: ^7.0.0 - dependencies: - react-hook-form: 7.43.9(react@18.2.0) - dev: false - - /@humanwhocodes/config-array@0.11.10: - resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} - engines: {node: '>=10.10.0'} - dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@humanwhocodes/module-importer@1.0.1: - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - dev: true - - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - dev: true - - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.18 - dev: false - - /@jridgewell/resolve-uri@3.1.0: - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} - dev: false - - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: false - - /@jridgewell/source-map@0.3.3: - resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.18 - dev: false - - /@jridgewell/sourcemap-codec@1.4.14: - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - dev: false - - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: false - - /@jridgewell/trace-mapping@0.3.18: - resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: false - - /@meronex/icons@4.0.0(react@18.2.0): - resolution: {integrity: sha512-WnoxUT02qawZSvsoPSwe7YOqOk0APysIHugiD3dYdc/QNeoigN4PD8mmmtmZFKlv8/Z7eERub0BmPkWcJ1BI+w==} - peerDependencies: - react: '*' - dependencies: - camelcase: 5.3.1 - ncp: 2.0.0 - react: 18.2.0 - dev: false - - /@next/env@13.4.3: - resolution: {integrity: sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ==} - dev: false - - /@next/env@13.4.5: - resolution: {integrity: sha512-SG/gKH6eij4vwQy87b/3mbpQ1X3x2vUdnpwq6/qL2IQWjtq58EY/UuNAp9CoEZoC9sI4L9AD1r+73Z9r4d3uug==} - dev: false - - /@next/eslint-plugin-next@13.0.3: - resolution: {integrity: sha512-slmTAHNKDyc7jhx4VF8lFbmOPWJ3PShtUUWpb6x9+ga59CyOxgP6AdcDhxfapnWYACKe/TwYiaveufu7LqXgZg==} - dependencies: - glob: 7.1.7 - dev: true - - /@next/swc-darwin-arm64@13.4.3: - resolution: {integrity: sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: false - optional: true + optional: true /@next/swc-darwin-x64@13.4.3: resolution: {integrity: sha512-Mi8xJWh2IOjryAM1mx18vwmal9eokJ2njY4nDh04scy37F0LEGJ/diL6JL6kTXi0UfUCGbMsOItf7vpReNiD2A==} @@ -2319,12 +1740,6 @@ packages: dev: false optional: true - /@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3: - resolution: {integrity: sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==} - requiresBuild: true - dev: false - optional: true - /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2366,47 +1781,400 @@ packages: fsevents: 2.3.2 dev: true - /@protobufjs/aspromise@1.1.2: - resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + /@radix-ui/primitive@1.0.1: + resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} + dependencies: + '@babel/runtime': 7.22.5 + dev: false + + /@radix-ui/react-collection@1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.0.25)(react@18.2.0) + '@types/react': 18.0.25 + '@types/react-dom': 18.0.9 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-compose-refs@1.0.1(@types/react@18.0.25)(react@18.2.0): + resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@types/react': 18.0.25 + react: 18.2.0 + dev: false + + /@radix-ui/react-context@1.0.1(@types/react@18.0.25)(react@18.2.0): + resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@types/react': 18.0.25 + react: 18.2.0 + dev: false + + /@radix-ui/react-direction@1.0.1(@types/react@18.0.25)(react@18.2.0): + resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@types/react': 18.0.25 + react: 18.2.0 + dev: false + + /@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.0.25)(react@18.2.0) + '@types/react': 18.0.25 + '@types/react-dom': 18.0.9 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-id@1.0.1(@types/react@18.0.25)(react@18.2.0): + resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@types/react': 18.0.25 + react: 18.2.0 + dev: false + + /@radix-ui/react-label@2.0.2(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.0.25 + '@types/react-dom': 18.0.9 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-navigation-menu@1.1.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-x4Uv0N47ABx3/frJazYXxvMpZeKJe0qmRIgQ2o3lhTqnTVg+CaZfVVO4nQLn3QJcDkTz8icElKffhFng47XIBA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.0.25 + '@types/react-dom': 18.0.9 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-presence@1.0.1(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@types/react': 18.0.25 + '@types/react-dom': 18.0.9 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/react-slot': 1.0.2(@types/react@18.0.25)(react@18.2.0) + '@types/react': 18.0.25 + '@types/react-dom': 18.0.9 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@types/react': 18.0.25 + '@types/react-dom': 18.0.9 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) dev: false - /@protobufjs/base64@1.1.2: - resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + /@radix-ui/react-separator@1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.0.25 + '@types/react-dom': 18.0.9 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) dev: false - /@protobufjs/codegen@2.0.4: - resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + /@radix-ui/react-slot@1.0.2(@types/react@18.0.25)(react@18.2.0): + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@types/react': 18.0.25 + react: 18.2.0 dev: false - /@protobufjs/eventemitter@1.1.0: - resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + /@radix-ui/react-tabs@1.0.4(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-context': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@types/react': 18.0.25 + '@types/react-dom': 18.0.9 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) dev: false - /@protobufjs/fetch@1.1.0: - resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.0.25)(react@18.2.0): + resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/inquire': 1.1.0 + '@babel/runtime': 7.22.5 + '@types/react': 18.0.25 + react: 18.2.0 dev: false - /@protobufjs/float@1.0.2: - resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.0.25)(react@18.2.0): + resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@types/react': 18.0.25 + react: 18.2.0 dev: false - /@protobufjs/inquire@1.1.0: - resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.0.25)(react@18.2.0): + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.0.25)(react@18.2.0) + '@types/react': 18.0.25 + react: 18.2.0 dev: false - /@protobufjs/path@1.1.2: - resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.0.25)(react@18.2.0): + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@types/react': 18.0.25 + react: 18.2.0 dev: false - /@protobufjs/pool@1.1.0: - resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + /@radix-ui/react-use-previous@1.0.1(@types/react@18.0.25)(react@18.2.0): + resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@types/react': 18.0.25 + react: 18.2.0 dev: false - /@protobufjs/utf8@1.1.0: - resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.22.5 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.0.9)(@types/react@18.0.25)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.0.25 + '@types/react-dom': 18.0.9 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) dev: false /@reach/observe-rect@1.2.0: @@ -2580,13 +2348,6 @@ packages: '@types/node': 20.3.1 dev: false - /@types/hoist-non-react-statics@3.3.1: - resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==} - dependencies: - '@types/react': 18.0.25 - hoist-non-react-statics: 3.3.2 - dev: true - /@types/json-schema@7.0.12: resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} @@ -2594,17 +2355,21 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@types/long@4.0.2: - resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} - dev: false - /@types/minimatch@5.1.2: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} dev: false + /@types/minimist@1.2.2: + resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} + dev: true + /@types/node@20.3.1: resolution: {integrity: sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==} + /@types/normalize-package-data@2.4.1: + resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} + dev: true + /@types/nprogress@0.2.0: resolution: {integrity: sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==} dev: false @@ -2620,7 +2385,6 @@ packages: resolution: {integrity: sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg==} dependencies: '@types/react': 18.0.25 - dev: true /@types/react-modal@3.13.1: resolution: {integrity: sha512-iY/gPvTDIy6Z+37l+ibmrY+GTV4KQTHcCyR5FIytm182RQS69G5ps4PH2FxtC7bAQ2QRHXMevsBgck7IQruHNg==} @@ -2654,61 +2418,78 @@ packages: resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} dev: true - /@types/styled-components@5.1.26: - resolution: {integrity: sha512-KuKJ9Z6xb93uJiIyxo/+ksS7yLjS1KzG6iv5i78dhVg/X3u5t1H7juRWqVmodIdz6wGVaIApo1u01kmFRdJHVw==} - dependencies: - '@types/hoist-non-react-statics': 3.3.1 - '@types/react': 18.0.25 - csstype: 3.1.2 - dev: true - /@types/trusted-types@2.0.3: resolution: {integrity: sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==} dev: false - /@typescript-eslint/eslint-plugin@5.43.0(@typescript-eslint/parser@5.43.0)(eslint@8.27.0)(typescript@4.8.4): - resolution: {integrity: sha512-wNPzG+eDR6+hhW4yobEmpR36jrqqQv1vxBq5LJO3fBAktjkvekfr4BRl+3Fn1CM/A+s8/EiGUbOMDoYqWdbtXA==} + /@typescript-eslint/eslint-plugin@6.0.0(@typescript-eslint/parser@6.0.0)(eslint@8.27.0)(typescript@5.1.3): + resolution: {integrity: sha512-xuv6ghKGoiq856Bww/yVYnXGsKa588kY3M0XK7uUW/3fJNNULKRfZfSBkMTSpqGG/8ZCXCadfh8G/z/B4aqS/A==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.5.1 + '@typescript-eslint/parser': 6.0.0(eslint@8.27.0)(typescript@5.1.3) + '@typescript-eslint/scope-manager': 6.0.0 + '@typescript-eslint/type-utils': 6.0.0(eslint@8.27.0)(typescript@5.1.3) + '@typescript-eslint/utils': 6.0.0(eslint@8.27.0)(typescript@5.1.3) + '@typescript-eslint/visitor-keys': 6.0.0 + debug: 4.3.4 + eslint: 8.27.0 + grapheme-splitter: 1.0.4 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare: 1.4.0 + natural-compare-lite: 1.4.0 + semver: 7.5.1 + ts-api-utils: 1.0.1(typescript@5.1.3) + typescript: 5.1.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@5.43.0(eslint@8.27.0)(typescript@5.1.3): + resolution: {integrity: sha512-2iHUK2Lh7PwNUlhFxxLI2haSDNyXvebBO9izhjhMoDC+S3XI9qt2DGFUsiJ89m2k7gGYch2aEpYqV5F/+nwZug==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - '@typescript-eslint/parser': ^5.0.0 eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.43.0(eslint@8.27.0)(typescript@4.8.4) '@typescript-eslint/scope-manager': 5.43.0 - '@typescript-eslint/type-utils': 5.43.0(eslint@8.27.0)(typescript@4.8.4) - '@typescript-eslint/utils': 5.43.0(eslint@8.27.0)(typescript@4.8.4) + '@typescript-eslint/types': 5.43.0 + '@typescript-eslint/typescript-estree': 5.43.0(typescript@5.1.3) debug: 4.3.4 eslint: 8.27.0 - ignore: 5.2.4 - natural-compare-lite: 1.4.0 - regexpp: 3.2.0 - semver: 7.5.1 - tsutils: 3.21.0(typescript@4.8.4) - typescript: 4.8.4 + typescript: 5.1.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@5.43.0(eslint@8.27.0)(typescript@4.8.4): - resolution: {integrity: sha512-2iHUK2Lh7PwNUlhFxxLI2haSDNyXvebBO9izhjhMoDC+S3XI9qt2DGFUsiJ89m2k7gGYch2aEpYqV5F/+nwZug==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/parser@6.0.0(eslint@8.27.0)(typescript@5.1.3): + resolution: {integrity: sha512-TNaufYSPrr1U8n+3xN+Yp9g31vQDJqhXzzPSHfQDLcaO4tU+mCfODPxCwf4H530zo7aUBE3QIdxCXamEnG04Tg==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.43.0 - '@typescript-eslint/types': 5.43.0 - '@typescript-eslint/typescript-estree': 5.43.0(typescript@4.8.4) + '@typescript-eslint/scope-manager': 6.0.0 + '@typescript-eslint/types': 6.0.0 + '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.1.3) + '@typescript-eslint/visitor-keys': 6.0.0 debug: 4.3.4 eslint: 8.27.0 - typescript: 4.8.4 + typescript: 5.1.3 transitivePeerDependencies: - supports-color dev: true @@ -2721,22 +2502,30 @@ packages: '@typescript-eslint/visitor-keys': 5.43.0 dev: true - /@typescript-eslint/type-utils@5.43.0(eslint@8.27.0)(typescript@4.8.4): - resolution: {integrity: sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/scope-manager@6.0.0: + resolution: {integrity: sha512-o4q0KHlgCZTqjuaZ25nw5W57NeykZT9LiMEG4do/ovwvOcPnDO1BI5BQdCsUkjxFyrCL0cSzLjvIMfR9uo7cWg==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.0.0 + '@typescript-eslint/visitor-keys': 6.0.0 + dev: true + + /@typescript-eslint/type-utils@6.0.0(eslint@8.27.0)(typescript@5.1.3): + resolution: {integrity: sha512-ah6LJvLgkoZ/pyJ9GAdFkzeuMZ8goV6BH7eC9FPmojrnX9yNCIsfjB+zYcnex28YO3RFvBkV6rMV6WpIqkPvoQ==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: '*' + eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.43.0(typescript@4.8.4) - '@typescript-eslint/utils': 5.43.0(eslint@8.27.0)(typescript@4.8.4) + '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.1.3) + '@typescript-eslint/utils': 6.0.0(eslint@8.27.0)(typescript@5.1.3) debug: 4.3.4 eslint: 8.27.0 - tsutils: 3.21.0(typescript@4.8.4) - typescript: 4.8.4 + ts-api-utils: 1.0.1(typescript@5.1.3) + typescript: 5.1.3 transitivePeerDependencies: - supports-color dev: true @@ -2746,7 +2535,12 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree@5.43.0(typescript@4.8.4): + /@typescript-eslint/types@6.0.0: + resolution: {integrity: sha512-Zk9KDggyZM6tj0AJWYYKgF0yQyrcnievdhG0g5FqyU3Y2DRxJn4yWY21sJC0QKBckbsdKKjYDV2yVrrEvuTgxg==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + /@typescript-eslint/typescript-estree@5.43.0(typescript@5.1.3): resolution: {integrity: sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -2761,26 +2555,47 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.1 - tsutils: 3.21.0(typescript@4.8.4) - typescript: 4.8.4 + tsutils: 3.21.0(typescript@5.1.3) + typescript: 5.1.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.43.0(eslint@8.27.0)(typescript@4.8.4): - resolution: {integrity: sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/typescript-estree@6.0.0(typescript@5.1.3): + resolution: {integrity: sha512-2zq4O7P6YCQADfmJ5OTDQTP3ktajnXIRrYAtHM9ofto/CJZV3QfJ89GEaM2BNGeSr1KgmBuLhEkz5FBkS2RQhQ==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.0.0 + '@typescript-eslint/visitor-keys': 6.0.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.1 + ts-api-utils: 1.0.1(typescript@5.1.3) + typescript: 5.1.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@6.0.0(eslint@8.27.0)(typescript@5.1.3): + resolution: {integrity: sha512-SOr6l4NB6HE4H/ktz0JVVWNXqCJTOo/mHnvIte1ZhBQ0Cvd04x5uKZa3zT6tiodL06zf5xxdK8COiDvPnQ27JQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.27.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 5.43.0 - '@typescript-eslint/types': 5.43.0 - '@typescript-eslint/typescript-estree': 5.43.0(typescript@4.8.4) + '@typescript-eslint/scope-manager': 6.0.0 + '@typescript-eslint/types': 6.0.0 + '@typescript-eslint/typescript-estree': 6.0.0(typescript@5.1.3) eslint: 8.27.0 eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@8.27.0) semver: 7.5.1 transitivePeerDependencies: - supports-color @@ -2795,6 +2610,14 @@ packages: eslint-visitor-keys: 3.4.1 dev: true + /@typescript-eslint/visitor-keys@6.0.0: + resolution: {integrity: sha512-cvJ63l8c0yXdeT5POHpL0Q1cZoRcmRKFCtSjNGJxPkcP571EfZMcNbzWAc7oK3D1dRzm/V5EwtkANTZxqvuuUA==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.0.0 + eslint-visitor-keys: 3.4.1 + dev: true + /@webassemblyjs/ast@1.11.6: resolution: {integrity: sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==} dependencies: @@ -2909,12 +2732,12 @@ packages: resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} dev: false - /acorn-import-assertions@1.9.0(acorn@8.8.2): + /acorn-import-assertions@1.9.0(acorn@8.9.0): resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} peerDependencies: acorn: ^8 dependencies: - acorn: 8.8.2 + acorn: 8.9.0 dev: false /acorn-jsx@5.3.2(acorn@8.8.2): @@ -2930,6 +2753,12 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + /acorn@8.9.0: + resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: false + /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -2961,7 +2790,6 @@ packages: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 uri-js: 4.4.1 - dev: false /ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} @@ -2973,6 +2801,7 @@ packages: /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + dev: true /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} @@ -2984,7 +2813,6 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 - dev: false /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} @@ -3004,7 +2832,6 @@ packages: normalize-path: 3.0.0 picomatch: 2.3.1 dev: false - optional: true /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -3079,6 +2906,11 @@ packages: get-intrinsic: 1.2.1 dev: true + /arrify@1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + dev: true + /ast-types-flow@0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} dev: true @@ -3126,7 +2958,7 @@ packages: dequal: 2.0.3 dev: true - /babel-loader@8.3.0(@babel/core@7.22.5)(webpack@5.87.0): + /babel-loader@8.3.0(@babel/core@7.22.5)(webpack@5.88.0): resolution: {integrity: sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==} engines: {node: '>= 8.9'} peerDependencies: @@ -3138,7 +2970,7 @@ packages: loader-utils: 2.0.4 make-dir: 3.1.0 schema-utils: 2.7.1 - webpack: 5.87.0 + webpack: 5.88.0 dev: false /babel-plugin-macros@3.1.0: @@ -3189,6 +3021,10 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + /balanced-match@2.0.0: + resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} + dev: true + /big-integer@1.6.51: resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} engines: {node: '>=0.6'} @@ -3202,7 +3038,6 @@ packages: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} dev: false - optional: true /bplist-parser@0.2.0: resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} @@ -3240,6 +3075,17 @@ packages: update-browserslist-db: 1.0.11(browserslist@4.21.8) dev: false + /browserslist@4.21.9: + resolution: {integrity: sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001508 + electron-to-chromium: 1.4.441 + node-releases: 2.0.12 + update-browserslist-db: 1.0.11(browserslist@4.21.9) + dev: false + /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: false @@ -3273,19 +3119,27 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + /camelcase-keys@6.2.2: + resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + map-obj: 4.3.0 + quick-lru: 4.0.1 + dev: true + /camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} - dev: false - - /camelize@1.0.1: - resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} - dev: false /caniuse-lite@1.0.30001503: resolution: {integrity: sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==} dev: false + /caniuse-lite@1.0.30001508: + resolution: {integrity: sha512-sdQZOJdmt3GJs1UMNpCCCyeuS2IEGLXnHyAo9yIO5JJDjbjoVRij4M1qep6P6gFpptD1PqIYgzM+gwJbOi92mw==} + dev: false + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -3293,7 +3147,6 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: false /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -3322,13 +3175,18 @@ packages: optionalDependencies: fsevents: 2.3.2 dev: false - optional: true /chrome-trace-event@1.0.3: resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} engines: {node: '>=6.0'} dev: false + /class-variance-authority@0.6.1: + resolution: {integrity: sha512-eurOEGc7YVx3majOrOb099PNKgO3KnKSApOprXI4BTq6bcfbqbQXPN2u+rPPmIJ2di23bMwhk0SxCCthBmszEQ==} + dependencies: + clsx: 1.2.1 + dev: false + /classnames@2.3.2: resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} dev: false @@ -3338,14 +3196,14 @@ packages: engines: {node: '>=6'} dev: true - /clean-webpack-plugin@4.0.0(webpack@5.87.0): + /clean-webpack-plugin@4.0.0(webpack@5.88.0): resolution: {integrity: sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==} engines: {node: '>=10.0.0'} peerDependencies: webpack: '>=4.0.0 <6.0.0' dependencies: del: 4.1.1 - webpack: 5.87.0 + webpack: 5.88.0 dev: false /cli-cursor@3.1.0: @@ -3375,28 +3233,15 @@ packages: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} dev: false - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: false - - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 + /clsx@1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} + engines: {node: '>=6'} dev: false /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 - dev: false /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -3406,11 +3251,14 @@ packages: /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: false /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + /colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + dev: true + /colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} dev: true @@ -3431,11 +3279,6 @@ packages: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: false - /commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - dev: false - /common-tags@1.8.2: resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} engines: {node: '>=4.0.0'} @@ -3476,6 +3319,16 @@ packages: yaml: 1.10.2 dev: false + /cosmiconfig@8.2.0: + resolution: {integrity: sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==} + engines: {node: '>=14'} + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + dev: true + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -3490,18 +3343,24 @@ packages: engines: {node: '>=8'} dev: false - /css-color-keywords@1.0.0: - resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} - engines: {node: '>=4'} - dev: false + /css-functions-list@3.1.0: + resolution: {integrity: sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w==} + engines: {node: '>=12.22'} + dev: true - /css-to-react-native@3.2.0: - resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} + /css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} dependencies: - camelize: 1.0.1 - css-color-keywords: 1.0.0 - postcss-value-parser: 4.2.0 - dev: false + mdn-data: 2.0.30 + source-map-js: 1.0.2 + dev: true + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true /csstype@3.1.2: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} @@ -3543,6 +3402,19 @@ packages: dependencies: ms: 2.1.2 + /decamelize-keys@1.1.1: + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} + engines: {node: '>=0.10.0'} + dependencies: + decamelize: 1.2.0 + map-obj: 1.0.1 + dev: true + + /decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: true + /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true @@ -3648,8 +3520,13 @@ packages: resolution: {integrity: sha512-m232JTVmCawA2vG+1azVxhKZ9Sv1Q//xxNv5PkP5rWxGgQE8c3CiZFrh8Xnp+d1NmNxlu3QQrGIfdeW5TtXX5w==} dev: false + /electron-to-chromium@1.4.441: + resolution: {integrity: sha512-LlCgQ8zgYZPymf5H4aE9itwiIWH4YlCiv1HFLmmcBeFYi5E+3eaIFnjHzYtcFQbaKfAW+CqZ9pgxo33DZuoqPg==} + dev: false + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} @@ -3671,7 +3548,6 @@ packages: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 - dev: false /es-abstract@1.21.2: resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==} @@ -3746,13 +3622,12 @@ packages: /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - dev: false /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - /eslint-config-next@13.0.3(eslint@8.27.0)(typescript@4.8.4): + /eslint-config-next@13.0.3(eslint@8.27.0)(typescript@5.1.3): resolution: {integrity: sha512-i2JoQP8gGv303GjXTonA27fm1ckRRkRoAP1WYEQgN0D2DDoFeBPqlJgHlMHnXKWjmNct/sW8jQEvy9am2juc8g==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 @@ -3763,7 +3638,7 @@ packages: dependencies: '@next/eslint-plugin-next': 13.0.3 '@rushstack/eslint-patch': 1.3.2 - '@typescript-eslint/parser': 5.43.0(eslint@8.27.0)(typescript@4.8.4) + '@typescript-eslint/parser': 5.43.0(eslint@8.27.0)(typescript@5.1.3) eslint: 8.27.0 eslint-import-resolver-node: 0.3.7 eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.26.0)(eslint@8.27.0) @@ -3771,7 +3646,7 @@ packages: eslint-plugin-jsx-a11y: 6.7.1(eslint@8.27.0) eslint-plugin-react: 7.32.2(eslint@8.27.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.27.0) - typescript: 4.8.4 + typescript: 5.1.3 transitivePeerDependencies: - eslint-import-resolver-webpack - supports-color @@ -3824,7 +3699,7 @@ packages: debug: 4.3.4 enhanced-resolve: 5.15.0 eslint: 8.27.0 - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-typescript@3.5.2)(eslint@8.27.0) + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@6.0.0)(eslint-import-resolver-typescript@3.5.2)(eslint@8.27.0) get-tsconfig: 4.6.0 globby: 13.1.4 is-core-module: 2.12.1 @@ -3855,7 +3730,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.43.0(eslint@8.27.0)(typescript@4.8.4) + '@typescript-eslint/parser': 5.43.0(eslint@8.27.0)(typescript@5.1.3) debug: 3.2.7 eslint: 8.27.0 eslint-import-resolver-node: 0.3.7 @@ -3864,7 +3739,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.2)(eslint@8.27.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.0.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.2)(eslint@8.27.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -3885,7 +3760,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.43.0(eslint@8.27.0)(typescript@4.8.4) + '@typescript-eslint/parser': 6.0.0(eslint@8.27.0)(typescript@5.1.3) debug: 3.2.7 eslint: 8.27.0 eslint-import-resolver-node: 0.3.7 @@ -3904,7 +3779,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.43.0(eslint@8.27.0)(typescript@4.8.4) + '@typescript-eslint/parser': 5.43.0(eslint@8.27.0)(typescript@5.1.3) array-includes: 3.1.6 array.prototype.flat: 1.3.1 debug: 2.6.9 @@ -3925,7 +3800,7 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-typescript@3.5.2)(eslint@8.27.0): + /eslint-plugin-import@2.26.0(@typescript-eslint/parser@6.0.0)(eslint-import-resolver-typescript@3.5.2)(eslint@8.27.0): resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: @@ -3935,14 +3810,14 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.43.0(eslint@8.27.0)(typescript@4.8.4) + '@typescript-eslint/parser': 6.0.0(eslint@8.27.0)(typescript@5.1.3) array-includes: 3.1.6 array.prototype.flat: 1.3.1 debug: 2.6.9 doctrine: 2.1.0 eslint: 8.27.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.2)(eslint@8.27.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.0.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.2)(eslint@8.27.0) has: 1.0.3 is-core-module: 2.12.1 is-glob: 4.0.3 @@ -3981,21 +3856,25 @@ packages: semver: 6.3.0 dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.5.0)(eslint@8.27.0)(prettier@2.7.1): - resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} - engines: {node: '>=12.0.0'} + /eslint-plugin-prettier@5.0.0(eslint-config-prettier@8.5.0)(eslint@8.27.0)(prettier@3.0.0): + resolution: {integrity: sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - eslint: '>=7.28.0' + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' eslint-config-prettier: '*' - prettier: '>=2.0.0' + prettier: '>=3.0.0' peerDependenciesMeta: + '@types/eslint': + optional: true eslint-config-prettier: optional: true dependencies: eslint: 8.27.0 eslint-config-prettier: 8.5.0(eslint@8.27.0) - prettier: 2.7.1 + prettier: 3.0.0 prettier-linter-helpers: 1.0.0 + synckit: 0.8.5 dev: true /eslint-plugin-react-hooks@4.6.0(eslint@8.27.0): @@ -4215,18 +4094,16 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + dev: true + /fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: reusify: 1.0.4 - /faye-websocket@0.11.4: - resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} - engines: {node: '>=0.8.0'} - dependencies: - websocket-driver: 0.7.4 - dev: false - /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -4265,7 +4142,6 @@ packages: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 - dev: false /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} @@ -4275,39 +4151,6 @@ packages: path-exists: 4.0.0 dev: true - /firebase@9.22.0: - resolution: {integrity: sha512-Ay1u8IOfhPh58RFAHF7A9cKHACCgV6uI2bhkzKdkjnV0n2AAxn4tDtdXvJ3BEbfhF4WWBC2dFcEXH8cd14ptaw==} - dependencies: - '@firebase/analytics': 0.10.0(@firebase/app@0.9.10) - '@firebase/analytics-compat': 0.2.6(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10) - '@firebase/app': 0.9.10 - '@firebase/app-check': 0.7.0(@firebase/app@0.9.10) - '@firebase/app-check-compat': 0.3.6(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10) - '@firebase/app-compat': 0.2.10 - '@firebase/app-types': 0.9.0 - '@firebase/auth': 0.23.2(@firebase/app@0.9.10) - '@firebase/auth-compat': 0.4.2(@firebase/app-compat@0.2.10)(@firebase/app-types@0.9.0)(@firebase/app@0.9.10) - '@firebase/database': 0.14.4 - '@firebase/database-compat': 0.3.4 - '@firebase/firestore': 3.12.0(@firebase/app@0.9.10) - '@firebase/firestore-compat': 0.3.9(@firebase/app-compat@0.2.10)(@firebase/app-types@0.9.0)(@firebase/app@0.9.10) - '@firebase/functions': 0.9.4(@firebase/app@0.9.10) - '@firebase/functions-compat': 0.3.4(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10) - '@firebase/installations': 0.6.4(@firebase/app@0.9.10) - '@firebase/installations-compat': 0.2.4(@firebase/app-compat@0.2.10)(@firebase/app-types@0.9.0)(@firebase/app@0.9.10) - '@firebase/messaging': 0.12.4(@firebase/app@0.9.10) - '@firebase/messaging-compat': 0.2.4(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10) - '@firebase/performance': 0.6.4(@firebase/app@0.9.10) - '@firebase/performance-compat': 0.2.4(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10) - '@firebase/remote-config': 0.4.4(@firebase/app@0.9.10) - '@firebase/remote-config-compat': 0.2.4(@firebase/app-compat@0.2.10)(@firebase/app@0.9.10) - '@firebase/storage': 0.11.2(@firebase/app@0.9.10) - '@firebase/storage-compat': 0.3.2(@firebase/app-compat@0.2.10)(@firebase/app-types@0.9.0)(@firebase/app@0.9.10) - '@firebase/util': 1.9.3 - transitivePeerDependencies: - - encoding - dev: false - /flat-cache@3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -4354,10 +4197,6 @@ packages: universalify: 2.0.0 dev: false - /fs-readdir-recursive@1.1.0: - resolution: {integrity: sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==} - dev: false - /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -4393,11 +4232,6 @@ packages: engines: {node: '>=6.9.0'} dev: false - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: false - /get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} dependencies: @@ -4466,6 +4300,22 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 + /global-modules@2.0.0: + resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} + engines: {node: '>=6'} + dependencies: + global-prefix: 3.0.0 + dev: true + + /global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + dev: true + /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -4517,6 +4367,10 @@ packages: pinkie-promise: 2.0.1 dev: false + /globjoin@0.1.4: + resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} + dev: true + /goober@2.1.13(csstype@3.1.2): resolution: {integrity: sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==} peerDependencies: @@ -4537,6 +4391,10 @@ packages: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} dev: true + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + /hamburger-react@2.5.0(react@18.2.0): resolution: {integrity: sha512-5GSXe+ucxTPJ0SkhIsPQ/PRDweZPIKya1lfahAuExx31SdheeUA4uOPfQIAirbKona8hvo79VDr5LJQzPXsdpw==} peerDependencies: @@ -4545,13 +4403,17 @@ packages: react: 18.2.0 dev: false + /hard-rejection@2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} + dev: true + /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} - dev: false /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -4586,11 +4448,24 @@ packages: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} dependencies: react-is: 16.13.1 - - /http-parser-js@0.5.8: - resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==} dev: false + /hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: true + + /hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + dependencies: + lru-cache: 6.0.0 + dev: true + + /html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + dev: true + /human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -4607,10 +4482,6 @@ packages: hasBin: true dev: true - /idb@7.0.1: - resolution: {integrity: sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==} - dev: false - /idb@7.1.1: resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} dev: false @@ -4619,6 +4490,10 @@ packages: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} + /immutable@4.3.0: + resolution: {integrity: sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==} + dev: false + /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -4626,6 +4501,11 @@ packages: parent-module: 1.0.1 resolve-from: 4.0.0 + /import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + dev: true + /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -4645,6 +4525,10 @@ packages: /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: true + /internal-slot@1.0.5: resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} engines: {node: '>= 0.4'} @@ -4662,7 +4546,6 @@ packages: /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: false /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} @@ -4675,7 +4558,6 @@ packages: dependencies: binary-extensions: 2.2.0 dev: false - optional: true /is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} @@ -4718,6 +4600,7 @@ packages: /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + dev: true /is-fullwidth-code-point@4.0.0: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} @@ -4785,6 +4668,16 @@ packages: engines: {node: '>=8'} dev: true + /is-plain-obj@1.1.0: + resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} + engines: {node: '>=0.10.0'} + dev: true + + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -4910,14 +4803,12 @@ packages: /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: false /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: false /json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -4961,6 +4852,15 @@ packages: object.assign: 4.1.4 dev: true + /kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + dev: true + + /known-css-properties@0.27.0: + resolution: {integrity: sha512-uMCj6+hZYDoffuvAJjFAPz56E9uoowFHmTkqRtRq5WyC5Q6Cu/fTZKNQpX/RbzChBYLLl3lo8CjFZBAZXq9qFg==} + dev: true + /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} dev: true @@ -4991,7 +4891,6 @@ packages: /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: false /lint-staged@13.2.2: resolution: {integrity: sha512-71gSwXKy649VrSU09s10uAT0rWCcY3aewhMaHyl2N84oBk4Xs9HgxvUp3AYu+bNsK4NrOYYxvSgg7FyGJ+jGcA==} @@ -5054,7 +4953,6 @@ packages: engines: {node: '>=8'} dependencies: p-locate: 4.1.0 - dev: false /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} @@ -5063,10 +4961,6 @@ packages: p-locate: 5.0.0 dev: true - /lodash.camelcase@4.3.0: - resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - dev: false - /lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} dev: false @@ -5079,6 +4973,10 @@ packages: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} dev: false + /lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + dev: true + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: false @@ -5093,14 +4991,6 @@ packages: wrap-ansi: 6.2.0 dev: true - /long@4.0.0: - resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - dev: false - - /long@5.2.3: - resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} - dev: false - /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -5126,14 +5016,6 @@ packages: sourcemap-codec: 1.4.8 dev: false - /make-dir@2.1.0: - resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} - engines: {node: '>=6'} - dependencies: - pify: 4.0.1 - semver: 5.7.1 - dev: false - /make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -5141,10 +5023,46 @@ packages: semver: 6.3.0 dev: false + /map-obj@1.0.1: + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} + dev: true + + /map-obj@4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + dev: true + + /mathml-tag-names@2.1.3: + resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} + dev: true + + /mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + dev: true + /memoize-one@6.0.0: resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} dev: false + /meow@9.0.0: + resolution: {integrity: sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==} + engines: {node: '>=10'} + dependencies: + '@types/minimist': 1.2.2 + camelcase-keys: 6.2.2 + decamelize: 1.2.0 + decamelize-keys: 1.1.1 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 3.0.3 + read-pkg-up: 7.0.1 + redent: 3.0.0 + trim-newlines: 3.0.1 + type-fest: 0.18.1 + yargs-parser: 20.2.9 + dev: true + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -5181,6 +5099,11 @@ packages: engines: {node: '>=12'} dev: true + /min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + dev: true + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -5193,6 +5116,15 @@ packages: brace-expansion: 2.0.1 dev: false + /minimist-options@4.1.0: + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} + dependencies: + arrify: 1.0.1 + is-plain-obj: 1.1.0 + kind-of: 6.0.3 + dev: true + /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -5211,7 +5143,6 @@ packages: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: false /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} @@ -5237,22 +5168,22 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - next: 13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0) + next: 13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0)(sass@1.63.4) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /next-pwa@5.6.0(@babel/core@7.22.5)(next@13.4.3)(webpack@5.87.0): + /next-pwa@5.6.0(@babel/core@7.22.5)(next@13.4.3)(webpack@5.88.0): resolution: {integrity: sha512-XV8g8C6B7UmViXU8askMEYhWwQ4qc/XqJGnexbLV68hzKaGHZDMtHsm2TNxFcbR7+ypVuth/wwpiIlMwpRJJ5A==} peerDependencies: next: '>=9.0.0' dependencies: - babel-loader: 8.3.0(@babel/core@7.22.5)(webpack@5.87.0) - clean-webpack-plugin: 4.0.0(webpack@5.87.0) + babel-loader: 8.3.0(@babel/core@7.22.5)(webpack@5.88.0) + clean-webpack-plugin: 4.0.0(webpack@5.88.0) globby: 11.1.0 - next: 13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0) - terser-webpack-plugin: 5.3.9(webpack@5.87.0) - workbox-webpack-plugin: 6.6.0(webpack@5.87.0) + next: 13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0)(sass@1.63.4) + terser-webpack-plugin: 5.3.9(webpack@5.88.0) + workbox-webpack-plugin: 6.6.0(webpack@5.88.0) workbox-window: 6.6.0 transitivePeerDependencies: - '@babel/core' @@ -5264,7 +5195,7 @@ packages: - webpack dev: false - /next-sitemap@4.1.3(@next/env@13.4.5)(next@13.4.3): + /next-sitemap@4.1.3(@next/env@13.4.7)(next@13.4.3): resolution: {integrity: sha512-eCvbXMCqbD/rYx912y4FzGOqPCbWOIBL4UkgVY5R15eCXygKFKWzEVZGPNVBDu2KVpRCeG943NibOchfyQGDhQ==} engines: {node: '>=14.18'} hasBin: true @@ -5273,13 +5204,13 @@ packages: next: '*' dependencies: '@corex/deepmerge': 4.0.43 - '@next/env': 13.4.5 + '@next/env': 13.4.7 fast-glob: 3.2.12 minimist: 1.2.8 - next: 13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0) + next: 13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0)(sass@1.63.4) dev: false - /next@13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0): + /next@13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0)(sass@1.63.4): resolution: {integrity: sha512-FV3pBrAAnAIfOclTvncw9dDohyeuEEXPe5KNcva91anT/rdycWbgtu3IjUj4n5yHnWK8YEPo0vrUecHmnmUNbA==} engines: {node: '>=16.8.0'} hasBin: true @@ -5307,6 +5238,7 @@ packages: postcss: 8.4.14 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + sass: 1.63.4 styled-jsx: 5.1.1(@babel/core@7.22.5)(react@18.2.0) zod: 3.21.4 optionalDependencies: @@ -5331,28 +5263,35 @@ packages: react: '>= 16.0.0' dependencies: '@types/nprogress': 0.2.0 - next: 13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0) + next: 13.4.3(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0)(sass@1.63.4) nprogress: 0.2.0 prop-types: 15.8.1 react: 18.2.0 dev: false - /node-fetch@2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: false - /node-releases@2.0.12: resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==} dev: false + /normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.2 + semver: 5.7.1 + validate-npm-package-license: 3.0.4 + dev: true + + /normalize-package-data@3.0.3: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + dependencies: + hosted-git-info: 4.1.0 + is-core-module: 2.12.1 + semver: 7.5.1 + validate-npm-package-license: 3.0.4 + dev: true + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -5475,7 +5414,6 @@ packages: engines: {node: '>=6'} dependencies: p-try: 2.2.0 - dev: false /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} @@ -5489,7 +5427,6 @@ packages: engines: {node: '>=8'} dependencies: p-limit: 2.3.0 - dev: false /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} @@ -5513,7 +5450,6 @@ packages: /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - dev: false /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} @@ -5529,7 +5465,6 @@ packages: error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - dev: false /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} @@ -5608,9 +5543,43 @@ packages: hasBin: true dev: true + /postcss-media-query-parser@0.2.3: + resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==} + dev: true + + /postcss-resolve-nested-selector@0.1.1: + resolution: {integrity: sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==} + dev: true + + /postcss-safe-parser@6.0.0(postcss@8.4.24): + resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.3.3 + dependencies: + postcss: 8.4.24 + dev: true + + /postcss-scss@4.0.6(postcss@8.4.24): + resolution: {integrity: sha512-rLDPhJY4z/i4nVFZ27j9GqLxj1pwxE80eAzUNRMXtcpipFYIeowerzBgG3yJhMtObGEXidtIgbUpQ3eLDsf5OQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.19 + dependencies: + postcss: 8.4.24 + dev: true + + /postcss-selector-parser@6.0.13: + resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - dev: false + dev: true /postcss@8.4.14: resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} @@ -5628,7 +5597,7 @@ packages: nanoid: 3.3.6 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: false + dev: true /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -5642,9 +5611,9 @@ packages: fast-diff: 1.3.0 dev: true - /prettier@2.7.1: - resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==} - engines: {node: '>=10.13.0'} + /prettier@3.0.0: + resolution: {integrity: sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==} + engines: {node: '>=14'} hasBin: true dev: true @@ -5664,45 +5633,6 @@ packages: resolution: {integrity: sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==} dev: false - /protobufjs@6.11.3: - resolution: {integrity: sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==} - hasBin: true - requiresBuild: true - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/base64': 1.1.2 - '@protobufjs/codegen': 2.0.4 - '@protobufjs/eventemitter': 1.1.0 - '@protobufjs/fetch': 1.1.0 - '@protobufjs/float': 1.0.2 - '@protobufjs/inquire': 1.1.0 - '@protobufjs/path': 1.1.2 - '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.0 - '@types/long': 4.0.2 - '@types/node': 20.3.1 - long: 4.0.0 - dev: false - - /protobufjs@7.2.3: - resolution: {integrity: sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==} - engines: {node: '>=12.0.0'} - requiresBuild: true - dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/base64': 1.1.2 - '@protobufjs/codegen': 2.0.4 - '@protobufjs/eventemitter': 1.1.0 - '@protobufjs/fetch': 1.1.0 - '@protobufjs/float': 1.0.2 - '@protobufjs/inquire': 1.1.0 - '@protobufjs/path': 1.1.2 - '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.0 - '@types/node': 20.3.1 - long: 5.2.3 - dev: false - /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: false @@ -5714,6 +5644,11 @@ packages: /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + /quick-lru@4.0.1: + resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} + engines: {node: '>=8'} + dev: true + /randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: @@ -5864,13 +5799,39 @@ packages: loose-envify: 1.4.0 dev: false + /read-pkg-up@7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + dev: true + + /read-pkg@5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + dependencies: + '@types/normalize-package-data': 2.4.1 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + dev: true + /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 dev: false - optional: true + + /redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + dev: true /regenerate-unicode-properties@10.1.0: resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} @@ -5928,20 +5889,19 @@ packages: resolution: {integrity: sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==} dev: false - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: false - /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - dev: false /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + /resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} dev: true @@ -6043,6 +6003,16 @@ packages: get-intrinsic: 1.2.1 is-regex: 1.1.4 + /sass@1.63.4: + resolution: {integrity: sha512-Sx/+weUmK+oiIlI+9sdD0wZHsqpbgQg8wSwSnGBjwb5GwqFhYNwwnI+UWZtLjKvKyFlKkatRK235qQ3mokyPoQ==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + immutable: 4.3.0 + source-map-js: 1.0.2 + dev: false + /scheduler@0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: @@ -6070,7 +6040,7 @@ packages: /semver@5.7.1: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} hasBin: true - dev: false + dev: true /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} @@ -6096,10 +6066,6 @@ packages: randombytes: 2.1.0 dev: false - /shallowequal@1.1.0: - resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} - dev: false - /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -6123,10 +6089,10 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true - /slash@2.0.0: - resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==} - engines: {node: '>=6'} - dev: false + /signal-exit@4.0.2: + resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} + engines: {node: '>=14'} + dev: true /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} @@ -6170,7 +6136,6 @@ packages: /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - dev: false /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -6201,6 +6166,28 @@ packages: deprecated: Please use @jridgewell/sourcemap-codec instead dev: false + /spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.13 + dev: true + + /spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: true + + /spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.13 + dev: true + + /spdx-license-ids@3.0.13: + resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} + dev: true + /streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -6218,6 +6205,7 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + dev: true /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} @@ -6276,6 +6264,7 @@ packages: engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 + dev: true /strip-ansi@7.1.0: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} @@ -6304,43 +6293,21 @@ packages: engines: {node: '>=12'} dev: true + /strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + dependencies: + min-indent: 1.0.1 + dev: true + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} dev: true - /styled-components@6.0.0-rc.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-5FbCTxynopck99GRwM5Ey0+VRp8pkQq69TwGOJJeYtR7gPvwGjNx8yBPLN7/dfxwwvn9ymOZYB19eQkv2k70wQ==} - engines: {node: '>= 16'} - peerDependencies: - babel-plugin-styled-components: '>= 2' - react: '>= 16.8.0' - react-dom: '>= 16.8.0' - peerDependenciesMeta: - babel-plugin-styled-components: - optional: true - dependencies: - '@babel/cli': 7.22.5(@babel/core@7.22.5) - '@babel/core': 7.22.5 - '@babel/helper-module-imports': 7.22.5 - '@babel/plugin-external-helpers': 7.22.5(@babel/core@7.22.5) - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.22.5) - '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.22.5) - '@babel/preset-env': 7.22.5(@babel/core@7.22.5) - '@babel/preset-react': 7.22.5(@babel/core@7.22.5) - '@babel/preset-typescript': 7.22.5(@babel/core@7.22.5) - '@babel/traverse': 7.22.5 - '@emotion/unitless': 0.8.1 - css-to-react-native: 3.2.0 - postcss: 8.4.24 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - shallowequal: 1.1.0 - stylis: 4.2.0 - tslib: 2.5.3 - transitivePeerDependencies: - - supports-color - dev: false + /style-search@0.1.0: + resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==} + dev: true /styled-jsx@5.1.1(@babel/core@7.22.5)(react@18.2.0): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} @@ -6360,6 +6327,126 @@ packages: react: 18.2.0 dev: false + /stylelint-config-prettier-scss@1.0.0(stylelint@15.9.0): + resolution: {integrity: sha512-Gr2qLiyvJGKeDk0E/+awNTrZB/UtNVPLqCDOr07na/sLekZwm26Br6yYIeBYz3ulsEcQgs5j+2IIMXCC+wsaQA==} + engines: {node: 14.* || 16.* || >= 18} + hasBin: true + peerDependencies: + stylelint: '>=15.0.0' + dependencies: + stylelint: 15.9.0 + dev: true + + /stylelint-config-recommended-scss@12.0.0(postcss@8.4.24)(stylelint@15.9.0): + resolution: {integrity: sha512-5Bb2mlGy6WLa30oNeKpZvavv2lowJUsUJO25+OA68GFTemlwd1zbFsL7q0bReKipOSU3sG47hKneZ6Nd+ctrFA==} + peerDependencies: + postcss: ^8.3.3 + stylelint: ^15.5.0 + peerDependenciesMeta: + postcss: + optional: true + dependencies: + postcss: 8.4.24 + postcss-scss: 4.0.6(postcss@8.4.24) + stylelint: 15.9.0 + stylelint-config-recommended: 12.0.0(stylelint@15.9.0) + stylelint-scss: 5.0.1(stylelint@15.9.0) + dev: true + + /stylelint-config-recommended@12.0.0(stylelint@15.9.0): + resolution: {integrity: sha512-x6x8QNARrGO2sG6iURkzqL+Dp+4bJorPMMRNPScdvaUK8PsynriOcMW7AFDKqkWAS5wbue/u8fUT/4ynzcmqdQ==} + peerDependencies: + stylelint: ^15.5.0 + dependencies: + stylelint: 15.9.0 + dev: true + + /stylelint-config-standard-scss@10.0.0(postcss@8.4.24)(stylelint@15.9.0): + resolution: {integrity: sha512-bChBEo1p3xUVWh/wenJI+josoMk21f2yuLDGzGjmKYcALfl2u3DFltY+n4UHswYiXghqXaA8mRh+bFy/q1hQlg==} + peerDependencies: + postcss: ^8.3.3 + stylelint: ^15.5.0 + peerDependenciesMeta: + postcss: + optional: true + dependencies: + postcss: 8.4.24 + stylelint: 15.9.0 + stylelint-config-recommended-scss: 12.0.0(postcss@8.4.24)(stylelint@15.9.0) + stylelint-config-standard: 33.0.0(stylelint@15.9.0) + dev: true + + /stylelint-config-standard@33.0.0(stylelint@15.9.0): + resolution: {integrity: sha512-eyxnLWoXImUn77+ODIuW9qXBDNM+ALN68L3wT1lN2oNspZ7D9NVGlNHb2QCUn4xDug6VZLsh0tF8NyoYzkgTzg==} + peerDependencies: + stylelint: ^15.5.0 + dependencies: + stylelint: 15.9.0 + stylelint-config-recommended: 12.0.0(stylelint@15.9.0) + dev: true + + /stylelint-scss@5.0.1(stylelint@15.9.0): + resolution: {integrity: sha512-n87iCRZrr2J7//I/QFsDXxFLnHKw633U4qvWZ+mOW6KDAp/HLj06H+6+f9zOuTYy+MdGdTuCSDROCpQIhw5fvQ==} + peerDependencies: + stylelint: ^14.5.1 || ^15.0.0 + dependencies: + postcss-media-query-parser: 0.2.3 + postcss-resolve-nested-selector: 0.1.1 + postcss-selector-parser: 6.0.13 + postcss-value-parser: 4.2.0 + stylelint: 15.9.0 + dev: true + + /stylelint@15.9.0: + resolution: {integrity: sha512-sXtAZi64CllWr6A+8ymDWnlIaYwuAa7XRmGnJxLQXFNnLjd3Izm4HAD+loKVaZ7cpK6SLxhAUX1lwPJKGCn0mg==} + engines: {node: ^14.13.1 || >=16.0.0} + hasBin: true + dependencies: + '@csstools/css-parser-algorithms': 2.2.0(@csstools/css-tokenizer@2.1.1) + '@csstools/css-tokenizer': 2.1.1 + '@csstools/media-query-list-parser': 2.1.1(@csstools/css-parser-algorithms@2.2.0)(@csstools/css-tokenizer@2.1.1) + '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.0.13) + balanced-match: 2.0.0 + colord: 2.9.3 + cosmiconfig: 8.2.0 + css-functions-list: 3.1.0 + css-tree: 2.3.1 + debug: 4.3.4 + fast-glob: 3.2.12 + fastest-levenshtein: 1.0.16 + file-entry-cache: 6.0.1 + global-modules: 2.0.0 + globby: 11.1.0 + globjoin: 0.1.4 + html-tags: 3.3.1 + ignore: 5.2.4 + import-lazy: 4.0.0 + imurmurhash: 0.1.4 + is-plain-object: 5.0.0 + known-css-properties: 0.27.0 + mathml-tag-names: 2.1.3 + meow: 9.0.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.24 + postcss-media-query-parser: 0.2.3 + postcss-resolve-nested-selector: 0.1.1 + postcss-safe-parser: 6.0.0(postcss@8.4.24) + postcss-selector-parser: 6.0.13 + postcss-value-parser: 4.2.0 + resolve-from: 5.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + style-search: 0.1.0 + supports-hyperlinks: 3.0.0 + svg-tags: 1.0.0 + table: 6.8.1 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + dev: true + /stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} dev: false @@ -6376,7 +6463,6 @@ packages: engines: {node: '>=4'} dependencies: has-flag: 3.0.0 - dev: false /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -6391,10 +6477,22 @@ packages: has-flag: 4.0.0 dev: false + /supports-hyperlinks@3.0.0: + resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} + engines: {node: '>=14.18'} + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + dev: true + /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + /svg-tags@1.0.0: + resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + dev: true + /synckit@0.8.5: resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==} engines: {node: ^14.18.0 || >=16.0.0} @@ -6403,6 +6501,17 @@ packages: tslib: 2.5.3 dev: true + /table@6.8.1: + resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} + engines: {node: '>=10.0.0'} + dependencies: + ajv: 8.12.0 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} @@ -6422,7 +6531,7 @@ packages: unique-string: 2.0.0 dev: false - /terser-webpack-plugin@5.3.9(webpack@5.87.0): + /terser-webpack-plugin@5.3.9(webpack@5.88.0): resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==} engines: {node: '>= 10.13.0'} peerDependencies: @@ -6443,7 +6552,7 @@ packages: schema-utils: 3.3.0 serialize-javascript: 6.0.1 terser: 5.18.0 - webpack: 5.87.0 + webpack: 5.88.0 dev: false /terser@5.18.0: @@ -6489,16 +6598,26 @@ packages: resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} dev: false - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: false - /tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} dependencies: punycode: 2.3.0 dev: false + /trim-newlines@3.0.1: + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} + dev: true + + /ts-api-utils@1.0.1(typescript@5.1.3): + resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==} + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.1.3 + dev: true + /tsconfig-paths@3.14.2: resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} dependencies: @@ -6515,14 +6634,14 @@ packages: /tslib@2.5.3: resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==} - /tsutils@3.21.0(typescript@4.8.4): + /tsutils@3.21.0(typescript@5.1.3): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.8.4 + typescript: 5.1.3 dev: true /type-check@0.4.0: @@ -6537,6 +6656,11 @@ packages: engines: {node: '>=10'} dev: false + /type-fest@0.18.1: + resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} + engines: {node: '>=10'} + dev: true + /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} @@ -6547,6 +6671,16 @@ packages: engines: {node: '>=10'} dev: true + /type-fest@0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + dev: true + + /type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + dev: true + /type-fest@2.19.0: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} @@ -6559,9 +6693,9 @@ packages: for-each: 0.3.3 is-typed-array: 1.1.10 - /typescript@4.8.4: - resolution: {integrity: sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==} - engines: {node: '>=4.2.0'} + /typescript@5.1.3: + resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==} + engines: {node: '>=14.17'} hasBin: true dev: true @@ -6629,6 +6763,17 @@ packages: picocolors: 1.0.0 dev: false + /update-browserslist-db@1.0.11(browserslist@4.21.9): + resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.9 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: false + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: @@ -6655,6 +6800,17 @@ packages: react: 18.2.0 dev: false + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + dev: true + /warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} dependencies: @@ -6669,10 +6825,6 @@ packages: graceful-fs: 4.2.11 dev: false - /webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: false - /webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} dev: false @@ -6689,8 +6841,8 @@ packages: engines: {node: '>=10.13.0'} dev: false - /webpack@5.87.0: - resolution: {integrity: sha512-GOu1tNbQ7p1bDEoFRs2YPcfyGs8xq52yyPBZ3m2VGnXGtV9MxjrkABHm4V9Ia280OefsSLzvbVoXcfLxjKY/Iw==} + /webpack@5.88.0: + resolution: {integrity: sha512-O3jDhG5e44qIBSi/P6KpcCcH7HD+nYIHVBhdWFxcLOcIGN8zGo5nqF3BjyNCxIh4p1vFdNnreZv2h2KkoAw3lw==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -6704,9 +6856,9 @@ packages: '@webassemblyjs/ast': 1.11.6 '@webassemblyjs/wasm-edit': 1.11.6 '@webassemblyjs/wasm-parser': 1.11.6 - acorn: 8.8.2 - acorn-import-assertions: 1.9.0(acorn@8.8.2) - browserslist: 4.21.8 + acorn: 8.9.0 + acorn-import-assertions: 1.9.0(acorn@8.9.0) + browserslist: 4.21.9 chrome-trace-event: 1.0.3 enhanced-resolve: 5.15.0 es-module-lexer: 1.3.0 @@ -6720,7 +6872,7 @@ packages: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.9(webpack@5.87.0) + terser-webpack-plugin: 5.3.9(webpack@5.88.0) watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -6729,27 +6881,6 @@ packages: - uglify-js dev: false - /websocket-driver@0.7.4: - resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} - engines: {node: '>=0.8.0'} - dependencies: - http-parser-js: 0.5.8 - safe-buffer: 5.2.1 - websocket-extensions: 0.1.4 - dev: false - - /websocket-extensions@0.1.4: - resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} - engines: {node: '>=0.8.0'} - dev: false - - /whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - dev: false - /whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} dependencies: @@ -6778,6 +6909,13 @@ packages: has-tostringtag: 1.0.0 is-typed-array: 1.1.10 + /which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -6931,7 +7069,7 @@ packages: resolution: {integrity: sha512-R2IkwDokbtHUE4Kus8pKO5+VkPHD2oqTgl+XJwh4zbF1HyjAbgNmK/FneZHVU7p03XUt9ICfuGDYISWG9qV/CQ==} dev: false - /workbox-webpack-plugin@6.6.0(webpack@5.87.0): + /workbox-webpack-plugin@6.6.0(webpack@5.88.0): resolution: {integrity: sha512-xNZIZHalboZU66Wa7x1YkjIqEy1gTR+zPM+kjrYJzqN7iurYZBctBLISyScjhkJKYuRrZUP0iqViZTh8rS0+3A==} engines: {node: '>=10.0.0'} peerDependencies: @@ -6940,7 +7078,7 @@ packages: fast-json-stable-stringify: 2.1.0 pretty-bytes: 5.6.0 upath: 1.2.0 - webpack: 5.87.0 + webpack: 5.88.0 webpack-sources: 1.4.3 workbox-build: 6.6.0 transitivePeerDependencies: @@ -6971,14 +7109,18 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 + dev: true /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: false + /write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.0.2 + dev: true /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -7001,38 +7143,7 @@ packages: /yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} - dev: false - - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: false - - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - dependencies: - cliui: 7.0.4 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - dev: false - - /yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - dependencies: - cliui: 8.0.1 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - dev: false + dev: true /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} diff --git a/src/components/Button/Button.module.scss b/src/components/Button/Button.module.scss new file mode 100644 index 00000000..7abdf27d --- /dev/null +++ b/src/components/Button/Button.module.scss @@ -0,0 +1,63 @@ +@use '@/styles/abstracts' as *; + +.base { + display: flex; + align-items: center; + justify-content: center; + padding: 1rem 1.5rem; + font-size: 1.5rem; + font-weight: 600; + border-radius: 5px; + cursor: pointer; +} + +.back { + width: fit-content; + gap: 1rem; + background: none; + @include themed { + color: t('text'); + border: 1px solid t('text'); + } + + &:hover { + @include themed { + background: t('text'); + color: t('bg'); + border: 1px solid t('bg'); + } + } +} + +.primary { + border: 1px solid transparent; + @include themed { + background-color: t('text'); + color: t('bg'); + } + + &:hover { + background: transparent; + + @include themed { + border-color: t('text'); + color: t('text'); + } + } + + @include md { + font-size: 3rem; + } +} + +.secondary { + @include themed { + background-color: t('bg'); + border: 1px solid t('text'); + color: t('text'); + } + + @include md { + font-size: 3rem; + } +} diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx new file mode 100644 index 00000000..d1d4b99b --- /dev/null +++ b/src/components/Button/Button.tsx @@ -0,0 +1,33 @@ +import { type ButtonHTMLAttributes, forwardRef } from 'react'; + +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import styles from './Button.module.scss'; + +const button = cva(styles.base, { + variants: { + intent: { + back: styles.back, + primary: styles.primary, + secondary: styles.secondary, + }, + }, +}); + +interface ButtonProps + extends ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +export const Button = forwardRef( + ({ className, intent, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : `button`; + return ( + + ); + }, +); + +Button.displayName = `Button`; diff --git a/src/components/Button/index.ts b/src/components/Button/index.ts new file mode 100644 index 00000000..8b166a86 --- /dev/null +++ b/src/components/Button/index.ts @@ -0,0 +1 @@ +export * from './Button'; diff --git a/src/components/Input/Input.tsx b/src/components/Input/Input.tsx new file mode 100644 index 00000000..6615d4ea --- /dev/null +++ b/src/components/Input/Input.tsx @@ -0,0 +1,11 @@ +import { type InputHTMLAttributes, forwardRef } from 'react'; + +type InputProps = InputHTMLAttributes; + +export const Input = forwardRef( + ({ className, type, ...props }, ref) => { + return ; + }, +); + +Input.displayName = `Input`; diff --git a/src/components/Input/index.ts b/src/components/Input/index.ts new file mode 100644 index 00000000..ba9fe7eb --- /dev/null +++ b/src/components/Input/index.ts @@ -0,0 +1 @@ +export * from './Input'; diff --git a/src/components/common/ui/Loader/StyledLoader.tsx b/src/components/Loader/Loader.module.scss similarity index 62% rename from src/components/common/ui/Loader/StyledLoader.tsx rename to src/components/Loader/Loader.module.scss index fd9cb49b..19dc11e2 100644 --- a/src/components/common/ui/Loader/StyledLoader.tsx +++ b/src/components/Loader/Loader.module.scss @@ -1,7 +1,6 @@ -import { Wiggle } from '@/components/common/styles/Animations'; -import styled from 'styled-components'; +@use '@/styles/abstracts' as *; -export const LoadingImg = styled.div` +%loading { position: relative; width: 100%; height: 100vh; @@ -14,14 +13,20 @@ export const LoadingImg = styled.div` margin-top: -96px; margin-left: -96px; transform: translateX(-50%); - animation: ${Wiggle} 2s infinite; text-align: center; font-size: 1.7rem; font-weight: 700; + @include animation('wiggle, 2s, infinite'); } -`; +} + +.loading { + @extend %loading; +} + +.smallLoading { + @extend %loading; -export const SmallLoadingImg = styled(LoadingImg)` margin: 3rem 0; height: 48px; @@ -29,4 +34,4 @@ export const SmallLoadingImg = styled(LoadingImg)` margin-top: -24px; margin-left: -24px; } -`; +} diff --git a/src/components/Loader/Loader.tsx b/src/components/Loader/Loader.tsx new file mode 100644 index 00000000..3d230bf8 --- /dev/null +++ b/src/components/Loader/Loader.tsx @@ -0,0 +1,19 @@ +import Image from 'next/image'; + +import styles from './Loader.module.scss'; + +export function Loader() { + return ( +
+ +
+ ); +} + +export function SmallLoader() { + return ( +
+ +
+ ); +} diff --git a/src/components/Loader/index.ts b/src/components/Loader/index.ts new file mode 100644 index 00000000..d5ce9811 --- /dev/null +++ b/src/components/Loader/index.ts @@ -0,0 +1 @@ +export * from './Loader'; diff --git a/src/components/Nav/GenNav.tsx b/src/components/Nav/GenNav.tsx new file mode 100644 index 00000000..ef90016e --- /dev/null +++ b/src/components/Nav/GenNav.tsx @@ -0,0 +1,42 @@ +import { type Dispatch, type SetStateAction } from 'react'; + +import * as NavigationMenu from '@radix-ui/react-navigation-menu'; + +import { genNav, removeDash } from '@/utils'; + +type Props = { + setGame: Dispatch>; + setVersion: Dispatch>; +}; + +export function GenNav({ setGame, setVersion }: Props) { + return ( + + + {genNav.map((g) => ( + + + {g.gen} + + + {g.details.map((gd) => ( + + ))} + + + ))} + +
+ +
+
+ ); +} diff --git a/src/components/Nav/index.ts b/src/components/Nav/index.ts new file mode 100644 index 00000000..24887f82 --- /dev/null +++ b/src/components/Nav/index.ts @@ -0,0 +1 @@ +export * from './GenNav'; diff --git a/src/components/Separator/Separator.module.scss b/src/components/Separator/Separator.module.scss new file mode 100644 index 00000000..de8ad00a --- /dev/null +++ b/src/components/Separator/Separator.module.scss @@ -0,0 +1,11 @@ +@use '@/styles/abstracts' as *; + +.separator { + width: 90%; + height: 1px; + margin: 5rem auto; + border: 0; + @include themed { + background-color: t('text'); + } +} diff --git a/src/components/Separator/Separator.tsx b/src/components/Separator/Separator.tsx new file mode 100644 index 00000000..7708f4fe --- /dev/null +++ b/src/components/Separator/Separator.tsx @@ -0,0 +1,7 @@ +import * as RadixSeparator from '@radix-ui/react-separator'; + +import styles from './Separator.module.scss'; + +export function Separator() { + return ; +} diff --git a/src/components/Separator/index.ts b/src/components/Separator/index.ts new file mode 100644 index 00000000..6e974799 --- /dev/null +++ b/src/components/Separator/index.ts @@ -0,0 +1 @@ +export * from './Separator'; diff --git a/src/components/Toast/Toast.tsx b/src/components/Toast/Toast.tsx new file mode 100644 index 00000000..aa41287d --- /dev/null +++ b/src/components/Toast/Toast.tsx @@ -0,0 +1,36 @@ +import { toast } from 'react-hot-toast'; + +type Props = { + error?: Error | null; + text?: string; +}; + +export const ErrorToast = ({ error }: Props) => { + return ( + <> + {toast.error( + error + ? `Something went wrong: ${error.message}` + : `Something went wrong`, + { + style: { + fontSize: `1.7rem`, + }, + }, + )} + + ); +}; + +export const SuccessToast = ({ text }: Props) => { + const toastText = text ?? `Done`; + return ( + <> + {toast.success(toastText, { + style: { + fontSize: `1.7rem`, + }, + })} + + ); +}; diff --git a/src/components/Toast/index.ts b/src/components/Toast/index.ts new file mode 100644 index 00000000..1b794ee7 --- /dev/null +++ b/src/components/Toast/index.ts @@ -0,0 +1 @@ +export * from './Toast'; diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx new file mode 100644 index 00000000..e2a7fe49 --- /dev/null +++ b/src/components/Tooltip/Tooltip.tsx @@ -0,0 +1,13 @@ +import { Tooltip as ReactTooltip } from 'react-tooltip'; + +type Props = { + id: string; +}; + +export const Tooltip = ({ id }: Props) => { + return ( + <> + + + ); +}; diff --git a/src/components/Tooltip/index.ts b/src/components/Tooltip/index.ts new file mode 100644 index 00000000..7594a8f0 --- /dev/null +++ b/src/components/Tooltip/index.ts @@ -0,0 +1 @@ +export * from './Tooltip'; diff --git a/src/components/common/styles/Animations.tsx b/src/components/common/styles/Animations.tsx deleted file mode 100644 index 0e4bf14c..00000000 --- a/src/components/common/styles/Animations.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { keyframes } from 'styled-components'; - -export const Pulse = keyframes` - 0% { transform: scale(1.01); } - 50% { transform: scale(0.99); } - 100% { transform: scale(1.01); } -`; - -export const Wiggle = keyframes` - 0% {transform: rotate(0deg);} - 80% {transform: rotate(0deg);} - 85% {transform: rotate(5deg);} - 95% {transform: rotate(-5deg);} - 100% {transform: rotate(0deg);} -`; - -export const fadeInUpVariant = { - hidden: { - y: 60, - opacity: 0, - }, - show: { - y: 0, - opacity: 1, - transition: { - type: `spring`, - mass: 1, - damping: 15, - stiffness: 200, - }, - }, - exit: { - y: 0, - opacity: 0, - }, - hover: { - zIndex: 1, - scale: [1, 1.05, 1.02], - rotate: [0, 1, -1, 0], - transition: { - duration: 0.2, - }, - }, - tap: { scale: 0.99 }, -}; - -export const placeholderVariant = { - initial: { - opacity: 1, - scale: 1, - }, - animate: { - opacity: 1, - scale: 1, - }, - exit: { - opacity: 0, - scale: 0, - transition: { - duration: 0.2, - ease: `easeInOut`, - }, - }, -}; diff --git a/src/components/common/styles/Headings.tsx b/src/components/common/styles/Headings.tsx deleted file mode 100644 index b213af8e..00000000 --- a/src/components/common/styles/Headings.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import styled from 'styled-components'; -import { device } from './Sizing'; -import { Tooltip } from 'react-tooltip'; - -export const H1 = styled.h1` - padding: 0 1rem; - font-size: 10rem; - letter-spacing: 3px; - cursor: pointer; - color: ${({ theme }) => theme.main}; - text-shadow: ${({ theme }) => theme.secondary} -1px -1px 0px, - ${({ theme }) => theme.secondary} 1px -1px 0px, - ${({ theme }) => theme.secondary} -1px 1px 0px, - ${({ theme }) => theme.secondary} 1px 1px 0px; - - @media ${device.lg} { - font-size: 9rem; - } - - @media ${device.md} { - font-size: 8.5rem; - } - - @media ${device.sm} { - font-size: 7.5rem; - } - - @media ${device.xs} { - font-size: 7rem; - } - - & a { - display: inline-block; - height: 100%; - width: 100%; - cursor: pointer; - } -`; - -export const Title = styled.h2` - margin-bottom: 1.5rem; - font-size: 6rem; - color: #c4c4c4; - text-transform: capitalize; - text-align: center; - color: ${({ theme }) => theme.main}; - text-shadow: ${({ theme }) => theme.secondary} -1px -1px 0px, - ${({ theme }) => theme.secondary} 1px -1px 0px, - ${({ theme }) => theme.secondary} -1px 1px 0px, - ${({ theme }) => theme.secondary} 1px 1px 0px; -`; - -export const CardTitle = styled(Title)` - margin-bottom: 0.5rem; -`; - -export const CardTitleWithImage = styled.div` - display: flex; - align-items: center; - justify-content: center; - gap: 2rem; - - & img { - @media ${device.sm} { - width: 48px; - height: 48px; - } - } -`; - -export const Subtitle = styled.h4` - font-size: 2rem; - text-transform: uppercase; - letter-spacing: 0.1rem; - text-align: center; -`; - -export const LeftSubtitle = styled(Subtitle)` - text-align: left; -`; - -export const H2 = styled.h2` - margin-bottom: 1rem; - font-size: 4.5rem; - text-transform: capitalize; - text-align: center; -`; - -export const LeftH2 = styled(H2)` - text-align: left; -`; - -export const H3 = styled.h3` - margin-bottom: 1.5rem; - font-size: 3.5rem; - text-transform: capitalize; - - &:first-letter { - background: ${({ theme }) => theme.red}; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - } -`; - -export const H4 = styled.h4` - margin-bottom: 1rem; - font-size: 2.5rem; - text-transform: capitalize; -`; - -export const Capitalize = styled.span` - text-transform: capitalize; -`; - -export const Bold = styled.span` - font-weight: 600; -`; - -export const Small = styled.small` - font-size: 1.5rem; - font-weight: 400; - text-transform: lowercase; -`; - -export const StyledTooltip = styled(Tooltip)` - font-size: 1.3rem !important; -`; diff --git a/src/components/common/styles/Navbars.tsx b/src/components/common/styles/Navbars.tsx deleted file mode 100644 index 04aeaef6..00000000 --- a/src/components/common/styles/Navbars.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import styled from 'styled-components'; -import { device } from './Sizing'; - -export const GenNav = styled.nav` - position: relative; - padding: 5rem 0; - z-index: 5; - - & ul { - display: flex; - align-items: center; - justify-content: space-around; - - & li { - margin: 0 0.5rem; - display: inline-block; - position: relative; - - & button { - background: none; - border: none; - font-size: 2rem; - color: ${({ theme }) => theme.secondary}; - - @media ${device.sm} { - font-size: 1.7rem; - } - } - - & div { - display: none; - position: absolute; - white-space: nowrap; - background: #c4c4c4; - border-radius: 5px; - -webkit-box-shadow: 2px 2px 15px 2px #161616; - box-shadow: 2px 2px 15px 2px #161616; - - & button { - display: block; - background: none; - font-size: 1.5rem; - border: none; - margin: 1rem; - text-align: left; - color: #161616; - text-transform: capitalize; - cursor: pointer; - &:hover { - color: ${({ theme }) => theme.red}; - } - - @media ${device.sm} { - white-space: break-spaces; - } - } - } - - &:hover { - & div { - display: block; - } - } - - &:first-of-type { - margin-left: 0; - } - - &:last-of-type { - margin-right: 0; - } - } - } -`; - -export const MethodNav = styled.nav` - padding-bottom: 2.5rem; - display: flex; - align-items: center; - justify-content: space-around; - flex-wrap: wrap; - gap: 1rem; - - & button { - position: relative; - background: none; - border: 1px solid transparent; - color: ${({ theme }) => theme.secondary}; - font-size: 1.7rem; - font-weight: 600; - transition: 0.3s ease-in-out; - - &::before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1; - border-radius: 5px; - transition: 0.3s ease-in-out; - } - - &:hover::before { - opacity: 0; - transform: scale(0.5, 0.5); - } - - &::after { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1; - opacity: 0; - transition: 0.3s ease-in-out; - background: ${({ theme }) => theme.secondary}; - border: 1px solid ${({ theme }) => theme.secondary}; - border-radius: 5px; - transform: scale(1.2, 1.2); - } - - &:hover::after { - opacity: 1; - transform: scale(1, 1); - } - - & p { - position: relative; - text-transform: capitalize; - padding: 1rem 1.5rem; - z-index: 2; - cursor: pointer; - transition: 0.3s ease-in-out; - &:hover { - color: ${({ theme }) => theme.main}; - } - } - } - - .button_active { - position: relative; - font-size: 1.7rem; - font-weight: 600; - border: 1px solid transparent; - border-radius: 5px; - background: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.main}; - transition: 0.3s ease-in-out; - - &::before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1; - border-radius: 5px; - transition: 0.3s ease-in-out; - } - - &:hover::before { - opacity: 0; - transform: scale(0.5, 0.5); - } - - &::after { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1; - opacity: 0; - transition: 0.3s ease-in-out; - background: ${({ theme }) => theme.main}; - border: 1px solid ${({ theme }) => theme.secondary}; - border-radius: 5px; - transform: scale(1.2, 1.2); - } - - &:hover::after { - opacity: 1; - transform: scale(1, 1); - } - - & p { - position: relative; - padding: 1rem 1.5rem; - width: 100%; - height: 100%; - z-index: 3; - color: ${({ theme }) => theme.main}; - cursor: pointer; - transition: 0.3s ease-in-out; - &:hover { - color: ${({ theme }) => theme.secondary}; - } - } - } -`; diff --git a/src/components/common/styles/Reset.tsx b/src/components/common/styles/Reset.tsx deleted file mode 100644 index 0c1a5e4f..00000000 --- a/src/components/common/styles/Reset.tsx +++ /dev/null @@ -1,147 +0,0 @@ -// @ts-nocheck - -import { createGlobalStyle } from 'styled-components'; -import { device } from './Sizing'; - -export const Reset = createGlobalStyle` - - *, - *::before, - *::after { - margin: 0; - padding: 0; - box-sizing: border-box; - scroll-behavior: smooth; - } - - html, body, div, span, applet, object, iframe, - h1, h2, h3, h4, h5, h6, p, blockquote, pre, - a, abbr, acronym, address, big, cite, code, - del, dfn, em, img, ins, kbd, q, s, samp, - small, strike, strong, sub, sup, tt, var, - b, u, center, - dl, dt, dd, ul, ul, li, - fieldset, form, label, legend, - table, caption, tbody, tfoot, thead, tr, th, td, - article, aside, canvas, details, embed, - figure, figcaption, footer, header, hgroup, - menu, nav, output, ruby, section, summary, - time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font: inherit; - vertical-align: baseline; - cursor: default; - } - - a { - text-decoration: none; - color: inherit; - } - - button { - cursor: pointer; - } - - article, aside, details, figcaption, figure, - footer, header, hgroup, menu, nav, section { - display: block; - } - - ul, ul { - list-style: none; - } - - blockquote, q { - quotes: none; - } - - blockquote:before, blockquote:after, - q:before, q:after { - content: ''; - content: none; - } - - table { - border-collapse: collapse; - border-spacing: 0; - } - - html { - font-size: 10px; - line-height: 1.5; - } - - body { - color: ${({ theme }) => theme.secondary}; - background-color: ${({ theme }) => theme.main}; - background-image: ${({ theme }) => theme.background}; - font-family: 'Quicksand', serif; - font-weight: 400; - - & #nprogress { - & .bar { - background: hsla(29, 92%, 70%, 1); - background: linear-gradient( - 0deg, - hsla(29, 92%, 70%, 1) 0%, - hsla(0, 87%, 73%, 1) 100% - ); - background: -moz-linear-gradient( - 0deg, - hsla(29, 92%, 70%, 1) 0%, - hsla(0, 87%, 73%, 1) 100% - ); - background: -webkit-linear-gradient( - 0deg, - hsla(29, 92%, 70%, 1) 0%, - hsla(0, 87%, 73%, 1) 100% - ); - } - - & .spinner-icon { - display: none; - } - } - } - - h1, h2, h3, h4, h5, h6, nav { - font-family: 'Oswald', sans-serif; - } - - @media ${device.md} { - html { - font-size: 9px; - } - } - - @media ${device.sm} { - html { - font-size: 8px; - } - } - - @media ${device.xs} { - html { - font-size: 7px; - } - } - - .ReactModal__Overlay { - width: 100vw; - height: 100vh; - background-color: ${({ theme }) => theme.secondary} !important; - z-index: 1000; - opacity: 0; - transition: opacity 0.5s ease-in-out; - - &--after-open { - opacity: 1; - } - - &--before-close { - opacity: 0; - } - } -`; diff --git a/src/components/common/styles/Sizing.tsx b/src/components/common/styles/Sizing.tsx deleted file mode 100644 index 132536d0..00000000 --- a/src/components/common/styles/Sizing.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import styled from 'styled-components'; - -const size = { - xs: `440px`, - sm: `650px`, - md: `890px`, - lg: `1150px`, - xl: `1700px`, -}; - -export const device = { - xs: `(max-width: ${size.xs})`, - sm: `(max-width: ${size.sm})`, - md: `(max-width: ${size.md})`, - lg: `(max-width: ${size.lg})`, - xl: `(max-width: ${size.xl})`, -}; - -export const MainSmall = styled.main` - min-height: 100vh; - max-width: 1300px; - margin: 0 auto; - padding: 5rem; - - @media ${device.sm} { - padding: 3rem 0 5rem; - } -`; - -export const MainBig = styled.main` - min-height: 100vh; - position: relative; - max-width: 1700px; - margin: 0 auto; - padding: 5rem; - - @media ${device.sm} { - padding: 3rem; - } -`; - -export const MainForm = styled(MainBig)` - position: absolute; - top: 0; - left: 0; - height: 100vh; - width: 100vw; - display: flex; - align-items: center; - justify-content: center; - padding: 0; - z-index: 100; -`; - -export const Section = styled.section` - margin-bottom: 5rem; -`; diff --git a/src/components/common/styles/Themes.tsx b/src/components/common/styles/Themes.tsx deleted file mode 100644 index 6cdda7da..00000000 --- a/src/components/common/styles/Themes.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import styled from 'styled-components'; - -export type Theme = { - main: string; - secondary: string; - red: string; - purple: string; - background: string; -}; - -export const darkTheme: Theme = { - main: `#161616`, - secondary: `#c4c4c4`, - red: `#cc0000`, - purple: `#5e318f`, - background: `url("https://www.transparenttextures.com/patterns/asfalt-dark.png")`, -}; - -export const lightTheme: Theme = { - main: `#c4c4c4`, - secondary: `#161616`, - red: `#cc0000`, - purple: `#5e318f`, - background: `url("https://www.transparenttextures.com/patterns/asfalt-light.png")`, -}; - -export const Type = styled.div` - &#normal { - background-color: #969592; - } - - &#fire { - background-color: #db4249; - } - - &#water { - background-color: #55b8e2; - } - - &#grass { - background-color: #459f4d; - } - - &#electric { - background-color: #dbb508; - } - - &#ice { - background-color: #6db5ba; - } - - &#fighting { - background-color: #d77a49; - } - - &#poison { - background-color: #82549a; - } - - &#ground { - background-color: #9a5e41; - } - - &#flying { - background-color: #5983ef; - } - - &#psychic { - background-color: #e76e9a; - } - - &#bug { - background-color: #9eb559; - } - - &#rock { - background-color: #a28d79; - } - - &#ghost { - background-color: #a2729a; - } - - &#dark { - background-color: #555461; - } - - &#dragon { - background-color: #1085a2; - } - - &#steel { - background-color: #7d879a; - } - - &#fairy { - background-color: #ef9bb6; - } -`; diff --git a/src/components/common/ui/BackBtn.tsx b/src/components/common/ui/BackBtn.tsx deleted file mode 100644 index 88e9bc82..00000000 --- a/src/components/common/ui/BackBtn.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { FaChevronLeft } from '@meronex/icons/fa'; -import styled from 'styled-components'; - -type Props = { - name: string; -}; - -const BackButton = styled.span` - display: flex; - align-items: center; - width: fit-content; - padding: 1rem 1.5rem; - font-size: 1.5rem; - font-weight: 600; - background: none; - color: ${({ theme }) => theme.secondary}; - border: 1px solid ${({ theme }) => theme.secondary}; - border-radius: 5px; - transition: 0.3s ease-in-out; - cursor: pointer; - - &:hover { - background: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.main}; - border: 1px solid ${({ theme }) => theme.main}; - } -`; - -function BackBtn({ name }: Props) { - return ( - - Back to {name} - - ); -} - -export default BackBtn; diff --git a/src/components/common/ui/Divider.tsx b/src/components/common/ui/Divider.tsx deleted file mode 100644 index 0bfd0b0a..00000000 --- a/src/components/common/ui/Divider.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import styled from 'styled-components'; - -export const Divider = styled.hr` - width: 90%; - height: 1px; - margin: 5rem auto; - background-image: linear-gradient( - 0deg, - hsla(29, 92%, 70%, 1) 0%, - hsla(0, 87%, 73%, 1) 100% - ); - border: 0; -`; diff --git a/src/components/common/ui/GenNav.tsx b/src/components/common/ui/GenNav.tsx deleted file mode 100644 index 402f7778..00000000 --- a/src/components/common/ui/GenNav.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { GenNav } from '@/components/common/styles/Navbars'; -import { genNav } from '@/utils/DataArrays'; -import { removeDash } from '@/utils/Typography'; -import { Dispatch, SetStateAction } from 'react'; - -type Props = { - setGame: Dispatch>; - setVersion: Dispatch>; -}; - -function Nav({ setGame, setVersion }: Props) { - return ( - -
    - {genNav.map((g) => ( -
  • - -
    - {g.details.map((gd) => ( - - ))} -
    -
  • - ))} -
-
- ); -} - -export default Nav; diff --git a/src/components/common/ui/Loader/Loader.tsx b/src/components/common/ui/Loader/Loader.tsx deleted file mode 100644 index 19bd9d4d..00000000 --- a/src/components/common/ui/Loader/Loader.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import Image from 'next/image'; -import { LoadingImg } from './StyledLoader'; - -function Loader() { - return ( - - - - ); -} - -export default Loader; diff --git a/src/components/common/ui/Loader/SmallLoader.tsx b/src/components/common/ui/Loader/SmallLoader.tsx deleted file mode 100644 index 7340cbc1..00000000 --- a/src/components/common/ui/Loader/SmallLoader.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import Image from 'next/image'; -import { SmallLoadingImg } from './StyledLoader'; - -function SmallLoader() { - return ( - - - - ); -} - -export default SmallLoader; diff --git a/src/components/common/ui/ToolTip.tsx b/src/components/common/ui/ToolTip.tsx deleted file mode 100644 index ed989e90..00000000 --- a/src/components/common/ui/ToolTip.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { StyledTooltip } from '../styles/Headings'; - -type Props = { - id: string; -}; - -const ToolTip = ({ id }: Props) => { - return ( - <> - - - ); -}; - -export default ToolTip; diff --git a/src/components/index.ts b/src/components/index.ts new file mode 100644 index 00000000..9c9ea3eb --- /dev/null +++ b/src/components/index.ts @@ -0,0 +1,7 @@ +export * from './Button'; +export * from './Input'; +export * from './Loader'; +export * from './Nav'; +export * from './Separator'; +export * from './Toast'; +export * from './Tooltip'; diff --git a/src/components/layout/Footer/Footer.tsx b/src/components/layout/Footer/Footer.tsx deleted file mode 100644 index 5d874a58..00000000 --- a/src/components/layout/Footer/Footer.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { FaGithub } from '@meronex/icons/fa'; -import { - CenterFooter, - FooterContainer, - FooterInner, - LeftFooter, - RightFooter, -} from './Styled.Footer'; - -function Footer() { - const year = new Date().getFullYear(); - - return ( - - - © {year} PokéRef - PokéRef - - - - - - - - ); -} - -export default Footer; diff --git a/src/components/layout/Footer/Styled.Footer.tsx b/src/components/layout/Footer/Styled.Footer.tsx deleted file mode 100644 index a9e03bda..00000000 --- a/src/components/layout/Footer/Styled.Footer.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import styled from 'styled-components'; - -export const FooterContainer = styled.footer` - display: flex; - align-items: center; - background: hsla(29, 92%, 70%, 1); - background: linear-gradient( - 0deg, - hsla(29, 92%, 70%, 1) 0%, - hsla(0, 87%, 73%, 1) 100% - ); - background: -moz-linear-gradient( - 0deg, - hsla(29, 92%, 70%, 1) 0%, - hsla(0, 87%, 73%, 1) 100% - ); - background: -webkit-linear-gradient( - 0deg, - hsla(29, 92%, 70%, 1) 0%, - hsla(0, 87%, 73%, 1) 100% - ); -`; - -export const FooterInner = styled.div` - width: 90%; - margin: 0 auto; - display: grid; - grid-template-columns: 30% 40% 30%; - align-items: center; - color: #161616; -`; - -export const LeftFooter = styled.div` - justify-self: left; - font-size: 1.3rem; -`; - -export const CenterFooter = styled.div` - justify-self: center; - font-size: 4rem; - letter-spacing: 1px; - font-family: 'Oswald'; - color: ${({ theme }) => theme.secondary}; - text-shadow: ${({ theme }) => theme.main} -1px -1px 0px, - ${({ theme }) => theme.main} 1px -1px 0px, - ${({ theme }) => theme.main} -1px 1px 0px, - ${({ theme }) => theme.main} 1px 1px 0px; - text-align: center; -`; - -export const RightFooter = styled.div` - justify-self: right; - height: 4rem; - width: 4rem; - - & a { - display: block; - width: 100%; - height: 100%; - cursor: pointer; - - & svg { - width: 100%; - height: 100%; - } - } -`; diff --git a/src/components/layout/Header/Header.tsx b/src/components/layout/Header/Header.tsx deleted file mode 100644 index ff7cb1b4..00000000 --- a/src/components/layout/Header/Header.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { H1 } from '@/components/common/styles/Headings'; -import { - BurgerClose, - BurgerOpen, - HeaderBtnConnect, - HeaderBtnConnected, - HeaderBtnContainer, - HeaderBtnTheme, - HeaderContainer, -} from '@/components/layout/Header/Styled.Header'; -import { auth } from '@/firebase-config'; -import { FiMenu, FiX } from '@meronex/icons/fi'; -import { RiMoonClearLine, RiSunLine } from '@meronex/icons/ri'; -import { onAuthStateChanged, signOut, User } from 'firebase/auth'; -import Link from 'next/link'; -import { Dispatch, SetStateAction, useEffect, useState } from 'react'; - -type Props = { - navOpen: boolean; - setNavOpen: Dispatch>; - themeToggler: () => void; - theme: string; -}; - -function Header({ navOpen, setNavOpen, themeToggler, theme }: Props) { - const [user, setUser] = useState(); - // const usersCollectionRef = collection(db, `users`); - - const logout = async () => { - await signOut(auth); - }; - - useEffect(() => { - onAuthStateChanged(auth, (currentUser) => { - return setUser(currentUser); - }); - }, []); - - return ( - -

- PokéRef -

- - - {theme === `dark` ? ( - - ) : ( - - )} - - {user ? ( - - - Profile - - ) : ( - - Login - Register - - )} - {navOpen ? ( - setNavOpen(!navOpen)} - > - - - ) : ( - setNavOpen(!navOpen)} - > - - - )} - -
- ); -} - -export default Header; diff --git a/src/components/layout/Header/Styled.Header.tsx b/src/components/layout/Header/Styled.Header.tsx deleted file mode 100644 index eeb519a2..00000000 --- a/src/components/layout/Header/Styled.Header.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import styled from 'styled-components'; -import { device } from '../../common/styles/Sizing'; - -export const HeaderBtnConnect = styled.div` - display: grid; - grid-template-columns: 1fr 1fr; - gap: 1rem; - margin: 0 auto; - & a { - display: flex; - align-items: center; - justify-content: center; - padding: 0.7rem 1.5rem; - background: ${({ theme }) => theme.secondary}; - border: 1px solid transparent; - border-radius: 5px; - color: ${({ theme }) => theme.main}; - font-size: 1.5rem; - font-weight: 600; - cursor: pointer; - transition: 0.3s ease-in-out; - - @media ${device.md} { - font-size: 3rem; - } - - &:first-of-type { - background: transparent; - border-color: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.secondary}; - } - - &:hover { - background: transparent; - border-color: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.secondary}; - } - } - - @media ${device.md} { - width: 80%; - justify-content: space-evenly; - } -`; - -export const HeaderBtnConnected = styled.div` - display: grid; - grid-template-columns: 1fr 1fr; - gap: 1rem; - margin: 0 auto; - & a, - button { - display: flex; - align-items: center; - justify-content: center; - padding: 0.7rem 1.5rem; - background: ${({ theme }) => theme.secondary}; - border: 1px solid transparent; - border-radius: 5px; - color: ${({ theme }) => theme.main}; - font-size: 1.5rem; - font-weight: 600; - cursor: pointer; - transition: 0.3s ease-in-out; - - &:hover { - background: transparent; - border-color: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.secondary}; - } - - @media ${device.md} { - font-size: 3rem; - } - } - - & :first-child { - background: transparent; - border-color: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.secondary}; - } - - @media ${device.md} { - width: 80%; - justify-content: space-evenly; - } -`; - -export const HeaderContainer = styled.header` - width: 90%; - margin: 2rem auto; - display: flex; - align-items: center; - justify-content: space-between; - - @media ${device.sm} { - width: 95%; - } - - & ${HeaderBtnConnect}, ${HeaderBtnConnected} { - @media ${device.md} { - display: none; - } - } -`; - -export const HeaderBtnContainer = styled.div` - display: flex; - align-items: center; - gap: 3rem; -`; - -export const HeaderBtnTheme = styled.button` - width: 48px; - height: 48px; - background: none; - border: none; - color: ${({ theme }) => theme.secondary}; - font-size: 48px; -`; - -export const BurgerOpen = styled.button` - display: none; - align-items: center; - justify-content: center; - position: fixed; - top: 5vh; - right: 5vw; - z-index: 99; - padding: 1rem; - border: 1px solid transparent; - border-radius: 50px; - background-color: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.main}; - font-size: 48px; - transition: 0.3s ease-in-out; - - &:hover { - border: 1px solid ${({ theme }) => theme.secondary}; - background-color: ${({ theme }) => theme.main}; - color: ${({ theme }) => theme.secondary}; - } - - @media ${device.md} { - display: flex; - } -`; - -export const BurgerClose = styled.button` - display: none; - font-size: 48px; - background: transparent; - border: none; - color: ${({ theme }) => theme.secondary}; - - @media ${device.md} { - display: flex; - } -`; diff --git a/src/components/pages/404/Styled.NotFound.tsx b/src/components/pages/404/Styled.NotFound.tsx deleted file mode 100644 index 0ead8c98..00000000 --- a/src/components/pages/404/Styled.NotFound.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import styled from 'styled-components'; -import { MainBig } from '../../common/styles/Sizing'; - -export const NotFoundMain = styled(MainBig)` - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; -`; - -export const NotFoundImg = styled.img` - width: 10%; - height: 10%; -`; - -export const NotFoundText = styled.p` - font-size: 2rem; - font-weight: 600; - &:first-of-type { - padding-top: 3rem; - } -`; diff --git a/src/components/pages/Abilities/AbilityCard/Components/Desc.AbilityCard.tsx b/src/components/pages/Abilities/AbilityCard/Components/Desc.AbilityCard.tsx deleted file mode 100644 index 216ab8df..00000000 --- a/src/components/pages/Abilities/AbilityCard/Components/Desc.AbilityCard.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { H3 } from '@/components/common/styles/Headings'; -import { IAbilityFlavorText } from '@/types/Pokemon/Ability'; -import { removeDash } from '@/utils/Typography'; -import { AbilityCardSection, AbilityCardTable } from '../Styled.AbilityCard'; - -type Props = { - filterDesc?: IAbilityFlavorText[]; -}; - -function DescAbilityCard({ filterDesc }: Props) { - return ( - -

Game descriptions

- - - {filterDesc?.map((fd) => ( - - {removeDash(fd?.version_group.name)} - {fd?.flavor_text} - - ))} - - -
- ); -} - -export default DescAbilityCard; diff --git a/src/components/pages/Abilities/AbilityCard/Styled.AbilityCard.tsx b/src/components/pages/Abilities/AbilityCard/Styled.AbilityCard.tsx deleted file mode 100644 index 4410b93a..00000000 --- a/src/components/pages/Abilities/AbilityCard/Styled.AbilityCard.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import styled from 'styled-components'; -import { Table } from '../../../common/styles/Table'; - -export const AbilityCardSection = styled.section` - margin: 5rem 0; -`; - -export const AbilityCardEffect = styled.div` - margin: 0 0 3rem; - - & p { - font-size: 1.7rem; - } -`; - -export const AbilityCardTable = styled(Table)` - width: 100%; - & th { - background: rgba(130, 130, 130, 0.2); - font-size: 1.5rem; - font-weight: 600; - text-transform: capitalize; - } - - & td { - text-align: left; - } -`; - -export const Sup = styled.sup` - vertical-align: super; - font-size: smaller; -`; diff --git a/src/components/pages/Auth/ResetPwd.tsx b/src/components/pages/Auth/ResetPwd.tsx deleted file mode 100644 index cb4a29f3..00000000 --- a/src/components/pages/Auth/ResetPwd.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { H2 } from '@/components/common/styles/Headings'; -import { auth } from '@/firebase-config'; -import { capitalize } from '@/utils/Typography'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { FiX } from '@meronex/icons/fi'; -import { sendPasswordResetEmail } from 'firebase/auth'; -import React, { Dispatch, SetStateAction } from 'react'; -import { useForm } from 'react-hook-form'; -import toast from 'react-hot-toast'; -import { - AuthModal, - AuthResetClose, - AuthResetForm, - AuthResetInput, - AuthBtn, -} from './Styled.Auth'; -import * as yup from 'yup'; - -type Props = { - modalIsOpen: boolean; - setIsOpen: Dispatch>; -}; - -type FormInput = { - resetEmail: string; -}; - -const schema = yup - .object({ - resetEmail: yup.string().email().required(), - }) - .required(); - -function ResetPwd({ modalIsOpen, setIsOpen }: Props) { - const { - register, - handleSubmit, - formState: { errors }, - } = useForm({ - resolver: yupResolver(schema), - }); - - const closeModal = () => { - setIsOpen(false); - }; - - const resetPwdForm = async (data: FormInput) => { - try { - await sendPasswordResetEmail(auth, data.resetEmail); - toast.success(`Check your mails ✉`, { - style: { - fontSize: `1.7rem`, - }, - }); - } catch (error) { - if (error instanceof Error) { - toast.error(error.message, { - style: { - fontSize: `1.7rem`, - }, - }); - } - } - }; - - return ( - - - - -

Reset your password

- - -
- - {typeof errors.resetEmail?.message === `string` && ( - {capitalize(errors.resetEmail?.message)} - )} -
-
- Reset -
-
- ); -} - -export default ResetPwd; diff --git a/src/components/pages/Items/Hooks/useToggleTable.tsx b/src/components/pages/Items/Hooks/useToggleTable.tsx deleted file mode 100644 index 7f1af0ba..00000000 --- a/src/components/pages/Items/Hooks/useToggleTable.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { getBerries, getItems } from '@/utils/DataFetch'; -import dynamic from 'next/dynamic'; -import { useState } from 'react'; -import { useQueries } from '@tanstack/react-query'; - -const ItemsTable = dynamic( - () => import(`@/components/pages/Items/Components/ItemsTable.Items`), -); -const BerriesTable = dynamic( - () => import(`@/components/pages/Items/Components/BerriesTable.Items`), -); - -export const useToggleTable = () => { - const [items, berries] = useQueries({ - queries: [ - { - queryKey: [`items`], - queryFn: getItems, - }, - { - queryKey: [`berries`], - queryFn: getBerries, - }, - ], - }); - - const [toggle, setToggle] = useState(1); - const pageShown = () => { - if (toggle === 1) { - return ; - } else if (toggle === 2) { - return ; - } - }; - - return { items, berries, toggle, setToggle, pageShown }; -}; diff --git a/src/components/pages/Items/ItemCard/Components/Cost.ItemCard.tsx b/src/components/pages/Items/ItemCard/Components/Cost.ItemCard.tsx deleted file mode 100644 index a0a490be..00000000 --- a/src/components/pages/Items/ItemCard/Components/Cost.ItemCard.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { IItem } from '@/types/Items/Item'; -import { ItemCardDataCost } from '../Styled.ItemCard'; - -type Props = { - item?: IItem; -}; - -function CostItemCard({ item }: Props) { - return ( - <> - {item?.cost !== 0 && ( - - Cost : {item?.cost} Pokédollars - - )} - - ); -} - -export default CostItemCard; diff --git a/src/components/pages/Items/ItemCard/Components/Desc.Itemcard.tsx b/src/components/pages/Items/ItemCard/Components/Desc.Itemcard.tsx deleted file mode 100644 index 2334f8b7..00000000 --- a/src/components/pages/Items/ItemCard/Components/Desc.Itemcard.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { IItem } from '@/types/Items/Item'; -import { removeDash } from '@/utils/Typography'; -import { - ItemCardDescSection, - ItemCardDescTable, - ItemCardDescTitle, -} from '../Styled.ItemCard'; - -type Props = { - item?: IItem; -}; - -function DescItemcard({ item }: Props) { - return ( - - Game descriptions - - - {item?.flavor_text_entries?.map((ift) => - ift.language.name === `en` ? ( - - {removeDash(ift.version_group.name)} - {ift.text} - - ) : ( - `` - ), - )} - - - - ); -} - -export default DescItemcard; diff --git a/src/components/pages/Items/ItemCard/Styled.ItemCard.tsx b/src/components/pages/Items/ItemCard/Styled.ItemCard.tsx deleted file mode 100644 index 6ff0fb72..00000000 --- a/src/components/pages/Items/ItemCard/Styled.ItemCard.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import styled from 'styled-components'; -import { Table } from '../../../common/styles/Table'; - -export const ItemCardDataSection = styled.section` - margin: 5rem 0; - display: grid; - grid-template-columns: 75% 25%; -`; - -export const ItemCardDataEffect = styled.div` - margin: 0 0 3rem; - - & h3 { - margin: 0 0 1rem; - font-size: 3rem; - font-weight: 600; - } - - & p { - font-size: 1.7rem; - } -`; - -export const ItemCardDataCost = styled.p` - margin: 0 0 1rem; - font-size: 1.7rem; - - & span { - font-weight: 600; - } -`; - -export const ItemCardDataHeld = styled.p` - margin: 0 0 1rem; - font-size: 1.7rem; - - & span { - font-weight: 600; - } - - & a { - display: inline-block; - padding: 0 0.5rem; - text-transform: capitalize; - } -`; - -export const ItemCardDataFling = styled.p` - font-size: 1.7rem; -`; - -export const ItemCardDataImage = styled.div` - display: flex; - align-items: center; - justify-content: center; -`; - -export const ItemCardDescSection = styled.section` - margin: 5rem 0; -`; - -export const ItemCardDescTitle = styled.h3` - margin: 0 0 2rem; - font-size: 3rem; - font-weight: 600; - text-transform: capitalize; -`; -export const ItemCardDescTable = styled(Table)` - & th { - background: rgba(130, 130, 130, 0.2); - font-size: 1.5rem; - font-weight: 600; - text-transform: capitalize; - } - - & td { - text-align: center; - } -`; diff --git a/src/components/pages/Locations/Components/List.Locations.tsx b/src/components/pages/Locations/Components/List.Locations.tsx deleted file mode 100644 index 360ac2ad..00000000 --- a/src/components/pages/Locations/Components/List.Locations.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { IRegion } from '@/types/Locations/Region'; -import { removeDash } from '@/utils/Typography'; -import Link from 'next/link'; -import { LocationList, LocationSection } from '../Styled.Locations'; - -type Props = { - location: string | null; - locations?: IRegion[]; -}; - -function ListLocations({ location, locations }: Props) { - return ( - - {locations?.map( - (l) => - l.name === location && ( - - {l.locations - .sort((a, b) => a.name.localeCompare(b.name)) - ?.map((ll) => ( -
  • - - {removeDash(ll.name).replace( - /kanto|johto|hoenn|sinnoh|unova|kalos|alola|galar|hisui|paldea/g, - ``, - )} - -
  • - ))} -
    - ), - )} -
    - ); -} - -export default ListLocations; diff --git a/src/components/pages/Moves/Components/MovesTable.Moves.tsx b/src/components/pages/Moves/Components/MovesTable.Moves.tsx deleted file mode 100644 index dc309542..00000000 --- a/src/components/pages/Moves/Components/MovesTable.Moves.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { LeftH2 } from '@/components/common/styles/Headings'; -import { - FullWidthTable, - TableContainer, - TBold, - TCategory, - TEffect, - TLink, - TType, -} from '@/components/common/styles/Table'; -import { Type } from '@/components/common/styles/Themes'; -import { usePaginatedTableParams } from '@/hooks/usePaginatedTableParams'; -import { IMove } from '@/types/Moves/Move'; -import { removeDash } from '@/utils/Typography'; -import { ColumnDef } from '@tanstack/react-table'; -import Image from 'next/image'; -import Link from 'next/link'; -import { useMemo } from 'react'; -import { SearchContainer } from '../Styled.Moves'; -import SearchMoves from './Search.Moves'; - -type Props = { - moves?: IMove[]; -}; - -function MovesTable({ moves }: Props) { - const data = useMemo(() => moves, [moves]); - - const columns = useMemo[]>( - () => [ - { - accessorKey: `name`, - id: `sort`, - header: `Name`, - cell: (info) => ( - - ()} - href={{ - pathname: `/move/[name]`, - query: { name: info.getValue() }, - }} - > - {removeDash(info.getValue())} - - - ), - }, - { - accessorKey: `damage_class.name`, - id: `category`, - header: `Category`, - cell: (info) => ( - ()}> -
    - {info.getValue<string()} - width={20} - height={20} - src={`/images/status/move-${info.getValue()}.png`} - /> - {info.getValue()} -
    -
    - ), - }, - { - accessorKey: `type.name`, - id: `type`, - header: `Type`, - cell: (info) => ( - - ()}> - () }, - }} - > - {info.getValue<string()} - width={20} - height={20} - src={`/images/types/${info.getValue()}.png`} - /> - {info.getValue()} - - - - ), - }, - { - accessorFn: (row) => - row.flavor_text_entries.find((rf) => { - return rf.language.name === `en` && rf.flavor_text !== `Dummy Data`; - })?.flavor_text || `-`, - id: `effect`, - header: `Effect`, - cell: (info) => {info.getValue()}, - }, - ], - [], - ); - - const { tableContainerRef, tableHeader, tableBody, tablePagination } = - usePaginatedTableParams(data, columns); - - return ( -
    - - Moves - - - - - {tableHeader()} - {tableBody()} - - {tablePagination()} - -
    - ); -} - -export default MovesTable; diff --git a/src/components/pages/Moves/Hooks/useToggleTable.tsx b/src/components/pages/Moves/Hooks/useToggleTable.tsx deleted file mode 100644 index 0d3f7aa0..00000000 --- a/src/components/pages/Moves/Hooks/useToggleTable.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { getMoves, getStats, getStatus } from '@/utils/DataFetch'; -import dynamic from 'next/dynamic'; -import { useState } from 'react'; -import { useQueries } from '@tanstack/react-query'; - -const MovesTable = dynamic( - () => import(`@/components/pages/Moves/Components/MovesTable.Moves`), -); -const StatusTable = dynamic( - () => import(`@/components/pages/Moves/Components/StatusTable.Moves`), -); -const StatsTable = dynamic(() => import(`../Components/StatsTable.Moves`)); - -export const useToggleTable = () => { - const [moves, status, stats] = useQueries({ - queries: [ - { - queryKey: [`moves`], - queryFn: getMoves, - }, - { - queryKey: [`status`], - queryFn: getStatus, - }, - { - queryKey: [`stats`], - queryFn: getStats, - }, - ], - }); - - const [toggle, setToggle] = useState(1); - const pageShown = () => { - if (toggle === 1) { - return ; - } else if (toggle === 2) { - return ; - } else if (toggle === 3) { - return ; - } - }; - - return { moves, status, stats, toggle, setToggle, pageShown }; -}; diff --git a/src/components/pages/Moves/MoveCard/Data/Data.MoveCard.tsx b/src/components/pages/Moves/MoveCard/Data/Data.MoveCard.tsx deleted file mode 100644 index d5541ef5..00000000 --- a/src/components/pages/Moves/MoveCard/Data/Data.MoveCard.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { IMachine } from '@/types/Machines/Machine'; -import { IMove } from '@/types/Moves/Move'; -import { MoveCardDataSection } from './Styled.Data.MoveCard'; -import dynamic from 'next/dynamic'; - -interface IEffectProps { - move: IMove; - version: string; -} - -const Desc = dynamic(() => import(`./Desc/Desc.MoveCard`)); -const Effect = dynamic( - () => import(`./Effect/Effect.MoveCard`) as any, -); - -type Props = { - move: IMove; - machine?: IMachine[]; - version: string; -}; - -function Data({ move, machine, version }: Props) { - return ( - - - - - ); -} - -export default Data; diff --git a/src/components/pages/Pokemon/Components/List.Pokemon.tsx b/src/components/pages/Pokemon/Components/List.Pokemon.tsx deleted file mode 100644 index cb2aead7..00000000 --- a/src/components/pages/Pokemon/Components/List.Pokemon.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { removeDash, removeLongName } from '@/utils/Typography'; -import dynamic from 'next/dynamic'; -import Link from 'next/link'; -import { PokedexElement, PokedexList, PokedexTypes } from '../Styled.Pokemon'; - -interface ITypesProps { - p: IPokemon; -} - -const Sprites = dynamic( - () => import(`@/components/pages/Pokemon/Components/Sprites.Pokemon`), -); -const TypesPokemon = dynamic( - () => import(`@/components/pages/Pokemon/Components/Types.Pokemon`) as any, -); - -type Props = { - filteredPokedex: IPokemon[]; -}; - -function ListPokemon({ filteredPokedex }: Props) { - return ( - - {filteredPokedex?.map((p: IPokemon) => ( - - - {p.id < 1011 && ( -

    #{p.id.toString().padStart(3, `0`)}

    - )} -

    - - {removeLongName(removeDash(p.name))} - -

    - - - -
    - ))} -
    - ); -} - -export default ListPokemon; diff --git a/src/components/pages/Pokemon/Components/Types.Pokemon.tsx b/src/components/pages/Pokemon/Components/Types.Pokemon.tsx deleted file mode 100644 index 4e28cb61..00000000 --- a/src/components/pages/Pokemon/Components/Types.Pokemon.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Type } from '@/components/common/styles/Themes'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import Image from 'next/image'; -import Link from 'next/link'; - -type Props = { - p: IPokemon; -}; - -function TypesPokemon({ p }: Props) { - return p.types?.map((pt) => ( - - - {pt.type.name} - {pt.type.name} - - - )); -} - -export default TypesPokemon; diff --git a/src/components/pages/Pokemon/PokemonCard/Competitive/Competitive.PokemonCard.tsx b/src/components/pages/Pokemon/PokemonCard/Competitive/Competitive.PokemonCard.tsx deleted file mode 100644 index a9b4eb65..00000000 --- a/src/components/pages/Pokemon/PokemonCard/Competitive/Competitive.PokemonCard.tsx +++ /dev/null @@ -1,272 +0,0 @@ -// @ts-nocheck - -import { H3, H4 } from '@/components/common/styles/Headings'; -import { MethodNav } from '@/components/common/styles/Navbars'; -import { Section } from '@/components/common/styles/Sizing'; -import SmallLoader from '@/components/common/ui/Loader/SmallLoader'; -import { - IFormatAnalysesSets, - IFormatsAnalysesSetName, -} from '@/types/Competitive/Analyses'; -import { getFormat } from '@/utils/DataFetch'; -import { capitalize, removeLongName } from '@/utils/Typography'; -import { useQueries } from '@tanstack/react-query'; -import { useState } from 'react'; -import toast from 'react-hot-toast'; -import { - PokemonSetComment, - PokemonSetDesc, - PokemonSetsContainer, - PokemonSetSpecs, -} from './Styled.Competitive.PokemonCard'; - -type Props = { - format: string; - name: string; -}; - -function Competitive({ format, name }: Props) { - const [toggle, setToggle] = useState(0); - - const [analyses, formats, sets] = useQueries({ - queries: [ - { - queryKey: [`analyses`, format], - queryFn: () => - getFormat( - `https://raw.githubusercontent.com/pkmn/smogon/main/data/analyses/${format}.json`, - ), - }, - { - queryKey: [`formats`], - queryFn: () => - getFormat( - `https://raw.githubusercontent.com/pkmn/smogon/main/data/formats/index.json`, - ), - }, - { - queryKey: [`sets`, format], - queryFn: () => - getFormat( - `https://raw.githubusercontent.com/pkmn/smogon/main/data/sets/${format}.json`, - ), - }, - ], - }); - - if ( - analyses.status === `error` || - formats.status === `error` || - sets.status === `error` - ) { - return toast.error(`Something went wrong`, { - style: { - fontSize: `1.7rem`, - }, - }); - } - - if ( - analyses.status === `loading` || - formats.status === `loading` || - sets.status === `loading` - ) { - return ; - } - - const pokemonAnalyses = Object.entries(analyses.data) - .map(([pokemonAnalysesName, value]) => - Object.assign({ pokemonAnalysesName }, value), - ) - .find((n) => n.pokemonAnalysesName === removeLongName(capitalize(name))); - - const pokemonSets = Object.entries(sets.data) - .map(([pokemonSetsName, value]) => - Object.assign({ pokemonSetsName }, value), - ) - .find((n) => n.pokemonSetsName === removeLongName(capitalize(name))); - - if (pokemonAnalyses && pokemonSets) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { pokemonAnalysesName, ...filteredAnalyses } = pokemonAnalyses; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { pokemonSetsName, ...filteredSets } = pokemonSets; - - if ( - Object.keys(filteredAnalyses).length > 0 && - Object.keys(filteredSets).length > 0 - ) { - const formattedName = (formatName: string) => { - return ( - Object.entries(formats.data) - .filter((f) => f[0] === formatName && f[1]) - .flat()[1] || formatName - ); - }; - - const setsEntries = (obj: T): T => { - return Object.entries(obj)[toggle][1]; - }; - - const overview: string | undefined = setsEntries( - filteredAnalyses as IFormatAnalysesSets, - ).overview; - - const comments: string | undefined = setsEntries( - filteredAnalyses as IFormatAnalysesSets, - ).comments; - - const textFormatting = (str: string) => - str.replaceAll(`-types`, ` types`).replaceAll(`-type`, ` type`); - - const setSpecs = ( - obj: Record, - i: number, - value: string, - ) => { - return Object.values(Object.entries(obj)[toggle][1])[i][value]; - }; - - const wrapMoves = (tag: string, move: string | number, index: number) => { - if (tag === `li` && typeof move === `string`) { - return `<${tag}>Move ${index + 1}: ${move}`; - } else if (tag === `span` && typeof move === `string`) { - return `<${tag}>${move}`; - } else if (typeof move === `number`) { - return null; - } - }; - - const majEv = { - hp: `Hp`, - atk: `Atk`, - def: `Def`, - spa: `SpA`, - spd: `SpD`, - spe: `Spe`, - }; - - const detailedSets = Object.keys( - Object.values(Object.entries(filteredSets)[toggle][1])[0], - ); - - return ( -
    -

    Competitive

    - - {Object.keys(filteredAnalyses).map((fa, i) => ( - - ))} - - - {overview && ( -
  • -

    Analysis

    - -
  • - )} - {setsEntries(filteredAnalyses as IFormatAnalysesSets).sets?.map( - (s: IFormatsAnalysesSetName, i) => ( -
  • -

    {s.name}

    - -
      - wrapMoves( - `li`, - Array.isArray(move) - ? move - .map((j) => wrapMoves(`span`, j, index)) - .join(` / `) - : move, - index, - ), - ), - }} - /> - {detailedSets.length > 1 && - detailedSets.find( - (d: string) => d !== `level` && d !== `moves`, - ) && ( -
        -
      • - {typeof setSpecs(filteredSets, i, `item`) === - `string` ? ( - <> - Item: {setSpecs(filteredSets, i, `item`)} - - ) : ( - <> - Items:{` `} - - {setSpecs(filteredSets, i, `item`).join( - ` / `, - )} - - - )} -
      • -
      • - Nature:{` `} - - {typeof setSpecs(filteredSets, i, `nature`) === - `string` - ? setSpecs(filteredSets, i, `nature`) - : `-`} - -
      • -
      • - EVs:{` `} - - {typeof setSpecs(filteredSets, i, `evs`) === - `object` - ? Object.entries( - setSpecs(filteredSets, i, `evs`), - ) - .join(` / `) - .replaceAll(`,`, ` `) - .replace( - /\b(?:hp|atk|def|spa|spd|spe)\b/gi, - (matched) => majEv[matched], - ) - : `-`} - -
      • -
      - )} - - {s.description && ( - - )} - - ), - )} - {comments && ( -
    • - -
    • - )} - -
  • - ); - } - } -} - -export default Competitive; diff --git a/src/components/pages/Pokemon/PokemonCard/Data/Data.PokemonCard.tsx b/src/components/pages/Pokemon/PokemonCard/Data/Data.PokemonCard.tsx deleted file mode 100644 index 393bbe4b..00000000 --- a/src/components/pages/Pokemon/PokemonCard/Data/Data.PokemonCard.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { auth, db } from '@/firebase-config'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { IPokemonSpecies } from '@/types/Pokemon/PokemonSpecies'; -import { removeDash } from '@/utils/Typography'; -import { - arrayUnion, - doc, - DocumentData, - getDoc, - onSnapshot, - updateDoc, -} from 'firebase/firestore'; -import { useEffect, useState } from 'react'; -import toast from 'react-hot-toast'; -import Base from './Base/Base.PokemonCard'; -import Desc from './Desc/Desc.PokemonCard'; -import Sprite from './Sprite/Sprite.PokemonCard'; -import { - PokemonCatchButton, - PokemonCaughtText, - PokemonDataContainer, - PokemonDataSection, - PokemonDataSprite, -} from './Styled.Data.PokemonCard'; - -type Props = { - pokemon: IPokemon; - species: IPokemonSpecies; - game: string | null; -}; - -function Data({ pokemon, species, game }: Props) { - const [user, setUser] = useState(); - - const getUserDoc = async () => { - if (auth.currentUser) { - const usersCollectionRef = doc(db, `users`, auth.currentUser.uid); - const docSnap = await getDoc(usersCollectionRef); - setUser(docSnap.data()); - } - }; - - const catchHandler = async () => { - if (Math.random() < species.capture_rate / 765 && auth.currentUser) { - const usersCollectionRef = doc(db, `users`, auth.currentUser?.uid); - await updateDoc(usersCollectionRef, { - caught: arrayUnion({ - 0: pokemon.name, - 1: pokemon.sprites.front_default, - }), - }); - toast.success(`Congrats 🎉 ! You caught ${removeDash(pokemon.name)}`, { - style: { - fontSize: `1.7rem`, - textTransform: `capitalize`, - }, - }); - } - }; - - useEffect(() => { - if (auth.currentUser) { - getUserDoc(); - const usersCollectionRef = doc(db, `users`, auth.currentUser?.uid); - const unsubscribe = onSnapshot(usersCollectionRef, (doc) => { - setUser(doc.data()); - }); - return () => { - unsubscribe(); - }; - } - }, []); - - return ( - - {user && - pokemon.id < 10000 && - (user.caught.every( - (n: Record) => n[0] !== pokemon.name, - ) ? ( - Catch - ) : ( - Caught - ))} - - - - - - - - - ); -} - -export default Data; diff --git a/src/components/pages/Pokemon/PokemonCard/Data/Sprite/Sprite.PokemonCard.tsx b/src/components/pages/Pokemon/PokemonCard/Data/Sprite/Sprite.PokemonCard.tsx deleted file mode 100644 index 36f139e8..00000000 --- a/src/components/pages/Pokemon/PokemonCard/Data/Sprite/Sprite.PokemonCard.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { IPokemonSpecies } from '@/types/Pokemon/PokemonSpecies'; -import { PokemonDataImg, PokemonDataSpecial } from '../Styled.Data.PokemonCard'; - -type Props = { - pokemon: IPokemon; - species: IPokemonSpecies; -}; - -function Sprite({ pokemon, species }: Props) { - return ( - <> - - {pokemon.id < 10000 && ( - <> - {species?.is_legendary && ( - Legendary - )} - {species?.is_mythical && ( - Mythical - )} - {species.is_baby && Baby} - - )} - - ); -} - -export default Sprite; diff --git a/src/components/pages/Pokemon/PokemonCard/Data/Styled.Data.PokemonCard.tsx b/src/components/pages/Pokemon/PokemonCard/Data/Styled.Data.PokemonCard.tsx deleted file mode 100644 index 0431f443..00000000 --- a/src/components/pages/Pokemon/PokemonCard/Data/Styled.Data.PokemonCard.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import styled from 'styled-components'; -import { Pulse } from '../../../../common/styles/Animations'; -import { device, Section } from '../../../../common/styles/Sizing'; -import { Table } from '../../../../common/styles/Table'; - -export const PokemonDataSection = styled(Section)` - position: relative; - display: grid; - align-items: center; - grid-template-columns: 55% 45%; - gap: 3rem; - - @media ${device.md} { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column-reverse; - } -`; - -export const PokemonCatchButton = styled.button` - position: absolute; - top: 1rem; - right: 1rem; - padding: 0.7rem 1.5rem; - background: ${({ theme }) => theme.secondary}; - border: 1px solid ${({ theme }) => theme.secondary}; - border-radius: 5px; - font-size: 1.5rem; - font-weight: 600; - transition: 0.3s ease-in-out; - - &:hover { - background: transparent; - color: ${({ theme }) => theme.secondary}; - } -`; - -export const PokemonCaughtText = styled.p` - position: absolute; - top: 1rem; - right: 1rem; - padding: 0.7rem 1.5rem; - background: transparent; - color: ${({ theme }) => theme.secondary}; - border: 1px solid ${({ theme }) => theme.secondary}; - border-radius: 5px; - font-size: 1.5rem; - font-weight: 600; - opacity: 0.7; -`; - -export const PokemonDataContainer = styled.div` - display: flex; - flex-direction: column; - gap: 2rem; -`; - -export const PokemonDataSprite = styled.div` - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; -`; - -export const PokemonDataDesc = styled.li` - font-size: 2rem; - - & p { - padding-top: 0.5rem; - font-size: 1.3rem; - } -`; - -export const PokemonDataTypes = styled.li` - position: relative; - width: 100%; - display: flex; - align-items: center; - justify-content: flex-start; - - & div { - margin: 2rem; - margin-left: 0; - padding: 0 1.5rem; - border-radius: 5px; - text-transform: uppercase; - text-align: center; - cursor: pointer; - - & a { - display: flex; - align-items: center; - gap: 0.5rem; - - & img { - cursor: pointer; - } - - & span { - font-family: 'Oswald'; - font-size: 3rem; - color: #c4c4c4; - text-shadow: ${({ theme }) => theme.main} -1px -1px 0px, - ${({ theme }) => theme.main} 1px -1px 0px, - ${({ theme }) => theme.main} -1px 1px 0px, - ${({ theme }) => theme.main} 1px 1px 0px; - cursor: pointer; - } - } - } - - @media ${device.sm} { - justify-content: center; - } -`; - -export const PokemonDataOldTypes = styled.li` - font-size: 1.7rem; - - & span { - text-transform: capitalize; - - &:not(:first-of-type) { - font-weight: 600; - } - } -`; - -export const PokemonDataTable = styled(Table)` - width: 90%; - - & th { - background: rgba(130, 130, 130, 0.2); - text-transform: capitalize; - } - - & td { - font-size: 1.7rem; - font-weight: 600; - text-align: left; - text-transform: capitalize; - - & ul { - margin-left: 2rem; - & li { - list-style-type: decimal; - text-align: left; - } - } - } -`; - -const PokemonDataPill = styled.span` - margin: 1rem 0 0; - padding: 1rem 1.5rem; - border-radius: 50px; - font-size: 2rem; - transition: 0.3s ease-in-out; -`; - -export const PokemonDataSpecial = styled(PokemonDataPill)` - border: 1px solid ${({ theme }) => theme.purple}; - background: ${({ theme }) => theme.purple}; - color: #c4c4c4; - font-weight: 600; -`; - -export const PokemonDataImg = styled.img` - animation: ${Pulse} 5s infinite; - - @media ${device.sm} { - width: 75%; - margin-bottom: 1rem; - } -`; diff --git a/src/components/pages/Pokemon/PokemonCard/Moves/Styled.Moves.PokemonCard.tsx b/src/components/pages/Pokemon/PokemonCard/Moves/Styled.Moves.PokemonCard.tsx deleted file mode 100644 index 37b87662..00000000 --- a/src/components/pages/Pokemon/PokemonCard/Moves/Styled.Moves.PokemonCard.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { Section } from '@/components/common/styles/Sizing'; -import styled from 'styled-components'; - -export const PokemonMovesSection = styled(Section)` - overflow-x: hidden; -`; - -export const PokemonMovesMachine = styled.td` - text-transform: uppercase; -`; diff --git a/src/components/pages/Pokemon/PokemonCard/Stats/Stats.PokemonCard.tsx b/src/components/pages/Pokemon/PokemonCard/Stats/Stats.PokemonCard.tsx deleted file mode 100644 index d89bfd17..00000000 --- a/src/components/pages/Pokemon/PokemonCard/Stats/Stats.PokemonCard.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import { Bold, H3 } from '@/components/common/styles/Headings'; -import { MethodNav } from '@/components/common/styles/Navbars'; -import { Section } from '@/components/common/styles/Sizing'; -import ToolTip from '@/components/common/ui/ToolTip'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import dynamic from 'next/dynamic'; -import { useState } from 'react'; -import { CircularProgressbar } from 'react-circular-progressbar'; -import 'react-circular-progressbar/dist/styles.css'; -import { - PokemonStatsCircles, - PokemonStatsDetails, - PokemonStatsTotal, -} from './Styled.Stats.PokemonCard'; - -const CalculatorStats = dynamic( - () => import(`./Calculator/Calculator.Stats.PokemonCard`), -); - -type Props = { - pokemon: IPokemon; -}; - -function Bars({ pokemon }: Props) { - const [toggle, setToggle] = useState(1); - - const percentageHp = pokemon.stats[0].base_stat; - const percentageAtk = pokemon.stats[1].base_stat; - const percentageDef = pokemon.stats[2].base_stat; - const percentageSpAtk = pokemon.stats[3].base_stat; - const percentageSpDef = pokemon.stats[4].base_stat; - const percentageSpd = pokemon.stats[5].base_stat; - const percentageTotal = - pokemon?.stats?.[0]?.base_stat + - pokemon?.stats?.[1]?.base_stat + - pokemon?.stats?.[2]?.base_stat + - pokemon?.stats?.[3]?.base_stat + - pokemon?.stats?.[4]?.base_stat + - pokemon?.stats?.[5]?.base_stat; - - const statCalc = (value: number) => { - if (toggle === 1) { - return value; - } else if (toggle === 2) { - return Math.floor((value * 2 + 5) * 0.9); - } else if (toggle === 3) { - return Math.floor(value * 2 + 5); - } else if (toggle === 4) { - return Math.floor(value * 2 + 31 + 252 / 4 + 5); - } else { - return Math.floor((value * 2 + 31 + 252 / 4 + 5) * 1.1); - } - }; - - const hpCalc = (value: number) => { - if (toggle === 1) { - return value; - } else if (toggle === 2) { - return Math.floor(value * 2 + 100 + 10); - } else if (toggle === 3) { - return Math.floor(value * 2 + 100 + 10); - } else if (toggle === 4) { - return Math.floor(value * 2 + 31 + 252 / 4 + 100 + 10); - } else { - return Math.floor(value * 2 + 31 + 252 / 4 + 100 + 10); - } - }; - - return ( - <> -
    -

    Base stats

    - - - - - - - - - - - - - - - - {toggle === 1 && ( - - Total: {percentageTotal} - - )} - - Stats calculator - - -
    - - - ); -} - -export default Bars; diff --git a/src/components/pages/Pokemon/PokemonCard/Types/Styled.Types.PokemonCard.tsx b/src/components/pages/Pokemon/PokemonCard/Types/Styled.Types.PokemonCard.tsx deleted file mode 100644 index a0abdbba..00000000 --- a/src/components/pages/Pokemon/PokemonCard/Types/Styled.Types.PokemonCard.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { TypeDamageTable } from '@/components/pages/Types/TypeCard/Styled.TypeCard'; -import styled from 'styled-components'; -import { PokedexTypes } from '../../Styled.Pokemon'; - -export const PokemonTypesList = styled(PokedexTypes)` - width: fit-content; - flex-direction: row; - margin-bottom: 1rem; - gap: 2rem; - - & div { - padding: 0.5rem 1.5rem; - font-size: 2rem; - } -`; - -export const PokemonTypesTable = styled(TypeDamageTable)` - height: auto; - width: 100%; - & tr { - & td { - height: auto; - } - - &:nth-of-type(4) { - border-bottom: 1px solid rgba(130, 130, 130, 0.2); - } - } - - &:first-of-type { - margin-bottom: 0; - } -`; diff --git a/src/components/pages/Pokemon/PokemonCard/Types/Types.PokemonCard.tsx b/src/components/pages/Pokemon/PokemonCard/Types/Types.PokemonCard.tsx deleted file mode 100644 index de2924ae..00000000 --- a/src/components/pages/Pokemon/PokemonCard/Types/Types.PokemonCard.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { H3 } from '@/components/common/styles/Headings'; -import { Section } from '@/components/common/styles/Sizing'; -import { Type } from '@/components/common/styles/Themes'; -import { IType } from '@/types/Pokemon/Type'; -import Image from 'next/image'; -import Link from 'next/link'; - -import { PokemonTypesList } from './Styled.Types.PokemonCard'; -import TableTyping from './Table/Table.Types.PokemonCard'; - -type Props = { - types: IType[]; -}; - -function Typing({ types }: Props) { - return ( -
    -

    Types relations

    - - {types.map((t) => ( - - - {t.name} - {t.name} - - - ))} - -
    - -
    -
    - ); -} - -export default Typing; diff --git a/src/components/pages/Types/Styled.Types.tsx b/src/components/pages/Types/Styled.Types.tsx deleted file mode 100644 index e23a4021..00000000 --- a/src/components/pages/Types/Styled.Types.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import styled from 'styled-components'; -import { device } from '../../common/styles/Sizing'; -import { Type } from '../../common/styles/Themes'; - -export const TypesList = styled.ul` - display: flex; - align-items: center; - justify-content: center; - flex-wrap: wrap; - - & li { - & div { - border: 1px solid ${({ theme }) => theme.secondary}; - transition: 0.3s ease-in-out; - - &:hover { - transform: scale(1.03); - } - } - } -`; - -export const ModifiedType = styled(Type)` - width: 20rem; - margin: 3rem; - border-radius: 5px; - - & a { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - padding: 3rem; - - & img { - cursor: pointer; - } - - & h2 { - margin-top: 1rem; - font-size: 3rem; - border-radius: 5px; - text-transform: uppercase; - text-align: center; - color: ${({ theme }) => theme.secondary}; - text-shadow: ${({ theme }) => theme.main} -1px -1px 0px, - ${({ theme }) => theme.main} 1px -1px 0px, - ${({ theme }) => theme.main} -1px 1px 0px, - ${({ theme }) => theme.main} 1px 1px 0px; - cursor: pointer; - } - } - - @media ${device.sm} { - margin: 2rem; - } -`; diff --git a/src/components/pages/Types/TypeCard/Hooks/useToggleTable.tsx b/src/components/pages/Types/TypeCard/Hooks/useToggleTable.tsx deleted file mode 100644 index d2c85394..00000000 --- a/src/components/pages/Types/TypeCard/Hooks/useToggleTable.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { IMove } from '@/types/Moves/Move'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { IType } from '@/types/Pokemon/Type'; -import { getType, getTypeMoves, getTypePokemon } from '@/utils/DataFetch'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; -import dynamic from 'next/dynamic'; -import { useState } from 'react'; - -interface IPokemonTypeProps { - typeName?: string; - pokemon?: IPokemon[]; -} - -const MovesType = dynamic(() => import(`../Moves/Moves.TypeCard`)); -const PokemonType = dynamic( - () => import(`../Pokemon/Pokemon.TypeCard`) as any, -); - -export const useToggleTable = (name: string) => { - const { - isLoading, - isError, - error, - data: type, - }: UseQueryResult = useQuery({ - queryKey: [`type`, name], - queryFn: () => getType(`https://pokeapi.co/api/v2/type/${name}`), - }); - - const { data: pokemon }: UseQueryResult = useQuery({ - queryKey: [`typePokemon`, name, type], - queryFn: () => type && getTypePokemon(type), - enabled: !!type, - }); - - const { data: moves }: UseQueryResult = useQuery({ - queryKey: [`typeMoves`, name, type], - queryFn: () => type && getTypeMoves(type), - enabled: !!type, - }); - - const [toggle, setToggle] = useState(1); - const pageShown = () => { - if (toggle === 1) { - return ; - } else if (toggle === 2 && type) { - return ; - } - }; - - return { type, isLoading, isError, error, toggle, setToggle, pageShown }; -}; diff --git a/src/contexts/Theme/ThemeContext.tsx b/src/contexts/Theme/ThemeContext.tsx new file mode 100644 index 00000000..d1f6db0c --- /dev/null +++ b/src/contexts/Theme/ThemeContext.tsx @@ -0,0 +1,8 @@ +import React, { type Dispatch, type SetStateAction } from 'react'; + +export const initialThemeState = { + theme: `dark`, + setTheme: (() => null) as Dispatch>, +}; + +export const ThemeContext = React.createContext(initialThemeState); diff --git a/src/contexts/Theme/ThemeProvider.tsx b/src/contexts/Theme/ThemeProvider.tsx new file mode 100644 index 00000000..66847195 --- /dev/null +++ b/src/contexts/Theme/ThemeProvider.tsx @@ -0,0 +1,35 @@ +import { type ReactNode, useEffect, useState } from 'react'; + +import { ThemeContext, initialThemeState } from './ThemeContext'; + +type Props = { + children: ReactNode; +}; + +export const ThemeProvider = ({ children }: Props) => { + const [theme, setTheme] = useState(initialThemeState.theme); + + const localStorage = globalThis.window?.localStorage; + + useEffect(() => { + const savedThemeLocal = localStorage.getItem(`globalTheme`); + + if (!!savedThemeLocal) { + setTheme(savedThemeLocal); + } + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + localStorage.setItem(`globalTheme`, theme); + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [theme]); + + return ( + +
    {children}
    +
    + ); +}; diff --git a/src/contexts/Theme/index.ts b/src/contexts/Theme/index.ts new file mode 100644 index 00000000..8d46e498 --- /dev/null +++ b/src/contexts/Theme/index.ts @@ -0,0 +1,2 @@ +export * from './ThemeProvider'; +export * from './ThemeContext'; diff --git a/src/contexts/index.ts b/src/contexts/index.ts new file mode 100644 index 00000000..d54caf89 --- /dev/null +++ b/src/contexts/index.ts @@ -0,0 +1 @@ +export * from './Theme'; diff --git a/src/firebase-config.js b/src/firebase-config.js deleted file mode 100644 index 080d03c2..00000000 --- a/src/firebase-config.js +++ /dev/null @@ -1,80 +0,0 @@ -/* eslint-disable*/ - -import { initializeApp } from 'firebase/app'; -import { getFirestore } from 'firebase/firestore'; -import { - getAuth, - GoogleAuthProvider, - GithubAuthProvider, - signInWithPopup, -} from 'firebase/auth'; - -const firebaseConfig = { - apiKey: process.env.NEXT_PUBLIC_FIREBASE_API, - authDomain: 'pokeref.firebaseapp.com', - databaseURL: 'https://pokeref-default-rtdb.europe-west1.firebasedatabase.app', - projectId: 'pokeref', - storageBucket: 'pokeref.appspot.com', - messagingSenderId: '302178530281', - appId: process.env.NEXT_PUBLIC_FIREBASE_APP, - measurementId: 'G-61JGJP2LRJ', -}; - -const app = initializeApp(firebaseConfig); -export const auth = getAuth(app); -export const db = getFirestore(app); - -const googleProvider = new GoogleAuthProvider(); -const githubProvider = new GithubAuthProvider(); - -export const signInWithGoogle = () => { - signInWithPopup(auth, googleProvider) - .then((result) => { - // This gives you a Google Access Token. You can use it to access the Google API. - const credential = GoogleAuthProvider.credentialFromResult(result); - const token = credential.accessToken; - // The signed-in user info. - const user = result.user; - const usersCollectionRef = doc(db, `users`, auth.currentUser?.uid); - setDoc(usersCollectionRef, { - name: user.username, - email: user.email, - caught: [], - }); - }) - .catch((error) => { - // Handle Errors here. - const errorCode = error.code; - const errorMessage = error.message; - // The email of the user's account used. - const email = error.customData.email; - // The AuthCredential type that was used. - const credential = GoogleAuthProvider.credentialFromError(error); - }); -}; - -export const signInWithGithub = () => { - signInWithPopup(auth, githubProvider) - .then((result) => { - // This gives you a GitHub Access Token. You can use it to access the GitHub API. - const credential = GithubAuthProvider.credentialFromResult(result); - const token = credential.accessToken; - // The signed-in user info. - const user = result.user; - const usersCollectionRef = doc(db, `users`, auth.currentUser?.uid); - setDoc(usersCollectionRef, { - name: user.username, - email: user.email, - caught: [], - }); - }) - .catch((error) => { - // Handle Errors here. - const errorCode = error.code; - const errorMessage = error.message; - // The email of the user's account used. - const email = error.customData.email; - // The AuthCredential type that was used. - const credential = GithubAuthProvider.credentialFromError(error); - }); -}; diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 00000000..52c60579 --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1,3 @@ +export * from './useMediaQuery'; +export * from './usePaginatedTableParams'; +export * from './useTableParams'; diff --git a/src/hooks/usePaginatedTableParams.tsx b/src/hooks/usePaginatedTableParams.tsx index f9a5291f..8515a75e 100644 --- a/src/hooks/usePaginatedTableParams.tsx +++ b/src/hooks/usePaginatedTableParams.tsx @@ -1,16 +1,18 @@ -import { Pagination } from '@/components/common/styles/Pagination'; -import { THead, TRow } from '@/components/common/styles/Table'; +/* eslint-disable jsx-a11y/click-events-have-key-events */ + +import { useEffect, useMemo, useRef, useState } from 'react'; + import { BisChevronDown, BisChevronUp } from '@meronex/icons/bi'; import { + type PaginationState, + type SortingState, flexRender, getCoreRowModel, getPaginationRowModel, getSortedRowModel, - PaginationState, - SortingState, useReactTable, } from '@tanstack/react-table'; -import { useEffect, useMemo, useRef, useState } from 'react'; +import ReactPaginate from 'react-paginate'; import { useVirtual } from 'react-virtual'; // @ts-ignore @@ -67,7 +69,7 @@ export function usePaginatedTableParams(data, columns) { const tableHeader = () => { return ( - + {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { @@ -103,7 +105,7 @@ export function usePaginatedTableParams(data, columns) { })} ))} - + ); }; @@ -113,7 +115,7 @@ export function usePaginatedTableParams(data, columns) { {virtualRows.map((virtualRow) => { const row = rows[virtualRow.index]; return ( - + {row.getVisibleCells().map((cell) => { return ( <> @@ -121,7 +123,7 @@ export function usePaginatedTableParams(data, columns) { ); })} - + ); })} @@ -130,7 +132,8 @@ export function usePaginatedTableParams(data, columns) { const tablePagination = () => { return ( - { return ( - + {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { @@ -80,7 +82,7 @@ export function useTableParams(data, columns) { })} ))} - + ); }; @@ -90,7 +92,7 @@ export function useTableParams(data, columns) { {virtualRows.map((virtualRow) => { const row = rows[virtualRow.index]; return ( - + {row.getVisibleCells().map((cell) => { return ( <> @@ -98,7 +100,7 @@ export function useTableParams(data, columns) { ); })} - + ); })} diff --git a/src/modules/404/NotFound.module.scss b/src/modules/404/NotFound.module.scss new file mode 100644 index 00000000..5b6e3a51 --- /dev/null +++ b/src/modules/404/NotFound.module.scss @@ -0,0 +1,24 @@ +@use '@/styles/common/sizing' as *; + +.main { + @extend %mainBig; + + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; +} + +.image { + width: 10%; + height: 10%; +} + +.text { + font-size: 2rem; + font-weight: 600; + + &:first-of-type { + padding-top: 3rem; + } +} diff --git a/src/components/pages/Abilities/Heading.tsx b/src/modules/abilities/Heading.tsx similarity index 90% rename from src/components/pages/Abilities/Heading.tsx rename to src/modules/abilities/Heading.tsx index 1d40a185..9d5687d4 100644 --- a/src/components/pages/Abilities/Heading.tsx +++ b/src/modules/abilities/Heading.tsx @@ -1,6 +1,6 @@ import Head from 'next/head'; -function HeadingAbilities() { +export function Heading() { return ( Abilities | Pokeref @@ -18,5 +18,3 @@ function HeadingAbilities() { ); } - -export default HeadingAbilities; diff --git a/src/modules/abilities/ability/Ability.module.scss b/src/modules/abilities/ability/Ability.module.scss new file mode 100644 index 00000000..f6051ce8 --- /dev/null +++ b/src/modules/abilities/ability/Ability.module.scss @@ -0,0 +1,12 @@ +.effect { + margin: 0 0 3rem; + + & p { + font-size: 1.7rem; + } +} + +.sup { + vertical-align: super; + font-size: smaller; +} diff --git a/src/components/pages/Abilities/AbilityCard/Heading.tsx b/src/modules/abilities/ability/Heading.tsx similarity index 90% rename from src/components/pages/Abilities/AbilityCard/Heading.tsx rename to src/modules/abilities/ability/Heading.tsx index c604cb10..cbddd315 100644 --- a/src/components/pages/Abilities/AbilityCard/Heading.tsx +++ b/src/modules/abilities/ability/Heading.tsx @@ -1,11 +1,12 @@ -import Head from 'next/head'; import React from 'react'; +import Head from 'next/head'; + type Props = { name: string; }; -function HeadingAbility({ name }: Props) { +export function Heading({ name }: Props) { return ( @@ -26,5 +27,3 @@ function HeadingAbility({ name }: Props) { </Head> ); } - -export default HeadingAbility; diff --git a/src/modules/abilities/ability/components/Description.tsx b/src/modules/abilities/ability/components/Description.tsx new file mode 100644 index 00000000..1bd9db94 --- /dev/null +++ b/src/modules/abilities/ability/components/Description.tsx @@ -0,0 +1,25 @@ +import { removeDash } from '@/utils'; + +import type { IAbilityFlavorText } from '@/types'; + +type Props = { + filterDesc?: IAbilityFlavorText[]; +}; + +export function Description({ filterDesc }: Props) { + return ( + <section className="sectionTop"> + <h3 className="h3">Game descriptions</h3> + <table className="descTable"> + <tbody> + {filterDesc?.map((fd) => ( + <tr key={fd.flavor_text}> + <th>{removeDash(fd?.version_group.name)}</th> + <td>{fd?.flavor_text}</td> + </tr> + ))} + </tbody> + </table> + </section> + ); +} diff --git a/src/components/pages/Abilities/AbilityCard/Components/Table.AbilityCard.tsx b/src/modules/abilities/ability/components/Table.tsx similarity index 69% rename from src/components/pages/Abilities/AbilityCard/Components/Table.AbilityCard.tsx rename to src/modules/abilities/ability/components/Table.tsx index 5ccb3f47..ee3d98f1 100644 --- a/src/components/pages/Abilities/AbilityCard/Components/Table.AbilityCard.tsx +++ b/src/modules/abilities/ability/components/Table.tsx @@ -1,24 +1,20 @@ -import { - FullWidthTable, - TableContainer, - TBold, - TLink, -} from '@/components/common/styles/Table'; -import { useTableParams } from '@/hooks/useTableParams'; -import { IAbility } from '@/types/Pokemon/Ability'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import ImageWithFallback from '@/utils/ImageWithFallback'; -import { removeDash } from '@/utils/Typography'; -import { ColumnDef } from '@tanstack/react-table'; import { useMemo } from 'react'; -import { Sup } from '../Styled.AbilityCard'; + +import { type ColumnDef } from '@tanstack/react-table'; +import Link from 'next/link'; + +import { useTableParams } from '@/hooks'; +import styles from '@/modules/abilities/ability/Ability.module.scss'; +import { ImageWithFallback, removeDash } from '@/utils'; + +import type { IAbility, IPokemon } from '@/types'; type Props = { ability?: IAbility; pokemon?: IPokemon[]; }; -function TableAbilityCard({ ability, pokemon }: Props) { +export function Table({ ability, pokemon }: Props) { const data = useMemo( () => pokemon && pokemon.length > 0 && pokemon, [pokemon], @@ -47,16 +43,17 @@ function TableAbilityCard({ ability, pokemon }: Props) { id: `sort`, header: `Name`, cell: (info) => ( - <TBold> - <TLink + <td className="tBold"> + <Link + className="tLink" href={{ pathname: `/pokemon/[name]`, query: { name: info.getValue<string>() }, }} > {removeDash(info.getValue<string>())} - </TLink> - </TBold> + </Link> + </td> ), }, { @@ -64,22 +61,24 @@ function TableAbilityCard({ ability, pokemon }: Props) { id: `firstAbility`, header: () => ( <span> - 1<Sup>st</Sup> ability + 1<sup className={styles.sup}>st</sup> ability </span> ), cell: (info) => ( <td> - <TLink + <Link href={{ pathname: `/ability/[name]`, query: { name: info.getValue<string>() }, }} className={ - info.getValue<string>() === ability?.name ? `bold` : `` + info.getValue<string>() === ability?.name + ? `tLink bold` + : `tLink` } > {removeDash(info.getValue<string>())} - </TLink> + </Link> </td> ), }, @@ -89,22 +88,24 @@ function TableAbilityCard({ ability, pokemon }: Props) { id: `secondAbility`, header: () => ( <span> - 2<Sup>nd</Sup> ability + 2<sup className={styles.sup}>nd</sup> ability </span> ), cell: (info) => ( <td> - <TLink + <Link href={{ pathname: `/ability/[name]`, query: { name: info.getValue<string>() }, }} className={ - info.getValue<string>() === ability?.name ? `bold` : `` + info.getValue<string>() === ability?.name + ? `tLink bold` + : `tLink` } > {removeDash(info.getValue<string>())} - </TLink> + </Link> </td> ), }, @@ -115,17 +116,19 @@ function TableAbilityCard({ ability, pokemon }: Props) { header: () => <span>hidden ability</span>, cell: (info) => ( <td> - <TLink + <Link href={{ pathname: `/ability/[name]`, query: { name: info.getValue<string>() }, }} className={ - info.getValue<string>() === ability?.name ? `bold` : `` + info.getValue<string>() === ability?.name + ? `tLink bold` + : `tLink` } > {removeDash(info.getValue<string>())} - </TLink> + </Link> </td> ), }, @@ -139,13 +142,11 @@ function TableAbilityCard({ ability, pokemon }: Props) { ); return ( - <TableContainer ref={tableContainerRef}> - <FullWidthTable> + <section className="tableContainer" ref={tableContainerRef}> + <table className="fullWidthTable"> {tableHeader()} {tableBody()} - </FullWidthTable> - </TableContainer> + </table> + </section> ); } - -export default TableAbilityCard; diff --git a/src/modules/abilities/ability/components/index.ts b/src/modules/abilities/ability/components/index.ts new file mode 100644 index 00000000..589db0a0 --- /dev/null +++ b/src/modules/abilities/ability/components/index.ts @@ -0,0 +1,2 @@ +export * from './Description'; +export * from './Table'; diff --git a/src/modules/abilities/ability/hooks/index.ts b/src/modules/abilities/ability/hooks/index.ts new file mode 100644 index 00000000..4d68185c --- /dev/null +++ b/src/modules/abilities/ability/hooks/index.ts @@ -0,0 +1 @@ +export * from './useFilterAbility'; diff --git a/src/components/pages/Abilities/AbilityCard/Hooks/useFilterAbility.tsx b/src/modules/abilities/ability/hooks/useFilterAbility.tsx similarity index 78% rename from src/components/pages/Abilities/AbilityCard/Hooks/useFilterAbility.tsx rename to src/modules/abilities/ability/hooks/useFilterAbility.tsx index 4152b59c..33dc0210 100644 --- a/src/components/pages/Abilities/AbilityCard/Hooks/useFilterAbility.tsx +++ b/src/modules/abilities/ability/hooks/useFilterAbility.tsx @@ -1,7 +1,8 @@ -import { IAbility, IAbilityFlavorText } from '@/types/Pokemon/Ability'; -import { IEffect } from '@/types/Utility/CommonModels'; -import { getAbility, getAbilityPokemon } from '@/utils/DataFetch'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { useQuery, type UseQueryResult } from '@tanstack/react-query'; + +import { getAbility, getAbilityPokemon } from '@/utils'; + +import type { IAbility, IAbilityFlavorText, IEffect } from '@/types'; export const useFilterAbility = (name: string) => { const { diff --git a/src/modules/abilities/ability/index.ts b/src/modules/abilities/ability/index.ts new file mode 100644 index 00000000..aa85b680 --- /dev/null +++ b/src/modules/abilities/ability/index.ts @@ -0,0 +1,3 @@ +export * from './components'; +export * from './Heading'; +export * from './hooks'; diff --git a/src/components/pages/Abilities/Components/Search.Abilities.tsx b/src/modules/abilities/components/Search.tsx similarity index 62% rename from src/components/pages/Abilities/Components/Search.Abilities.tsx rename to src/modules/abilities/components/Search.tsx index e0950e5b..87ac775f 100644 --- a/src/components/pages/Abilities/Components/Search.Abilities.tsx +++ b/src/modules/abilities/components/Search.tsx @@ -1,19 +1,19 @@ -import { - AutocompleteContainer, - AutocompleteId, - AutocompleteInput, - AutocompleteLink, -} from '@/components/common/styles/Autocomplete'; -import { IAbility } from '@/types/Pokemon/Ability'; -import { capitalize, removeDash } from '@/utils/Typography'; -import Fuse from 'fuse.js'; import { useState } from 'react'; +import * as Label from '@radix-ui/react-label'; +import Fuse from 'fuse.js'; +import Link from 'next/link'; + +import { Input } from '@/components'; +import { capitalize, removeDash } from '@/utils'; + +import type { IAbility } from '@/types'; + type Props = { abilities?: IAbility[]; }; -function SearchAbilities({ abilities }: Props) { +export function Search({ abilities }: Props) { const [searchRes, setSearchRes] = useState<Fuse.FuseResult<IAbility>[]>([]); const [searchText, setSearchText] = useState(``); @@ -29,38 +29,36 @@ function SearchAbilities({ abilities }: Props) { }; return ( - <AutocompleteInput> - <label htmlFor="search">Search</label> - <input + <div className="search"> + <Label.Root htmlFor="search">Search</Label.Root> + <Input type="text" placeholder="Ability Name" onChange={(e) => searchAbilities(e.target.value)} /> {searchText && ( - <AutocompleteContainer> + <div className="searchContainer"> <ul> {searchRes && searchRes?.map((res) => ( <li key={res.item.name}> - <AutocompleteLink + <Link href={{ pathname: `/ability/[name]`, query: { name: res.item.name }, }} - className="bold" + className="searchLink bold" > {capitalize(removeDash(res.item.name))} - </AutocompleteLink> - <AutocompleteId> + </Link> + <span className="searchId"> {res.item.pokemon.length} Pokémon - </AutocompleteId> + </span> </li> ))} </ul> - </AutocompleteContainer> + </div> )} - </AutocompleteInput> + </div> ); } - -export default SearchAbilities; diff --git a/src/modules/abilities/components/index.ts b/src/modules/abilities/components/index.ts new file mode 100644 index 00000000..addd5330 --- /dev/null +++ b/src/modules/abilities/components/index.ts @@ -0,0 +1 @@ +export * from './Search'; diff --git a/src/modules/abilities/index.ts b/src/modules/abilities/index.ts new file mode 100644 index 00000000..6f323b35 --- /dev/null +++ b/src/modules/abilities/index.ts @@ -0,0 +1,2 @@ +export * from './components'; +export * from './Heading'; diff --git a/src/components/pages/Auth/Styled.Auth.tsx b/src/modules/auth/Auth.module.scss similarity index 54% rename from src/components/pages/Auth/Styled.Auth.tsx rename to src/modules/auth/Auth.module.scss index cdb0cc7c..b3c1899e 100644 --- a/src/components/pages/Auth/Styled.Auth.tsx +++ b/src/modules/auth/Auth.module.scss @@ -1,9 +1,7 @@ -import { device } from '@/components/common/styles/Sizing'; -import styled from 'styled-components'; -import Link from 'next/link'; -import Modal from 'react-modal'; +@use '@/styles/common' as *; +@use '@/styles/abstracts' as *; -export const AuthContainer = styled.div` +.container { position: relative; display: grid; grid-template-columns: 1fr 1fr; @@ -11,15 +9,18 @@ export const AuthContainer = styled.div` width: 100vw; height: 100vh; margin: 0 auto; - background: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.main}; - @media ${device.sm} { + @include themed { + background-color: t('text'); + color: t('bg'); + } + + @include sm { grid-template-columns: 1fr; } -`; +} -export const AuthClose = styled(Link)` +.close { position: absolute; top: 3rem; right: 3rem; @@ -29,49 +30,66 @@ export const AuthClose = styled(Link)` padding: 1rem; border: 1px solid transparent; border-radius: 50px; - background-color: ${({ theme }) => theme.main}; - color: ${({ theme }) => theme.secondary}; font-size: 3rem; cursor: pointer; - transition: 0.3s ease-in-out; + + @include themed { + background-color: t('bg'); + color: t('text'); + } &:hover { - border: 1px solid ${({ theme }) => theme.main}; - background-color: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.main}; + @include themed { + border: 1px solid t('bg'); + background-color: t('text'); + color: t('bg'); + } } -`; +} -export const AuthImage = styled.div` +%image { width: 100%; height: 100%; - border-right: 1px solid ${({ theme }) => theme.main}; background-image: url('https://www.pokepedia.fr/images/2/26/Frimapic.png'), - linear-gradient(to right, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.3) 100%); + linear-gradient(to right, rgb(0 0 0 / 30%) 0%, rgb(0 0 0 / 30%) 100%); background-blend-mode: multiply; background-position: center; background-size: cover; background-repeat: no-repeat; - @media ${device.sm} { + @include themed { + border-right: 1px solid t('bg'); + } + + @include sm { display: none; } -`; +} + +.image { + @extend %image; +} + +.image2 { + @extend %image; -export const AuthImage2 = styled(AuthImage)` background-image: url('https://www.pokepedia.fr/images/0/0e/Rosalia_HGSS.png'), - linear-gradient(to right, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.3) 100%); -`; + linear-gradient(to right, rgb(0 0 0 / 30%) 0%, rgb(0 0 0 / 30%) 100%); +} -export const AuthForm = styled.form` +%form { display: flex; align-items: center; justify-content: space-around; flex-direction: column; gap: 3rem; -`; +} -export const AuthTitle = styled.div` +.form { + @extend %form; +} + +.title { & h2 { margin-bottom: 0; } @@ -83,14 +101,18 @@ export const AuthTitle = styled.div` text-align: center; font-weight: 400; } -`; -export const AuthChoice = styled.p` + @include themed { + color: t('bg'); + } +} + +.choice { font-size: 1.7rem; font-weight: 600; -`; +} -export const AuthInput = styled.div` +%input { display: flex; align-items: flex-start; justify-content: center; @@ -98,104 +120,134 @@ export const AuthInput = styled.div` gap: 2rem; width: 85%; margin: 0 auto; + & div { width: 100%; display: flex; align-items: flex-start; flex-direction: column; + & input { width: 100%; padding: 1rem; - background: rgba(255, 255, 255, 0.3); - border: 1px solid ${({ theme }) => theme.main}; + background: rgb(255 255 255 / 30%); border-radius: 5px; + + @include themed { + border: 1px solid t('bg'); + } + &:focus { - border: 1px solid ${({ theme }) => theme.red}; + border: 1px solid $red; outline: none; } } + & small { margin-top: 0.5rem; margin-left: 0.5rem; - color: ${({ theme }) => theme.red}; + color: $red; font-size: 1.3rem; } } -`; +} -export const AuthResetPwd = styled.button` +.input { + @extend %input; +} + +.reset { margin-top: 0.5rem; margin-left: 0.5rem; font-size: 1.3rem; background: none; border: none; border-bottom: 1px solid transparent; - transition: 0.3s ease-in-out; &:hover { - border-bottom: 1px solid ${({ theme }) => theme.main}; + @include themed { + border-bottom: 1px solid t('bg'); + } } -`; +} -export const AuthSwitch = styled.p` +.switch { width: 100%; text-align: center; font-size: 1.7rem; + & a { font-weight: 600; cursor: pointer; border-bottom: 1px solid transparent; - transition: 0.3s ease-in-out; + &:hover { - border-bottom: 1px solid ${({ theme }) => theme.main}; + @include themed { + border-bottom: 1px solid t('bg'); + } } } -`; +} -export const AuthBtn = styled.button` +%button { width: 100%; padding: 1rem 0; font-size: 1.7rem; font-weight: 600; text-align: center; - background: ${({ theme }) => theme.main}; - border: 1px solid ${({ theme }) => theme.main}; - color: ${({ theme }) => theme.secondary}; border-radius: 5px; - transition: 0.3s ease-in-out; + + @include themed { + background: t('bg'); + border: 1px solid t('bg'); + color: t('text'); + } + &:hover { background: none; - color: ${({ theme }) => theme.main}; + + @include themed { + color: t('bg'); + } } + &:active { transform: scale(0.98); } -`; +} + +.button { + @extend %button; +} -export const AuthButtons = styled.div` +.providers { width: 100%; display: flex; align-items: flex-start; justify-content: center; flex-direction: column; gap: 2rem; -`; +} + +.secButton { + @extend %button; -export const AuthSecBtn = styled(AuthBtn)` display: flex; align-items: center; justify-content: center; gap: 1rem; font-weight: 400; background: none; - color: ${({ theme }) => theme.main}; + @include themed { + color: t('text'); + } & span { cursor: pointer; } -`; +} -export const AuthModal = styled(Modal)` +.modal { width: fit-content; height: fit-content; padding: 5rem 8rem; @@ -205,37 +257,40 @@ export const AuthModal = styled(Modal)` justify-content: center; flex-direction: column; position: absolute; - top: 50%; - left: 50%; - right: auto; - bottom: auto; + inset: 50% auto auto 50%; margin-right: -50%; - color: ${({ theme }) => theme.main}; - border: 1px solid ${({ theme }) => theme.main}; border-radius: 5px; transform: translate(-50%, -50%); overflow-y: hidden !important; -`; -export const AuthResetClose = styled.button` + @include themed { + color: t('bg'); + border: 1px solid t('bg'); + } +} + +.closeReset { position: absolute; top: 1rem; right: 1rem; background: none; border: none; font-size: 2.5rem; - transition: 0.3s ease-in-out; &:hover { - color: ${({ theme }) => theme.red}; + color: $red; } -`; +} + +.resetForm { + @extend %form; -export const AuthResetForm = styled(AuthForm)` width: 100%; margin-top: 5rem; -`; +} + +.resetInput { + @extend %input; -export const AuthResetInput = styled(AuthInput)` width: 100%; -`; +} diff --git a/src/modules/auth/ResetPwd.tsx b/src/modules/auth/ResetPwd.tsx new file mode 100644 index 00000000..9ccce4ff --- /dev/null +++ b/src/modules/auth/ResetPwd.tsx @@ -0,0 +1,83 @@ +import { type Dispatch, type SetStateAction } from 'react'; + +import { yupResolver } from '@hookform/resolvers/yup'; +import { FiX } from '@meronex/icons/fi'; +import { useForm } from 'react-hook-form'; +import Modal from 'react-modal'; +import * as yup from 'yup'; + +import { ErrorToast, Input, SuccessToast } from '@/components'; +import { capitalize } from '@/utils'; + +import styles from './Auth.module.scss'; + +type Props = { + modalIsOpen: boolean; + setIsOpen: Dispatch<SetStateAction<boolean>>; +}; + +const schema = yup.object({ + resetEmail: yup.string().email().required(), +}); + +type FormInput = yup.Asserts<typeof schema>; + +function ResetPwd({ modalIsOpen, setIsOpen }: Props) { + const { + register, + handleSubmit, + formState: { errors }, + } = useForm<FormInput>({ + resolver: yupResolver<FormInput>(schema), + }); + + const closeModal = () => { + setIsOpen(false); + }; + + const resetPwdForm = async (data: FormInput) => { + try { + return <SuccessToast text="Check your mails ✉" />; + } catch (error) { + if (error instanceof Error) { + return <ErrorToast error={error} />; + } + } + }; + + return ( + <Modal + className={styles.modal} + isOpen={modalIsOpen} + onRequestClose={closeModal} + preventScroll={true} + closeTimeoutMS={500} + shouldCloseOnOverlayClick={false} + > + <button className={styles.closeReset} onClick={closeModal}> + <FiX /> + </button> + <h2 className="h2">Reset your password</h2> + <form className={styles.resetForm} onSubmit={handleSubmit(resetPwdForm)}> + <div className={styles.resetInput}> + <div> + <Input + type="email" + id="resetEmail" + placeholder="Email" + {...register(`resetEmail`)} + /> + {typeof errors.resetEmail?.message === `string` && ( + <small>{capitalize(errors.resetEmail?.message)}</small> + )} + </div> + </div> + <button className={styles.button} type="submit"> + Reset + </button> + </form> + </Modal> + ); +} + +export default ResetPwd; diff --git a/src/components/pages/Items/Heading.tsx b/src/modules/items/Heading.tsx similarity index 91% rename from src/components/pages/Items/Heading.tsx rename to src/modules/items/Heading.tsx index 47ebc747..0d2ce6d9 100644 --- a/src/components/pages/Items/Heading.tsx +++ b/src/modules/items/Heading.tsx @@ -1,6 +1,6 @@ import Head from 'next/head'; -function HeadingItems() { +export function Heading() { return ( <Head> <title>Items | Pokeref @@ -18,5 +18,3 @@ function HeadingItems() { ); } - -export default HeadingItems; diff --git a/src/components/pages/Items/Components/BerriesTable.Items.tsx b/src/modules/items/components/Berries.tsx similarity index 55% rename from src/components/pages/Items/Components/BerriesTable.Items.tsx rename to src/modules/items/components/Berries.tsx index 57276a27..8bfc888b 100644 --- a/src/components/pages/Items/Components/BerriesTable.Items.tsx +++ b/src/modules/items/components/Berries.tsx @@ -1,21 +1,17 @@ -import { LeftH2 } from '@/components/common/styles/Headings'; -import { - FullWidthTable, - TableContainer, - TBold, - TCapitalize, -} from '@/components/common/styles/Table'; -import { useTableParams } from '@/hooks/useTableParams'; -import { IBerry } from '@/types/Berries/Berry'; -import { removeDash } from '@/utils/Typography'; -import { ColumnDef } from '@tanstack/react-table'; import { useMemo } from 'react'; +import { type ColumnDef } from '@tanstack/react-table'; + +import { useTableParams } from '@/hooks'; +import { removeDash } from '@/utils'; + +import type { IBerry } from '@/types'; + type Props = { berries?: IBerry[]; }; -function BerriesTable({ berries }: Props) { +export function Berries({ berries }: Props) { const data = useMemo(() => berries, [berries]); const columns = useMemo[]>( @@ -24,14 +20,16 @@ function BerriesTable({ berries }: Props) { accessorKey: `name`, id: `sort`, header: `Name`, - cell: (info) => {removeDash(info.getValue())}, + cell: (info) => ( + {removeDash(info.getValue())} + ), }, { accessorKey: `firmness.name`, id: `firmness`, header: `Firmness`, cell: (info) => ( - {removeDash(info.getValue())} + {removeDash(info.getValue())} ), }, { @@ -39,14 +37,16 @@ function BerriesTable({ berries }: Props) { row.flavors.find((f) => f.potency > 0)?.flavor.name, id: `flavor`, header: `Flavor`, - cell: (info) => {info.getValue()}, + cell: (info) => ( + {info.getValue()} + ), }, { accessorKey: `growth_time`, id: `growth`, header: `Growth`, cell: (info) => ( - {info.getValue()} hr / stage + {info.getValue()} hr / stage ), }, { @@ -54,10 +54,10 @@ function BerriesTable({ berries }: Props) { id: `naturalGift`, header: `Natural Gift`, cell: (info) => ( - +

    {info.getValue().natural_gift_type.name}

    {info.getValue().natural_gift_power}

    -
    + ), }, ], @@ -71,15 +71,13 @@ function BerriesTable({ berries }: Props) { return (
    - Berries - - +

    Berries

    +
    + {tableHeader()} {tableBody()} - - +
    +
    ); } - -export default BerriesTable; diff --git a/src/components/pages/Items/Components/ItemsTable.Items.tsx b/src/modules/items/components/Items.tsx similarity index 60% rename from src/components/pages/Items/Components/ItemsTable.Items.tsx rename to src/modules/items/components/Items.tsx index d46780e4..34b22096 100644 --- a/src/components/pages/Items/Components/ItemsTable.Items.tsx +++ b/src/modules/items/components/Items.tsx @@ -1,26 +1,22 @@ -import { LeftH2 } from '@/components/common/styles/Headings'; -import { - FullWidthTable, - TableContainer, - TBold, - TCapitalize, - TEffect, - TLink, -} from '@/components/common/styles/Table'; -import { usePaginatedTableParams } from '@/hooks/usePaginatedTableParams'; -import { IItem } from '@/types/Items/Item'; -import { removeDash } from '@/utils/Typography'; -import { ColumnDef } from '@tanstack/react-table'; -import Image from 'next/image'; import { useMemo } from 'react'; -import { SearchContainer } from '../../Moves/Styled.Moves'; -import SearchItems from './Search.Items'; + +import { type ColumnDef } from '@tanstack/react-table'; +import Image from 'next/image'; +import Link from 'next/link'; + +import { usePaginatedTableParams } from '@/hooks'; +import moves from '@/modules/moves/Moves.module.scss'; +import { removeDash } from '@/utils'; + +import { Search } from './Search'; + +import type { IItem } from '@/types'; type Props = { items?: IItem[]; }; -function ItemsTable({ items }: Props) { +export function Items({ items }: Props) { const data = useMemo(() => items, [items]); const columns = useMemo[]>( @@ -45,16 +41,17 @@ function ItemsTable({ items }: Props) { id: `sort`, header: `Name`, cell: (info) => ( - - + () }, }} > {removeDash(info.getValue())} - - + + ), }, { @@ -62,7 +59,7 @@ function ItemsTable({ items }: Props) { id: `category`, header: `Category`, cell: (info) => ( - {removeDash(info.getValue())} + {removeDash(info.getValue())} ), }, { @@ -73,9 +70,9 @@ function ItemsTable({ items }: Props) { id: `effect`, header: `Effect`, cell: (info) => ( - + {info.getValue()} - + ), }, ], @@ -87,19 +84,17 @@ function ItemsTable({ items }: Props) { return (
    - - Items - - - - +
    +

    Items

    + +
    +
    + {tableHeader()} {tableBody()} - +
    {tablePagination()} - +
    ); } - -export default ItemsTable; diff --git a/src/components/pages/Items/Components/Search.Items.tsx b/src/modules/items/components/Search.tsx similarity index 65% rename from src/components/pages/Items/Components/Search.Items.tsx rename to src/modules/items/components/Search.tsx index 677687d0..c68efecc 100644 --- a/src/components/pages/Items/Components/Search.Items.tsx +++ b/src/modules/items/components/Search.tsx @@ -1,20 +1,19 @@ -import { - AutocompleteContainer, - AutocompleteId, - AutocompleteInput, - AutocompleteLink, -} from '@/components/common/styles/Autocomplete'; -import { IItem } from '@/types/Items/Item'; -import ImageWithFallback from '@/utils/ImageWithFallback'; -import { capitalize, removeDash } from '@/utils/Typography'; -import Fuse from 'fuse.js'; import { useState } from 'react'; +import * as Label from '@radix-ui/react-label'; +import Fuse from 'fuse.js'; +import Link from 'next/link'; + +import { Input } from '@/components'; +import { ImageWithFallback, capitalize, removeDash } from '@/utils'; + +import type { IItem } from '@/types'; + type Props = { items?: IItem[]; }; -function SearchItems({ items }: Props) { +export function Search({ items }: Props) { const [searchRes, setSearchRes] = useState[]>([]); const [searchText, setSearchText] = useState(``); @@ -30,15 +29,15 @@ function SearchItems({ items }: Props) { }; return ( - - - + Search + searchItems(e.target.value)} /> {searchText && ( - +
      {searchRes && searchRes?.map((res) => ( @@ -50,25 +49,23 @@ function SearchItems({ items }: Props) { height={32} fallbackSrc={`/images/other/unknown.png`} /> - {capitalize(removeDash(res.item.name))} - - + + {capitalize(removeDash(res.item.category.name))} - + ))}
    - +
    )} -
    +
    ); } - -export default SearchItems; diff --git a/src/modules/items/components/index.ts b/src/modules/items/components/index.ts new file mode 100644 index 00000000..ac4a26f2 --- /dev/null +++ b/src/modules/items/components/index.ts @@ -0,0 +1,3 @@ +export * from './Berries'; +export * from './Items'; +export * from './Search'; diff --git a/src/modules/items/hooks/index.ts b/src/modules/items/hooks/index.ts new file mode 100644 index 00000000..6378e334 --- /dev/null +++ b/src/modules/items/hooks/index.ts @@ -0,0 +1 @@ +export * from './useItemsQuery'; diff --git a/src/modules/items/hooks/useItemsQuery.tsx b/src/modules/items/hooks/useItemsQuery.tsx new file mode 100644 index 00000000..0a869147 --- /dev/null +++ b/src/modules/items/hooks/useItemsQuery.tsx @@ -0,0 +1,20 @@ +import { useQueries } from '@tanstack/react-query'; + +import { getBerries, getItems } from '@/utils'; + +export const useItemsQuery = () => { + const [items, berries] = useQueries({ + queries: [ + { + queryKey: [`items`], + queryFn: getItems, + }, + { + queryKey: [`berries`], + queryFn: getBerries, + }, + ], + }); + + return { items, berries }; +}; diff --git a/src/modules/items/index.ts b/src/modules/items/index.ts new file mode 100644 index 00000000..54332a9c --- /dev/null +++ b/src/modules/items/index.ts @@ -0,0 +1,3 @@ +export * from './components'; +export * from './hooks'; +export * from './Heading'; diff --git a/src/components/pages/Items/ItemCard/Heading.tsx b/src/modules/items/item/Heading.tsx similarity index 90% rename from src/components/pages/Items/ItemCard/Heading.tsx rename to src/modules/items/item/Heading.tsx index 922c3464..3bc773b0 100644 --- a/src/components/pages/Items/ItemCard/Heading.tsx +++ b/src/modules/items/item/Heading.tsx @@ -1,11 +1,12 @@ -import Head from 'next/head'; import React from 'react'; +import Head from 'next/head'; + type Props = { name: string; }; -function HeadingItem({ name }: Props) { +export function Heading({ name }: Props) { return ( @@ -24,5 +25,3 @@ function HeadingItem({ name }: Props) { </Head> ); } - -export default HeadingItem; diff --git a/src/modules/items/item/Item.module.scss b/src/modules/items/item/Item.module.scss new file mode 100644 index 00000000..970a8aa8 --- /dev/null +++ b/src/modules/items/item/Item.module.scss @@ -0,0 +1,56 @@ +@use '@/styles/common/sizing' as *; + +.section { + @extend %section; + + display: grid; + grid-template-columns: 75% 25%; +} + +.effect { + margin: 0 0 3rem; + + & h3 { + margin: 0 0 1rem; + font-size: 3rem; + font-weight: 600; + } + + & p { + font-size: 1.7rem; + } +} + +.cost { + margin: 0 0 1rem; + font-size: 1.7rem; + + & span { + font-weight: 600; + } +} + +.held { + margin: 0 0 1rem; + font-size: 1.7rem; + + & span { + font-weight: 600; + } + + & a { + display: inline-block; + padding: 0 0.5rem; + text-transform: capitalize; + } +} + +.fling { + font-size: 1.7rem; +} + +.image { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/src/modules/items/item/components/Cost.tsx b/src/modules/items/item/components/Cost.tsx new file mode 100644 index 00000000..1f6532ea --- /dev/null +++ b/src/modules/items/item/components/Cost.tsx @@ -0,0 +1,19 @@ +import styles from '@/modules/items/item/Item.module.scss'; + +import type { IItem } from '@/types'; + +type Props = { + item?: IItem; +}; + +export function Cost({ item }: Props) { + return ( + <> + {item?.cost !== 0 && ( + <p className={styles.cost}> + <span>Cost :</span> {item?.cost} Pokédollars + </p> + )} + </> + ); +} diff --git a/src/modules/items/item/components/Description.tsx b/src/modules/items/item/components/Description.tsx new file mode 100644 index 00000000..49026886 --- /dev/null +++ b/src/modules/items/item/components/Description.tsx @@ -0,0 +1,29 @@ +import { removeDash } from '@/utils'; + +import type { IItem } from '@/types'; + +type Props = { + item?: IItem; +}; + +export function Description({ item }: Props) { + return ( + <section className="section"> + <h3 className="h3">Game descriptions</h3> + <table className="descTable"> + <tbody> + {item?.flavor_text_entries?.map((ift) => + ift.language.name === `en` ? ( + <tr key={ift.text}> + <th>{removeDash(ift.version_group.name)}</th> + <td>{ift.text}</td> + </tr> + ) : ( + `` + ), + )} + </tbody> + </table> + </section> + ); +} diff --git a/src/components/pages/Items/ItemCard/Components/Fling.ItemCard.tsx b/src/modules/items/item/components/Fling.tsx similarity index 53% rename from src/components/pages/Items/ItemCard/Components/Fling.ItemCard.tsx rename to src/modules/items/item/components/Fling.tsx index e1ac54d2..ae84b38d 100644 --- a/src/components/pages/Items/ItemCard/Components/Fling.ItemCard.tsx +++ b/src/modules/items/item/components/Fling.tsx @@ -1,19 +1,19 @@ -import { Capitalize } from '@/components/common/styles/Headings'; -import { IItem } from '@/types/Items/Item'; -import { removeDash } from '@/utils/Typography'; -import { ItemCardDataFling } from '../Styled.ItemCard'; +import { removeDash } from '@/utils'; + +import type { IItem } from '@/types'; type Props = { item?: IItem; }; -function FlingItemCard({ item }: Props) { +export function Fling({ item }: Props) { return ( <> {item?.fling_effect && ( - <ItemCardDataFling> + <p className="fling"> When the pokémon holds{` `} - <Capitalize>{removeDash(item?.name)}</Capitalize> the move{` `} + <span className="capitalize">{removeDash(item?.name)}</span> the move + {` `} <i>Fling</i> has {item?.fling_power} power. {item?.fling_effect.name && item?.fling_effect.name !== `berry-effect` && @@ -22,10 +22,8 @@ function FlingItemCard({ item }: Props) { /-/g, ` `, )} the target.`} - </ItemCardDataFling> + </p> )} </> ); } - -export default FlingItemCard; diff --git a/src/components/pages/Items/ItemCard/Components/Held.Itemcard.tsx b/src/modules/items/item/components/Held.tsx similarity index 64% rename from src/components/pages/Items/ItemCard/Components/Held.Itemcard.tsx rename to src/modules/items/item/components/Held.tsx index 909c4840..d7173b5a 100644 --- a/src/components/pages/Items/ItemCard/Components/Held.Itemcard.tsx +++ b/src/modules/items/item/components/Held.tsx @@ -1,17 +1,18 @@ -import { IItem, IItemHolderPokemon } from '@/types/Items/Item'; -import { removeDash } from '@/utils/Typography'; import Link from 'next/link'; -import { ItemCardDataHeld } from '../Styled.ItemCard'; + +import { removeDash } from '@/utils'; + +import type { IItem, IItemHolderPokemon } from '@/types'; type Props = { item?: IItem; }; -function HeldItemcard({ item }: Props) { +export function Held({ item }: Props) { return ( <> {item?.held_by_pokemon.length !== 0 && ( - <ItemCardDataHeld> + <p className="held"> <span>Held by :</span> {item?.held_by_pokemon?.map((ih: IItemHolderPokemon) => ( <Link @@ -24,10 +25,8 @@ function HeldItemcard({ item }: Props) { {removeDash(ih.pokemon.name)} </Link> ))} - </ItemCardDataHeld> + </p> )} </> ); } - -export default HeldItemcard; diff --git a/src/modules/items/item/components/index.tsx b/src/modules/items/item/components/index.tsx new file mode 100644 index 00000000..e3b772ce --- /dev/null +++ b/src/modules/items/item/components/index.tsx @@ -0,0 +1,4 @@ +export * from './Cost'; +export * from './Description'; +export * from './Fling'; +export * from './Held'; diff --git a/src/modules/items/item/hooks/index.ts b/src/modules/items/item/hooks/index.ts new file mode 100644 index 00000000..f43a4b17 --- /dev/null +++ b/src/modules/items/item/hooks/index.ts @@ -0,0 +1 @@ +export * from './useFilterItem'; diff --git a/src/components/pages/Items/ItemCard/Hooks/useFilterItem.tsx b/src/modules/items/item/hooks/useFilterItem.tsx similarity index 71% rename from src/components/pages/Items/ItemCard/Hooks/useFilterItem.tsx rename to src/modules/items/item/hooks/useFilterItem.tsx index e7ebe7c8..14dba631 100644 --- a/src/components/pages/Items/ItemCard/Hooks/useFilterItem.tsx +++ b/src/modules/items/item/hooks/useFilterItem.tsx @@ -1,6 +1,8 @@ -import { IItem } from '@/types/Items/Item'; -import { getItem } from '@/utils/DataFetch'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { useQuery, type UseQueryResult } from '@tanstack/react-query'; + +import { getItem } from '@/utils'; + +import type { IItem } from '@/types'; export const useFilterItem = (name: string) => { const { diff --git a/src/modules/items/item/index.ts b/src/modules/items/item/index.ts new file mode 100644 index 00000000..54332a9c --- /dev/null +++ b/src/modules/items/item/index.ts @@ -0,0 +1,3 @@ +export * from './components'; +export * from './hooks'; +export * from './Heading'; diff --git a/src/modules/layout/Footer/Footer.module.scss b/src/modules/layout/Footer/Footer.module.scss new file mode 100644 index 00000000..6c70b4a3 --- /dev/null +++ b/src/modules/layout/Footer/Footer.module.scss @@ -0,0 +1,68 @@ +@use '@/styles/abstracts' as *; + +.footer { + display: flex; + align-items: center; + background: hsl(29deg 92% 70% / 100%); + background: linear-gradient( + 0deg, + hsl(29deg 92% 70% / 100%) 0%, + hsl(0deg 87% 73% / 100%) 100% + ); + background: linear-gradient( + 0deg, + hsl(29deg 92% 70% / 100%) 0%, + hsl(0deg 87% 73% / 100%) 100% + ); + background: linear-gradient( + 0deg, + hsl(29deg 92% 70% / 100%) 0%, + hsl(0deg 87% 73% / 100%) 100% + ); +} + +.inner { + width: 90%; + margin: 0 auto; + display: grid; + grid-template-columns: 30% 40% 30%; + align-items: center; + color: $dark; +} + +.left { + justify-self: left; + font-size: 1.3rem; +} + +.center { + justify-self: center; + font-size: 4rem; + letter-spacing: 1px; + font-family: Oswald, sans-serif; + text-align: center; + + @include themed { + color: t('text'); + text-shadow: t('bg') -1px -1px 0, t('bg') 1px -1px 0, t('bg') -1px 1px 0, + t('bg') 1px 1px 0; + } +} + +.right { + justify-self: right; + height: 4rem; + width: 4rem; + + & a { + display: block; + width: 100%; + height: 100%; + cursor: pointer; + + & svg { + width: 100%; + height: 100%; + } + } +} diff --git a/src/modules/layout/Footer/Footer.tsx b/src/modules/layout/Footer/Footer.tsx new file mode 100644 index 00000000..2f96b291 --- /dev/null +++ b/src/modules/layout/Footer/Footer.tsx @@ -0,0 +1,26 @@ +import { FaGithub } from '@meronex/icons/fa'; + +import styles from './Footer.module.scss'; + +export function Footer() { + const year = new Date().getFullYear(); + + return ( + <footer className={styles.footer} id="footer"> + <div className={styles.inner}> + <div className={styles.left}>© {year} PokéRef</div> + <div className={styles.center}>PokéRef</div> + <div className={styles.right}> + <a + href="https://github.com/thibaudbrault/PokeRef" + aria-label="Github" + target="_blank" + rel="noreferrer" + > + <FaGithub /> + </a> + </div> + </div> + </footer> + ); +} diff --git a/src/modules/layout/Footer/index.ts b/src/modules/layout/Footer/index.ts new file mode 100644 index 00000000..ddcc5a9c --- /dev/null +++ b/src/modules/layout/Footer/index.ts @@ -0,0 +1 @@ +export * from './Footer'; diff --git a/src/modules/layout/Header/Header.module.scss b/src/modules/layout/Header/Header.module.scss new file mode 100644 index 00000000..1f1ce22b --- /dev/null +++ b/src/modules/layout/Header/Header.module.scss @@ -0,0 +1,148 @@ +@use '@/styles/abstracts' as *; + +.connect { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; + margin: 0 auto; + + @include md { + width: 80%; + justify-content: space-evenly; + } +} + +.connected { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; + margin: 0 auto; + + & a, + button { + display: flex; + align-items: center; + justify-content: center; + padding: 0.7rem 1.5rem; + border: 1px solid transparent; + border-radius: 5px; + font-size: 1.5rem; + font-weight: 600; + cursor: pointer; + + @include themed { + background-color: t('text'); + color: t('bg'); + } + + &:hover { + background: transparent; + + @include themed { + border-color: t('text'); + color: t('text'); + } + } + + @include md { + font-size: 3rem; + } + } + + & :first-child { + background: transparent; + + @include themed { + border-color: t('text'); + color: t('text'); + } + } + + @include md { + width: 80%; + justify-content: space-evenly; + } +} + +.header { + width: 90%; + margin: 0 auto 2rem; + display: flex; + align-items: center; + justify-content: space-between; + + @include sm { + width: 95%; + } + + & .connect, + .connected { + @include md { + display: none; + } + } +} + +.buttons { + display: flex; + align-items: center; + gap: 3rem; +} + +.theme { + width: 48px; + height: 48px; + background: none; + border: none; + font-size: 48px; + + @include themed { + color: t('text'); + } +} + +.open { + display: none; + align-items: center; + justify-content: center; + position: fixed; + top: 5vh; + right: 5vw; + z-index: 99; + padding: 1rem; + border: 1px solid transparent; + border-radius: 50px; + font-size: 48px; + + @include themed { + background-color: t('text'); + color: t('bg'); + } + + &:hover { + @include themed { + border: 1px solid t('text'); + background-color: t('bg'); + color: t('text'); + } + } + + @include md { + display: flex; + } +} + +.close { + display: none; + font-size: 48px; + background: transparent; + border: none; + + @include themed { + color: t('text'); + } + + @include md { + display: flex; + } +} diff --git a/src/modules/layout/Header/Header.tsx b/src/modules/layout/Header/Header.tsx new file mode 100644 index 00000000..ef474c92 --- /dev/null +++ b/src/modules/layout/Header/Header.tsx @@ -0,0 +1,98 @@ +import { + type Dispatch, + type SetStateAction, + useContext, + useEffect, + useState, +} from 'react'; + +import { FiMenu, FiX } from '@meronex/icons/fi'; +import { RiMoonClearLine, RiSunLine } from '@meronex/icons/ri'; +import Link from 'next/link'; + +import { Button } from '@/components'; +import { ThemeContext } from '@/contexts'; + +import styles from './Header.module.scss'; + +type Props = { + navOpen: boolean; + setNavOpen: Dispatch<SetStateAction<boolean>>; +}; + +export function Header({ navOpen, setNavOpen }: Props) { + // will have the user's info + const [user, setUser] = useState(); + + const { theme, setTheme } = useContext(ThemeContext); + + const logout = async () => { + // will be used to logout + }; + + const themeHandler = () => { + if (theme === `light`) { + setTheme(`dark`); + } else { + setTheme(`light`); + } + }; + + return ( + <header className={styles.header} id="header"> + <h1 className="h1"> + <Link href={`/`}>PokéRef</Link> + </h1> + <div className={styles.buttons}> + <button + className={styles.theme} + onClick={themeHandler} + aria-label="Switch Theme" + data-testid="themeBtn" + > + {theme === `dark` ? ( + <RiSunLine data-testid="sun" /> + ) : ( + <RiMoonClearLine data-testid="moon" /> + )} + </button> + {user ? ( + <div className={styles.connected}> + <Button intent="secondary" onClick={logout}> + Sign Out + </Button> + <Button intent="primary" asChild> + <Link href="/profile">Profile</Link> + </Button> + </div> + ) : ( + <div className={styles.connect}> + <Button intent="secondary" asChild> + <Link href="/login">Login</Link> + </Button> + <Button intent="primary" asChild> + <Link href="/register">Register</Link> + </Button> + </div> + )} + {navOpen ? ( + <button + className={styles.open} + aria-label="Open menu" + onClick={() => setNavOpen(!navOpen)} + > + <FiX /> + </button> + ) : ( + <button + className={styles.close} + aria-label="Close menu" + onClick={() => setNavOpen(!navOpen)} + > + <FiMenu /> + </button> + )} + </div> + </header> + ); +} diff --git a/src/modules/layout/Header/index.ts b/src/modules/layout/Header/index.ts new file mode 100644 index 00000000..266dec8a --- /dev/null +++ b/src/modules/layout/Header/index.ts @@ -0,0 +1 @@ +export * from './Header'; diff --git a/src/components/layout/Nav/Styled.Nav.tsx b/src/modules/layout/Nav/Nav.module.scss similarity index 63% rename from src/components/layout/Nav/Styled.Nav.tsx rename to src/modules/layout/Nav/Nav.module.scss index 4a1dd320..06d20adf 100644 --- a/src/components/layout/Nav/Styled.Nav.tsx +++ b/src/modules/layout/Nav/Nav.module.scss @@ -1,17 +1,16 @@ -import styled from 'styled-components'; -import { device } from '../../common/styles/Sizing'; +@use '@/styles/abstracts' as *; -export const MainNav = styled.nav` +.nav { min-height: 4vh; max-width: 1700px; margin: 0 auto; - @media ${device.md} { + @include md { display: none; } -`; +} -export const MainNavList = styled.ul` +.list { display: flex; justify-content: space-around; flex-wrap: wrap; @@ -28,12 +27,13 @@ export const MainNavList = styled.ul` font-weight: 600; text-transform: capitalize; cursor: pointer; - transition: 0.3s ease-in-out; - &::before { + + &::before, + &::after { + content: ''; position: absolute; width: 100%; height: 1px; - background-color: ${({ theme }) => theme.secondary}; top: 100%; left: 0; pointer-events: none; @@ -43,67 +43,57 @@ export const MainNavList = styled.ul` transition-property: transform, opacity; transition-duration: 0.3s; transition-timing-function: cubic-bezier(0.2, 1, 0.8, 1); + + @include themed { + background-color: t('text'); + } } + &::after { - position: absolute; - width: 100%; - height: 1px; - background: ${({ theme }) => theme.secondary}; - top: 100%; - left: 0; - pointer-events: none; - opacity: 0; - transform-origin: 50% 0%; - transform: translate3d(0, 3px, 0); - transition-property: transform, opacity; - transition-duration: 0.3s; - transition-timing-function: cubic-bezier(0.2, 1, 0.8, 1); + top: calc(100% + 4px); + width: 70%; + left: 15%; } + &:hover::before { opacity: 1; transform: translate3d(0, 0, 0); transition-timing-function: cubic-bezier(0.2, 0, 0.3, 1); + transition-delay: 0s; } + &:hover::after { opacity: 1; transform: translate3d(0, 0, 0); transition-timing-function: cubic-bezier(0.2, 0, 0.3, 1); } - &::before { - content: ''; - } - &::after { - content: ''; - top: calc(100% + 4px); - width: 70%; - left: 15%; - } + &::before, &:hover::after { transition-delay: 0.1s; } - &:hover::before { - transition-delay: 0s; - } } - @media ${device.lg} { + @include lg { margin-bottom: 2rem; } } -`; +} -export const ResponsiveNav = styled.nav` +.mobileNav { height: 100vh; width: 100%; position: fixed; top: 0; left: 0; - background: ${({ theme }) => theme.main}; z-index: 98; -`; -export const ResponsiveNavContainer = styled.div` + @include themed { + background: t('bg'); + } +} + +.mobileInner { height: 100%; width: 100%; padding: 2rem; @@ -111,9 +101,9 @@ export const ResponsiveNavContainer = styled.div` align-items: center; justify-content: center; flex-direction: column; -`; +} -export const ResponsiveNavList = styled.ul` +.mobileList { display: flex; align-items: center; justify-content: center; @@ -127,4 +117,4 @@ export const ResponsiveNavList = styled.ul` cursor: pointer; } } -`; +} diff --git a/src/components/layout/Nav/Nav.tsx b/src/modules/layout/Nav/Nav.tsx similarity index 59% rename from src/components/layout/Nav/Nav.tsx rename to src/modules/layout/Nav/Nav.tsx index 6c2596d7..0d1c73e1 100644 --- a/src/components/layout/Nav/Nav.tsx +++ b/src/modules/layout/Nav/Nav.tsx @@ -1,17 +1,12 @@ -import { Divider } from '@/components/common/ui/Divider'; -import { auth } from '@/firebase-config'; -import { useMediaQuery } from '@/hooks/useMediaQuery'; -import { onAuthStateChanged, signOut, User } from 'firebase/auth'; +import { type Dispatch, type SetStateAction, useEffect, useState } from 'react'; + import Link from 'next/link'; -import { Dispatch, SetStateAction, useEffect, useState } from 'react'; -import { HeaderBtnConnect, HeaderBtnConnected } from '../Header/Styled.Header'; -import { - MainNav, - MainNavList, - ResponsiveNav, - ResponsiveNavContainer, - ResponsiveNavList, -} from './Styled.Nav'; + +import { Separator } from '@/components'; +import { useMediaQuery } from '@/hooks'; +import header from '@/modules/layout/Header/Header.module.scss'; + +import styles from './Nav.module.scss'; type Props = { navOpen: boolean; @@ -22,19 +17,17 @@ type NavArray = { name: string; }[]; -function Nav({ navOpen, setNavOpen }: Props) { - const [user, setUser] = useState<User | null>(); +export function Nav({ navOpen, setNavOpen }: Props) { + // will have the user's info + const [user, setUser] = useState(); const isBreakpoint = useMediaQuery(890); const logout = async () => { - await signOut(auth); + // will be used to logout setNavOpen(false); }; useEffect(() => { - onAuthStateChanged(auth, (currentUser) => { - return setUser(currentUser); - }); if (!isBreakpoint) { setNavOpen(false); } @@ -52,9 +45,9 @@ function Nav({ navOpen, setNavOpen }: Props) { ]; return navOpen && isBreakpoint ? ( - <ResponsiveNav> - <ResponsiveNavContainer> - <ResponsiveNavList> + <nav className={styles.mobileNav}> + <div className={styles.mobileInner}> + <ul className={styles.mobileList}> {navArray.map((nav) => ( <li key={nav.name}> <Link @@ -65,30 +58,30 @@ function Nav({ navOpen, setNavOpen }: Props) { </Link> </li> ))} - </ResponsiveNavList> - <Divider /> + </ul> + <Separator /> {user ? ( - <HeaderBtnConnected> + <div className={header.connected}> <button onClick={logout}>Sign Out</button> <Link href="/profile" onClick={() => setNavOpen(false)}> Profile </Link> - </HeaderBtnConnected> + </div> ) : ( - <HeaderBtnConnect> + <div className={header.connect}> <Link href="/login" onClick={() => setNavOpen(false)}> Login </Link> <Link href="/register" onClick={() => setNavOpen(false)}> Register </Link> - </HeaderBtnConnect> + </div> )} - </ResponsiveNavContainer> - </ResponsiveNav> + </div> + </nav> ) : ( - <MainNav> - <MainNavList> + <nav className={styles.nav}> + <ul className={styles.list}> {navArray.map((nav) => ( <li key={nav.name}> <Link href={nav.name === `pokémon` ? `/` : `/${nav.name}`}> @@ -96,9 +89,7 @@ function Nav({ navOpen, setNavOpen }: Props) { </Link> </li> ))} - </MainNavList> - </MainNav> + </ul> + </nav> ); } - -export default Nav; diff --git a/src/modules/layout/Nav/index.ts b/src/modules/layout/Nav/index.ts new file mode 100644 index 00000000..93467d75 --- /dev/null +++ b/src/modules/layout/Nav/index.ts @@ -0,0 +1 @@ +export * from './Nav'; diff --git a/src/modules/layout/index.ts b/src/modules/layout/index.ts new file mode 100644 index 00000000..36421b9c --- /dev/null +++ b/src/modules/layout/index.ts @@ -0,0 +1,3 @@ +export * from './Footer'; +export * from './Header'; +export * from './Nav'; diff --git a/src/components/pages/Locations/Heading.tsx b/src/modules/locations/Heading.tsx similarity index 90% rename from src/components/pages/Locations/Heading.tsx rename to src/modules/locations/Heading.tsx index 6f6bd71e..0262cf06 100644 --- a/src/components/pages/Locations/Heading.tsx +++ b/src/modules/locations/Heading.tsx @@ -1,6 +1,6 @@ import Head from 'next/head'; -function HeadingLocations() { +export function Heading() { return ( <Head> <title>Locations | Pokeref @@ -18,5 +18,3 @@ function HeadingLocations() { ); } - -export default HeadingLocations; diff --git a/src/components/pages/Locations/Styled.Locations.tsx b/src/modules/locations/Locations.module.scss similarity index 58% rename from src/components/pages/Locations/Styled.Locations.tsx rename to src/modules/locations/Locations.module.scss index 8ed41593..d7cb5745 100644 --- a/src/components/pages/Locations/Styled.Locations.tsx +++ b/src/modules/locations/Locations.module.scss @@ -1,17 +1,7 @@ -import styled from 'styled-components'; -import { MethodNav } from '../../common/styles/Navbars'; -import { device } from '../../common/styles/Sizing'; -import { FullWidthTable } from '../../common/styles/Table'; - -export const LocationSection = styled.section` - & p { - font-size: 1.7rem; - font-weight: 600; - text-align: center; - } -`; +@use '@/styles/common' as *; +@use '@/styles/abstracts' as *; -export const LocationNavContainer = styled.section` +.navSection { width: 100%; height: 100%; @@ -33,9 +23,11 @@ export const LocationNavContainer = styled.section` & nav:empty + span { display: block; } -`; +} + +.nav { + @extend %methodNav; -export const LocationNav = styled(MethodNav)` padding-bottom: 3rem; & button { @@ -43,13 +35,20 @@ export const LocationNav = styled(MethodNav)` text-transform: capitalize; } - @media ${device.sm} { + @include sm { font-size: 1.5rem; } } -`; +} -export const LocationList = styled.ul` +.placeholder { + display: none; + font-size: 2rem; + font-weight: 600; + text-align: center; +} + +.list { display: grid; justify-items: center; grid-template-columns: repeat(4, 1fr); @@ -63,32 +62,41 @@ export const LocationList = styled.ul` & a { cursor: pointer; - transition: 0.3s ease-in-out; border-bottom: 1px solid transparent; + &:hover { - border-bottom: 1px solid ${({ theme }) => theme.secondary}; + @include themed { + border-bottom: 1px solid t('text'); + } } } } - @media ${device.sm} { + &:empty + .placeholder { + display: block; + } + + @include sm { grid-template-columns: repeat(3, 1fr); } -`; +} + +.table { + @extend %fullWidthTable; -export const LocationTable = styled(FullWidthTable)` & td { padding: 0; text-transform: capitalize; - border-top: 2px solid rgba(130, 130, 130, 0.2); - border-bottom: 2px solid rgba(130, 130, 130, 0.2); + border-top: 2px solid rgb(130 130 130 / 20%); + border-bottom: 2px solid rgb(130 130 130 / 20%); + & p { display: flex; justify-content: center; align-items: center; gap: 1rem; padding: 1.5rem; - border-top: 1px solid rgba(130, 130, 130, 0.2); + border-top: 1px solid rgb(130 130 130 / 20%); &:first-of-type { border-top: none; @@ -96,13 +104,13 @@ export const LocationTable = styled(FullWidthTable)` } & span { - &:after { + &::after { margin-left: 1rem; content: '&'; } &:last-of-type { - &:after { + &::after { content: ''; } } @@ -114,4 +122,4 @@ export const LocationTable = styled(FullWidthTable)` padding: 1.5rem; } } -`; +} diff --git a/src/modules/locations/components/List.tsx b/src/modules/locations/components/List.tsx new file mode 100644 index 00000000..4da40f98 --- /dev/null +++ b/src/modules/locations/components/List.tsx @@ -0,0 +1,48 @@ +import Link from 'next/link'; + +import styles from '@/modules/locations/Locations.module.scss'; +import { capitalize, removeDash } from '@/utils'; + +import type { IRegion } from '@/types'; + +type Props = { + location: string | null; + locations?: IRegion[]; +}; + +export function List({ location, locations }: Props) { + return ( +
    + {locations?.map( + (l) => + l.name === location && ( + <> + + + No data for {capitalize(location)} + + + ), + )} +
    + ); +} diff --git a/src/modules/locations/components/index.ts b/src/modules/locations/components/index.ts new file mode 100644 index 00000000..4994c181 --- /dev/null +++ b/src/modules/locations/components/index.ts @@ -0,0 +1 @@ +export * from './List'; diff --git a/src/modules/locations/index.ts b/src/modules/locations/index.ts new file mode 100644 index 00000000..6f323b35 --- /dev/null +++ b/src/modules/locations/index.ts @@ -0,0 +1,2 @@ +export * from './components'; +export * from './Heading'; diff --git a/src/components/pages/Locations/LocationCard/Heading.tsx b/src/modules/locations/location/Heading.tsx similarity index 90% rename from src/components/pages/Locations/LocationCard/Heading.tsx rename to src/modules/locations/location/Heading.tsx index 42f14aed..d23722f7 100644 --- a/src/components/pages/Locations/LocationCard/Heading.tsx +++ b/src/modules/locations/location/Heading.tsx @@ -4,7 +4,7 @@ type Props = { name: string; }; -function HeadingLocation({ name }: Props) { +export function Heading({ name }: Props) { return ( @@ -28,5 +28,3 @@ function HeadingLocation({ name }: Props) { </Head> ); } - -export default HeadingLocation; diff --git a/src/components/pages/Locations/LocationCard/Components/Area.LocationCard.tsx b/src/modules/locations/location/components/Area.tsx similarity index 61% rename from src/components/pages/Locations/LocationCard/Components/Area.LocationCard.tsx rename to src/modules/locations/location/components/Area.tsx index 77b896bd..c91f0ba1 100644 --- a/src/components/pages/Locations/LocationCard/Components/Area.LocationCard.tsx +++ b/src/modules/locations/location/components/Area.tsx @@ -1,6 +1,7 @@ -import { ILocation } from '@/types/Locations/Location'; -import { removeDash } from '@/utils/Typography'; -import { LocationNav, LocationNavContainer } from '../../Styled.Locations'; +import styles from '@/modules/locations/Locations.module.scss'; +import { removeDash } from '@/utils'; + +import type { ILocation } from '@/types'; type Props = { location?: ILocation; @@ -8,10 +9,10 @@ type Props = { toggleTable: (index: number) => void; }; -function AreaLocationCard({ location, toggleState, toggleTable }: Props) { +export function Area({ location, toggleState, toggleTable }: Props) { return ( - <LocationNavContainer> - <LocationNav> + <section className={styles.navSection}> + <nav className={styles.nav}> {location?.areas?.map((la, i) => ( <button key={la.name} @@ -25,10 +26,8 @@ function AreaLocationCard({ location, toggleState, toggleTable }: Props) { </p> </button> ))} - </LocationNav> + </nav> <span>There is no information about this area</span> - </LocationNavContainer> + </section> ); } - -export default AreaLocationCard; diff --git a/src/modules/locations/location/components/index.ts b/src/modules/locations/location/components/index.ts new file mode 100644 index 00000000..1a0ad47f --- /dev/null +++ b/src/modules/locations/location/components/index.ts @@ -0,0 +1 @@ +export * from './Area'; diff --git a/src/modules/locations/location/hooks/index.ts b/src/modules/locations/location/hooks/index.ts new file mode 100644 index 00000000..7fd4f634 --- /dev/null +++ b/src/modules/locations/location/hooks/index.ts @@ -0,0 +1 @@ +export * from './useSwitchGame'; diff --git a/src/components/pages/Locations/LocationCard/Hooks/useSwitchGame.tsx b/src/modules/locations/location/hooks/useSwitchGame.tsx similarity index 90% rename from src/components/pages/Locations/LocationCard/Hooks/useSwitchGame.tsx rename to src/modules/locations/location/hooks/useSwitchGame.tsx index ecc3bcc5..d767ae65 100644 --- a/src/components/pages/Locations/LocationCard/Hooks/useSwitchGame.tsx +++ b/src/modules/locations/location/hooks/useSwitchGame.tsx @@ -1,13 +1,19 @@ -import { ILocation } from '@/types/Locations/Location'; -import { ILocationArea } from '@/types/Locations/LocationArea'; +import { useEffect, useState } from 'react'; + +import { + useQueries, + useQuery, + type UseQueryResult, +} from '@tanstack/react-query'; + import { getArea, getEncounterCondition, getEncounterMethod, getLocation, -} from '@/utils/DataFetch'; -import { useQueries, useQuery, UseQueryResult } from '@tanstack/react-query'; -import { useEffect, useState } from 'react'; +} from '@/utils'; + +import type { ILocation, ILocationArea } from '@/types'; export const useSwitchGame = (name: string) => { const [game, setGame] = useState<string | null>(null); diff --git a/src/modules/locations/location/index.ts b/src/modules/locations/location/index.ts new file mode 100644 index 00000000..54332a9c --- /dev/null +++ b/src/modules/locations/location/index.ts @@ -0,0 +1,3 @@ +export * from './components'; +export * from './hooks'; +export * from './Heading'; diff --git a/src/components/pages/Machines/Heading.tsx b/src/modules/machines/Heading.tsx similarity index 91% rename from src/components/pages/Machines/Heading.tsx rename to src/modules/machines/Heading.tsx index 0ae11283..16fa61da 100644 --- a/src/components/pages/Machines/Heading.tsx +++ b/src/modules/machines/Heading.tsx @@ -1,6 +1,6 @@ import Head from 'next/head'; -function HeadingMachines() { +export function Heading() { return ( <Head> <title>Machines | Pokeref @@ -18,5 +18,3 @@ function HeadingMachines() { ); } - -export default HeadingMachines; diff --git a/src/modules/machines/index.ts b/src/modules/machines/index.ts new file mode 100644 index 00000000..6406e7b0 --- /dev/null +++ b/src/modules/machines/index.ts @@ -0,0 +1 @@ +export * from './Heading'; diff --git a/src/components/pages/Moves/Heading.tsx b/src/modules/moves/Heading.tsx similarity index 91% rename from src/components/pages/Moves/Heading.tsx rename to src/modules/moves/Heading.tsx index 3aa96701..4aaf2105 100644 --- a/src/components/pages/Moves/Heading.tsx +++ b/src/modules/moves/Heading.tsx @@ -1,6 +1,6 @@ import Head from 'next/head'; -function HeadingMoves() { +export function Heading() { return ( Moves | Pokeref @@ -18,5 +18,3 @@ function HeadingMoves() { ); } - -export default HeadingMoves; diff --git a/src/components/pages/Moves/Styled.Moves.tsx b/src/modules/moves/Moves.module.scss similarity index 60% rename from src/components/pages/Moves/Styled.Moves.tsx rename to src/modules/moves/Moves.module.scss index 5d153774..ef83c344 100644 --- a/src/components/pages/Moves/Styled.Moves.tsx +++ b/src/modules/moves/Moves.module.scss @@ -1,7 +1,6 @@ -import { device } from '@/components/common/styles/Sizing'; -import styled from 'styled-components'; +@use '@/styles/abstracts' as *; -export const SearchContainer = styled.div` +.search { display: grid; grid-template-columns: 1fr 2fr; gap: 1rem; @@ -11,12 +10,12 @@ export const SearchContainer = styled.div` margin-bottom: 0; } - @media ${device.md} { + @include md { grid-template-areas: '. search search'; } -`; +} -export const StatusMoves = styled.td` +.status { display: flex; align-items: center; justify-content: center; @@ -27,31 +26,34 @@ export const StatusMoves = styled.td` display: inline-block; text-transform: capitalize; border-bottom: 1px solid transparent; - transition: 0.3s ease-in-out; cursor: pointer; &:hover { - border-bottom: 1px solid ${({ theme }) => theme.secondary}; + @include themed { + border-bottom: 1px solid t('text'); + } } } -`; +} -export const StatsMoves = styled.td` +.stats { & a { display: flex; justify-content: center; width: 100%; margin: 0.5rem; + & p { width: fit-content; text-transform: capitalize; border-bottom: 1px solid transparent; cursor: pointer; - transition: 0.3s ease-in-out; &:hover { - border-bottom: 1px solid ${({ theme }) => theme.secondary}; + @include themed { + border-bottom: 1px solid t('text'); + } } } } -`; +} diff --git a/src/modules/moves/components/Moves.tsx b/src/modules/moves/components/Moves.tsx new file mode 100644 index 00000000..93f07930 --- /dev/null +++ b/src/modules/moves/components/Moves.tsx @@ -0,0 +1,92 @@ +import { useMemo } from 'react'; + +import { type ColumnDef } from '@tanstack/react-table'; +import Image from 'next/image'; +import Link from 'next/link'; + +import { usePaginatedTableParams } from '@/hooks'; +import { removeDash } from '@/utils'; + +import styles from '../Moves.module.scss'; +import { Search } from './Search'; + +import type { IMove } from '@/types'; + +type Props = { + moves?: IMove[]; +}; + +export function Moves({ moves }: Props) { + const data = useMemo(() => moves, [moves]); + + const columns = useMemo[]>( + () => [ + { + accessorKey: `name`, + id: `sort`, + header: `Name`, + cell: (info) => ( + + ()} + href={{ + pathname: `/move/[name]`, + query: { name: info.getValue() }, + }} + > + {removeDash(info.getValue())} + + + ), + }, + { + accessorKey: `damage_class.name`, + id: `category`, + header: `Category`, + cell: (info) => ( + ()}> +
    + {info.getValue<string()} + width={20} + height={20} + src={`/images/status/move-${info.getValue()}.png`} + /> + {info.getValue()} +
    + + ), + }, + { + accessorFn: (row) => + row.flavor_text_entries.find((rf) => { + return rf.language.name === `en` && rf.flavor_text !== `Dummy Data`; + })?.flavor_text || `-`, + id: `effect`, + header: `Effect`, + cell: (info) => {info.getValue()}, + }, + ], + [], + ); + + const { tableContainerRef, tableHeader, tableBody, tablePagination } = + usePaginatedTableParams(data, columns); + + return ( +
    +
    +

    Moves

    + +
    +
    + + {tableHeader()} + {tableBody()} +
    + {tablePagination()} +
    +
    + ); +} diff --git a/src/components/pages/Moves/Components/Search.Moves.tsx b/src/modules/moves/components/Search.tsx similarity index 66% rename from src/components/pages/Moves/Components/Search.Moves.tsx rename to src/modules/moves/components/Search.tsx index 5b33e029..5f9b5ae8 100644 --- a/src/components/pages/Moves/Components/Search.Moves.tsx +++ b/src/modules/moves/components/Search.tsx @@ -1,20 +1,19 @@ -import { - AutocompleteContainer, - AutocompleteId, - AutocompleteInput, - AutocompleteLink, -} from '@/components/common/styles/Autocomplete'; -import { IMove } from '@/types/Moves/Move'; -import ImageWithFallback from '@/utils/ImageWithFallback'; -import { capitalize, removeDash } from '@/utils/Typography'; -import Fuse from 'fuse.js'; import { useState } from 'react'; +import * as Label from '@radix-ui/react-label'; +import Fuse from 'fuse.js'; +import Link from 'next/link'; + +import { Input } from '@/components'; +import { ImageWithFallback, capitalize, removeDash } from '@/utils'; + +import type { IMove } from '@/types'; + type Props = { moves?: IMove[]; }; -function SearchMoves({ moves }: Props) { +export function Search({ moves }: Props) { const [searchRes, setSearchRes] = useState[]>([]); const [searchText, setSearchText] = useState(``); @@ -30,15 +29,15 @@ function SearchMoves({ moves }: Props) { }; return ( - - - + Search + searchMoves(e.target.value)} /> {searchText && ( - +
      {searchRes && searchRes?.map((res) => ( @@ -50,25 +49,23 @@ function SearchMoves({ moves }: Props) { height={32} fallbackSrc={`/images/other/unknown.png`} /> - {capitalize(removeDash(res.item.name))} - - + + {capitalize(res.item.type.name)} - + ))}
    - +
    )} -
    + ); } - -export default SearchMoves; diff --git a/src/components/pages/Moves/Components/StatsTable.Moves.tsx b/src/modules/moves/components/Stats.tsx similarity index 72% rename from src/components/pages/Moves/Components/StatsTable.Moves.tsx rename to src/modules/moves/components/Stats.tsx index a3475fa7..f962dcb5 100644 --- a/src/components/pages/Moves/Components/StatsTable.Moves.tsx +++ b/src/modules/moves/components/Stats.tsx @@ -1,24 +1,20 @@ -import { LeftH2 } from '@/components/common/styles/Headings'; -import { - FullWidthTable, - TableContainer, - TBold, - TCapitalize, -} from '@/components/common/styles/Table'; -import { useTableParams } from '@/hooks/useTableParams'; -import { INature } from '@/types/Pokemon/Nature'; -import { IMoveStatAffect, IStat } from '@/types/Pokemon/Stat'; -import { removeDash } from '@/utils/Typography'; -import { ColumnDef } from '@tanstack/react-table'; -import Link from 'next/link'; import { useMemo } from 'react'; -import { StatsMoves } from '../Styled.Moves'; + +import { type ColumnDef } from '@tanstack/react-table'; +import Link from 'next/link'; + +import { useTableParams } from '@/hooks'; +import { removeDash } from '@/utils'; + +import styles from '../Moves.module.scss'; + +import type { IMoveStatAffect, INature, IStat } from '@/types'; type Props = { stats?: IStat[]; }; -function StatsTable({ stats }: Props) { +export function Stats({ stats }: Props) { const data = useMemo(() => stats?.filter((s) => s.name !== `hp`), [stats]); const columns = useMemo[]>( @@ -30,7 +26,7 @@ function StatsTable({ stats }: Props) { accessorKey: `name`, id: `sort`, cell: (info) => ( - {removeDash(info.getValue())} + {removeDash(info.getValue())} ), }, ], @@ -42,7 +38,7 @@ function StatsTable({ stats }: Props) { accessorKey: `affecting_moves.increase`, header: `Increase`, cell: (info) => ( - + {info.getValue().map((i) => ( ))} - + ), }, { accessorKey: `affecting_moves.decrease`, header: `Decrease`, cell: (info) => ( - + {info.getValue().map((i) => ( ))} - + ), }, ], @@ -89,22 +85,22 @@ function StatsTable({ stats }: Props) { accessorKey: `affecting_natures.increase`, header: `Increase`, cell: (info) => ( - + {info.getValue().map((i) => (

    {i.name}

    ))} -
    + ), }, { accessorKey: `affecting_natures.decrease`, header: `Decrease`, cell: (info) => ( - + {info.getValue().map((i) => (

    {i.name}

    ))} -
    + ), }, ], @@ -120,15 +116,13 @@ function StatsTable({ stats }: Props) { return (
    - Stats - - +

    Stats

    +
    + {tableHeader()} {tableBody()} - - +
    +
    ); } - -export default StatsTable; diff --git a/src/components/pages/Moves/Components/StatusTable.Moves.tsx b/src/modules/moves/components/Status.tsx similarity index 55% rename from src/components/pages/Moves/Components/StatusTable.Moves.tsx rename to src/modules/moves/components/Status.tsx index 7ef64b1c..54fe80db 100644 --- a/src/components/pages/Moves/Components/StatusTable.Moves.tsx +++ b/src/modules/moves/components/Status.tsx @@ -1,24 +1,20 @@ import { useMemo } from 'react'; -import { LeftH2 } from '@/components/common/styles/Headings'; -import { - FullWidthTable, - TableContainer, - TBold, -} from '@/components/common/styles/Table'; -import { useTableParams } from '@/hooks/useTableParams'; -import { IMove } from '@/types/Moves/Move'; -import { IMoveAilment } from '@/types/Moves/MoveAilment'; -import { removeDash } from '@/utils/Typography'; -import { ColumnDef } from '@tanstack/react-table'; +import { type ColumnDef } from '@tanstack/react-table'; import Link from 'next/link'; -import { StatusMoves } from '../Styled.Moves'; + +import { useTableParams } from '@/hooks'; +import { removeDash } from '@/utils'; + +import styles from '../Moves.module.scss'; + +import type { IMove, IMoveAilment } from '@/types'; type Props = { status?: IMoveAilment[]; }; -function StatusTable({ status }: Props) { +export function Status({ status }: Props) { const data = useMemo( () => status?.filter((s) => s.name !== `none`), [status], @@ -30,13 +26,15 @@ function StatusTable({ status }: Props) { accessorKey: `name`, id: `sort`, header: `Status`, - cell: (info) => {removeDash(info.getValue())}, + cell: (info) => ( + {removeDash(info.getValue())} + ), }, { accessorFn: (row) => row.moves, header: `Moves`, cell: (info) => ( - + {info.getValue().map((i) => ( ))} - + ), }, ], @@ -62,15 +60,13 @@ function StatusTable({ status }: Props) { return ( <> - Status - - +

    Status

    +
    + {tableHeader()} {tableBody()} - - +
    +
    ); } - -export default StatusTable; diff --git a/src/modules/moves/components/index.ts b/src/modules/moves/components/index.ts new file mode 100644 index 00000000..89f82416 --- /dev/null +++ b/src/modules/moves/components/index.ts @@ -0,0 +1,4 @@ +export * from './Moves'; +export * from './Search'; +export * from './Stats'; +export * from './Status'; diff --git a/src/modules/moves/hooks/index.ts b/src/modules/moves/hooks/index.ts new file mode 100644 index 00000000..f0774f7f --- /dev/null +++ b/src/modules/moves/hooks/index.ts @@ -0,0 +1 @@ +export * from './useMovesQuery'; diff --git a/src/modules/moves/hooks/useMovesQuery.tsx b/src/modules/moves/hooks/useMovesQuery.tsx new file mode 100644 index 00000000..beec00f1 --- /dev/null +++ b/src/modules/moves/hooks/useMovesQuery.tsx @@ -0,0 +1,24 @@ +import { useQueries } from '@tanstack/react-query'; + +import { getMoves, getStats, getStatus } from '@/utils'; + +export const useMovesQuery = () => { + const [moves, status, stats] = useQueries({ + queries: [ + { + queryKey: [`moves`], + queryFn: getMoves, + }, + { + queryKey: [`status`], + queryFn: getStatus, + }, + { + queryKey: [`stats`], + queryFn: getStats, + }, + ], + }); + + return { moves, status, stats }; +}; diff --git a/src/modules/moves/index.ts b/src/modules/moves/index.ts new file mode 100644 index 00000000..54332a9c --- /dev/null +++ b/src/modules/moves/index.ts @@ -0,0 +1,3 @@ +export * from './components'; +export * from './hooks'; +export * from './Heading'; diff --git a/src/components/pages/Moves/MoveCard/Heading.tsx b/src/modules/moves/move/Heading.tsx similarity index 87% rename from src/components/pages/Moves/MoveCard/Heading.tsx rename to src/modules/moves/move/Heading.tsx index b78947cc..37028c2c 100644 --- a/src/components/pages/Moves/MoveCard/Heading.tsx +++ b/src/modules/moves/move/Heading.tsx @@ -1,11 +1,10 @@ import Head from 'next/head'; -import React from 'react'; type Props = { name: string; }; -function HeadingMove({ name }: Props) { +export function Heading({ name }: Props) { return ( @@ -24,5 +23,3 @@ function HeadingMove({ name }: Props) { </Head> ); } - -export default HeadingMove; diff --git a/src/components/pages/Moves/MoveCard/Styled.MoveCard.tsx b/src/modules/moves/move/Move.module.scss similarity index 58% rename from src/components/pages/Moves/MoveCard/Styled.MoveCard.tsx rename to src/modules/moves/move/Move.module.scss index d11a21d5..f6af4f09 100644 --- a/src/components/pages/Moves/MoveCard/Styled.MoveCard.tsx +++ b/src/modules/moves/move/Move.module.scss @@ -1,8 +1,7 @@ -import Link from 'next/link'; -import styled from 'styled-components'; -import { device, MainBig } from '../../../common/styles/Sizing'; +@use '@/styles/abstracts' as *; +@use '@/styles/common' as *; -export const MoveList = styled.ul` +.list { min-height: 25vh; display: flex; align-items: center; @@ -19,18 +18,17 @@ export const MoveList = styled.ul` width: 21rem; height: 32rem; padding: 2rem 3rem; - background: rgba(255, 255, 255, 0.4); + background: rgb(255 255 255 / 40%); border-radius: 5px; font-size: 1.5rem; text-align: center; border: 1px solid transparent; - transition: 0.3s ease-in-out; &:hover { - border: 1px solid ${({ theme }) => theme.red}; + border: 1px solid $red; } - @media ${device.sm} { + @include sm { width: 18rem; height: 27rem; margin: 2rem; @@ -42,43 +40,44 @@ export const MoveList = styled.ul` margin-bottom: 0; } - @media ${device.sm} { + @include sm { justify-content: space-evenly; } -`; +} -export const MoveText = styled.p` +.text { margin: 0 0 3rem; font-size: 1.5rem; & span { text-transform: capitalize; } -`; +} -export const MoveLink = styled(Link)` +.link { font-size: 3rem; - font-family: 'Oswald', sans-serif; + font-family: Oswald, sans-serif; text-transform: capitalize; - transition: 0.3s ease-in-out; cursor: pointer; &:hover { - color: ${({ theme }) => theme.red}; + color: $red; } -`; +} -export const MoveListEmpty = styled.span` +.empty { width: 100%; min-height: 25vh; display: none; font-size: 2rem; font-weight: 600; text-align: center; -`; +} -export const MoveMainBig = styled(MainBig)` - & ${MoveList}:empty + ${MoveListEmpty} { +.main { + @extend %mainBig; + + & .list:empty + .empty { display: block; } -`; +} diff --git a/src/components/pages/Moves/MoveCard/Data/Styled.Data.MoveCard.tsx b/src/modules/moves/move/components/data/Data.module.scss similarity index 55% rename from src/components/pages/Moves/MoveCard/Data/Styled.Data.MoveCard.tsx rename to src/modules/moves/move/components/data/Data.module.scss index a53332b8..1a9b0565 100644 --- a/src/components/pages/Moves/MoveCard/Data/Styled.Data.MoveCard.tsx +++ b/src/modules/moves/move/components/data/Data.module.scss @@ -1,23 +1,26 @@ -import styled from 'styled-components'; -import { device, Section } from '@/components/common/styles/Sizing'; -import { Table, TType } from '@/components/common/styles/Table'; +@use '@/styles/abstracts' as *; +@use '@/styles/common' as *; + +.section { + @extend %section; -export const MoveCardDataSection = styled(Section)` display: grid; grid-template-columns: 1fr 1.3fr; column-gap: 3rem; - @media ${device.sm} { + @include sm { display: flex; align-items: center; justify-content: center; flex-direction: column-reverse; } -`; +} + +.table { + @extend %table; -export const MoveCardDataTable = styled(Table)` & th { - background: rgba(130, 130, 130, 0.2); + background: rgb(130 130 130 / 20%); } & td { @@ -27,18 +30,20 @@ export const MoveCardDataTable = styled(Table)` text-transform: capitalize; } - @media ${device.sm} { + @include sm { width: 100%; } -`; +} + +.type { + @extend %tType; -export const MoveCardDataType = styled(TType)` & div { margin: 0; } -`; +} -export const MoveCardDataCategory = styled.td` +.category { & div { display: flex; align-items: center; @@ -47,7 +52,7 @@ export const MoveCardDataCategory = styled.td` & img { vertical-align: middle; - @media ${device.sm} { + @include sm { width: 25px; height: 25px; } @@ -59,37 +64,37 @@ export const MoveCardDataCategory = styled.td` vertical-align: middle; } } -`; +} -export const MoveCardDataList = styled.ul` +.list { margin-top: 2rem; & li { margin: 0 0 2rem; } - @media ${device.sm} { + @include sm { width: 100%; margin: 0 0 2rem; } -`; +} -export const MoveCardDataText = styled.p` +.text { font-size: 1.7rem; -`; +} -export const MoveCardDataMeta = styled.ul` +.meta { margin-top: 1rem; font-size: 1.5rem; -`; +} -export const MoveCardDataStat = styled.ul` +.stat { margin-left: 2rem; font-size: 1.5rem; -`; +} -export const MoveCardDataTarget = styled.p` +.target { text-transform: capitalize; margin-left: 2rem; font-size: 1.5rem; -`; +} diff --git a/src/modules/moves/move/components/data/Data.tsx b/src/modules/moves/move/components/data/Data.tsx new file mode 100644 index 00000000..b3b1f017 --- /dev/null +++ b/src/modules/moves/move/components/data/Data.tsx @@ -0,0 +1,20 @@ +import styles from './Data.module.scss'; +import { Description } from './description'; +import { Effect } from './effect'; + +import type { IMachine, IMove } from '@/types'; + +type Props = { + move: IMove; + machine?: IMachine[]; + version: string; +}; + +export function Data({ move, machine, version }: Props) { + return ( + <section className={styles.section}> + <Description move={move} machine={machine} version={version} /> + <Effect move={move} version={version} /> + </section> + ); +} diff --git a/src/components/pages/Moves/MoveCard/Data/Desc/Desc.MoveCard.tsx b/src/modules/moves/move/components/data/description/Description.tsx similarity index 73% rename from src/components/pages/Moves/MoveCard/Data/Desc/Desc.MoveCard.tsx rename to src/modules/moves/move/components/data/description/Description.tsx index 9704bdeb..3b8488f4 100644 --- a/src/components/pages/Moves/MoveCard/Data/Desc/Desc.MoveCard.tsx +++ b/src/modules/moves/move/components/data/description/Description.tsx @@ -1,14 +1,9 @@ -import { Small } from '@/components/common/styles/Headings'; -import { Type } from '@/components/common/styles/Themes'; -import { IMachine } from '@/types/Machines/Machine'; -import { IMove } from '@/types/Moves/Move'; import Image from 'next/image'; import Link from 'next/link'; -import { - MoveCardDataCategory, - MoveCardDataTable, - MoveCardDataType, -} from '../Styled.Data.MoveCard'; + +import styles from '../Data.module.scss'; + +import type { IMachine, IMove } from '@/types'; type Props = { move: IMove; @@ -16,17 +11,17 @@ type Props = { machine?: IMachine[]; }; -function Desc({ move, version, machine }: Props) { +export function Description({ move, version, machine }: Props) { // Calculate the max number of pp for a move const maxPp = move.pp * 1.6; return ( - <MoveCardDataTable> + <table className={styles.table}> <tbody> <tr> <th>Type</th> - <MoveCardDataType> - <Type id={move?.type?.name}> + <td className={styles.type}> + <div className="type" id={move?.type?.name}> <Link href={{ pathname: `/type/[name]`, @@ -42,12 +37,12 @@ function Desc({ move, version, machine }: Props) { /> <span>{move?.type?.name}</span> </Link> - </Type> - </MoveCardDataType> + </div> + </td> </tr> <tr> <th>Category</th> - <MoveCardDataCategory id={move.damage_class.name}> + <td className={styles.category} id={move.damage_class.name}> <div> <Image src={`/images/status/move-${move.damage_class.name}.png`} @@ -57,7 +52,7 @@ function Desc({ move, version, machine }: Props) { /> <span>{move.damage_class.name}</span> </div> - </MoveCardDataCategory> + </td> </tr> {machine?.map( (ma) => @@ -77,7 +72,7 @@ function Desc({ move, version, machine }: Props) { <tr> <th>PP</th> <td> - {move.pp} <Small>(max. {maxPp})</Small> + {move.pp} <small className="small">(max. {maxPp})</small> </td> </tr> <tr> @@ -93,8 +88,6 @@ function Desc({ move, version, machine }: Props) { <td>{move.priority}</td> </tr> </tbody> - </MoveCardDataTable> + </table> ); } - -export default Desc; diff --git a/src/modules/moves/move/components/data/description/index.ts b/src/modules/moves/move/components/data/description/index.ts new file mode 100644 index 00000000..2b6c4564 --- /dev/null +++ b/src/modules/moves/move/components/data/description/index.ts @@ -0,0 +1 @@ +export * from './Description'; diff --git a/src/components/pages/Moves/MoveCard/Data/Effect/Effect.MoveCard.tsx b/src/modules/moves/move/components/data/effect/Effect.tsx similarity index 72% rename from src/components/pages/Moves/MoveCard/Data/Effect/Effect.MoveCard.tsx rename to src/modules/moves/move/components/data/effect/Effect.tsx index 7e688e46..416e459b 100644 --- a/src/components/pages/Moves/MoveCard/Data/Effect/Effect.MoveCard.tsx +++ b/src/modules/moves/move/components/data/effect/Effect.tsx @@ -1,27 +1,18 @@ -/* eslint-disable react/no-unescaped-entities */ -import { Bold, Capitalize, H3, H4 } from '@/components/common/styles/Headings'; -import SmallLoader from '@/components/common/ui/Loader/SmallLoader'; -import { IMove } from '@/types/Moves/Move'; -import { IMoveTarget } from '@/types/Moves/MoveTarget'; -import { IDescription } from '@/types/Utility/CommonModels'; -import { getMoveTarget } from '@/utils/DataFetch'; -import { removeDash } from '@/utils/Typography'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; -import toast from 'react-hot-toast'; -import { - MoveCardDataList, - MoveCardDataMeta, - MoveCardDataStat, - MoveCardDataTarget, - MoveCardDataText, -} from '../Styled.Data.MoveCard'; +import { type UseQueryResult, useQuery } from '@tanstack/react-query'; + +import { ErrorToast, SmallLoader } from '@/components'; +import { getMoveTarget, removeDash } from '@/utils'; + +import styles from '../Data.module.scss'; + +import type { IDescription, IMove, IMoveTarget } from '@/types'; type Props = { move: IMove; version: string; }; -function Effect({ move, version }: Props) { +export function Effect({ move, version }: Props) { const { isLoading, isError, @@ -37,11 +28,7 @@ function Effect({ move, version }: Props) { }; if (isError) { - return toast.error(`Something went wrong: ${error?.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -49,15 +36,15 @@ function Effect({ move, version }: Props) { } return ( - <MoveCardDataList> + <ul className={styles.list}> <li> - <H3>Effects</H3> + <h3 className="h3">Effects</h3> - <MoveCardDataText> - <Capitalize> + <p className={styles.text}> + <span className="capitalize"> <i>{removeDash(move?.name)}</i> {` `} - </Capitalize> + </span> {move.effect_entries ?.find((me) => me.language.name === `en`) ?.short_effect.replace( @@ -75,14 +62,14 @@ function Effect({ move, version }: Props) { ?.flavor_text.replace(/(?<=(?:^|[.?!])\W*)[a-z]/g, (i) => i.toUpperCase(), )} - </MoveCardDataText> + </p> - <MoveCardDataMeta> + <ul className={styles.meta}> {move?.meta.ailment?.name !== `none` && ( <li> <p> - <Bold>Status</Bold> :{` `} - <Capitalize>{move.meta.ailment.name}</Capitalize> + <span className="bold">Status</span> :{` `} + <span className="capitalize">{move.meta.ailment.name}</span> </p> <p> {move?.meta?.ailment_chance !== 0 && ( @@ -132,14 +119,14 @@ function Effect({ move, version }: Props) { move.meta.min_turns === move.meta.max_turns && ( <li>This move last {move.meta.min_turns} turns</li> )} - </MoveCardDataMeta> + </ul> </li> <li> {move.stat_changes.length > 0 && ( <> - <H4>Stat modification</H4> - <MoveCardDataStat> + <h4 className="h4">Stat modification</h4> + <ul className={styles.stat}> {move.stat_changes?.map((ms) => ms.change < 0 ? ( <li key={ms.stat.name}> @@ -148,7 +135,11 @@ function Effect({ move, version }: Props) { `has a ${move.meta.stat_chance}% chance to`} {` `} lower the target's{` `} - <Capitalize>{removeDash(ms.stat.name)}</Capitalize> by{` `} + <span className="capitalize"> + {removeDash(ms.stat.name)} + </span> + {` `} + by{` `} {Math.abs(ms.change)} stage </li> ) : ( @@ -159,13 +150,13 @@ function Effect({ move, version }: Props) { : `raises`} {` `} the target's{` `} - <Capitalize>{ms.stat.name}</Capitalize> + <span className="capitalize">{ms.stat.name}</span> {` `} by {Math.abs(ms.change)} stage </li> ), )} - </MoveCardDataStat> + </ul> </> )} </li> @@ -173,20 +164,20 @@ function Effect({ move, version }: Props) { <li> {move.past_values.length > 0 && ( <> - <H4>Changes</H4> - <MoveCardDataStat> + <h4 className="h4">Changes</h4> + <ul className={styles.stat}> {move.past_values?.map((mp) => ( <> {mp.power && ( <li> Before{` `} - <Capitalize> + <span className="capitalize"> {removeDash(mp.version_group.name)} - </Capitalize> + </span> {` `}:{` `} - <Capitalize> + <span className="capitalize"> <i>{removeDash(move.name)}</i> - </Capitalize> + </span> {` `} had {mp.power} base power </li> @@ -194,13 +185,13 @@ function Effect({ move, version }: Props) { {mp.accuracy && ( <li> Before{` `} - <Capitalize> + <span className="capitalize"> {removeDash(mp.version_group.name)} - </Capitalize> + </span> {` `}:{` `} - <Capitalize> + <span className="capitalize"> <i>{removeDash(move.name)}</i> - </Capitalize> + </span> {` `} had {mp.accuracy} accuracy </li> @@ -208,13 +199,13 @@ function Effect({ move, version }: Props) { {mp.pp && ( <li> Before{` `} - <Capitalize> + <span className="capitalize"> {removeDash(mp.version_group.name)} - </Capitalize> + </span> {` `}:{` `} - <Capitalize> + <span className="capitalize"> <i>{removeDash(move.name)}</i> - </Capitalize> + </span> {` `} had {mp.pp} PP </li> @@ -222,36 +213,34 @@ function Effect({ move, version }: Props) { {mp.type && ( <li> Before{` `} - <Capitalize> + <span className="capitalize"> {removeDash(mp.version_group.name)} - </Capitalize> + </span> {` `}:{` `} - <Capitalize> + <span className="capitalize"> <i>{removeDash(move.name)}</i> - </Capitalize> + </span> {` `} was {mp.type?.name} type </li> )} </> ))} - </MoveCardDataStat> + </ul> </> )} </li> <li> - <H4>Target</H4> - <MoveCardDataTarget> + <h4 className="h4">Target</h4> + <p className={styles.target}> { filteredTarget(move.target.name)?.descriptions.find( (td: IDescription) => td.language.name === `en`, )?.description } - </MoveCardDataTarget> + </p> </li> - </MoveCardDataList> + </ul> ); } - -export default Effect; diff --git a/src/modules/moves/move/components/data/effect/index.ts b/src/modules/moves/move/components/data/effect/index.ts new file mode 100644 index 00000000..db431134 --- /dev/null +++ b/src/modules/moves/move/components/data/effect/index.ts @@ -0,0 +1 @@ +export * from './Effect'; diff --git a/src/modules/moves/move/components/data/index.ts b/src/modules/moves/move/components/data/index.ts new file mode 100644 index 00000000..4ef61080 --- /dev/null +++ b/src/modules/moves/move/components/data/index.ts @@ -0,0 +1,3 @@ +export * from './Data'; +export * from './description'; +export * from './effect'; diff --git a/src/modules/moves/move/components/index.ts b/src/modules/moves/move/components/index.ts new file mode 100644 index 00000000..1e8ae101 --- /dev/null +++ b/src/modules/moves/move/components/index.ts @@ -0,0 +1,3 @@ +export * from './data'; +export * from './list'; +export * from './nav'; diff --git a/src/components/pages/Moves/MoveCard/List/List.MoveCard.tsx b/src/modules/moves/move/components/list/List.tsx similarity index 75% rename from src/components/pages/Moves/MoveCard/List/List.MoveCard.tsx rename to src/modules/moves/move/components/list/List.tsx index a758c53a..570452e5 100644 --- a/src/components/pages/Moves/MoveCard/List/List.MoveCard.tsx +++ b/src/modules/moves/move/components/list/List.tsx @@ -1,13 +1,15 @@ -import SmallLoader from '@/components/common/ui/Loader/SmallLoader'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import Content from './Content/Content.MoveCard'; +import { SmallLoader } from '@/components'; + +import { Content } from './content'; import { BreedingMoveText, EvolvingMoveText, LevelMoveText, MachinesMoveText, TutorMoveText, -} from './Text/Text.MoveCard'; +} from './text/Text'; + +import type { IPokemon } from '@/types'; type Props = { pokemon?: IPokemon[]; @@ -17,7 +19,7 @@ type Props = { toggle: number; }; -function List({ pokemon, status, moveName, version, toggle }: Props) { +export function List({ pokemon, status, moveName, version, toggle }: Props) { const textShown = () => { if (toggle === 0) { return <LevelMoveText version={version} />; @@ -48,5 +50,3 @@ function List({ pokemon, status, moveName, version, toggle }: Props) { </> ); } - -export default List; diff --git a/src/components/pages/Moves/MoveCard/List/Content/Content.MoveCard.tsx b/src/modules/moves/move/components/list/content/Content.tsx similarity index 77% rename from src/components/pages/Moves/MoveCard/List/Content/Content.MoveCard.tsx rename to src/modules/moves/move/components/list/content/Content.tsx index ebddcdb3..2d1f0a13 100644 --- a/src/components/pages/Moves/MoveCard/List/Content/Content.MoveCard.tsx +++ b/src/modules/moves/move/components/list/content/Content.tsx @@ -1,11 +1,10 @@ -import { - MoveLink, - MoveList, - MoveListEmpty, -} from '@/components/pages/Moves/MoveCard/Styled.MoveCard'; -import { IPokemon, IPokemonMoveVersion } from '@/types/Pokemon/Pokemon'; -import ImageWithFallback from '@/utils/ImageWithFallback'; -import { removeDash } from '@/utils/Typography'; +import Link from 'next/link'; + +import { ImageWithFallback, removeDash, removeLongName } from '@/utils'; + +import styles from '../../../Move.module.scss'; + +import type { IPokemon, IPokemonMoveVersion } from '@/types'; type Props = { pokemon?: IPokemon[]; @@ -14,7 +13,7 @@ type Props = { toggle: number; }; -function Content({ pokemon, moveName, version, toggle }: Props) { +export function Content({ pokemon, moveName, version, toggle }: Props) { const conditionFilter = (pmv: IPokemonMoveVersion) => { if (toggle === 0) { return ( @@ -41,7 +40,7 @@ function Content({ pokemon, moveName, version, toggle }: Props) { return ( <> - <MoveList> + <ul className={styles.list}> {pokemon?.map((p) => p.moves.map( (pm) => @@ -58,15 +57,16 @@ function Content({ pokemon, moveName, version, toggle }: Props) { height={96} fallbackSrc={`/images/other/unknown.png`} /> - <MoveLink + <Link + className={styles.link} href={{ pathname: `/pokemon/[name]`, query: { name: p.name }, }} key={p.name} > - {removeDash(p.name)} - </MoveLink> + {removeLongName(removeDash(p.name))} + </Link> {pmv.level_learned_at > 1 && ( <p>Level {pmv.level_learned_at}</p> )} @@ -76,10 +76,10 @@ function Content({ pokemon, moveName, version, toggle }: Props) { ), ), )} - </MoveList> - <MoveListEmpty>This move can't be learned with this method</MoveListEmpty> + </ul> + <span className={styles.empty}> + This move can't be learned with this method + </span> </> ); } - -export default Content; diff --git a/src/modules/moves/move/components/list/content/index.ts b/src/modules/moves/move/components/list/content/index.ts new file mode 100644 index 00000000..b39182a1 --- /dev/null +++ b/src/modules/moves/move/components/list/content/index.ts @@ -0,0 +1 @@ +export * from './Content'; diff --git a/src/modules/moves/move/components/list/index.ts b/src/modules/moves/move/components/list/index.ts new file mode 100644 index 00000000..1a660dfd --- /dev/null +++ b/src/modules/moves/move/components/list/index.ts @@ -0,0 +1,3 @@ +export * from './List'; +export * from './content'; +export * from './text'; diff --git a/src/components/pages/Moves/MoveCard/List/Text/Text.MoveCard.tsx b/src/modules/moves/move/components/list/text/Text.tsx similarity index 58% rename from src/components/pages/Moves/MoveCard/List/Text/Text.MoveCard.tsx rename to src/modules/moves/move/components/list/text/Text.tsx index cf0373c6..7f520b07 100644 --- a/src/components/pages/Moves/MoveCard/List/Text/Text.MoveCard.tsx +++ b/src/modules/moves/move/components/list/text/Text.tsx @@ -1,6 +1,6 @@ -import { H3 } from '@/components/common/styles/Headings'; -import { MoveText } from '@/components/pages/Moves/MoveCard/Styled.MoveCard'; -import { removeDash } from '@/utils/Typography'; +import { removeDash } from '@/utils'; + +import styles from '../../../Move.module.scss'; type Props = { version: string; @@ -9,25 +9,26 @@ type Props = { export const LevelMoveText = ({ version }: Props) => { return ( <> - <H3>Learned by leveling up</H3> - <MoveText> + <h3 className="h3">Learned by leveling up</h3> + {` `} + <p className={styles.text}> Learned when the pokémon reach a certain level. Data from Pokémon{` `} <span>{removeDash(version)}</span>. These information may vary in other - games. Check the respective pokédex pages for details. - </MoveText> + games. Check the respective pokédex pages for details.{` `} + </p> </> ); }; - export const MachinesMoveText = ({ version }: Props) => { return ( <> - <H3>Learned from a TM / HM</H3> - <MoveText> + <h3 className="h3">Learned from a TM / HM</h3> + {` `} + <p className={styles.text}> Learned by using a TM or a HM. Data from Pokémon{` `} <span>{removeDash(version)}</span>. These information may vary in other - games. Check the respective pokédex pages for details. - </MoveText> + games. Check the respective pokédex pages for details.{` `} + </p> </> ); }; @@ -35,13 +36,14 @@ export const MachinesMoveText = ({ version }: Props) => { export const BreedingMoveText = ({ version }: Props) => { return ( <> - <H3>Learned from the move relearner / by breeding</H3> - <MoveText> + <h3 className="h3">Learned from the move relearner / by breeding</h3> + {` `} + <p className={styles.text}> Learned via the move relearner or through breeding. Data from Pokémon {` `} <span>{removeDash(version)}</span>. These information may vary in other - games. Check the respective pokédex pages for details. - </MoveText> + games. Check the respective pokédex pages for details.{` `} + </p> </> ); }; @@ -49,12 +51,13 @@ export const BreedingMoveText = ({ version }: Props) => { export const TutorMoveText = ({ version }: Props) => { return ( <> - <H3>Learned from the move tutor</H3> - <MoveText> + <h3 className="h3">Learned from the move tutor</h3> + {` `} + <p className={styles.text}> Learned by going to the move tutor. Data from Pokémon{` `} <span>{removeDash(version)}</span>. These information may vary in other - games. Check the respective pokédex pages for details. - </MoveText> + games. Check the respective pokédex pages for details.{` `} + </p> </> ); }; @@ -62,12 +65,13 @@ export const TutorMoveText = ({ version }: Props) => { export const EvolvingMoveText = ({ version }: Props) => { return ( <> - <H3>Learned when evolving</H3> - <MoveText> + <h3 className="h3">Learned when evolving</h3> + {` `} + <p className={styles.text}> Learned when the pokémon is evolving no matter its level. Data from Pokémon <span>{removeDash(version)}</span>. These information may vary - in other games. Check the respective pokédex pages for details. - </MoveText> + in other games. Check the respective pokédex pages for details.{` `} + </p> </> ); }; diff --git a/src/modules/moves/move/components/list/text/index.ts b/src/modules/moves/move/components/list/text/index.ts new file mode 100644 index 00000000..b0c76af0 --- /dev/null +++ b/src/modules/moves/move/components/list/text/index.ts @@ -0,0 +1 @@ +export * from './Text'; diff --git a/src/components/pages/Moves/MoveCard/Nav/Nav.MoveCard.tsx b/src/modules/moves/move/components/nav/Nav.tsx similarity index 59% rename from src/components/pages/Moves/MoveCard/Nav/Nav.MoveCard.tsx rename to src/modules/moves/move/components/nav/Nav.tsx index 09907b92..fe4011d0 100644 --- a/src/components/pages/Moves/MoveCard/Nav/Nav.MoveCard.tsx +++ b/src/modules/moves/move/components/nav/Nav.tsx @@ -1,44 +1,52 @@ /* eslint-disable react/no-unescaped-entities */ -import { GenNav } from '@/components/common/styles/Navbars'; -import { IMove } from '@/types/Moves/Move'; -import { Dispatch, SetStateAction } from 'react'; +import type { Dispatch, SetStateAction } from 'react'; + +import * as NavigationMenu from '@radix-ui/react-navigation-menu'; + +import type { IMove } from '@/types'; type Props = { move: IMove; setVersion: Dispatch<SetStateAction<string>>; }; -function Nav({ move, setVersion }: Props) { +export function Nav({ move, setVersion }: Props) { return ( - <GenNav> - <ul> + <NavigationMenu.Root className="NavigationMenuRoot"> + <NavigationMenu.List className="NavigationMenuList"> {move?.generation?.name === `generation-i` && ( - <li> - <button>Gen I</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen I + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => setVersion(`red-blue`)}>Red / Blue</button> <button onClick={() => setVersion(`yellow`)}>Yellow</button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(move?.generation?.name === `generation-i` || move?.generation?.name === `generation-ii`) && ( - <li> - <button>Gen II</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen II + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => setVersion(`gold-silver`)}> Gold / Silver </button> <button onClick={() => setVersion(`crystal`)}>Crystal</button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(move?.generation?.name === `generation-i` || move?.generation?.name === `generation-ii` || move?.generation?.name === `generation-iii`) && ( - <li> - <button>Gen III</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen III + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => setVersion(`ruby-sapphire`)}> Ruby / Sapphire </button> @@ -46,16 +54,18 @@ function Nav({ move, setVersion }: Props) { <button onClick={() => setVersion(`firered-greenleaf`)}> Fire Red / Green Leaf </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(move?.generation?.name === `generation-i` || move?.generation?.name === `generation-ii` || move?.generation?.name === `generation-iii` || move?.generation?.name === `generation-iv`) && ( - <li> - <button>Gen IV</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen IV + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => setVersion(`diamond-pearl`)}> Diamond / Pearl </button> @@ -63,25 +73,27 @@ function Nav({ move, setVersion }: Props) { <button onClick={() => setVersion(`heartgold-soulsilver`)}> Heart Gold / Soul Silver </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(move?.generation?.name === `generation-i` || move?.generation?.name === `generation-ii` || move?.generation?.name === `generation-iii` || move?.generation?.name === `generation-iv` || move?.generation?.name === `generation-v`) && ( - <li> - <button>Gen V</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen V + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => setVersion(`black-white`)}> Black / White </button> <button onClick={() => setVersion(`black-2-white-2`)}> Black 2 / White 2 </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(move?.generation?.name === `generation-i` || move?.generation?.name === `generation-ii` || @@ -89,15 +101,17 @@ function Nav({ move, setVersion }: Props) { move?.generation?.name === `generation-iv` || move?.generation?.name === `generation-v` || move?.generation?.name === `generation-vi`) && ( - <li> - <button>Gen VI</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen VI + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => setVersion(`x-y`)}>X / Y</button> <button onClick={() => setVersion(`omega-ruby-alpha-sapphire`)}> Omega Ruby / Alpha Sapphire </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(move?.generation?.name === `generation-i` || move?.generation?.name === `generation-ii` || @@ -106,9 +120,11 @@ function Nav({ move, setVersion }: Props) { move?.generation?.name === `generation-v` || move?.generation?.name === `generation-vi` || move?.generation?.name === `generation-vii`) && ( - <li> - <button>Gen VII</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen VII + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => setVersion(`sun-moon`)}>Sun / Moon</button> <button onClick={() => setVersion(`ultra-sun-ultra-moon`)}> Ultra Sun / Ultra Moon @@ -118,8 +134,8 @@ function Nav({ move, setVersion }: Props) { > Let's Go Pikachu / Let's Go Eevee </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(move?.generation?.name === `generation-i` || move?.generation?.name === `generation-ii` || @@ -129,18 +145,21 @@ function Nav({ move, setVersion }: Props) { move?.generation?.name === `generation-vi` || move?.generation?.name === `generation-vii` || move?.generation?.name === `generation-viii`) && ( - <li> - <button>Gen VIII</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen VIII + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => setVersion(`sword-shield`)}> Sword / Shield </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} - </ul> - </GenNav> + </NavigationMenu.List> + <div className="ViewportPosition"> + <NavigationMenu.Viewport className="NavigationMenuViewport" /> + </div> + </NavigationMenu.Root> ); } - -export default Nav; diff --git a/src/modules/moves/move/components/nav/index.ts b/src/modules/moves/move/components/nav/index.ts new file mode 100644 index 00000000..93467d75 --- /dev/null +++ b/src/modules/moves/move/components/nav/index.ts @@ -0,0 +1 @@ +export * from './Nav'; diff --git a/src/modules/moves/move/hooks/index.ts b/src/modules/moves/move/hooks/index.ts new file mode 100644 index 00000000..858cec8e --- /dev/null +++ b/src/modules/moves/move/hooks/index.ts @@ -0,0 +1 @@ +export * from './useFetchMove'; diff --git a/src/components/pages/Moves/MoveCard/Hooks/useFetchMove.tsx b/src/modules/moves/move/hooks/useFetchMove.tsx similarity index 83% rename from src/components/pages/Moves/MoveCard/Hooks/useFetchMove.tsx rename to src/modules/moves/move/hooks/useFetchMove.tsx index cf7769bb..1bcd0071 100644 --- a/src/components/pages/Moves/MoveCard/Hooks/useFetchMove.tsx +++ b/src/modules/moves/move/hooks/useFetchMove.tsx @@ -1,10 +1,11 @@ -import { IMachine } from '@/types/Machines/Machine'; -import { IMove } from '@/types/Moves/Move'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { getMove, getMoveMachines, getMovePokemon } from '@/utils/DataFetch'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; import { useState } from 'react'; +import { useQuery, type UseQueryResult } from '@tanstack/react-query'; + +import { getMove, getMoveMachines, getMovePokemon } from '@/utils'; + +import type { IMachine, IMove, IPokemon } from '@/types'; + export const useFetchMove = (name: string) => { const { isLoading, diff --git a/src/modules/moves/move/index.ts b/src/modules/moves/move/index.ts new file mode 100644 index 00000000..54332a9c --- /dev/null +++ b/src/modules/moves/move/index.ts @@ -0,0 +1,3 @@ +export * from './components'; +export * from './hooks'; +export * from './Heading'; diff --git a/src/components/pages/Pokemon/Heading.tsx b/src/modules/pokedex/Heading.tsx similarity index 92% rename from src/components/pages/Pokemon/Heading.tsx rename to src/modules/pokedex/Heading.tsx index 95915aaf..831b4630 100644 --- a/src/components/pages/Pokemon/Heading.tsx +++ b/src/modules/pokedex/Heading.tsx @@ -1,7 +1,8 @@ -import Head from 'next/head'; import React from 'react'; -function HeadingPokedex() { +import Head from 'next/head'; + +export function Heading() { return ( <Head> <meta @@ -19,5 +20,3 @@ function HeadingPokedex() { </Head> ); } - -export default HeadingPokedex; diff --git a/src/components/pages/Pokemon/Styled.Pokemon.tsx b/src/modules/pokedex/Pokedex.module.scss similarity index 58% rename from src/components/pages/Pokemon/Styled.Pokemon.tsx rename to src/modules/pokedex/Pokedex.module.scss index e29c8a2c..893179d9 100644 --- a/src/components/pages/Pokemon/Styled.Pokemon.tsx +++ b/src/modules/pokedex/Pokedex.module.scss @@ -1,29 +1,25 @@ -import ImageWithFallback from '@/utils/ImageWithFallback'; -import styled from 'styled-components'; -import { device } from '../../common/styles/Sizing'; +@use '@/styles/abstracts' as *; -export const PokedexSearch = styled.section` +.search { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-areas: 'search form generation'; gap: 2rem; - @media ${device.md} { + @include md { display: grid; - grid-template-columns: 1fr 1fr; - grid-template-rows: 1fr 1fr; - grid-template-areas: + grid-template: 'search search' 'form generation'; row-gap: 2rem; column-gap: 4rem; } -`; +} -export const PokedexDropdown = styled.div` +.dropdown { width: 100%; display: flex; - align-items: start; + align-items: flex-start; justify-content: stretch; flex-direction: column; @@ -40,27 +36,31 @@ export const PokedexDropdown = styled.div` &:last-of-type { grid-area: generation; } -`; +} -export const PokedexVerticalText = styled.p` +.verticalText { @supports (writing-mode: sideways-rl) { display: block; writing-mode: sideways-rl; } + display: none; font-size: 7rem; - color: ${({ theme }) => theme.secondary}; position: fixed; top: 50%; right: 5%; transform: translate(-50%, -50%); - @media ${device.xl} { + @include themed { + color: t('text'); + } + + @include xl { display: none; } -`; +} -export const PokedexList = styled.ul` +.list { max-width: 1300px; min-height: 80vh; margin: 0 auto; @@ -69,9 +69,9 @@ export const PokedexList = styled.ul` justify-content: space-evenly; flex-wrap: wrap; gap: 2rem; -`; +} -export const PokedexElement = styled.li` +.element { width: 21rem; height: 32rem; padding: 2rem 3rem; @@ -80,39 +80,30 @@ export const PokedexElement = styled.li` justify-content: center; flex-direction: column; gap: 1rem; - background: rgba(255, 255, 255, 0.4); + background: rgb(255 255 255 / 40%); border: 1px solid transparent; border-radius: 25px; text-align: center; - transition: 0.3s ease-in-out; & h2 { font-size: 3rem; - font-family: 'Oswald'; + font-family: Oswald, sans-serif; text-transform: capitalize; & a { cursor: pointer; - transition: 0.3s ease-in-out; + &:hover { - color: ${({ theme }) => theme.red}; + color: $red; } } } - & .number { - padding: 0.1rem 0.7rem; - font-size: 1.3rem; - color: #c4c4c4; - background-color: #161616; - border-radius: 50px; - } - &:nth-child(even) { &:hover { border-radius: 10px 50px; - @media ${device.sm} { + @include sm { border-radius: 7px 35px; } } @@ -122,52 +113,58 @@ export const PokedexElement = styled.li` &:hover { border-radius: 50px 10px; - @media ${device.sm} { + @include sm { border-radius: 35px 7px; } } } - @media ${device.sm} { + @include sm { width: 20rem; height: 29rem; padding: 1.5rem 2.5rem; } -`; +} + +.number { + padding: 0.1rem 0.7rem; + font-size: 1.3rem; + color: #c4c4c4; + background-color: #161616; + border-radius: 50px; +} -export const SpriteNormal = styled(ImageWithFallback)` +.sprite { position: relative; top: 0; left: 0; - transition: 0.3s ease-in-out; -`; +} -export const SpriteShiny = styled(ImageWithFallback)` +.shiny { position: absolute; top: 0; left: 0; opacity: 0; - transition: 0.3s ease-in-out; -`; +} -export const PokedexImage = styled.div` +.image { position: relative; margin: 0 auto; - &:hover ${SpriteShiny} { + &:hover .shiny { opacity: 1; z-index: 3; } & img { - @media ${device.sm} { + @include sm { width: 72px; height: 72px; } } -`; +} -export const PokedexTypes = styled.div` +%types { width: 100%; display: flex; align-items: center; @@ -181,13 +178,14 @@ export const PokedexTypes = styled.div` border-radius: 5px; text-transform: uppercase; text-align: center; - color: ${({ theme }) => theme.secondary}; font-size: 1.7rem; - text-shadow: ${({ theme }) => theme.main} -1px -1px 0px, - ${({ theme }) => theme.main} 1px -1px 0px, - ${({ theme }) => theme.main} -1px 1px 0px, - ${({ theme }) => theme.main} 1px 1px 0px; - border: 1px solid rgba(22, 22, 22, 0.2); + border: 1px solid rgb(22 22 22 / 20%); + + @include themed { + color: t('text'); + text-shadow: t('bg') -1px -1px 0, t('bg') 1px -1px 0, t('bg') -1px 1px 0, + t('bg') 1px 1px 0; + } & a { display: flex; @@ -201,14 +199,18 @@ export const PokedexTypes = styled.div` } & span { - font-family: 'Oswald', sans-serif; + font-family: Oswald, sans-serif; cursor: pointer; } } } -`; +} + +.types { + @extend %types; +} -export const ToBottom = styled.a` +.scroll { padding: 0.5rem; display: flex; position: fixed; @@ -216,23 +218,24 @@ export const ToBottom = styled.a` bottom: 5rem; font-size: 5rem; border-radius: 50%; - background-color: rgba(140, 140, 140, 0.2); - transition: 0.3s ease-in-out; + background-color: rgb(140 140 140 / 20%); cursor: pointer; &:hover { - color: ${({ theme }) => theme.main}; - background: ${({ theme }) => theme.secondary}; + @include themed { + color: t('bg'); + background: t('text'); + } } - @media ${device.sm} { + @include sm { right: 3rem; bottom: 3rem; font-size: 3rem; } -`; +} -export const PokemonTitle = styled.section` +.section { display: flex; align-items: center; justify-content: center; @@ -249,11 +252,15 @@ export const PokemonTitle = styled.section` & svg { font-size: 4rem; + & path { - fill: ${({ theme }) => theme.main}; - stroke: ${({ theme }) => theme.secondary}; stroke-width: 1; + + @include themed { + fill: t('bg'); + stroke: t('text'); + } } } } -`; +} diff --git a/src/components/pages/Pokemon/Components/Filters.Pokemon.tsx b/src/modules/pokedex/components/Filters.tsx similarity index 75% rename from src/components/pages/Pokemon/Components/Filters.Pokemon.tsx rename to src/modules/pokedex/components/Filters.tsx index f7d66649..9593662d 100644 --- a/src/components/pages/Pokemon/Components/Filters.Pokemon.tsx +++ b/src/modules/pokedex/components/Filters.tsx @@ -1,16 +1,25 @@ -import { Dropdown } from '@/components/common/styles/Inputs'; -import { Divider } from '@/components/common/ui/Divider'; -import SearchPokemon from '@/components/pages/Pokemon/Components/Search.Pokemon'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; +import { + type Dispatch, + type SetStateAction, + useCallback, + useEffect, +} from 'react'; + +import * as Label from '@radix-ui/react-label'; +import Select, { type SingleValue } from 'react-select'; +import makeAnimated from 'react-select/animated'; + +import { Separator } from '@/components'; import { formOptions, generationsOptions, - IOptionsOffsetLimit, -} from '@/utils/DataArrays'; -import { Dispatch, SetStateAction, useCallback, useEffect } from 'react'; -import { SingleValue } from 'react-select'; -import makeAnimated from 'react-select/animated'; -import { PokedexDropdown, PokedexSearch } from '../Styled.Pokemon'; + type IOptionsOffsetLimit, +} from '@/utils'; + +import styles from '../Pokedex.module.scss'; +import { Search } from './Search'; + +import type { IPokemon } from '@/types'; type Props = { pokedex: IPokemon[]; @@ -26,7 +35,7 @@ type Props = { setGeneration: Dispatch<SetStateAction<IOptionsOffsetLimit | null>>; }; -function Filters({ +export function Filters({ pokedex, setFilteredPokedex, offset, @@ -86,16 +95,16 @@ function Filters({ return ( <> - <PokedexSearch> - <SearchPokemon /> - <PokedexDropdown> - <label htmlFor="form">Form</label> - <Dropdown + <section className={styles.search}> + <Search /> + <div className={styles.dropdown}> + <Label.Root htmlFor="form">Form</Label.Root> + <Select key={form?.value} name="form" id="form" value={form} - className="selectOptions" + className="dropdown selectOptions" classNamePrefix="select" components={animatedComponents} isClearable @@ -106,16 +115,16 @@ function Filters({ action === `clear` && setForm(null); }} /> - </PokedexDropdown> + </div> - <PokedexDropdown> - <label htmlFor="generation">Generation</label> - <Dropdown + <div className={styles.dropdown}> + <Label.Root htmlFor="generation">Generation</Label.Root> + <Select key={generation?.value} name="generation" id="generation" value={generation} - className="selectOptions" + className="dropdown selectOptions" classNamePrefix="select" components={animatedComponents} isClearable @@ -126,11 +135,9 @@ function Filters({ action === `clear` && setGeneration(null); }} /> - </PokedexDropdown> - </PokedexSearch> - <Divider /> + </div> + </section> + <Separator /> </> ); } - -export default Filters; diff --git a/src/modules/pokedex/components/List.tsx b/src/modules/pokedex/components/List.tsx new file mode 100644 index 00000000..ea0a3e79 --- /dev/null +++ b/src/modules/pokedex/components/List.tsx @@ -0,0 +1,42 @@ +import Link from 'next/link'; + +import { removeDash, removeLongName } from '@/utils'; + +import styles from '../Pokedex.module.scss'; +import { Sprites } from './Sprites'; +import { Types } from './Types'; + +import type { IPokemon } from '@/types'; + +type Props = { + filteredPokedex: IPokemon[]; +}; + +export function List({ filteredPokedex }: Props) { + return ( + <ul className={styles.list} data-test-id="pokemonList"> + {filteredPokedex?.map((p: IPokemon) => ( + <li className={styles.element} key={p.id} data-test-id="pokemonElement"> + <Sprites p={p} /> + {p.id < 1011 && ( + <p className={styles.number}>#{p.id.toString().padStart(3, `0`)}</p> + )} + <h2> + <Link + href={{ + pathname: `/pokemon/[name]`, + query: { name: p?.name }, + }} + key={p.name} + > + {removeLongName(removeDash(p.name))} + </Link> + </h2> + <div className={styles.types}> + <Types p={p} /> + </div> + </li> + ))} + </ul> + ); +} diff --git a/src/components/pages/Pokemon/Components/Search.Pokemon.tsx b/src/modules/pokedex/components/Search.tsx similarity index 68% rename from src/components/pages/Pokemon/Components/Search.Pokemon.tsx rename to src/modules/pokedex/components/Search.tsx index d2c4b35b..207189e9 100644 --- a/src/components/pages/Pokemon/Components/Search.Pokemon.tsx +++ b/src/modules/pokedex/components/Search.tsx @@ -1,18 +1,21 @@ -import { getPokedexResults } from '@/utils/DataFetch'; -import ImageWithFallback from '@/utils/ImageWithFallback'; -import { removeDash, removeLongName } from '@/utils/Typography'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; -import Fuse from 'fuse.js'; import { useState } from 'react'; -import { INamedApiResource } from '@/types/Utility/NamedApiResourceList'; + +import * as Label from '@radix-ui/react-label'; +import { type UseQueryResult, useQuery } from '@tanstack/react-query'; +import Fuse from 'fuse.js'; +import Link from 'next/link'; + +import { Input } from '@/components'; import { - AutocompleteContainer, - AutocompleteId, - AutocompleteInput, - AutocompleteLink, -} from '@/components/common/styles/Autocomplete'; + ImageWithFallback, + getPokedexResults, + removeDash, + removeLongName, +} from '@/utils'; + +import type { INamedApiResource } from '@/types'; -function SearchPokemon() { +export function Search() { const { data: pokedex }: UseQueryResult<INamedApiResource[]> = useQuery({ queryKey: [`pokedex`], queryFn: getPokedexResults, @@ -35,15 +38,16 @@ function SearchPokemon() { }; return ( - <AutocompleteInput> - <label htmlFor="search">Search</label> - <input + <div className="search"> + <Label.Root htmlFor="search">Search</Label.Root> + <Input type="text" + id="search" placeholder="Pokémon Name" onChange={(e) => searchPokedex(e.target.value)} /> {searchText && ( - <AutocompleteContainer> + <div className="searchContainer"> <ul> {searchRes && searchRes?.map((res) => ( @@ -59,29 +63,27 @@ function SearchPokemon() { height={48} fallbackSrc={`/images/other/unknown.png`} /> - <AutocompleteLink + <Link href={{ pathname: `/pokemon/[name]`, query: { name: res.item.name }, }} - className="bold" + className="searchLink bold" > {removeLongName(removeDash(res.item.name))} - </AutocompleteLink> - <AutocompleteId> + </Link> + <span className="searchId"> # {res.item.url .replace(`https://pokeapi.co/api/v2/pokemon/`, ``) .slice(0, -1) .padStart(3, `0`)} - </AutocompleteId> + </span> </li> ))} </ul> - </AutocompleteContainer> + </div> )} - </AutocompleteInput> + </div> ); } - -export default SearchPokemon; diff --git a/src/components/pages/Pokemon/Components/Sprites.Pokemon.tsx b/src/modules/pokedex/components/Sprites.tsx similarity index 82% rename from src/components/pages/Pokemon/Components/Sprites.Pokemon.tsx rename to src/modules/pokedex/components/Sprites.tsx index 4b4ec325..cea3a966 100644 --- a/src/components/pages/Pokemon/Components/Sprites.Pokemon.tsx +++ b/src/modules/pokedex/components/Sprites.tsx @@ -1,16 +1,20 @@ -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { PokedexImage, SpriteNormal, SpriteShiny } from '../Styled.Pokemon'; +import { ImageWithFallback } from '@/utils'; + +import styles from '../Pokedex.module.scss'; + +import type { IPokemon } from '@/types'; type Props = { p: IPokemon; }; -function Sprites({ p }: Props) { +export function Sprites({ p }: Props) { return ( - <PokedexImage> + <div className={styles.image}> {p.id < 152 && p.sprites.versions[`generation-i`][`red-blue`].front_transparent && ( - <SpriteNormal + <ImageWithFallback + className={styles.sprite} src={ p.sprites.versions[`generation-i`][`red-blue`].front_transparent } @@ -28,7 +32,8 @@ function Sprites({ p }: Props) { p.sprites.versions[`generation-ii`].crystal.front_transparent && p.sprites.versions[`generation-ii`].crystal.front_shiny_transparent && ( <> - <SpriteNormal + <ImageWithFallback + className={styles.sprite} src={ p.sprites.versions[`generation-ii`].crystal.front_transparent } @@ -40,7 +45,8 @@ function Sprites({ p }: Props) { height={96} fallbackSrc={`/images/other/unknown.png`} /> - <SpriteShiny + <ImageWithFallback + className={styles.shiny} src={ p.sprites.versions[`generation-ii`].crystal .front_shiny_transparent @@ -61,7 +67,8 @@ function Sprites({ p }: Props) { p.sprites.versions[`generation-iii`].emerald.front_default && p.sprites.versions[`generation-iii`].emerald.front_shiny && ( <> - <SpriteNormal + <ImageWithFallback + className={styles.sprite} src={p.sprites.versions[`generation-iii`].emerald.front_default} key={p.sprites.versions[`generation-iii`].emerald.front_default} alt={p.name} @@ -69,7 +76,8 @@ function Sprites({ p }: Props) { height={96} fallbackSrc={`/images/other/unknown.png`} /> - <SpriteShiny + <ImageWithFallback + className={styles.shiny} src={p.sprites.versions[`generation-iii`].emerald.front_shiny} key={p.sprites.versions[`generation-iii`].emerald.front_shiny} alt={p.name} @@ -84,7 +92,8 @@ function Sprites({ p }: Props) { p.sprites.versions[`generation-iv`].platinum.front_default && p.sprites.versions[`generation-iv`].platinum.front_shiny && ( <> - <SpriteNormal + <ImageWithFallback + className={styles.sprite} src={p.sprites.versions[`generation-iv`].platinum.front_default} key={p.sprites.versions[`generation-iv`].platinum.front_default} alt={p.name} @@ -92,7 +101,8 @@ function Sprites({ p }: Props) { height={96} fallbackSrc={`/images/other/unknown.png`} /> - <SpriteShiny + <ImageWithFallback + className={styles.shiny} src={p.sprites.versions[`generation-iv`].platinum.front_shiny} key={p.sprites.versions[`generation-iv`].platinum.front_shiny} alt={p.name} @@ -107,7 +117,8 @@ function Sprites({ p }: Props) { p.sprites.versions[`generation-v`][`black-white`].front_default && p.sprites.versions[`generation-v`][`black-white`].front_shiny && ( <> - <SpriteNormal + <ImageWithFallback + className={styles.sprite} src={ p.sprites.versions[`generation-v`][`black-white`].front_default } @@ -119,7 +130,8 @@ function Sprites({ p }: Props) { height={96} fallbackSrc={`/images/other/unknown.png`} /> - <SpriteShiny + <ImageWithFallback + className={styles.shiny} src={ p.sprites.versions[`generation-v`][`black-white`].front_shiny } @@ -135,7 +147,8 @@ function Sprites({ p }: Props) { )} {p.id > 649 && ( <> - <SpriteNormal + <ImageWithFallback + className={styles.sprite} src={p.sprites.front_default || ``} key={p.sprites.front_default || ``} alt={p.name} @@ -143,7 +156,8 @@ function Sprites({ p }: Props) { height={96} fallbackSrc={`/images/other/unknown.png`} /> - <SpriteShiny + <ImageWithFallback + className={styles.shiny} src={p.sprites.front_shiny || ``} key={p.sprites.front_shiny || ``} alt={p.name} @@ -153,8 +167,6 @@ function Sprites({ p }: Props) { /> </> )} - </PokedexImage> + </div> ); } - -export default Sprites; diff --git a/src/modules/pokedex/components/Types.tsx b/src/modules/pokedex/components/Types.tsx new file mode 100644 index 00000000..346dab62 --- /dev/null +++ b/src/modules/pokedex/components/Types.tsx @@ -0,0 +1,33 @@ +import Image from 'next/image'; +import Link from 'next/link'; + +import type { IPokemon } from '@/types'; + +type Props = { + p: IPokemon; +}; + +export function Types({ p }: Props) { + return ( + <> + {p.types?.map((pt) => ( + <div key={pt.type.name} className="type" id={pt.type.name}> + <Link + href={{ + pathname: `/type/[name]`, + query: { name: pt.type.name }, + }} + > + <Image + src={`/images/types/${pt.type.name}.png`} + alt={pt.type.name} + width={20} + height={20} + /> + <span>{pt.type.name}</span> + </Link> + </div> + ))} + </> + ); +} diff --git a/src/modules/pokedex/components/index.ts b/src/modules/pokedex/components/index.ts new file mode 100644 index 00000000..04ff5fac --- /dev/null +++ b/src/modules/pokedex/components/index.ts @@ -0,0 +1,5 @@ +export * from './Filters'; +export * from './List'; +export * from './Search'; +export * from './Sprites'; +export * from './Types'; diff --git a/src/modules/pokedex/hooks/index.ts b/src/modules/pokedex/hooks/index.ts new file mode 100644 index 00000000..8f952fb6 --- /dev/null +++ b/src/modules/pokedex/hooks/index.ts @@ -0,0 +1 @@ +export * from './useScrollDir'; diff --git a/src/components/pages/Pokemon/Hooks/useScrollDir.tsx b/src/modules/pokedex/hooks/useScrollDir.tsx similarity index 76% rename from src/components/pages/Pokemon/Hooks/useScrollDir.tsx rename to src/modules/pokedex/hooks/useScrollDir.tsx index 83bcb779..ca2f907e 100644 --- a/src/components/pages/Pokemon/Hooks/useScrollDir.tsx +++ b/src/modules/pokedex/hooks/useScrollDir.tsx @@ -1,17 +1,19 @@ -import { ToBottom } from '@/components/pages/Pokemon/Styled.Pokemon'; -import { FaAngleDown, FaAngleUp } from '@meronex/icons/fa'; import { useEffect, useState } from 'react'; +import { FaAngleDown, FaAngleUp } from '@meronex/icons/fa'; + +import styles from '@/modules/pokedex/Pokedex.module.scss'; + export const useScrollDir = () => { const [scrollDir, setScrollDir] = useState(`down`); useEffect(() => { const threshold = 0; - let lastScrollY = window.pageYOffset; + let lastScrollY = window.scrollY; let ticking = false; const updateScrollDir = () => { - const scrollY = window.pageYOffset; + const scrollY = window.scrollY; if (Math.abs(scrollY - lastScrollY) < threshold) { ticking = false; @@ -36,15 +38,15 @@ export const useScrollDir = () => { const scrollBtn = () => { if (scrollDir === `down`) { return ( - <ToBottom href="#footer" aria-label="To Bottom"> + <a className={styles.scroll} href="#footer" aria-label="To Bottom"> <FaAngleDown /> - </ToBottom> + </a> ); } else { return ( - <ToBottom href="#header" aria-label="To Top"> + <a className={styles.scroll} href="#header" aria-label="To Top"> <FaAngleUp /> - </ToBottom> + </a> ); } }; diff --git a/src/modules/pokedex/index.ts b/src/modules/pokedex/index.ts new file mode 100644 index 00000000..54332a9c --- /dev/null +++ b/src/modules/pokedex/index.ts @@ -0,0 +1,3 @@ +export * from './components'; +export * from './hooks'; +export * from './Heading'; diff --git a/src/components/pages/Pokemon/PokemonCard/Heading.tsx b/src/modules/pokedex/pokemon/Heading.tsx similarity index 90% rename from src/components/pages/Pokemon/PokemonCard/Heading.tsx rename to src/modules/pokedex/pokemon/Heading.tsx index f92d73a2..35a0e47e 100644 --- a/src/components/pages/Pokemon/PokemonCard/Heading.tsx +++ b/src/modules/pokedex/pokemon/Heading.tsx @@ -1,11 +1,12 @@ -import Head from 'next/head'; import React from 'react'; +import Head from 'next/head'; + type Props = { name: string; }; -function HeadingPokemon({ name }: Props) { +export function Heading({ name }: Props) { return ( <Head> <title> @@ -26,5 +27,3 @@ function HeadingPokemon({ name }: Props) { </Head> ); } - -export default HeadingPokemon; diff --git a/src/components/pages/Pokemon/PokemonCard/Cards/Styled.Cards.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/cards/Cards.module.scss similarity index 63% rename from src/components/pages/Pokemon/PokemonCard/Cards/Styled.Cards.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/cards/Cards.module.scss index 67c009f3..0623c7d3 100644 --- a/src/components/pages/Pokemon/PokemonCard/Cards/Styled.Cards.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/cards/Cards.module.scss @@ -1,8 +1,6 @@ -import { device } from '@/components/common/styles/Sizing'; -import styled from 'styled-components'; -import Modal from 'react-modal'; +@use '@/styles/abstracts' as *; -export const PokemonCardList = styled.ul` +.list { display: grid; grid-template-columns: repeat(3, 1fr); justify-items: center; @@ -19,7 +17,6 @@ export const PokemonCardList = styled.ul` & img { cursor: zoom-in; - transition: 0.3s ease-in-out; &:hover { transform: scale(1.02); @@ -28,34 +25,31 @@ export const PokemonCardList = styled.ul` } } - @media ${device.md} { + @include md { grid-template-columns: 1fr 1fr; } - @media ${device.sm} { + @include sm { & img { width: 150px; height: 210px; } } -`; +} -export const PokemonCardModal = styled(Modal)` +.modal { width: 60%; height: auto; display: flex; align-items: center; justify-content: center; position: absolute; - top: 50%; - left: 50%; - right: auto; - bottom: auto; + inset: 50% auto auto 50%; margin-right: -50%; transform: translate(-50%, -50%); overflow-y: hidden !important; - @media ${device.sm} { + @include sm { width: 80%; } -`; +} diff --git a/src/components/pages/Pokemon/PokemonCard/Cards/Cards.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/cards/Cards.tsx similarity index 67% rename from src/components/pages/Pokemon/PokemonCard/Cards/Cards.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/cards/Cards.tsx index 99978a7a..e4aaab5f 100644 --- a/src/components/pages/Pokemon/PokemonCard/Cards/Cards.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/cards/Cards.tsx @@ -1,15 +1,17 @@ -import { Bold, H3 } from '@/components/common/styles/Headings'; -import { Section } from '@/components/common/styles/Sizing'; -import { ICard } from '@/types/Cards/Card'; -import Image from 'next/image'; import { useState } from 'react'; -import { PokemonCardList, PokemonCardModal } from './Styled.Cards.PokemonCard'; + +import Image from 'next/image'; +import Modal from 'react-modal'; + +import styles from './Cards.module.scss'; + +import type { ICard } from '@/types'; type Props = { cards: ICard[]; }; -function Cards({ cards }: Props) { +export function Cards({ cards }: Props) { const [modalIsOpen, setIsOpen] = useState<boolean>(false); const [modalData, setModalData] = useState<string | null>(null); @@ -22,9 +24,9 @@ function Cards({ cards }: Props) { }; return ( - <Section id="cards"> - <H3>Cards</H3> - <PokemonCardList> + <section className="section" id="cards"> + <h3 className="h3">Cards</h3> + <ul className={styles.list}> {cards.map((c) => ( <li key={c.id}> <button @@ -36,12 +38,14 @@ function Cards({ cards }: Props) { <Image src={c.images.small} alt={``} width={220} height={308} /> </button> <p> - Set: <Bold>{c.set.name.replaceAll(`—`, ` `)}</Bold> + Set:{` `} + <span className="bold">{c.set.name.replaceAll(`—`, ` `)}</span> </p> </li> ))} {modalData && ( - <PokemonCardModal + <Modal + className={styles.modal} isOpen={modalIsOpen} onRequestClose={closeModal} preventScroll={true} @@ -55,11 +59,9 @@ function Cards({ cards }: Props) { sizes="100vw" style={{ width: `100%`, height: `auto` }} /> - </PokemonCardModal> + </Modal> )} - </PokemonCardList> - </Section> + </ul> + </section> ); } - -export default Cards; diff --git a/src/modules/pokedex/pokemon/components/cards/index.ts b/src/modules/pokedex/pokemon/components/cards/index.ts new file mode 100644 index 00000000..a89151ff --- /dev/null +++ b/src/modules/pokedex/pokemon/components/cards/index.ts @@ -0,0 +1 @@ +export * from './Cards'; diff --git a/src/components/pages/Pokemon/PokemonCard/Competitive/Styled.Competitive.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/competitive/Competitive.module.scss similarity index 69% rename from src/components/pages/Pokemon/PokemonCard/Competitive/Styled.Competitive.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/competitive/Competitive.module.scss index 65fb90fc..6ea2d76b 100644 --- a/src/components/pages/Pokemon/PokemonCard/Competitive/Styled.Competitive.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/competitive/Competitive.module.scss @@ -1,7 +1,6 @@ -import { device } from '@/components/common/styles/Sizing'; -import styled from 'styled-components'; +@use '@/styles/abstracts' as *; -export const PokemonSetsContainer = styled.ul` +.list { display: flex; flex-direction: column; gap: 2rem; @@ -17,19 +16,22 @@ export const PokemonSetsContainer = styled.ul` margin-top: 1rem; } } -`; +} -export const PokemonSetSpecs = styled.div` +.specs { display: grid; align-items: stretch; grid-template-columns: 1fr 1fr; gap: 2rem; margin-bottom: 1rem; padding: 1.5rem; - background-color: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.main}; border-radius: 5px; + @include themed { + background-color: t('text'); + color: t('bg'); + } + & ul { display: flex; flex-direction: column; @@ -54,13 +56,13 @@ export const PokemonSetSpecs = styled.div` } } - @media ${device.md} { + @include md { display: flex; flex-direction: column; } -`; +} -export const PokemonSetDesc = styled.div` +%desc { display: flex; flex-direction: column; gap: 1rem; @@ -72,15 +74,21 @@ export const PokemonSetDesc = styled.div` } & hr { - border-width: 0 0 1px 0; + border-width: 0 0 1px; } -`; +} + +.desc { + @extend %desc; +} + +.comment { + @extend %desc; -export const PokemonSetComment = styled(PokemonSetDesc)` & h1 { margin: 1rem 0 0; font-size: 2.5rem; font-weight: 600; text-transform: capitalize; } -`; +} diff --git a/src/modules/pokedex/pokemon/components/competitive/Competitive.tsx b/src/modules/pokedex/pokemon/components/competitive/Competitive.tsx new file mode 100644 index 00000000..fff5a972 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/competitive/Competitive.tsx @@ -0,0 +1,275 @@ +// @ts-nocheck + +import { useState } from 'react'; + +import * as Tabs from '@radix-ui/react-tabs'; +import { useQueries } from '@tanstack/react-query'; + +import { ErrorToast, SmallLoader } from '@/components'; +import { capitalize, getFormat, removeLongName } from '@/utils'; + +import styles from './Competitive.module.scss'; + +import type { IFormatAnalysesSets, IFormatsAnalysesSetName } from '@/types'; + +type Props = { + format: string; + name: string; +}; + +export function Competitive({ format, name }: Props) { + const [toggle, setToggle] = useState<number>(0); + + const [analyses, formats, sets] = useQueries({ + queries: [ + { + queryKey: [`analyses`, format], + queryFn: () => + getFormat( + `https://raw.githubusercontent.com/pkmn/smogon/main/data/analyses/${format}.json`, + ), + }, + { + queryKey: [`formats`], + queryFn: () => + getFormat( + `https://raw.githubusercontent.com/pkmn/smogon/main/data/formats/index.json`, + ), + }, + { + queryKey: [`sets`, format], + queryFn: () => + getFormat( + `https://raw.githubusercontent.com/pkmn/smogon/main/data/sets/${format}.json`, + ), + }, + ], + }); + + if ( + analyses.status === `error` || + formats.status === `error` || + sets.status === `error` + ) { + return <ErrorToast />; + } + + if ( + analyses.status === `loading` || + formats.status === `loading` || + sets.status === `loading` + ) { + return <SmallLoader />; + } + + const pokemonAnalyses = Object.entries(analyses.data) + .map(([pokemonAnalysesName, value]) => + Object.assign({ pokemonAnalysesName }, value), + ) + .find((n) => n.pokemonAnalysesName === removeLongName(capitalize(name))); + + const pokemonSets = Object.entries(sets.data) + .map(([pokemonSetsName, value]) => + Object.assign({ pokemonSetsName }, value), + ) + .find((n) => n.pokemonSetsName === removeLongName(capitalize(name))); + + if (pokemonAnalyses && pokemonSets) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { pokemonAnalysesName, ...filteredAnalyses } = pokemonAnalyses; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { pokemonSetsName, ...filteredSets } = pokemonSets; + + if ( + Object.keys(filteredAnalyses).length > 0 && + Object.keys(filteredSets).length > 0 + ) { + const formattedName = (formatName: string) => { + return ( + Object.entries(formats.data) + .filter((f) => f[0] === formatName && f[1]) + .flat()[1] || formatName + ); + }; + + const setsEntries = (obj) => { + return Object.entries(obj)[toggle][1]; + }; + + const overview: string | undefined = + setsEntries(filteredAnalyses).overview; + + const comments: string | undefined = + setsEntries(filteredAnalyses).comments; + + const textFormatting = (str: string) => + str.replaceAll(`-types`, ` types`).replaceAll(`-type`, ` type`); + + const setSpecs = ( + obj: Record<string, unknown>, + i: number, + value: string, + ) => { + return Object.values(Object.entries(obj)[toggle][1])[i][value]; + }; + + const wrapMoves = (tag: string, move: string | number, index: number) => { + if (tag === `li` && typeof move === `string`) { + return `<${tag}>Move ${index + 1}: <b>${move}</b></${tag}>`; + } else if (tag === `span` && typeof move === `string`) { + return `<${tag}>${move}</${tag}>`; + } else if (typeof move === `number`) { + return null; + } + }; + + const majEv = { + hp: `Hp`, + atk: `Atk`, + def: `Def`, + spa: `SpA`, + spd: `SpD`, + spe: `Spe`, + }; + + const detailedSets = Object.keys( + Object.values(Object.entries(filteredSets)[toggle][1])[0], + ); + + return ( + <Tabs.Root + className="TabsRootSection" + id="competitive" + defaultValue={String(toggle)} + > + <h3 className="h3">Competitive</h3> + <Tabs.List className="TabsList" aria-label="Switch between formats"> + {Object.keys(filteredAnalyses).map((fa, i) => ( + <Tabs.Trigger + key={fa} + className="TabsTrigger" + value={String(i)} + onClick={() => setToggle(i)} + > + {formattedName(fa) as string} + </Tabs.Trigger> + ))} + </Tabs.List> + <Tabs.Content value={String(toggle)}> + <ul className={styles.list}> + {overview && ( + <li> + <h4 className="h4">Analysis</h4> + <div + className={styles.desc} + dangerouslySetInnerHTML={{ __html: overview }} + /> + </li> + )} + {setsEntries(filteredAnalyses as IFormatAnalysesSets).sets?.map( + (s: IFormatsAnalysesSetName, i: number) => ( + <li key={s.name}> + <h4 className="h4">{s.name}</h4> + <div className={styles.specs}> + <ul + dangerouslySetInnerHTML={{ + __html: setSpecs(filteredSets, i, `moves`).map( + (move: string | string[], index: number) => + wrapMoves( + `li`, + Array.isArray(move) + ? move + .map((j) => wrapMoves(`span`, j, index)) + .join(` / `) + : move, + index, + ), + ), + }} + /> + {detailedSets.length > 1 && + detailedSets.find( + (d: string) => d !== `level` && d !== `moves`, + ) && ( + <ul> + <li> + {typeof setSpecs(filteredSets, i, `item`) === + `string` ? ( + <> + Item:{` `} + <b>{setSpecs(filteredSets, i, `item`)}</b> + </> + ) : ( + <> + Items:{` `} + <b> + {setSpecs(filteredSets, i, `item`).join( + ` / `, + )} + </b> + </> + )} + </li> + <li> + Nature:{` `} + <b> + {typeof setSpecs(filteredSets, i, `nature`) === + `string` + ? setSpecs(filteredSets, i, `nature`) + : `-`} + </b> + </li> + <li> + EVs:{` `} + <b> + {typeof setSpecs(filteredSets, i, `evs`) === + `object` + ? Object.entries( + setSpecs(filteredSets, i, `evs`), + ) + .join(` / `) + .replaceAll(`,`, ` `) + .replace( + /\b(?:hp|atk|def|spa|spd|spe)\b/gi, + (matched) => majEv[matched], + ) + : `-`} + </b> + </li> + </ul> + )} + </div> + {s.description && ( + <div + className={styles.desc} + dangerouslySetInnerHTML={{ + __html: textFormatting(s.description), + }} + /> + )} + </li> + ), + )} + {comments && ( + <li> + <div + className={styles.comment} + dangerouslySetInnerHTML={{ + __html: textFormatting(comments), + }} + /> + </li> + )} + </ul> + </Tabs.Content> + </Tabs.Root> + ); + } + } + + if (!pokemonAnalyses || !pokemonSets) { + return <div className="subtitle">No data available</div>; + } + + return null; +} diff --git a/src/modules/pokedex/pokemon/components/competitive/index.ts b/src/modules/pokedex/pokemon/components/competitive/index.ts new file mode 100644 index 00000000..a0c85c06 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/competitive/index.ts @@ -0,0 +1 @@ +export * from './Competitive'; diff --git a/src/components/pages/Pokemon/PokemonCard/Contents/Styled.Contents.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/content/Content.module.scss similarity index 72% rename from src/components/pages/Pokemon/PokemonCard/Contents/Styled.Contents.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/content/Content.module.scss index a2cafadf..c551ef55 100644 --- a/src/components/pages/Pokemon/PokemonCard/Contents/Styled.Contents.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/content/Content.module.scss @@ -1,16 +1,19 @@ -import styled from 'styled-components'; +@use '@/styles/abstracts' as *; -export const PokemonContents = styled.section` +.section { position: sticky; padding: 1rem 1.5rem; margin-bottom: 5rem; top: 0; font-size: 2rem; - background: ${({ theme }) => theme.main}; - border: 1px solid ${({ theme }) => theme.secondary}; border-radius: 5px; z-index: 3; + @include themed { + background: t('bg'); + border: 1px solid t('text'); + } + & div { display: flex; align-items: center; @@ -33,11 +36,13 @@ export const PokemonContents = styled.section` border-radius: 50%; font-size: 2.5rem; font-weight: 600; - color: ${({ theme }) => theme.secondary}; - transition: 0.3s ease-in-out; + + @include themed { + color: t('text'); + } &:hover { - background: rgba(130, 130, 130, 0.2); + background: rgb(130 130 130 / 20%); } } } @@ -57,4 +62,4 @@ export const PokemonContents = styled.section` } } } -`; +} diff --git a/src/components/pages/Pokemon/PokemonCard/Contents/Contents.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/content/Content.tsx similarity index 89% rename from src/components/pages/Pokemon/PokemonCard/Contents/Contents.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/content/Content.tsx index 3261d99b..3db21f5d 100644 --- a/src/components/pages/Pokemon/PokemonCard/Contents/Contents.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/content/Content.tsx @@ -1,12 +1,14 @@ -import { MdAdd, MdRemove } from '@meronex/icons/ios'; import { useState } from 'react'; -import { PokemonContents } from './Styled.Contents.PokemonCard'; -function Contents() { +import { MdAdd, MdRemove } from '@meronex/icons/ios'; + +import styles from './Content.module.scss'; + +export function Content() { const [contentsOpen, setContentsOpen] = useState<boolean>(false); return ( - <PokemonContents> + <section className={styles.section}> <div> <p>Table of contents</p> <button onClick={() => setContentsOpen(!contentsOpen)}> @@ -53,8 +55,6 @@ function Contents() { </li> </ol> )} - </PokemonContents> + </section> ); } - -export default Contents; diff --git a/src/modules/pokedex/pokemon/components/content/index.ts b/src/modules/pokedex/pokemon/components/content/index.ts new file mode 100644 index 00000000..b39182a1 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/content/index.ts @@ -0,0 +1 @@ +export * from './Content'; diff --git a/src/modules/pokedex/pokemon/components/data/Data.module.scss b/src/modules/pokedex/pokemon/components/data/Data.module.scss new file mode 100644 index 00000000..af913d5c --- /dev/null +++ b/src/modules/pokedex/pokemon/components/data/Data.module.scss @@ -0,0 +1,179 @@ +@use '@/styles/abstracts' as *; +@use '@/styles/common' as *; + +.section { + @extend %section; + + position: relative; + display: grid; + align-items: center; + grid-template-columns: 55% 45%; + gap: 3rem; + + @include md { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column-reverse; + } +} + +.catch { + position: absolute; + top: 1rem; + right: 1rem; + padding: 0.7rem 1.5rem; + border-radius: 5px; + font-size: 1.5rem; + font-weight: 600; + + @include themed { + background: t('text'); + border: 1px solid t('text'); + } + + &:hover { + background: transparent; + @include themed { + color: t('text'); + } + } +} + +.caught { + position: absolute; + top: 1rem; + right: 1rem; + padding: 0.7rem 1.5rem; + background: transparent; + border-radius: 5px; + font-size: 1.5rem; + font-weight: 600; + opacity: 0.7; + @include themed { + color: t('text'); + border: 1px solid t('text'); + } +} + +.container { + display: flex; + flex-direction: column; + gap: 2rem; +} + +.sprite { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + height: 100%; +} + +.desc { + font-size: 2rem; + + & p { + padding-top: 0.5rem; + font-size: 1.3rem; + } +} + +.types { + position: relative; + width: 100%; + display: flex; + align-items: center; + justify-content: flex-start; + @extend %tType; + + & div { + margin: 2rem; + margin-left: 0; + padding: 0 1.5rem; + + & a { + & span { + font-size: 3rem; + } + } + } + + @include sm { + justify-content: center; + } +} + +.oldTypes { + font-size: 1.7rem; + + & span { + text-transform: capitalize; + + &:not(:first-of-type) { + font-weight: 600; + } + } +} + +.table { + @extend %table; + + width: 90%; + + & th { + background: rgb(130 130 130 / 20%); + text-transform: capitalize; + } + + & td { + font-size: 1.7rem; + font-weight: 600; + text-align: left; + text-transform: capitalize; + + & ul { + margin-left: 2rem; + + & li { + list-style-type: decimal; + text-align: left; + } + } + } +} + +%pill { + margin: 1rem 0 0; + padding: 1rem 1.5rem; + border-radius: 50px; + font-size: 2rem; +} + +.pill { + @extend %pill; +} + +.special { + @extend %pill; + + border: 1px solid $purple; + background: $purple; + color: #c4c4c4; + font-weight: 600; +} + +.imageContainer { + position: relative; + width: 75%; + height: 75%; +} + +.image { + @include animation('pulse, 5s, inifnite'); + + @include sm { + width: 75%; + margin-bottom: 1rem; + } +} diff --git a/src/modules/pokedex/pokemon/components/data/Data.tsx b/src/modules/pokedex/pokemon/components/data/Data.tsx new file mode 100644 index 00000000..18da33fe --- /dev/null +++ b/src/modules/pokedex/pokemon/components/data/Data.tsx @@ -0,0 +1,56 @@ +import { useState } from 'react'; + +import { SuccessToast } from '@/components'; +import { removeDash } from '@/utils'; + +import { Base } from './base'; +import styles from './Data.module.scss'; +import { Description } from './description'; +import { Sprite } from './sprite'; + +import type { IPokemon, IPokemonSpecies } from '@/types'; + +type Props = { + pokemon: IPokemon; + species: IPokemonSpecies; + game: string | null; +}; + +export function Data({ pokemon, species, game }: Props) { + // will have the user's info + const [user, setUser] = useState(); + + const catchHandler = async () => { + if (Math.random() < species.capture_rate / 765) { + // will have the catch function + return ( + <SuccessToast + text={`Congrats 🎉 ! You caught ${removeDash(pokemon.name)}`} + /> + ); + } + }; + + return ( + <section className={styles.section} id="presentation"> + {/* {user && + pokemon.id < 10000 && + (user.caught.every( + (n: Record<string, string>) => n[0] !== pokemon.name, + ) ? ( + <button className={styles.catch} onClick={catchHandler}> + Catch + </button> + ) : ( + <p className={styles.caught}>Caught</p> + ))} */} + <div className={styles.container}> + <Description species={species} pokemon={pokemon} game={game} /> + <Base species={species} pokemon={pokemon} /> + </div> + <div className={styles.sprite}> + <Sprite species={species} pokemon={pokemon} /> + </div> + </section> + ); +} diff --git a/src/components/pages/Pokemon/PokemonCard/Data/Base/Base.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/data/base/Base.tsx similarity index 77% rename from src/components/pages/Pokemon/PokemonCard/Data/Base/Base.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/data/base/Base.tsx index 46f499b6..7eafcc42 100644 --- a/src/components/pages/Pokemon/PokemonCard/Data/Base/Base.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/data/base/Base.tsx @@ -1,16 +1,17 @@ -import { Small } from '@/components/common/styles/Headings'; -import { TLink } from '@/components/common/styles/Table'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { IGenus, IPokemonSpecies } from '@/types/Pokemon/PokemonSpecies'; -import { removeDash } from '@/utils/Typography'; -import { PokemonDataTable } from '../Styled.Data.PokemonCard'; +import Link from 'next/link'; + +import { removeDash } from '@/utils'; + +import styles from '../Data.module.scss'; + +import type { IGenus, IPokemon, IPokemonSpecies } from '@/types'; type Props = { pokemon: IPokemon; species: IPokemonSpecies; }; -function Base({ pokemon, species }: Props) { +export function Base({ pokemon, species }: Props) { // Convert height and weight to meters and kilograms and round the number const height = Number.parseFloat((pokemon.height * 0.1).toFixed(2)); const weight = Number.parseFloat((pokemon.weight * 0.1).toFixed(2)); @@ -21,7 +22,7 @@ function Base({ pokemon, species }: Props) { species && species.genera.find((sg) => sg.language.name === `en`); return ( - <PokemonDataTable> + <table className={styles.table}> <tbody> <tr> <th>pokédex number</th> @@ -37,7 +38,8 @@ function Base({ pokemon, species }: Props) { <ul> {pokemon.abilities?.map((pa) => ( <li key={pa.ability.name}> - <TLink + <Link + className="tLink" href={{ pathname: `/ability/[name]`, query: { name: pa.ability.name }, @@ -45,8 +47,10 @@ function Base({ pokemon, species }: Props) { key={pa.ability.name} > {removeDash(pa.ability.name)} - </TLink> - {pa.is_hidden && <Small> (hidden ability)</Small>} + </Link> + {pa.is_hidden && ( + <small className="small"> (hidden ability)</small> + )} </li> ))} </ul> @@ -81,8 +85,6 @@ function Base({ pokemon, species }: Props) { </> )} </tbody> - </PokemonDataTable> + </table> ); } - -export default Base; diff --git a/src/modules/pokedex/pokemon/components/data/base/index.ts b/src/modules/pokedex/pokemon/components/data/base/index.ts new file mode 100644 index 00000000..063c47a6 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/data/base/index.ts @@ -0,0 +1 @@ +export * from './Base'; diff --git a/src/components/pages/Pokemon/PokemonCard/Data/Desc/Desc.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/data/description/Description.tsx similarity index 65% rename from src/components/pages/Pokemon/PokemonCard/Data/Desc/Desc.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/data/description/Description.tsx index f0548300..a1f6c081 100644 --- a/src/components/pages/Pokemon/PokemonCard/Data/Desc/Desc.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/data/description/Description.tsx @@ -1,15 +1,11 @@ -import { Bold, Capitalize } from '@/components/common/styles/Headings'; -import { Type } from '@/components/common/styles/Themes'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { IPokemonSpecies } from '@/types/Pokemon/PokemonSpecies'; -import { removeDash } from '@/utils/Typography'; import Image from 'next/image'; import Link from 'next/link'; -import { - PokemonDataDesc, - PokemonDataOldTypes, - PokemonDataTypes, -} from '../Styled.Data.PokemonCard'; + +import { removeDash } from '@/utils'; + +import styles from '../Data.module.scss'; + +import type { IPokemon, IPokemonSpecies } from '@/types'; type Props = { pokemon: IPokemon; @@ -17,7 +13,7 @@ type Props = { game: string | null; }; -function Desc({ pokemon, species, game }: Props) { +export function Description({ pokemon, species, game }: Props) { const filterDesc = species?.flavor_text_entries && game && @@ -29,27 +25,29 @@ function Desc({ pokemon, species, game }: Props) { <> <ul> {pokemon.id < 10000 && ( - <PokemonDataDesc> + <li className={styles.desc}> <span> {filterDesc && filterDesc?.flavor_text ? ( filterDesc?.flavor_text .replace(`\u000c`, ` `) .replace(`POKéMON`, `Pokémon`) ) : ( - <Bold>There is no description for this Pokémon</Bold> + <span className="bold"> + There is no description for this Pokémon + </span> )} </span> <p> Pokémon{` `} - <Capitalize> + <span className="capitalize"> <i>{game && removeDash(game)}</i> - </Capitalize> + </span> </p> - </PokemonDataDesc> + </li> )} - <PokemonDataTypes> + <li className={styles.types}> {pokemon?.types?.map((pt) => ( - <Type id={pt.type.name} key={pt.type.name}> + <div className="type" id={pt.type.name} key={pt.type.name}> <Link href={{ pathname: `/type/[name]`, @@ -64,10 +62,10 @@ function Desc({ pokemon, species, game }: Props) { /> <span>{pt.type.name}</span> </Link> - </Type> + </div> ))} - </PokemonDataTypes> - <PokemonDataOldTypes> + </li> + <li className={styles.oldTypes}> {pokemon.past_types.map((pp) => ( <p key={pp.generation.name}> Up to <span>{removeDash(pp.generation.name)}</span> (included) : @@ -77,10 +75,8 @@ function Desc({ pokemon, species, game }: Props) { ))} </p> ))} - </PokemonDataOldTypes> + </li> </ul> </> ); } - -export default Desc; diff --git a/src/modules/pokedex/pokemon/components/data/description/index.ts b/src/modules/pokedex/pokemon/components/data/description/index.ts new file mode 100644 index 00000000..2b6c4564 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/data/description/index.ts @@ -0,0 +1 @@ +export * from './Description'; diff --git a/src/modules/pokedex/pokemon/components/data/index.ts b/src/modules/pokedex/pokemon/components/data/index.ts new file mode 100644 index 00000000..560ef2c4 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/data/index.ts @@ -0,0 +1,4 @@ +export * from './Data'; +export * from './base'; +export * from './description'; +export * from './sprite'; diff --git a/src/modules/pokedex/pokemon/components/data/sprite/Sprite.tsx b/src/modules/pokedex/pokemon/components/data/sprite/Sprite.tsx new file mode 100644 index 00000000..7a96c3c8 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/data/sprite/Sprite.tsx @@ -0,0 +1,36 @@ +import Image from 'next/image'; + +import styles from '../Data.module.scss'; + +import type { IPokemon, IPokemonSpecies } from '@/types'; + +type Props = { + pokemon: IPokemon; + species: IPokemonSpecies; +}; + +export function Sprite({ pokemon, species }: Props) { + return ( + <> + <div className={styles.imageContainer}> + <Image + className={styles.image} + src={pokemon.sprites.other[`official-artwork`].front_default} + alt={pokemon.name} + fill={true} + /> + </div> + {pokemon.id < 10000 && ( + <> + {species?.is_legendary && ( + <span className={styles.special}>Legendary</span> + )} + {species?.is_mythical && ( + <span className={styles.special}>Mythical</span> + )} + {species.is_baby && <span className={styles.special}>Baby</span>} + </> + )} + </> + ); +} diff --git a/src/modules/pokedex/pokemon/components/data/sprite/index.ts b/src/modules/pokedex/pokemon/components/data/sprite/index.ts new file mode 100644 index 00000000..a5699c9f --- /dev/null +++ b/src/modules/pokedex/pokemon/components/data/sprite/index.ts @@ -0,0 +1 @@ +export * from './Sprite'; diff --git a/src/components/pages/Pokemon/PokemonCard/Evolution/Styled.Evolution.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/evolution/Evolution.module.scss similarity index 65% rename from src/components/pages/Pokemon/PokemonCard/Evolution/Styled.Evolution.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/evolution/Evolution.module.scss index fb345818..ad35157b 100644 --- a/src/components/pages/Pokemon/PokemonCard/Evolution/Styled.Evolution.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/evolution/Evolution.module.scss @@ -1,13 +1,14 @@ -import styled from 'styled-components'; -import { device, Section } from '../../../../common/styles/Sizing'; +@use '@/styles/abstracts' as *; +@use '@/styles/common' as *; -export const PokemonEvolutionSection = styled(Section)` - @media ${device.sm} { +.section { + @extend %section; + @include sm { padding-bottom: 0; } -`; +} -export const PokemonEvolutionContainer = styled.div` +.container { width: 100%; display: flex; justify-content: space-between; @@ -17,15 +18,15 @@ export const PokemonEvolutionContainer = styled.div` width: 100%; } - @media ${device.sm} { + @include sm { display: flex; align-items: center; justify-content: space-around; flex-direction: column; } -`; +} -export const PokemonEvolutionBase = styled.div` +.base { text-align: center; width: 20%; @@ -41,41 +42,40 @@ export const PokemonEvolutionBase = styled.div` font-weight: 600; text-transform: capitalize; cursor: pointer; - transition: 0.3s ease-in-out; &:hover { - color: ${({ theme }) => theme.red}; + color: $red; } } } -`; +} -export const PokemonEvolution = styled.div` +.evolution { width: 80%; display: flex; justify-content: space-between; - @media ${device.sm} { + @include sm { justify-content: space-around; flex-direction: column; } -`; +} -export const PokemonEvolutionStages = styled.div` +.stage { width: 100%; display: flex; flex-direction: column; justify-content: center; -`; +} -export const PokemonEvolutionFinal = styled.div` +.final { width: 100%; display: flex; flex-direction: column; justify-content: center; -`; +} -export const PokemonEvolutionElement = styled.div` +.element { display: flex; justify-content: space-between; margin: 3rem 0; @@ -94,32 +94,31 @@ export const PokemonEvolutionElement = styled.div` text-align: center; text-transform: capitalize; cursor: pointer; - transition: 0.3s ease-in-out; &:hover { - color: ${({ theme }) => theme.red}; + color: $red; } } & svg { font-size: 2.7rem; - @media ${device.sm} { + @include sm { transform: rotate(90deg); } } } - @media ${device.sm} { + @include sm { flex-direction: column; & div { width: auto; } } -`; +} -export const PokemonEvolutionText = styled.p` +.text { font-size: 1.7rem; text-align: center; @@ -127,4 +126,4 @@ export const PokemonEvolutionText = styled.p` font-weight: 600; text-transform: capitalize; } -`; +} diff --git a/src/components/pages/Pokemon/PokemonCard/Evolution/Evolution.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/evolution/Evolution.tsx similarity index 71% rename from src/components/pages/Pokemon/PokemonCard/Evolution/Evolution.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/evolution/Evolution.tsx index d7d3dc92..c424d70b 100644 --- a/src/components/pages/Pokemon/PokemonCard/Evolution/Evolution.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/evolution/Evolution.tsx @@ -1,31 +1,21 @@ -import { H3 } from '@/components/common/styles/Headings'; -import SmallLoader from '@/components/common/ui/Loader/SmallLoader'; -import { IEvolutionChain } from '@/types/Evolution/EvolutionChain'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { getAllEvo } from '@/utils/DataFetch'; -import { removeDash } from '@/utils/Typography'; import { FaChevronRight } from '@meronex/icons/fa'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { type UseQueryResult, useQuery } from '@tanstack/react-query'; import Image from 'next/image'; import Link from 'next/link'; -import toast from 'react-hot-toast'; -import { - PokemonEvolution, - PokemonEvolutionBase, - PokemonEvolutionContainer, - PokemonEvolutionElement, - PokemonEvolutionFinal, - PokemonEvolutionSection, - PokemonEvolutionStages, - PokemonEvolutionText, -} from './Styled.Evolution.PokemonCard'; + +import { ErrorToast, SmallLoader } from '@/components'; +import { getAllEvo, removeDash } from '@/utils'; + +import styles from './Evolution.module.scss'; + +import type { IEvolutionChain, IPokemon } from '@/types'; type Props = { evolution: IEvolutionChain; name: string; }; -function Evolution({ evolution, name }: Props) { +export function Evolution({ evolution, name }: Props) { const { isLoading, isError, @@ -38,11 +28,7 @@ function Evolution({ evolution, name }: Props) { }); if (isError) { - return toast.error(`Something went wrong: ${error.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -50,10 +36,10 @@ function Evolution({ evolution, name }: Props) { } return ( - <PokemonEvolutionSection id="evolution"> - <H3>Evolution chain</H3> - <PokemonEvolutionContainer> - <PokemonEvolutionBase> + <section className={styles.section} id="evolution"> + <h3 className="h3">Evolution chain</h3> + <div className={styles.container}> + <div className={styles.base}> <div> <> {evo?.map( @@ -78,39 +64,42 @@ function Evolution({ evolution, name }: Props) { </Link> </> </div> - </PokemonEvolutionBase> + </div> {evolution?.chain?.evolves_to?.length !== 0 && ( - <PokemonEvolution> - <PokemonEvolutionStages> + <div className={styles.evolution}> + <div className={styles.stage}> {evolution?.chain?.evolves_to?.map((ee) => ( - <PokemonEvolutionElement key={evolution?.chain?.species?.name}> + <div + className={styles.element} + key={evolution?.chain?.species?.name} + > <div> {ee?.evolution_details?.map((eed) => ( <> {eed.gender && (eed.gender === 1 ? ( - <PokemonEvolutionText> + <p className={styles.text}> <span> Female</span> - </PokemonEvolutionText> + </p> ) : ( - <PokemonEvolutionText> + <p className={styles.text}> <span> Male</span> - </PokemonEvolutionText> + </p> ))} {eed.trigger.name === `trade` && !eed.held_item && ( - <PokemonEvolutionText>Trade</PokemonEvolutionText> + <p className={styles.text}>Trade</p> )} {eed.held_item && eed.trigger.name === `trade` && ( - <PokemonEvolutionText> + <p className={styles.text}> Trade holding <span> {` `} {removeDash(eed.held_item.name)} </span> - </PokemonEvolutionText> + </p> )} {eed.held_item && eed.trigger.name === `level-up` && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up holding{` `} <span> {` `} @@ -118,25 +107,25 @@ function Evolution({ evolution, name }: Props) { </span> {` `} during the <span> {eed.time_of_day}</span> - </PokemonEvolutionText> + </p> )} {eed.item && ( - <PokemonEvolutionText> + <p className={styles.text}> Use{` `} <span> {removeDash(eed.item.name)}</span> - </PokemonEvolutionText> + </p> )} {eed.known_move && ( - <PokemonEvolutionText> + <p className={styles.text}> Learn{` `} <span> {` `} {removeDash(eed.known_move.name)} </span> - </PokemonEvolutionText> + </p> )} {eed.known_move_type && eed.min_affection && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up with{` `} <span> {eed.min_affection}+ affection</span> {` `} @@ -147,10 +136,10 @@ function Evolution({ evolution, name }: Props) { </span> {` `} type move - </PokemonEvolutionText> + </p> )} {eed.known_move_type && eed.min_happiness && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up with{` `} <span> {eed.min_happiness}+ happiness</span> {` `} @@ -161,59 +150,59 @@ function Evolution({ evolution, name }: Props) { </span> {` `} type move - </PokemonEvolutionText> + </p> )} {eed.location && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up at{` `} <span> {` `} {removeDash(eed.location.name)} </span> - </PokemonEvolutionText> + </p> )} {eed.min_beauty && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up with{` `} <span> {eed.min_beauty}+ beauty</span> - </PokemonEvolutionText> + </p> )} {eed.min_happiness && eed.time_of_day !== `` && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up with{` `} <span> {eed.min_happiness}+ happiness</span> during the <span> {eed.time_of_day}</span> - </PokemonEvolutionText> + </p> )} {eed.min_happiness && eed.time_of_day === `` && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up with{` `} <span> {eed.min_happiness}+ happiness</span> - </PokemonEvolutionText> + </p> )} {eed.min_level && eed.time_of_day === `` && !eed.party_type && !eed.relative_physical_stats && eed.turn_upside_down === false && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eed.min_level}</span> - </PokemonEvolutionText> + </p> )} {eed.min_level && eed.time_of_day !== `` && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eed.min_level}</span> during the{` `} <span> {eed.time_of_day}</span> - </PokemonEvolutionText> + </p> )} {eed.needs_overworld_rain === true && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eed.min_level}</span> while{` `} <span>raining</span> - </PokemonEvolutionText> + </p> )} {eed.party_species && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up with a{` `} <span> {` `} @@ -221,17 +210,17 @@ function Evolution({ evolution, name }: Props) { </span> {` `} in the party - </PokemonEvolutionText> + </p> )} {eed.party_type && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eed.min_level}</span> with a{` `} <span> {eed.party_type.name}</span> type pokémon in the party - </PokemonEvolutionText> + </p> )} {eed.relative_physical_stats && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eed.min_level}</span> with <span> {eed.relative_physical_stats === 1 @@ -240,35 +229,35 @@ function Evolution({ evolution, name }: Props) { ? ` Attack = Defense` : ` Defense > Attack`} </span> - </PokemonEvolutionText> + </p> )} {eed.trade_species && ( - <PokemonEvolutionText> + <p className={styles.text}> Trade with <span> {eed.trade_species.name}</span> - </PokemonEvolutionText> + </p> )} {eed.turn_upside_down === true && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eed.min_level} </span> while{` `} <span>holding the console upside-down</span> - </PokemonEvolutionText> + </p> )} {eed.trigger.name === `shed` && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span>20</span> with an{` `} <span>empty slot in the party</span> and an{` `} <span>extra PokéBall</span> - </PokemonEvolutionText> + </p> )} {eed.trigger.name === `take-damage` && ( - <PokemonEvolutionText> + <p className={styles.text}> Travel{` `} <span>under the stone bridge in Dusty Bowl</span> {` `} after taking at least <span>49 HP in damage</span> {` `} without fainting - </PokemonEvolutionText> + </p> )} </> ))} @@ -296,48 +285,46 @@ function Evolution({ evolution, name }: Props) { {removeDash(ee.species.name)} </Link> </div> - </PokemonEvolutionElement> + </div> ))} - </PokemonEvolutionStages> + </div> {evolution?.chain?.evolves_to?.map( (ee) => ee?.evolves_to?.length !== 0 && ( - <PokemonEvolutionFinal key={ee.species.name}> + <div className={styles.final} key={ee.species.name}> {ee?.evolves_to?.map((eee) => ( - <PokemonEvolutionStages key={ee.species.name}> - <PokemonEvolutionElement> + <div className={styles.stage} key={ee.species.name}> + <div className={styles.element}> <div> {eee?.evolution_details?.map((eeed) => ( <> {eeed.gender && (eeed.gender === 1 ? ( - <PokemonEvolutionText> + <p className={styles.text}> <span> Female</span> - </PokemonEvolutionText> + </p> ) : ( - <PokemonEvolutionText> + <p className={styles.text}> <span> Male</span> - </PokemonEvolutionText> + </p> ))} {eeed.trigger.name === `trade` && !eeed.held_item && ( - <PokemonEvolutionText> - Trade - </PokemonEvolutionText> + <p className={styles.text}>Trade</p> )} {eeed.held_item && eeed.trigger.name === `trade` && ( - <PokemonEvolutionText> + <p className={styles.text}> Trade holding <span> {` `} {removeDash(eeed.held_item.name)} </span> - </PokemonEvolutionText> + </p> )} {eeed.held_item && eeed.trigger.name === `level-up` && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up holding{` `} <span> {` `} @@ -346,28 +333,28 @@ function Evolution({ evolution, name }: Props) { {` `} during the{` `} <span> {eeed.time_of_day}</span> - </PokemonEvolutionText> + </p> )} {eeed.item && ( - <PokemonEvolutionText> + <p className={styles.text}> Use{` `} <span> {` `} {removeDash(eeed.item.name)} </span> - </PokemonEvolutionText> + </p> )} {eeed.known_move && ( - <PokemonEvolutionText> + <p className={styles.text}> Learn{` `} <span> {` `} {removeDash(eeed.known_move.name)} </span> - </PokemonEvolutionText> + </p> )} {eeed.known_move_type && eeed.min_affection && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up with{` `} <span> {` `} @@ -384,10 +371,10 @@ function Evolution({ evolution, name }: Props) { </span> {` `} type move - </PokemonEvolutionText> + </p> )} {eeed.known_move_type && eeed.min_happiness && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up with{` `} <span> {` `} @@ -404,68 +391,70 @@ function Evolution({ evolution, name }: Props) { </span> {` `} type move - </PokemonEvolutionText> + </p> )} {eeed.location && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up at{` `} <span> {` `} {removeDash(eeed.location.name)} </span> - </PokemonEvolutionText> + </p> )} {eeed.min_beauty && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up with{` `} <span> {eeed.min_beauty}+ beauty</span> - </PokemonEvolutionText> - )} - {eeed.min_happiness && eeed.time_of_day !== `` && ( - <PokemonEvolutionText> - Level up with{` `} - <span> - {` `} - {eeed.min_happiness}+ happiness - </span> - {` `} - during the{` `} - <span> {eeed.time_of_day}</span> - </PokemonEvolutionText> + </p> )} - {eeed.min_happiness && eeed.time_of_day === `` && ( - <PokemonEvolutionText> - Level up with{` `} - <span> + {eeed.min_happiness && + eeed.time_of_day !== `` && ( + <p className={styles.text}> + Level up with{` `} + <span> + {` `} + {eeed.min_happiness}+ happiness + </span> {` `} - {eeed.min_happiness}+ happiness - </span> - </PokemonEvolutionText> - )} + during the{` `} + <span> {eeed.time_of_day}</span> + </p> + )} + {eeed.min_happiness && + eeed.time_of_day === `` && ( + <p className={styles.text}> + Level up with{` `} + <span> + {` `} + {eeed.min_happiness}+ happiness + </span> + </p> + )} {eeed.min_level && eeed.time_of_day === `` && !eeed.party_type && !eeed.relative_physical_stats && eeed.turn_upside_down === false && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eeed.min_level}</span> - </PokemonEvolutionText> + </p> )} {eeed.min_level && eeed.time_of_day !== `` && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eeed.min_level}</span> during the <span> {eeed.time_of_day}</span> - </PokemonEvolutionText> + </p> )} {eeed.needs_overworld_rain === true && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eeed.min_level}</span> while {` `} <span>raining</span> - </PokemonEvolutionText> + </p> )} {eeed.party_species && ( - <PokemonEvolutionText> + <p className={styles.text}> Level up with a{` `} <span> {` `} @@ -476,18 +465,18 @@ function Evolution({ evolution, name }: Props) { </span> {` `} in the party - </PokemonEvolutionText> + </p> )} {eeed.party_type && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eeed.min_level}</span> with a {` `} <span> {eeed.party_type.name}</span> type pokémon in the party - </PokemonEvolutionText> + </p> )} {eeed.relative_physical_stats && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eeed.min_level}</span> with <span> {eeed.relative_physical_stats === 1 @@ -496,31 +485,31 @@ function Evolution({ evolution, name }: Props) { ? ` Attack = Defense` : ` Defense > Attack`} </span> - </PokemonEvolutionText> + </p> )} {eeed.trade_species && ( - <PokemonEvolutionText> + <p className={styles.text}> Trade with{` `} <span> {eeed.trade_species.name}</span> - </PokemonEvolutionText> + </p> )} {eeed.turn_upside_down === true && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span> {eeed.min_level} </span> while {` `} <span>holding the console upside-down</span> - </PokemonEvolutionText> + </p> )} {eeed.trigger.name === `shed` && ( - <PokemonEvolutionText> + <p className={styles.text}> Level <span>20</span> with an{` `} <span>empty slot in the party</span> and an {` `} <span>extra PokéBall</span> - </PokemonEvolutionText> + </p> )} {eeed.trigger.name === `take-damage` && ( - <PokemonEvolutionText> + <p className={styles.text}> Travel{` `} <span> under the stone bridge in Dusty Bowl @@ -529,7 +518,7 @@ function Evolution({ evolution, name }: Props) { after taking at least{` `} <span>49 HP in damage</span> without fainting - </PokemonEvolutionText> + </p> )} </> ))} @@ -557,17 +546,15 @@ function Evolution({ evolution, name }: Props) { {removeDash(eee.species.name)} </Link> </div> - </PokemonEvolutionElement> - </PokemonEvolutionStages> + </div> + </div> ))} - </PokemonEvolutionFinal> + </div> ), )} - </PokemonEvolution> + </div> )} - </PokemonEvolutionContainer> - </PokemonEvolutionSection> + </div> + </section> ); } - -export default Evolution; diff --git a/src/modules/pokedex/pokemon/components/evolution/index.ts b/src/modules/pokedex/pokemon/components/evolution/index.ts new file mode 100644 index 00000000..e5dde2c0 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/evolution/index.ts @@ -0,0 +1 @@ +export * from './Evolution'; diff --git a/src/components/pages/Pokemon/PokemonCard/Forms/Forms.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/forms/Forms.tsx similarity index 66% rename from src/components/pages/Pokemon/PokemonCard/Forms/Forms.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/forms/Forms.tsx index 6d3770aa..a1895ab8 100644 --- a/src/components/pages/Pokemon/PokemonCard/Forms/Forms.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/forms/Forms.tsx @@ -1,31 +1,21 @@ -import { H3 } from '@/components/common/styles/Headings'; -import { Section } from '@/components/common/styles/Sizing'; -import { - FullWidthTable, - TableContainer, - TBold, - TType, -} from '@/components/common/styles/Table'; -import { Type } from '@/components/common/styles/Themes'; -import SmallLoader from '@/components/common/ui/Loader/SmallLoader'; -import { Sup } from '@/components/pages/Abilities/AbilityCard/Styled.AbilityCard'; -import { useTableParams } from '@/hooks/useTableParams'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { IPokemonForm } from '@/types/Pokemon/PokemonForm'; -import { getPokemonForms } from '@/utils/DataFetch'; -import { removeDash } from '@/utils/Typography'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; -import { ColumnDef } from '@tanstack/react-table'; +import { useMemo } from 'react'; + +import { type UseQueryResult, useQuery } from '@tanstack/react-query'; +import { type ColumnDef } from '@tanstack/react-table'; import Image from 'next/image'; import Link from 'next/link'; -import { useMemo } from 'react'; -import toast from 'react-hot-toast'; + +import { ErrorToast, SmallLoader } from '@/components'; +import { useTableParams } from '@/hooks'; +import { getPokemonForms, removeDash } from '@/utils'; + +import type { IPokemon, IPokemonForm } from '@/types'; type Props = { pokemon: IPokemon; }; -function Forms({ pokemon }: Props) { +export function Forms({ pokemon }: Props) { const { isLoading, isError, @@ -62,7 +52,9 @@ function Forms({ pokemon }: Props) { accessorFn: (row) => row.form_name, id: `sort`, header: `Name`, - cell: (info) => <TBold>{removeDash(info.getValue<string>())}</TBold>, + cell: (info) => ( + <td className="tBold">{removeDash(info.getValue<string>())}</td> + ), }, { accessorKey: `is_battle_only`, @@ -91,12 +83,12 @@ function Forms({ pokemon }: Props) { id: `type1`, header: () => ( <span> - 1<Sup>st</Sup> type + 1<sup className="sup">st</sup> type </span> ), cell: (info) => ( - <TType> - <Type id={info.getValue<string>()}> + <td className="tType"> + <div className="type" id={info.getValue<string>()}> <Link href={{ pathname: `/type/[name]`, @@ -111,8 +103,8 @@ function Forms({ pokemon }: Props) { /> <span>{info.getValue<string>()}</span> </Link> - </Type> - </TType> + </div> + </td> ), }, { @@ -120,12 +112,12 @@ function Forms({ pokemon }: Props) { id: `type2`, header: () => ( <span> - 2<Sup>nd</Sup> type + 2<sup className="sup">nd</sup> type </span> ), cell: (info) => ( - <TType> - <Type id={info.getValue<string>()}> + <td className="tType"> + <div className="type" id={info.getValue<string>()}> <Link href={{ pathname: `/type/[name]`, @@ -140,8 +132,8 @@ function Forms({ pokemon }: Props) { /> <span>{info.getValue<string>()}</span> </Link> - </Type> - </TType> + </div> + </td> ), }, ], @@ -154,11 +146,7 @@ function Forms({ pokemon }: Props) { ); if (isError) { - return toast.error(`Something went wrong: ${error.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -166,16 +154,14 @@ function Forms({ pokemon }: Props) { } return ( - <Section id="forms"> - <H3>Forms</H3> - <TableContainer ref={tableContainerRef}> - <FullWidthTable> + <section className="section" id="forms"> + <h3 className="h3">Forms</h3> + <div className="tableContainer" ref={tableContainerRef}> + <table className="fullWidthTable"> {tableHeader()} {tableBody()} - </FullWidthTable> - </TableContainer> - </Section> + </table> + </div> + </section> ); } - -export default Forms; diff --git a/src/modules/pokedex/pokemon/components/forms/index.ts b/src/modules/pokedex/pokemon/components/forms/index.ts new file mode 100644 index 00000000..88815a71 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/forms/index.ts @@ -0,0 +1 @@ +export * from './Forms'; diff --git a/src/modules/pokedex/pokemon/components/index.ts b/src/modules/pokedex/pokemon/components/index.ts new file mode 100644 index 00000000..dc059746 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/index.ts @@ -0,0 +1,13 @@ +export * from './cards'; +export * from './competitive'; +export * from './content'; +export * from './data'; +export * from './evolution'; +export * from './forms'; +export * from './info'; +export * from './locations'; +export * from './moves'; +export * from './nav'; +export * from './sprites'; +export * from './stats'; +export * from './types'; diff --git a/src/components/pages/Pokemon/PokemonCard/Info/Styled.Info.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/info/Info.module.scss similarity index 65% rename from src/components/pages/Pokemon/PokemonCard/Info/Styled.Info.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/info/Info.module.scss index d91026d5..d78c55ba 100644 --- a/src/components/pages/Pokemon/PokemonCard/Info/Styled.Info.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/info/Info.module.scss @@ -1,13 +1,14 @@ -import styled from 'styled-components'; -import { device, Section } from '@/components/common/styles/Sizing'; -import { Table } from '@/components/common/styles/Table'; +@use '@/styles/abstracts' as *; +@use '@/styles/common' as *; + +.section { + @extend %section; -export const PokemonInfoSection = styled(Section)` display: grid; grid-template-columns: repeat(3, 1fr); gap: 3rem; - @media ${device.lg} { + @include lg { display: flex; align-items: center; justify-content: center; @@ -26,13 +27,15 @@ export const PokemonInfoSection = styled(Section)` } } } -`; +} + +.table { + @extend %table; -export const PokemonInfoTable = styled(Table)` width: 90%; & th { - background: rgba(130, 130, 130, 0.2); + background: rgb(130 130 130 / 20%); text-transform: capitalize; } @@ -46,7 +49,6 @@ export const PokemonInfoTable = styled(Table)` width: fit-content; display: block; cursor: pointer; - transition: 0.3s ease-in-out; &:hover { text-decoration: underline; @@ -57,4 +59,4 @@ export const PokemonInfoTable = styled(Table)` & tr:has(td:empty) { display: none; } -`; +} diff --git a/src/components/pages/Pokemon/PokemonCard/Info/Info.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/info/Info.tsx similarity index 51% rename from src/components/pages/Pokemon/PokemonCard/Info/Info.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/info/Info.tsx index 2a013ebb..7aa540d5 100644 --- a/src/components/pages/Pokemon/PokemonCard/Info/Info.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/info/Info.tsx @@ -1,15 +1,11 @@ // @ts-nocheck -import { H3 } from '@/components/common/styles/Headings'; -import { IEvolutionChain } from '@/types/Evolution/EvolutionChain'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { IPokemonSpecies } from '@/types/Pokemon/PokemonSpecies'; -import { capitalize } from '@/utils/Typography'; -import { InfoTable } from '../Utils/DataTables'; -import { - PokemonInfoSection, - PokemonInfoTable, -} from './Styled.Info.PokemonCard'; +import { capitalize } from '@/utils'; + +import { InfoTable } from '../../utils'; +import styles from './Info.module.scss'; + +import type { IEvolutionChain, IPokemon, IPokemonSpecies } from '@/types'; type Props = { pokemon: IPokemon; @@ -17,24 +13,24 @@ type Props = { evolution: IEvolutionChain; }; -function Info({ pokemon, species, evolution }: Props) { +export function Info({ pokemon, species, evolution }: Props) { const female = (species?.gender_rate / 8) * 100; const male = 100 - (species?.gender_rate / 8) * 100; return ( - <PokemonInfoSection id="information"> + <section className={styles.section} id="information"> {InfoTable.map((data) => ( <div key={data.category}> - <H3>{capitalize(data.category)}</H3> - <PokemonInfoTable> + <h3 className="h3">{capitalize(data.category)}</h3> + <table className={styles.table}> <tbody> {Array(Object.keys(data).length - 1) .fill(true) .map((_, i) => ( <tr key={i}> - <th>{data[`desc_` + (i + 1)]?.title}</th> + <th>{data[`desc_` + i++]?.title}</th> <td> - {data[`desc_` + (i + 1)]?.value({ + {data[`desc_` + i++]?.value({ pokemon: pokemon, species: species, evolution: evolution, @@ -45,11 +41,9 @@ function Info({ pokemon, species, evolution }: Props) { </tr> ))} </tbody> - </PokemonInfoTable> + </table> </div> ))} - </PokemonInfoSection> + </section> ); } - -export default Info; diff --git a/src/modules/pokedex/pokemon/components/info/index.ts b/src/modules/pokedex/pokemon/components/info/index.ts new file mode 100644 index 00000000..3d93d87e --- /dev/null +++ b/src/modules/pokedex/pokemon/components/info/index.ts @@ -0,0 +1 @@ +export * from './Info'; diff --git a/src/components/pages/Pokemon/PokemonCard/Locations/Locations.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/locations/Locations.tsx similarity index 76% rename from src/components/pages/Pokemon/PokemonCard/Locations/Locations.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/locations/Locations.tsx index fa23a2a1..e03e41f3 100644 --- a/src/components/pages/Pokemon/PokemonCard/Locations/Locations.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/locations/Locations.tsx @@ -1,20 +1,18 @@ -import { H3 } from '@/components/common/styles/Headings'; -import { Section } from '@/components/common/styles/Sizing'; -import { TableContainer, TBold } from '@/components/common/styles/Table'; -import { LocationTable } from '@/components/pages/Locations/Styled.Locations'; -import { useTableParams } from '@/hooks/useTableParams'; -import { ILocationAreaEncounter } from '@/types/Pokemon/Pokemon'; -import { IEncounter } from '@/types/Utility/CommonModels'; -import { removeDash } from '@/utils/Typography'; -import { ColumnDef } from '@tanstack/react-table'; import { useMemo } from 'react'; +import { useTableParams } from '@/hooks'; +import styles from '@/modules/locations/Locations.module.scss'; +import { removeDash } from '@/utils'; + +import type { IEncounter, ILocationAreaEncounter } from '@/types'; +import type { ColumnDef } from '@tanstack/react-table'; + type Props = { location: ILocationAreaEncounter[]; game: string; }; -function Locations({ location, game }: Props) { +export function Locations({ location, game }: Props) { const filteredLocation = location .map((l) => { const version_details = l.version_details.filter( @@ -37,12 +35,12 @@ function Locations({ location, game }: Props) { id: `sort`, header: `Location`, cell: (info) => ( - <TBold> + <td className="tBold"> {removeDash(info.getValue<string>()).replace( /kanto|johto|hoenn|sinnoh|unova|kalos|alola|galar|hisui|paldea|area|sea/g, ``, )} - </TBold> + </td> ), }, { @@ -111,10 +109,10 @@ function Locations({ location, game }: Props) { ); return ( - <Section id="locations"> - <H3>Locations</H3> - <TableContainer ref={tableContainerRef}> - <LocationTable> + <section className="section" id="locations"> + <h3 className="h3">Locations</h3> + <div className="tableContainer" ref={tableContainerRef}> + <table className={styles.table}> {tableHeader()} {tableBody()} <tfoot> @@ -122,10 +120,8 @@ function Locations({ location, game }: Props) { <td colSpan={5}>Not present or not found in nature</td> </tr> </tfoot> - </LocationTable> - </TableContainer> - </Section> + </table> + </div> + </section> ); } - -export default Locations; diff --git a/src/modules/pokedex/pokemon/components/locations/index.ts b/src/modules/pokedex/pokemon/components/locations/index.ts new file mode 100644 index 00000000..223085fc --- /dev/null +++ b/src/modules/pokedex/pokemon/components/locations/index.ts @@ -0,0 +1 @@ +export * from './Locations'; diff --git a/src/modules/pokedex/pokemon/components/moves/Moves.module.scss b/src/modules/pokedex/pokemon/components/moves/Moves.module.scss new file mode 100644 index 00000000..11bf5eb2 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/moves/Moves.module.scss @@ -0,0 +1,8 @@ +@use '@/styles/abstracts' as *; +@use '@/styles/common' as *; + +.section { + @extend %section; + + overflow-x: hidden; +} diff --git a/src/components/pages/Pokemon/PokemonCard/Moves/Moves.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/moves/Moves.tsx similarity index 66% rename from src/components/pages/Pokemon/PokemonCard/Moves/Moves.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/moves/Moves.tsx index 9b5a74ad..4ef95659 100644 --- a/src/components/pages/Pokemon/PokemonCard/Moves/Moves.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/moves/Moves.tsx @@ -1,25 +1,22 @@ -import { H3 } from '@/components/common/styles/Headings'; -import { - FullWidthTable, - TableContainer, - TBold, - TCapitalize, - TLink, -} from '@/components/common/styles/Table'; -import SmallLoader from '@/components/common/ui/Loader/SmallLoader'; -import { useTableParams } from '@/hooks/useTableParams'; -import { IMoveAilment } from '@/types/Moves/MoveAilment'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { LearnMethod } from '@/utils/ObjectsMap'; -import { removeDash, uppercase } from '@/utils/Typography'; -import { CellContext, ColumnDef } from '@tanstack/react-table'; +import { useEffect, useMemo, useState } from 'react'; + +import * as Tabs from '@radix-ui/react-tabs'; +import { type CellContext, type ColumnDef } from '@tanstack/react-table'; import Image from 'next/image'; import Link from 'next/link'; -import { useEffect, useMemo, useState } from 'react'; -import toast from 'react-hot-toast'; -import { useFetchMachines } from '../Hooks/useFetchMachines'; -import { IMoveWithDetails, useFetchMoves } from '../Hooks/useFetchMoves'; -import { PokemonMovesSection } from './Styled.Moves.PokemonCard'; + +import { ErrorToast, SmallLoader } from '@/components'; +import { useTableParams } from '@/hooks'; +import { LearnMethod, removeDash, uppercase } from '@/utils'; + +import { + type IMoveWithDetails, + useFetchMachines, + useFetchMoves, +} from '../../hooks'; +import styles from './Moves.module.scss'; + +import type { IMoveAilment, IPokemon } from '@/types'; type Props = { pokemon: IPokemon; @@ -27,7 +24,7 @@ type Props = { name: string; }; -function MovesPokemon({ pokemon, version, name }: Props) { +export function Moves({ pokemon, version, name }: Props) { const [learn, setLearn] = useState<string>(`level-up`); const [toggle, setToggle] = useState<number>(0); @@ -93,16 +90,17 @@ function MovesPokemon({ pokemon, version, name }: Props) { id: `name`, header: `Name`, cell: (info) => ( - <TBold> - <TLink + <td className="tBold"> + <Link + className="tLink" href={{ pathname: `/move/[name]`, query: { name: info.getValue<string>() }, }} > {removeDash(info.getValue<string>())} - </TLink> - </TBold> + </Link> + </td> ), }, { @@ -132,49 +130,55 @@ function MovesPokemon({ pokemon, version, name }: Props) { accessorKey: `details.damage_class.name`, id: `category`, header: `Category`, - cell: (info) => <TCapitalize>{info.getValue<string>()}</TCapitalize>, + cell: (info) => ( + <td className="tCapitalize">{info.getValue<string>()}</td> + ), }, { accessorKey: `details.power`, id: `power`, header: `Power`, cell: (info) => ( - <TCapitalize>{info.getValue<string>() || `-`}</TCapitalize> + <td className="tCapitalize">{info.getValue<string>() || `-`}</td> ), }, { accessorKey: `details.pp`, id: `pp`, header: `PP`, - cell: (info) => <TCapitalize>{info.getValue<string>()}</TCapitalize>, + cell: (info) => ( + <td className="tCapitalize">{info.getValue<string>()}</td> + ), }, { accessorKey: `details.accuracy`, id: `accuracy`, header: `Accuracy`, cell: (info) => ( - <TCapitalize>{info.getValue<string>() || `-`}</TCapitalize> + <td className="tCapitalize">{info.getValue<string>() || `-`}</td> ), }, { accessorKey: `details.priority`, id: `priority`, header: `Priority`, - cell: (info) => <TCapitalize>{info.getValue<string>()}</TCapitalize>, + cell: (info) => ( + <td className="tCapitalize">{info.getValue<string>()}</td> + ), }, { accessorKey: `details.meta.ailment`, id: `status`, header: `Status`, cell: (info) => ( - <TCapitalize> + <td className="tCapitalize"> {info.getValue() ? removeDash(info?.getValue<IMoveAilment>().name).replace( `none`, `-`, ) : `-`} - </TCapitalize> + </td> ), }, ], @@ -189,11 +193,7 @@ function MovesPokemon({ pokemon, version, name }: Props) { ); if (isError) { - return toast.error(`Something went wrong: ${error?.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -201,22 +201,26 @@ function MovesPokemon({ pokemon, version, name }: Props) { } return ( - <PokemonMovesSection id="moves"> - <H3>Moves</H3> - <LearnMethod toggle={toggle} setToggle={setToggle} setLearn={setLearn} /> - <TableContainer ref={tableContainerRef}> - <FullWidthTable> - {tableHeader()} - {tableBody()} - <tfoot> - <tr> - <td colSpan={9}>There is no move learned this way</td> - </tr> - </tfoot> - </FullWidthTable> - </TableContainer> - </PokemonMovesSection> + <Tabs.Root + className={`${styles.section} TabsRootSection`} + id="moves" + defaultValue={String(toggle)} + > + <h3 className="h3">Moves</h3> + <LearnMethod setToggle={setToggle} setLearn={setLearn} /> + <Tabs.Content value={String(toggle)}> + <div className="tableContainer" ref={tableContainerRef}> + <table className="fullWidthTable"> + {tableHeader()} + {tableBody()} + <tfoot> + <tr> + <td colSpan={9}>There is no move learned this way</td> + </tr> + </tfoot> + </table> + </div> + </Tabs.Content> + </Tabs.Root> ); } - -export default MovesPokemon; diff --git a/src/modules/pokedex/pokemon/components/moves/index.ts b/src/modules/pokedex/pokemon/components/moves/index.ts new file mode 100644 index 00000000..eda649db --- /dev/null +++ b/src/modules/pokedex/pokemon/components/moves/index.ts @@ -0,0 +1 @@ +export * from './Moves'; diff --git a/src/components/pages/Pokemon/PokemonCard/Nav/Nav.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/nav/Nav.tsx similarity index 75% rename from src/components/pages/Pokemon/PokemonCard/Nav/Nav.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/nav/Nav.tsx index 28776777..cb03d8b2 100644 --- a/src/components/pages/Pokemon/PokemonCard/Nav/Nav.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/nav/Nav.tsx @@ -1,5 +1,6 @@ -import { GenNav } from '@/components/common/styles/Navbars'; -import { Dispatch, SetStateAction } from 'react'; +import { type Dispatch, type SetStateAction } from 'react'; + +import * as NavigationMenu from '@radix-ui/react-navigation-menu'; type Props = { pokemonId: number; @@ -8,14 +9,16 @@ type Props = { setFormat: Dispatch<SetStateAction<string | null>>; }; -function PokemonNav({ pokemonId, setGame, setVersion, setFormat }: Props) { +export function Nav({ pokemonId, setGame, setVersion, setFormat }: Props) { return ( - <GenNav id="generations"> - <ul> + <NavigationMenu.Root className="NavigationMenuRoot" id="generations"> + <NavigationMenu.List className="NavigationMenuList"> {(pokemonId < 152 || pokemonId > 10000) && ( - <li> - <button>Gen I</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen I + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => { setGame(`red`); @@ -43,13 +46,15 @@ function PokemonNav({ pokemonId, setGame, setVersion, setFormat }: Props) { > Yellow </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(pokemonId < 252 || pokemonId > 10000) && ( - <li> - <button>Gen II</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen II + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => { setGame(`gold`); @@ -77,13 +82,15 @@ function PokemonNav({ pokemonId, setGame, setVersion, setFormat }: Props) { > Crystal </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(pokemonId < 387 || pokemonId > 10000) && ( - <li> - <button>Gen III</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen III + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => { setGame(`ruby`); @@ -129,13 +136,15 @@ function PokemonNav({ pokemonId, setGame, setVersion, setFormat }: Props) { > Leaf Green </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(pokemonId < 494 || pokemonId > 10000) && ( - <li> - <button>Gen IV</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen IV + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => { setGame(`diamond`); @@ -181,13 +190,15 @@ function PokemonNav({ pokemonId, setGame, setVersion, setFormat }: Props) { > Soul Silver </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(pokemonId < 650 || pokemonId > 10000) && ( - <li> - <button>Gen V</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen V + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => { setGame(`black`); @@ -224,13 +235,15 @@ function PokemonNav({ pokemonId, setGame, setVersion, setFormat }: Props) { > White 2 </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(pokemonId < 722 || pokemonId > 10000) && ( - <li> - <button>Gen VI</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen VI + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => { setGame(`x`); @@ -267,13 +280,15 @@ function PokemonNav({ pokemonId, setGame, setVersion, setFormat }: Props) { > Alpha Sapphire </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(pokemonId < 810 || pokemonId > 10000) && ( - <li> - <button>Gen VII</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen VII + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => { setGame(`sun`); @@ -328,13 +343,15 @@ function PokemonNav({ pokemonId, setGame, setVersion, setFormat }: Props) { > Let's Go Eevee </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(pokemonId < 905 || pokemonId > 10000) && ( - <li> - <button>Gen VIII</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen VIII + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> {pokemonId < 898 && ( <> <button @@ -366,13 +383,15 @@ function PokemonNav({ pokemonId, setGame, setVersion, setFormat }: Props) { > Legends Arceus </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} {(pokemonId < 1011 || pokemonId > 10000) && ( - <li> - <button>Gen IX</button> - <div> + <NavigationMenu.Item> + <NavigationMenu.Trigger className="NavigationMenuTrigger"> + Gen IX + </NavigationMenu.Trigger> + <NavigationMenu.Content className="NavigationMenuContent"> <button onClick={() => { setGame(`scarlet`); @@ -391,12 +410,13 @@ function PokemonNav({ pokemonId, setGame, setVersion, setFormat }: Props) { > Violet </button> - </div> - </li> + </NavigationMenu.Content> + </NavigationMenu.Item> )} - </ul> - </GenNav> + </NavigationMenu.List> + <div className="ViewportPosition"> + <NavigationMenu.Viewport className="NavigationMenuViewport" /> + </div> + </NavigationMenu.Root> ); } - -export default PokemonNav; diff --git a/src/modules/pokedex/pokemon/components/nav/index.ts b/src/modules/pokedex/pokemon/components/nav/index.ts new file mode 100644 index 00000000..93467d75 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/nav/index.ts @@ -0,0 +1 @@ +export * from './Nav'; diff --git a/src/components/pages/Pokemon/PokemonCard/Sprites/Styled.Sprites.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/sprites/Sprites.module.scss similarity index 67% rename from src/components/pages/Pokemon/PokemonCard/Sprites/Styled.Sprites.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/sprites/Sprites.module.scss index be472d06..7fe9d9bf 100644 --- a/src/components/pages/Pokemon/PokemonCard/Sprites/Styled.Sprites.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/sprites/Sprites.module.scss @@ -1,7 +1,6 @@ -import styled from 'styled-components'; -import { device } from '@/components/common/styles/Sizing'; +@use '@/styles/abstracts' as *; -export const PokemonSpritesDiv = styled.div` +.sprites { display: grid; grid-template-columns: repeat(4, 1fr); row-gap: 3rem; @@ -20,7 +19,7 @@ export const PokemonSpritesDiv = styled.div` } } - @media ${device.xs} { + @include xs { grid-template-columns: repeat(2, 1fr); } -`; +} diff --git a/src/components/pages/Pokemon/PokemonCard/Sprites/Sprites.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/sprites/Sprites.tsx similarity index 91% rename from src/components/pages/Pokemon/PokemonCard/Sprites/Sprites.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/sprites/Sprites.tsx index cf6e0125..970aa7ed 100644 --- a/src/components/pages/Pokemon/PokemonCard/Sprites/Sprites.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/sprites/Sprites.tsx @@ -1,19 +1,19 @@ -import { H3 } from '@/components/common/styles/Headings'; -import { Section } from '@/components/common/styles/Sizing'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; import Image from 'next/image'; -import { PokemonSpritesDiv } from './Styled.Sprites.PokemonCard'; + +import styles from './Sprites.module.scss'; + +import type { IPokemon } from '@/types'; type Props = { pokemon: IPokemon; }; -function Sprites({ pokemon }: Props) { +export function Sprites({ pokemon }: Props) { return ( <> - <Section id="sprites"> - <H3>Sprites</H3> - <PokemonSpritesDiv> + <section className="section" id="sprites"> + <h3 className="h3">Sprites</h3> + <div className={styles.sprites}> <div> <Image src={pokemon?.sprites?.front_default} @@ -100,13 +100,13 @@ function Sprites({ pokemon }: Props) { <p>Back Shiny Female</p> </div> )} - </PokemonSpritesDiv> - </Section> + </div> + </section> {pokemon.id < 650 && ( - <Section> - <H3>Animated sprites</H3> - <PokemonSpritesDiv> + <section className="section"> + <h3 className="h3">Animated sprites</h3> + <div className={styles.sprites}> <div> <Image src={`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/versions/generation-v/black-white/animated/${pokemon.id}.gif`} @@ -187,11 +187,9 @@ function Sprites({ pokemon }: Props) { <p>Back Shiny Female</p> </div> )} - </PokemonSpritesDiv> - </Section> + </div> + </section> )} </> ); } - -export default Sprites; diff --git a/src/modules/pokedex/pokemon/components/sprites/index.ts b/src/modules/pokedex/pokemon/components/sprites/index.ts new file mode 100644 index 00000000..19cecc16 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/sprites/index.ts @@ -0,0 +1 @@ +export * from './Sprites'; diff --git a/src/components/pages/Pokemon/PokemonCard/Stats/Styled.Stats.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/stats/Stats.module.scss similarity index 50% rename from src/components/pages/Pokemon/PokemonCard/Stats/Styled.Stats.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/stats/Stats.module.scss index 819fe1b8..01235afe 100644 --- a/src/components/pages/Pokemon/PokemonCard/Stats/Styled.Stats.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/stats/Stats.module.scss @@ -1,57 +1,62 @@ -import { device } from '@/components/common/styles/Sizing'; -import { FullWidthTable } from '@/components/common/styles/Table'; -import styled from 'styled-components'; +@use '@/styles/abstracts' as *; +@use '@/styles/common' as *; -export const PokemonStatsCircles = styled.div` +.circles { margin: 3rem 0 0; display: grid; grid-template-columns: repeat(6, 1fr); gap: 1rem; height: 15rem; - & .CircularProgressbar { + svg { height: 100%; - &-trail { - stroke: ${({ theme }) => theme.secondary} !important; + path:first-of-type { + @include themed { + stroke: t('text') !important; + } } - &-path { - stroke: ${({ theme }) => theme.red} !important; + path:last-of-type { + stroke: $red !important; } - &-text { - fill: ${({ theme }) => theme.secondary} !important; + text { font-size: 1.3rem !important; font-weight: 600 !important; + @include themed { + fill: t('text') !important; + } } } - @media ${device.lg} { + @include lg { height: 30rem; row-gap: 3rem; grid-template-columns: repeat(3, 1fr); } - @media ${device.sm} { + @include sm { height: 45rem; row-gap: 4rem; grid-template-columns: 1fr 1fr; - & .CircularProgressbar { + .circle { &-text { font-size: 2rem; } } } -`; +} -export const PokemonStatsTotal = styled.p` +.total { margin: 2rem 0; font-size: 1.7rem; -`; +} + +.details { + margin-top: 1rem; -export const PokemonStatsDetails = styled.details` & summary { width: fit-content; margin-bottom: 2rem; @@ -60,16 +65,21 @@ export const PokemonStatsDetails = styled.details` text-transform: capitalize; cursor: pointer; } -`; +} + +.table { + @extend %fullWidthTable; -export const PokemonCalcTable = styled(FullWidthTable)` border-bottom: none; + & th { - color: ${({ theme }) => theme.secondary}; font-size: 1.7rem; font-weight: 600; text-transform: capitalize; - background: rgba(130, 130, 130, 0.2); + background: rgb(130 130 130 / 20%); + @include themed { + color: t('text'); + } } & tr:last-of-type { @@ -85,28 +95,31 @@ export const PokemonCalcTable = styled(FullWidthTable)` width: 100%; padding: 0.7rem; background: transparent; - color: ${({ theme }) => theme.secondary}; - border: 1px solid ${({ theme }) => theme.secondary}; border-radius: 5px; outline: none; + @include themed { + color: t('text'); + border: 1px solid t('text'); + } &::placeholder { - color: ${({ theme }) => theme.secondary}; opacity: 1; + @include themed { + color: t('text'); + } } &:focus { - border: 1px solid ${({ theme }) => theme.red}; + border: 1px solid $red; } } & input[type='number'] { appearance: textfield; - -moz-appearance: textfield; &::-webkit-inner-spin-button, ::-webkit-outer-spin-button { - -webkit-appearance: textfield; + appearance: textfield; } } @@ -116,25 +129,31 @@ export const PokemonCalcTable = styled(FullWidthTable)` & option { text-transform: capitalize; - background: ${({ theme }) => theme.main}; - color: ${({ theme }) => theme.secondary}; + @include themed { + background: t('bg'); + color: t('text'); + } } } & button { - background: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.main}; border: 1px solid transparent; border-radius: 5px; padding: 1rem 1.5rem; font-size: 1.7rem; font-weight: 600; - transition: 0.3s ease-in-out; + + @include themed { + background: t('text'); + color: t('bg'); + } &:hover { - color: ${({ theme }) => theme.secondary}; - background: ${({ theme }) => theme.main}; - border: 1px solid ${({ theme }) => theme.secondary}; + @include themed { + border: 1px solid t('text'); + color: t('text'); + background: t('bg'); + } } &:active { @@ -142,11 +161,13 @@ export const PokemonCalcTable = styled(FullWidthTable)` } } } -`; +} + +.results { + @extend %fullWidthTable; -export const PokemonStatsResults = styled(FullWidthTable)` & td { - border-left: 1px solid rgba(130, 130, 130, 0.2); - border-right: 1px solid rgba(130, 130, 130, 0.2); + border-left: 1px solid rgb(130 130 130 / 20%); + border-right: 1px solid rgb(130 130 130 / 20%); } -`; +} diff --git a/src/modules/pokedex/pokemon/components/stats/Stats.tsx b/src/modules/pokedex/pokemon/components/stats/Stats.tsx new file mode 100644 index 00000000..c70b72df --- /dev/null +++ b/src/modules/pokedex/pokemon/components/stats/Stats.tsx @@ -0,0 +1,165 @@ +import { useState } from 'react'; + +import * as Tabs from '@radix-ui/react-tabs'; +import { CircularProgressbar } from 'react-circular-progressbar'; + +import { Tooltip } from '@/components'; + +import 'react-circular-progressbar/dist/styles.css'; +import { Calculator } from './calculator'; +import styles from './Stats.module.scss'; + +import type { IPokemon } from '@/types'; + +type Props = { + pokemon: IPokemon; +}; + +export function Stats({ pokemon }: Props) { + const [toggle, setToggle] = useState<number>(1); + + const percentageHp = pokemon.stats[0].base_stat; + const percentageAtk = pokemon.stats[1].base_stat; + const percentageDef = pokemon.stats[2].base_stat; + const percentageSpAtk = pokemon.stats[3].base_stat; + const percentageSpDef = pokemon.stats[4].base_stat; + const percentageSpd = pokemon.stats[5].base_stat; + const percentageTotal = + pokemon?.stats?.[0]?.base_stat + + pokemon?.stats?.[1]?.base_stat + + pokemon?.stats?.[2]?.base_stat + + pokemon?.stats?.[3]?.base_stat + + pokemon?.stats?.[4]?.base_stat + + pokemon?.stats?.[5]?.base_stat; + + const statCalc = (value: number) => { + if (toggle === 1) { + return value; + } else if (toggle === 2) { + return Math.floor((value * 2 + 5) * 0.9); + } else if (toggle === 3) { + return Math.floor(value * 2 + 5); + } else if (toggle === 4) { + return Math.floor(value * 2 + 31 + 252 / 4 + 5); + } else { + return Math.floor((value * 2 + 31 + 252 / 4 + 5) * 1.1); + } + }; + + const hpCalc = (value: number) => { + if (toggle === 1) { + return value; + } else if (toggle === 2) { + return Math.floor(value * 2 + 100 + 10); + } else if (toggle === 3) { + return Math.floor(value * 2 + 100 + 10); + } else if (toggle === 4) { + return Math.floor(value * 2 + 31 + 252 / 4 + 100 + 10); + } else { + return Math.floor(value * 2 + 31 + 252 / 4 + 100 + 10); + } + }; + + return ( + <> + <Tabs.Root className="TabsRootSection" id="stats" defaultValue="1"> + <h3 className="h3">Base stats</h3> + <Tabs.List className="TabsList" aria-label="Switch between stats value"> + <Tabs.Trigger + value="1" + className="TabsTrigger" + onClick={() => setToggle(1)} + > + Base + </Tabs.Trigger> + <Tabs.Trigger + value="2" + className="TabsTrigger" + onClick={() => setToggle(2)} + data-tooltip-id="stat-tooltip" + data-tooltip-content="0 IV, 0 EV and negative nature" + > + Min - + </Tabs.Trigger> + <Tabs.Trigger + value="3" + className="TabsTrigger" + onClick={() => setToggle(3)} + data-tooltip-id="stat-tooltip" + data-tooltip-content="0 IV, 0 EV and neutral nature" + > + Min + </Tabs.Trigger> + <Tabs.Trigger + value="4" + className="TabsTrigger" + onClick={() => setToggle(4)} + data-tooltip-id="stat-tooltip" + data-tooltip-content="31 IV, 252 EV and neutral nature" + > + Max + </Tabs.Trigger> + <Tabs.Trigger + value="5" + className="TabsTrigger" + onClick={() => setToggle(5)} + data-tooltip-id="stat-tooltip" + data-tooltip-content="31 IV, 252 EV and positive nature" + > + Max + + </Tabs.Trigger> + </Tabs.List> + <Tabs.Content value={String(toggle)}> + <div className={styles.circles}> + <CircularProgressbar + maxValue={toggle === 1 ? 255 : 720} + value={hpCalc(percentageHp)} + text={`${hpCalc(percentageHp)} Hp`} + strokeWidth={5} + /> + <CircularProgressbar + maxValue={toggle === 1 ? 255 : 720} + value={statCalc(percentageAtk)} + text={`${statCalc(percentageAtk)} Atk`} + strokeWidth={5} + /> + <CircularProgressbar + maxValue={toggle === 1 ? 255 : 720} + value={statCalc(percentageDef)} + text={`${statCalc(percentageDef)} Def`} + strokeWidth={5} + /> + <CircularProgressbar + maxValue={toggle === 1 ? 255 : 720} + value={statCalc(percentageSpAtk)} + text={`${statCalc(percentageSpAtk)} Sp Atk`} + strokeWidth={5} + /> + <CircularProgressbar + maxValue={toggle === 1 ? 255 : 720} + value={statCalc(percentageSpDef)} + text={`${statCalc(percentageSpDef)} Sp Def`} + strokeWidth={5} + /> + <CircularProgressbar + maxValue={toggle === 1 ? 255 : 720} + value={statCalc(percentageSpd)} + text={`${statCalc(percentageSpd)} Spd`} + strokeWidth={5} + /> + </div> + </Tabs.Content> + <Tabs.Content value="1"> + <p className={styles.total}> + <span className="bold">Total</span>: {percentageTotal} + </p> + </Tabs.Content> + <details className={styles.details}> + <summary>Stats calculator</summary> + <Calculator baseStat={pokemon.stats} /> + </details> + </Tabs.Root> + <Tooltip id="stat-tooltip" /> + </> + ); +} diff --git a/src/components/pages/Pokemon/PokemonCard/Stats/Calculator/Calculator.Stats.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/stats/calculator/Calculator.tsx similarity index 80% rename from src/components/pages/Pokemon/PokemonCard/Stats/Calculator/Calculator.Stats.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/stats/calculator/Calculator.tsx index 5a12ade8..631c335c 100644 --- a/src/components/pages/Pokemon/PokemonCard/Stats/Calculator/Calculator.Stats.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/stats/calculator/Calculator.tsx @@ -1,11 +1,15 @@ -import { Divider } from '@/components/common/ui/Divider'; -import { IPokemonStat } from '@/types/Pokemon/Pokemon'; -import { pokemonNatures } from '@/utils/DataArrays'; -import { removeDash } from '@/utils/Typography'; import { useState } from 'react'; -import { SubmitHandler, useForm } from 'react-hook-form'; -import Results from '../Results/Results.Stats.PokemonCard'; -import { PokemonCalcTable } from '../Styled.Stats.PokemonCard'; + +import * as Label from '@radix-ui/react-label'; +import { type SubmitHandler, useForm } from 'react-hook-form'; + +import { Input, Separator } from '@/components'; +import { pokemonNatures, removeDash } from '@/utils'; + +import { Results } from '../results'; +import styles from '../Stats.module.scss'; + +import type { IPokemonStat } from '@/types'; type Props = { baseStat: IPokemonStat[]; @@ -28,7 +32,7 @@ export interface IStatsForm { nature: string; } -function CalculatorStats({ baseStat }: Props) { +export function Calculator({ baseStat }: Props) { const [stats, setStats] = useState<IStatsForm | null>(null); const { register, handleSubmit } = useForm<IStatsForm>(); @@ -37,14 +41,14 @@ function CalculatorStats({ baseStat }: Props) { return ( <> <form onSubmit={handleSubmit(onSubmit)}> - <PokemonCalcTable> + <table className={styles.table}> <tbody> <tr> <th> - <label htmlFor="level">Level</label> + <Label.Root htmlFor="level">Level</Label.Root> </th> <td colSpan={2}> - <input + <Input type="number" min={1} max={100} @@ -56,10 +60,10 @@ function CalculatorStats({ baseStat }: Props) { </tr> <tr> <th> - <label htmlFor="hp">Hp</label> + <Label.Root htmlFor="hp">Hp</Label.Root> </th> <td> - <input + <Input type="number" min={0} max={252} @@ -69,7 +73,7 @@ function CalculatorStats({ baseStat }: Props) { /> </td> <td> - <input + <Input type="number" min={0} max={31} @@ -81,10 +85,10 @@ function CalculatorStats({ baseStat }: Props) { </tr> <tr> <th> - <label htmlFor="attack">Attack</label> + <Label.Root htmlFor="attack">Attack</Label.Root> </th> <td> - <input + <Input type="number" min={0} max={252} @@ -94,7 +98,7 @@ function CalculatorStats({ baseStat }: Props) { /> </td> <td> - <input + <Input type="number" min={0} max={31} @@ -106,10 +110,10 @@ function CalculatorStats({ baseStat }: Props) { </tr> <tr> <th> - <label htmlFor="defense">Defense</label> + <Label.Root htmlFor="defense">Defense</Label.Root> </th> <td> - <input + <Input type="number" min={0} max={252} @@ -119,7 +123,7 @@ function CalculatorStats({ baseStat }: Props) { /> </td> <td> - <input + <Input type="number" min={0} max={31} @@ -131,10 +135,10 @@ function CalculatorStats({ baseStat }: Props) { </tr> <tr> <th> - <label htmlFor="specialAttack">Special Attack</label> + <Label.Root htmlFor="specialAttack">Special Attack</Label.Root> </th> <td> - <input + <Input type="number" min={0} max={252} @@ -144,7 +148,7 @@ function CalculatorStats({ baseStat }: Props) { /> </td> <td> - <input + <Input type="number" min={0} max={31} @@ -156,10 +160,12 @@ function CalculatorStats({ baseStat }: Props) { </tr> <tr> <th> - <label htmlFor="specialDefense">Special Defense</label> + <Label.Root htmlFor="specialDefense"> + Special Defense + </Label.Root> </th> <td> - <input + <Input type="number" min={0} max={252} @@ -169,7 +175,7 @@ function CalculatorStats({ baseStat }: Props) { /> </td> <td> - <input + <Input type="number" min={0} max={31} @@ -181,10 +187,10 @@ function CalculatorStats({ baseStat }: Props) { </tr> <tr> <th> - <label htmlFor="speed">Speed</label> + <Label.Root htmlFor="speed">Speed</Label.Root> </th> <td> - <input + <Input type="number" min={0} max={252} @@ -194,7 +200,7 @@ function CalculatorStats({ baseStat }: Props) { /> </td> <td> - <input + <Input type="number" min={0} max={31} @@ -206,7 +212,7 @@ function CalculatorStats({ baseStat }: Props) { </tr> <tr> <th> - <label htmlFor="nature">Nature</label> + <Label.Root htmlFor="nature">Nature</Label.Root> </th> <td colSpan={2}> <select {...register(`nature`)} required> @@ -225,16 +231,14 @@ function CalculatorStats({ baseStat }: Props) { </td> </tr> </tbody> - </PokemonCalcTable> + </table> </form> {stats && ( <> - <Divider /> + <Separator /> <Results stats={stats} baseStat={baseStat} /> </> )} </> ); } - -export default CalculatorStats; diff --git a/src/modules/pokedex/pokemon/components/stats/calculator/index.ts b/src/modules/pokedex/pokemon/components/stats/calculator/index.ts new file mode 100644 index 00000000..66a40d92 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/stats/calculator/index.ts @@ -0,0 +1 @@ +export * from './Calculator'; diff --git a/src/modules/pokedex/pokemon/components/stats/index.ts b/src/modules/pokedex/pokemon/components/stats/index.ts new file mode 100644 index 00000000..248f7a60 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/stats/index.ts @@ -0,0 +1,3 @@ +export * from './Stats'; +export * from './calculator'; +export * from './results'; diff --git a/src/components/pages/Pokemon/PokemonCard/Stats/Results/Results.Stats.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/stats/results/Results.tsx similarity index 83% rename from src/components/pages/Pokemon/PokemonCard/Stats/Results/Results.Stats.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/stats/results/Results.tsx index 77afca7a..f168c764 100644 --- a/src/components/pages/Pokemon/PokemonCard/Stats/Results/Results.Stats.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/stats/results/Results.tsx @@ -1,15 +1,16 @@ -import { THead } from '@/components/common/styles/Table'; -import { IPokemonStat } from '@/types/Pokemon/Pokemon'; -import { pokemonNatures } from '@/utils/DataArrays'; -import { IStatsForm } from '../Calculator/Calculator.Stats.PokemonCard'; -import { PokemonStatsResults } from '../Styled.Stats.PokemonCard'; +import { pokemonNatures } from '@/utils'; + +import { type IStatsForm } from '../calculator/Calculator'; +import styles from '../Stats.module.scss'; + +import type { IPokemonStat } from '@/types'; type Props = { stats: IStatsForm; baseStat: IPokemonStat[]; }; -function Results({ stats, baseStat }: Props) { +export function Results({ stats, baseStat }: Props) { const getNatureInfluence = (stat: string) => { if ( pokemonNatures.find((n) => n.name === stats.nature)?.positive === stat @@ -24,8 +25,8 @@ function Results({ stats, baseStat }: Props) { }; return ( - <PokemonStatsResults> - <THead> + <table className={styles.results}> + <thead className="tHead"> <tr> <th>Hp</th> <th>Attack</th> @@ -34,7 +35,7 @@ function Results({ stats, baseStat }: Props) { <th>Special Defense</th> <th>Speed</th> </tr> - </THead> + </thead> <tbody> <tr> <td> @@ -97,8 +98,6 @@ function Results({ stats, baseStat }: Props) { </td> </tr> </tbody> - </PokemonStatsResults> + </table> ); } - -export default Results; diff --git a/src/modules/pokedex/pokemon/components/stats/results/index.ts b/src/modules/pokedex/pokemon/components/stats/results/index.ts new file mode 100644 index 00000000..9646dd49 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/stats/results/index.ts @@ -0,0 +1 @@ +export * from './Results'; diff --git a/src/components/pages/Pokemon/PokemonCard/Types/Table/Table.Types.PokemonCard.tsx b/src/modules/pokedex/pokemon/components/types/Table/Table.tsx similarity index 92% rename from src/components/pages/Pokemon/PokemonCard/Types/Table/Table.Types.PokemonCard.tsx rename to src/modules/pokedex/pokemon/components/types/Table/Table.tsx index 38506924..c8655b14 100644 --- a/src/components/pages/Pokemon/PokemonCard/Types/Table/Table.Types.PokemonCard.tsx +++ b/src/modules/pokedex/pokemon/components/types/Table/Table.tsx @@ -1,10 +1,13 @@ -import ToolTip from '@/components/common/ui/ToolTip'; -import { IType } from '@/types/Pokemon/Type'; -import { capitalize } from '@/utils/Typography'; import Image from 'next/image'; import Link from 'next/link'; -import { PokemonTypesTable } from '../Styled.Types.PokemonCard'; + +import { Tooltip } from '@/components'; import typesRelationData from '@/data/types.json'; +import { capitalize } from '@/utils'; + +import styles from '../Types.module.scss'; + +import type { IType } from '@/types'; type Props = { types: IType[]; @@ -14,7 +17,7 @@ type TypesRelation = { [key: string]: Record<string, number>; }; -function TableTyping({ types }: Props) { +export function Table({ types }: Props) { const typesRelation: TypesRelation = typesRelationData; const type1: Record<string, number> = typesRelation[types[0].name]; const type2: boolean | Record<string, number> = @@ -23,7 +26,7 @@ function TableTyping({ types }: Props) { const getTypeEffectiveness = (multiplier: number) => { if (types.length === 1) { return Object.entries(type1) - .filter(([key, value]) => value === multiplier) + .filter(([, value]) => value === multiplier) .map(([key]) => key); } else { const multipliedTypes: Record<string, number> = {}; @@ -37,14 +40,14 @@ function TableTyping({ types }: Props) { } } return Object.entries(multipliedTypes) - .filter(([key, value]) => value === multiplier) + .filter(([, value]) => value === multiplier) .map(([key]) => key); } }; return ( <> - <PokemonTypesTable> + <table className={styles.table}> <tbody> <tr> <th>0x damage from</th> @@ -201,10 +204,8 @@ function TableTyping({ types }: Props) { </tr> )} </tbody> - </PokemonTypesTable> - <ToolTip id="type-tooltip" /> + </table> + <Tooltip id="type-tooltip" /> </> ); } - -export default TableTyping; diff --git a/src/modules/pokedex/pokemon/components/types/Table/index.ts b/src/modules/pokedex/pokemon/components/types/Table/index.ts new file mode 100644 index 00000000..75193adc --- /dev/null +++ b/src/modules/pokedex/pokemon/components/types/Table/index.ts @@ -0,0 +1 @@ +export * from './Table'; diff --git a/src/modules/pokedex/pokemon/components/types/Types.module.scss b/src/modules/pokedex/pokemon/components/types/Types.module.scss new file mode 100644 index 00000000..96c5e6b6 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/types/Types.module.scss @@ -0,0 +1,37 @@ +@use '@/modules/pokedex/Pokedex.module.scss' as *; +@use '@/modules/types/type/Type.module.scss' as *; + +.typesList { + @extend %types; + + width: fit-content; + flex-direction: row; + margin-bottom: 1rem; + gap: 2rem; + + & div { + padding: 0.5rem 1.5rem; + font-size: 2rem; + } +} + +.table { + @extend %typeTable; + + height: auto; + width: 100%; + + & tr { + & td { + height: auto; + } + + &:nth-of-type(4) { + border-bottom: 1px solid rgb(130 130 130 / 20%); + } + } + + &:first-of-type { + margin-bottom: 0; + } +} diff --git a/src/modules/pokedex/pokemon/components/types/Types.tsx b/src/modules/pokedex/pokemon/components/types/Types.tsx new file mode 100644 index 00000000..5aae5c34 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/types/Types.tsx @@ -0,0 +1,42 @@ +import Image from 'next/image'; +import Link from 'next/link'; + +import { Table } from './Table'; +import styles from './Types.module.scss'; + +import type { IType } from '@/types'; + +type Props = { + types: IType[]; +}; + +export function Types({ types }: Props) { + return ( + <section className="section" id="types"> + <h3 className="h3">Types relations</h3> + <div className={styles.typesList}> + {types.map((t) => ( + <div className="type" id={t.name} key={t.name}> + <Link + href={{ + pathname: `/type/[name]`, + query: { name: t.name }, + }} + > + <Image + src={`/images/types/${t.name}.png`} + alt={t.name} + width={30} + height={30} + /> + <span>{t.name}</span> + </Link> + </div> + ))} + </div> + <div> + <Table types={types} /> + </div> + </section> + ); +} diff --git a/src/modules/pokedex/pokemon/components/types/index.ts b/src/modules/pokedex/pokemon/components/types/index.ts new file mode 100644 index 00000000..888b7ea3 --- /dev/null +++ b/src/modules/pokedex/pokemon/components/types/index.ts @@ -0,0 +1,2 @@ +export * from './Types'; +export * from './Table'; diff --git a/src/modules/pokedex/pokemon/hooks/index.ts b/src/modules/pokedex/pokemon/hooks/index.ts new file mode 100644 index 00000000..d2d4753d --- /dev/null +++ b/src/modules/pokedex/pokemon/hooks/index.ts @@ -0,0 +1,3 @@ +export * from './useFetchMachines'; +export * from './useFetchMoves'; +export * from './useFetchPokemon'; diff --git a/src/components/pages/Pokemon/PokemonCard/Hooks/useFetchMachines.tsx b/src/modules/pokedex/pokemon/hooks/useFetchMachines.tsx similarity index 93% rename from src/components/pages/Pokemon/PokemonCard/Hooks/useFetchMachines.tsx rename to src/modules/pokedex/pokemon/hooks/useFetchMachines.tsx index 4d99b8e1..ba388428 100644 --- a/src/components/pages/Pokemon/PokemonCard/Hooks/useFetchMachines.tsx +++ b/src/modules/pokedex/pokemon/hooks/useFetchMachines.tsx @@ -1,8 +1,8 @@ -import { IMove } from '@/types/Moves/Move'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { useQuery, type UseQueryResult } from '@tanstack/react-query'; import axios from 'axios'; +import type { IMove, IPokemon } from '@/types'; + export const useFetchMachines = ( pokemon: IPokemon, version: string, diff --git a/src/components/pages/Pokemon/PokemonCard/Hooks/useFetchMoves.tsx b/src/modules/pokedex/pokemon/hooks/useFetchMoves.tsx similarity index 90% rename from src/components/pages/Pokemon/PokemonCard/Hooks/useFetchMoves.tsx rename to src/modules/pokedex/pokemon/hooks/useFetchMoves.tsx index 58b8d256..64128366 100644 --- a/src/components/pages/Pokemon/PokemonCard/Hooks/useFetchMoves.tsx +++ b/src/modules/pokedex/pokemon/hooks/useFetchMoves.tsx @@ -1,8 +1,8 @@ -import { IMove } from '@/types/Moves/Move'; -import { IPokemon, IPokemonMove } from '@/types/Pokemon/Pokemon'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { useQuery, type UseQueryResult } from '@tanstack/react-query'; import axios from 'axios'; +import type { IMove, IPokemon, IPokemonMove } from '@/types'; + export interface IMoveWithDetails extends IPokemonMove { details: IMove; } diff --git a/src/components/pages/Pokemon/PokemonCard/Hooks/useFetchPokemon.tsx b/src/modules/pokedex/pokemon/hooks/useFetchPokemon.tsx similarity index 95% rename from src/components/pages/Pokemon/PokemonCard/Hooks/useFetchPokemon.tsx rename to src/modules/pokedex/pokemon/hooks/useFetchPokemon.tsx index f03d4416..f28512cd 100644 --- a/src/components/pages/Pokemon/PokemonCard/Hooks/useFetchPokemon.tsx +++ b/src/modules/pokedex/pokemon/hooks/useFetchPokemon.tsx @@ -1,4 +1,7 @@ -import { IPokemon } from '@/types/Pokemon/Pokemon'; +import { useState } from 'react'; + +import { useQueries, useQuery } from '@tanstack/react-query'; + import { getCards, getEvolution, @@ -6,9 +9,9 @@ import { getPokemonLocation, getPokemonTypes, getSpecies, -} from '@/utils/DataFetch'; -import { useQueries, useQuery } from '@tanstack/react-query'; -import { useState } from 'react'; +} from '@/utils'; + +import type { IPokemon } from '@/types'; export const useFetchPokemon = (name: string) => { const [pokemonId, setPokemonId] = useState<number | null>(null); diff --git a/src/modules/pokedex/pokemon/index.ts b/src/modules/pokedex/pokemon/index.ts new file mode 100644 index 00000000..800d684e --- /dev/null +++ b/src/modules/pokedex/pokemon/index.ts @@ -0,0 +1,4 @@ +export * from './components'; +export * from './hooks'; +export * from './utils'; +export * from './Heading'; diff --git a/src/components/pages/Pokemon/PokemonCard/Utils/DataTables.tsx b/src/modules/pokedex/pokemon/utils/InfoTable.tsx similarity index 94% rename from src/components/pages/Pokemon/PokemonCard/Utils/DataTables.tsx rename to src/modules/pokedex/pokemon/utils/InfoTable.tsx index 66505038..758de21e 100644 --- a/src/components/pages/Pokemon/PokemonCard/Utils/DataTables.tsx +++ b/src/modules/pokedex/pokemon/utils/InfoTable.tsx @@ -1,9 +1,14 @@ -import { IEvolutionChain } from '@/types/Evolution/EvolutionChain'; -import { IPokemon, IPokemonStat } from '@/types/Pokemon/Pokemon'; -import { IPokemonSpecies } from '@/types/Pokemon/PokemonSpecies'; -import { removeDash } from '@/utils/Typography'; import Link from 'next/link'; +import { removeDash } from '@/utils'; + +import type { + IEvolutionChain, + IPokemon, + IPokemonSpecies, + IPokemonStat, +} from '@/types'; + interface Pokemon { pokemon: IPokemon; } diff --git a/src/modules/pokedex/pokemon/utils/index.ts b/src/modules/pokedex/pokemon/utils/index.ts new file mode 100644 index 00000000..4aa5a49f --- /dev/null +++ b/src/modules/pokedex/pokemon/utils/index.ts @@ -0,0 +1 @@ +export * from './InfoTable'; diff --git a/src/components/pages/Profile/Styled.Profile.tsx b/src/modules/profile/Profile.module.scss similarity index 53% rename from src/components/pages/Profile/Styled.Profile.tsx rename to src/modules/profile/Profile.module.scss index 9a1842a5..e427ab90 100644 --- a/src/components/pages/Profile/Styled.Profile.tsx +++ b/src/modules/profile/Profile.module.scss @@ -1,19 +1,6 @@ -import styled from 'styled-components'; +@use '@/styles/abstracts' as *; -export const ProfileList = styled.ul` - display: grid; - grid-template-columns: repeat(3, 1fr); - align-items: center; - justify-items: center; - gap: 1rem; - padding: 2rem 0; - - & li { - font-size: 1.5rem; - } -`; - -export const ProfileCaught = styled.ul` +.caught { display: flex; align-items: center; justify-content: space-evenly; @@ -28,19 +15,20 @@ export const ProfileCaught = styled.ul` justify-content: center; flex-direction: column; padding: 4rem 2rem; - background: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.main}; border-radius: 5px; + @include themed { + background: t('text'); + color: t('bg'); + } & a { font-size: 2rem; font-weight: 600; text-transform: capitalize; cursor: pointer; - transition: 0.3s ease-in-out; &:hover { - color: ${({ theme }) => theme.red}; + color: $red; } } @@ -51,38 +39,42 @@ export const ProfileCaught = styled.ul` transform: translateX(-50%); width: 100%; padding: 1rem 0; - background: ${({ theme }) => theme.main}; - color: ${({ theme }) => theme.secondary}; border: none; - border: 1px solid ${({ theme }) => theme.secondary}; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; font-size: 1.5rem; - transition: 0.3s ease-in-out; + + @include themed { + background: t('bg'); + color: t('text'); + border: 1px solid t('text'); + } &:hover { - background: ${({ theme }) => theme.secondary}; - color: ${({ theme }) => theme.main}; - border-top: 1px solid ${({ theme }) => theme.main}; + @include themed { + background: t('text'); + color: t('bg'); + border-top: 1px solid t('bg'); + } } &:active { - color: ${({ theme }) => theme.red}; + color: $red; } } } -`; +} -export const ProfileDetails = styled.details` +.details { & summary { width: fit-content; font-size: 3rem; font-weight: 600; cursor: pointer; } -`; +} -export const ProfileForm = styled.form` +.form { width: 90%; margin: 2rem auto 0; display: grid; @@ -104,19 +96,23 @@ export const ProfileForm = styled.form` margin: 0 auto; padding: 0.5rem 1.5rem; font-size: 2rem; - background: ${({ theme }) => theme.secondary}; - border: 1px solid ${({ theme }) => theme.main}; border-radius: 5px; - transition: 0.3s ease-in-out; + + @include themed { + background: t('text'); + border: 1px solid t('bg'); + } &:hover { - color: ${({ theme }) => theme.secondary}; background: transparent; - border: 1px solid ${({ theme }) => theme.secondary}; + @include themed { + color: t('text'); + border: 1px solid t('text'); + } } &:active { transform: scale(0.98); } } -`; +} diff --git a/src/components/pages/Types/Heading.tsx b/src/modules/types/Heading.tsx similarity index 91% rename from src/components/pages/Types/Heading.tsx rename to src/modules/types/Heading.tsx index dfba7b4c..6ae5d4a5 100644 --- a/src/components/pages/Types/Heading.tsx +++ b/src/modules/types/Heading.tsx @@ -1,6 +1,6 @@ import Head from 'next/head'; -function HeadingTypes() { +export function Heading() { return ( <Head> <title>Types | Pokeref @@ -18,5 +18,3 @@ function HeadingTypes() { ); } - -export default HeadingTypes; diff --git a/src/modules/types/Types.module.scss b/src/modules/types/Types.module.scss new file mode 100644 index 00000000..8e3b2ef2 --- /dev/null +++ b/src/modules/types/Types.module.scss @@ -0,0 +1,56 @@ +@use '@/styles/abstracts' as *; + +.list { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + + & li { + & div { + @include themed { + border: 1px solid t('text'); + } + + &:hover { + transform: scale(1.03); + } + } + } +} + +.type { + width: 20rem; + margin: 3rem; + border-radius: 5px; + + & a { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + padding: 3rem; + + & img { + cursor: pointer; + } + + & h2 { + margin-top: 1rem; + font-size: 3rem; + border-radius: 5px; + text-transform: uppercase; + text-align: center; + cursor: pointer; + @include themed { + color: t('text'); + text-shadow: t('bg') -1px -1px 0, t('bg') 1px -1px 0, t('bg') -1px 1px 0, + t('bg') 1px 1px 0; + } + } + } + + @include sm { + margin: 2rem; + } +} diff --git a/src/components/pages/Types/Components/List.Types.tsx b/src/modules/types/components/List.tsx similarity index 70% rename from src/components/pages/Types/Components/List.Types.tsx rename to src/modules/types/components/List.tsx index 6698e11b..f1977743 100644 --- a/src/components/pages/Types/Components/List.Types.tsx +++ b/src/modules/types/components/List.tsx @@ -1,18 +1,20 @@ -import { ModifiedType } from '@/components/pages/Types/Styled.Types'; -import { IType } from '@/types/Pokemon/Type'; import Image from 'next/image'; import Link from 'next/link'; +import styles from '../Types.module.scss'; + +import type { IType } from '@/types'; + type Props = { types?: IType[]; }; -function ListTypes({ types }: Props) { +export function List({ types }: Props) { return ( <> {types?.map((t: IType) => (
  • - +

    {t.name}

    - +
  • ))} ); } - -export default ListTypes; diff --git a/src/modules/types/components/index.ts b/src/modules/types/components/index.ts new file mode 100644 index 00000000..4994c181 --- /dev/null +++ b/src/modules/types/components/index.ts @@ -0,0 +1 @@ +export * from './List'; diff --git a/src/modules/types/index.ts b/src/modules/types/index.ts new file mode 100644 index 00000000..6f323b35 --- /dev/null +++ b/src/modules/types/index.ts @@ -0,0 +1,2 @@ +export * from './components'; +export * from './Heading'; diff --git a/src/components/pages/Types/TypeCard/Heading.tsx b/src/modules/types/type/Heading.tsx similarity index 91% rename from src/components/pages/Types/TypeCard/Heading.tsx rename to src/modules/types/type/Heading.tsx index 32f405fa..b65a4cb8 100644 --- a/src/components/pages/Types/TypeCard/Heading.tsx +++ b/src/modules/types/type/Heading.tsx @@ -1,11 +1,12 @@ -import Head from 'next/head'; import React from 'react'; +import Head from 'next/head'; + type Props = { name: string; }; -function HeadingType({ name }: Props) { +export function Heading({ name }: Props) { return ( @@ -27,5 +28,3 @@ function HeadingType({ name }: Props) { </Head> ); } - -export default HeadingType; diff --git a/src/components/pages/Types/TypeCard/Styled.TypeCard.tsx b/src/modules/types/type/Type.module.scss similarity index 60% rename from src/components/pages/Types/TypeCard/Styled.TypeCard.tsx rename to src/modules/types/type/Type.module.scss index 02487dbe..af80205c 100644 --- a/src/components/pages/Types/TypeCard/Styled.TypeCard.tsx +++ b/src/modules/types/type/Type.module.scss @@ -1,9 +1,9 @@ -import styled from 'styled-components'; -import { Subtitle } from '../../../common/styles/Headings'; -import { Table, TBold } from '../../../common/styles/Table'; +@use '@/styles/abstracts' as *; +@use '@/styles/common' as *; + +.section { + @extend %sectionTop; -export const TypeDamageSection = styled.section` - margin: 5rem 0; display: flex; flex-direction: column; gap: 3rem; @@ -21,20 +21,36 @@ export const TypeDamageSection = styled.section` } } } -`; +} + +.title { + display: flex; + align-items: center; + justify-content: center; + gap: 2rem; + + & img { + @include sm { + width: 48px; + height: 48px; + } + } +} + +%typeTable { + @extend %table; -export const TypeDamageTable = styled(Table)` width: 100%; height: 100%; margin-top: 0.5rem; & tr { - border: 1px solid rgba(130, 130, 130, 0.2); + border: 1px solid rgb(130 130 130 / 20%); border-left: none; border-right: none; & th { - background: rgba(130, 130, 130, 0.2); + background: rgb(130 130 130 / 20%); font-size: 1.5rem; } @@ -61,46 +77,55 @@ export const TypeDamageTable = styled(Table)` } &:nth-of-type(4) { - border-bottom: 5px solid rgba(130, 130, 130, 0.2); + border-bottom: 5px solid rgb(130 130 130 / 20%); } } &:first-of-type { margin-bottom: 5rem; } -`; +} + +.table { + @extend %typeTable; +} -export const TypeListSubtitleContainer = styled.div` +.container { display: grid; grid-template-columns: 1fr 2fr; align-items: center; gap: 1rem; margin-bottom: 3rem; -`; +} + +.subtitle { + @extend %leftSubtitle; -export const TypeListSubtitle = styled(Subtitle)` text-transform: none; - text-align: left; -`; +} + +.name { + @extend %tBold; -export const TypeMovesName = styled(TBold)` & a { border-bottom: 1px solid transparent; cursor: pointer; &:hover { - border-bottom: 1px solid ${({ theme }) => theme.secondary}; + @include themed { + border-bottom: 1px solid t('text'); + } } } -`; +} -export const TypeMovesData = styled.td` +.data { text-align: center; text-transform: capitalize; -`; +} -export const TypeMovesComment = styled.p` +.comment { text-align: center; font-size: 1.5rem; margin: 0.75rem 0 0; -`; +} diff --git a/src/components/pages/Types/TypeCard/Damage/Damage.TypeCard.tsx b/src/modules/types/type/components/Damage.tsx similarity index 89% rename from src/components/pages/Types/TypeCard/Damage/Damage.TypeCard.tsx rename to src/modules/types/type/components/Damage.tsx index 320e0cfc..6f51ddc9 100644 --- a/src/components/pages/Types/TypeCard/Damage/Damage.TypeCard.tsx +++ b/src/modules/types/type/components/Damage.tsx @@ -1,12 +1,13 @@ -import { Capitalize } from '@/components/common/styles/Headings'; -import ToolTip from '@/components/common/ui/ToolTip'; -import { MoveCardDataTable } from '@/components/pages/Moves/MoveCard/Data/Styled.Data.MoveCard'; -import { IType } from '@/types/Pokemon/Type'; -import { capitalize, removeDash } from '@/utils/Typography'; import Image from 'next/image'; import Link from 'next/link'; -import { TypeDamageSection, TypeDamageTable } from '../Styled.TypeCard'; + +import { Tooltip } from '@/components'; import typesRelationData from '@/data/types.json'; +import moves from '@/modules/moves/move/components/data/Data.module.scss'; +import styles from '@/modules/types/type/Type.module.scss'; +import { capitalize, removeDash } from '@/utils'; + +import type { IType } from '@/types'; type Props = { type?: IType; @@ -16,14 +17,14 @@ type TypesRelation = { [key: string]: Record<string, number>; }; -function DamageType({ type }: Props) { +export function Damage({ type }: Props) { const typesRelation: TypesRelation = typesRelationData; const name = type?.name || ``; const typeEffectiveness: Record<string, number> = typesRelation[name]; const getTypeEffectiveness = (multiplier: number) => { return Object.entries(typeEffectiveness) - .filter(([key, value]) => value === multiplier) + .filter(([, value]) => value === multiplier) .map(([key]) => key); }; @@ -44,22 +45,26 @@ function DamageType({ type }: Props) { }; return ( - type && ( - <> - <TypeDamageSection> - <MoveCardDataTable> + <> + <section className={styles.section}> + <table className={moves.table}> + <tbody> <tr> <th>Generation</th> - <td>{removeDash(type?.generation.name)}</td> + <td>{type && removeDash(type?.generation.name)}</td> </tr> <tr> <th>Damage class</th> <td> - <Capitalize>{type?.move_damage_class.name}</Capitalize> + <span className="capitalize"> + {type?.move_damage_class.name} + </span> </td> </tr> - </MoveCardDataTable> - <TypeDamageTable> + </tbody> + </table> + <table className={styles.table}> + <tbody> <tr> <th>Deals 0X damage to</th> <td> @@ -260,12 +265,10 @@ function DamageType({ type }: Props) { </div> </td> </tr> - </TypeDamageTable> - </TypeDamageSection> - <ToolTip id="type-tooltip" /> - </> - ) + </tbody> + </table> + </section> + <Tooltip id="type-tooltip" /> + </> ); } - -export default DamageType; diff --git a/src/components/pages/Types/TypeCard/Moves/Moves.TypeCard.tsx b/src/modules/types/type/components/Moves.tsx similarity index 52% rename from src/components/pages/Types/TypeCard/Moves/Moves.TypeCard.tsx rename to src/modules/types/type/components/Moves.tsx index 801b0410..c0d3ab72 100644 --- a/src/components/pages/Types/TypeCard/Moves/Moves.TypeCard.tsx +++ b/src/modules/types/type/components/Moves.tsx @@ -1,30 +1,20 @@ -import { Capitalize, H3 } from '@/components/common/styles/Headings'; -import { Section } from '@/components/common/styles/Sizing'; -import { - FullWidthTable, - TableContainer, -} from '@/components/common/styles/Table'; -import { useTableParams } from '@/hooks/useTableParams'; -import { IMove } from '@/types/Moves/Move'; -import { IType } from '@/types/Pokemon/Type'; -import { removeDash } from '@/utils/Typography'; -import { ColumnDef } from '@tanstack/react-table'; -import Link from 'next/link'; import { useMemo } from 'react'; -import { - TypeListSubtitle, - TypeListSubtitleContainer, - TypeMovesComment, - TypeMovesData, - TypeMovesName, -} from '../Styled.TypeCard'; + +import { type ColumnDef } from '@tanstack/react-table'; +import Link from 'next/link'; + +import { useTableParams } from '@/hooks'; +import styles from '@/modules/types/type/Type.module.scss'; +import { removeDash } from '@/utils'; + +import type { IMove, IType } from '@/types'; type Props = { type?: IType; moves?: IMove[]; }; -function MovesType({ type, moves }: Props) { +export function Moves({ type, moves }: Props) { const data = useMemo( () => [ ...new Set( @@ -43,7 +33,7 @@ function MovesType({ type, moves }: Props) { id: `sort`, header: `Name`, cell: (info) => ( - <TypeMovesName> + <td className={styles.name}> <Link href={{ pathname: `/move/[name]`, @@ -52,7 +42,7 @@ function MovesType({ type, moves }: Props) { > {removeDash(info.getValue<string>())} </Link> - </TypeMovesName> + </td> ), }, { @@ -60,7 +50,7 @@ function MovesType({ type, moves }: Props) { id: `category`, header: `Category`, cell: (info) => ( - <TypeMovesData>{info.getValue<string>()}</TypeMovesData> + <td className={styles.data}>{info.getValue<string>()}</td> ), }, { @@ -68,7 +58,7 @@ function MovesType({ type, moves }: Props) { id: `power`, header: `Power`, cell: (info) => ( - <TypeMovesData>{info.getValue<string>() || `-`}</TypeMovesData> + <td className={styles.data}>{info.getValue<string>() || `-`}</td> ), }, { @@ -76,7 +66,7 @@ function MovesType({ type, moves }: Props) { id: `pp`, header: `PP`, cell: (info) => ( - <TypeMovesData>{info.getValue<string>()}</TypeMovesData> + <td className={styles.data}>{info.getValue<string>()}</td> ), }, { @@ -84,7 +74,7 @@ function MovesType({ type, moves }: Props) { id: `accuracy`, header: `Accuracy`, cell: (info) => ( - <TypeMovesData>{info.getValue<string>() || `-`}</TypeMovesData> + <td className={styles.data}>{info.getValue<string>() || `-`}</td> ), }, { @@ -92,11 +82,11 @@ function MovesType({ type, moves }: Props) { id: `status`, header: `Status`, cell: (info) => ( - <TypeMovesData> + <td className={styles.data}> {info.getValue<string>() !== `none` || !info.getValue<string>() ? info.getValue<string>() : `-`} - </TypeMovesData> + </td> ), }, ], @@ -109,29 +99,30 @@ function MovesType({ type, moves }: Props) { ); return ( - <Section> - <H3>Moves</H3> - <TypeListSubtitleContainer> - <TypeListSubtitle> - {data.length} moves are <Capitalize>{type?.name}</Capitalize> type - </TypeListSubtitle> - </TypeListSubtitleContainer> - <TableContainer ref={tableContainerRef}> + <section className="section"> + <h3 className="h3">Moves</h3> + <div className={styles.container}> + <h4 className={styles.subtitle}> + {data.length} moves are{` `} + <span className="capitalize">{type?.name}</span> type + </h4> + </div> + <div className="tableContainer" ref={tableContainerRef}> {data.length > 0 && ( - <FullWidthTable> + <table className="fullWidthTable"> {tableHeader()} {tableBody()} - </FullWidthTable> + </table> )} - </TableContainer> + </div> {type?.name !== `fairy` && ( - <TypeMovesComment> - <Capitalize>{type?.name}</Capitalize> attacks were{` `} - <Capitalize>{type?.move_damage_class?.name}</Capitalize> before Gen IV - </TypeMovesComment> + <p className={styles.comment}> + <span className="capitalize">{type?.name}</span> attacks were{` `} + <span className="capitalize">{type?.move_damage_class?.name}</span> + {` `} + before Gen IV + </p> )} - </Section> + </section> ); } - -export default MovesType; diff --git a/src/components/pages/Types/TypeCard/Pokemon/Pokemon.TypeCard.tsx b/src/modules/types/type/components/Pokemon.tsx similarity index 54% rename from src/components/pages/Types/TypeCard/Pokemon/Pokemon.TypeCard.tsx rename to src/modules/types/type/components/Pokemon.tsx index 3e7d1ba0..e0dc7064 100644 --- a/src/components/pages/Types/TypeCard/Pokemon/Pokemon.TypeCard.tsx +++ b/src/modules/types/type/components/Pokemon.tsx @@ -1,34 +1,22 @@ -import { Capitalize, H3 } from '@/components/common/styles/Headings'; -import { Dropdown } from '@/components/common/styles/Inputs'; -import { Section } from '@/components/common/styles/Sizing'; -import { - FullWidthTable, - TableContainer, - TBold, - TLink, - TType, -} from '@/components/common/styles/Table'; -import { Type } from '@/components/common/styles/Themes'; -import { Sup } from '@/components/pages/Abilities/AbilityCard/Styled.AbilityCard'; -import { useTableParams } from '@/hooks/useTableParams'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { IOptionsFixed, typeOptions } from '@/utils/DataArrays'; -import { removeDash } from '@/utils/Typography'; -import { ColumnDef } from '@tanstack/react-table'; +import { useCallback, useEffect, useMemo, useState } from 'react'; + +import { type ColumnDef } from '@tanstack/react-table'; import Image from 'next/image'; import Link from 'next/link'; -import { useEffect, useMemo, useState, useCallback } from 'react'; -import { - TypeListSubtitle, - TypeListSubtitleContainer, -} from '../Styled.TypeCard'; +import Select, { type PropsValue } from 'react-select'; + +import { useTableParams } from '@/hooks'; +import styles from '@/modules/types/type/Type.module.scss'; +import { type IOptionsFixed, removeDash, typeOptions } from '@/utils'; + +import type { IPokemon } from '@/types'; type Props = { typeName?: string; pokemon?: IPokemon[]; }; -function PokemonType({ typeName, pokemon }: Props) { +export function Pokemon({ typeName, pokemon }: Props) { const [type, setType] = useState<IOptionsFixed[]>([]); const [typeArray, setTypeArray] = useState<IOptionsFixed[]>(typeOptions); @@ -74,16 +62,17 @@ function PokemonType({ typeName, pokemon }: Props) { id: `sort`, header: `Name`, cell: (info) => ( - <TBold> - <TLink + <td className="tBold"> + <Link + className="tLink" href={{ pathname: `/pokemon/[name]`, query: { name: info.getValue<string>() }, }} > {removeDash(info.getValue<string>())} - </TLink> - </TBold> + </Link> + </td> ), }, { @@ -91,12 +80,12 @@ function PokemonType({ typeName, pokemon }: Props) { id: `type1`, header: () => ( <span> - 1<Sup>st</Sup> type + 1<sup className="sup">st</sup> type </span> ), cell: (info) => ( - <TType> - <Type id={info.getValue<string>()}> + <td className="tType"> + <div className="type" id={info.getValue<string>()}> <Link href={{ pathname: `/type/[name]`, @@ -111,8 +100,8 @@ function PokemonType({ typeName, pokemon }: Props) { /> <span>{info.getValue<string>()}</span> </Link> - </Type> - </TType> + </div> + </td> ), }, { @@ -120,13 +109,13 @@ function PokemonType({ typeName, pokemon }: Props) { id: `type2`, header: () => ( <span> - 2<Sup>nd</Sup> type + 2<sup className="sup">nd</sup> type </span> ), cell: (info) => info.getValue() ? ( - <TType> - <Type id={info.getValue<string>()}> + <td className="tType"> + <div className="type" id={info.getValue<string>()}> <Link href={{ pathname: `/type/[name]`, @@ -141,8 +130,8 @@ function PokemonType({ typeName, pokemon }: Props) { /> <span>{info.getValue<string>()}</span> </Link> - </Type> - </TType> + </div> + </td> ) : ( <td>-</td> ), @@ -156,7 +145,7 @@ function PokemonType({ typeName, pokemon }: Props) { columns, ); - const styles = { + const dropdownStyles = { // @ts-ignore multiValueRemove: (base, state) => { return state.data.isFixed ? { ...base, display: `none` } : base; @@ -167,53 +156,58 @@ function PokemonType({ typeName, pokemon }: Props) { if (typeName) { fixCurType(typeName, true); } + + // eslint-disable-next-line react-hooks/exhaustive-deps }, [typeName]); - if (data) { - return ( - <Section> - <H3>Pokémon</H3> - <TypeListSubtitleContainer> - <TypeListSubtitle> - {data.length} Pokémon are <Capitalize>{typeName}</Capitalize> type - </TypeListSubtitle> - <Dropdown - value={type} - defaultValue={typeArray.some((t) => t.isFixed)} - isMulti - isClearable={typeArray.some((t) => !t.isFixed)} - isSearchable={false} - styles={styles} - name="type" - id="type" - className="selectOptions" - classNamePrefix="select" - options={typeArray} - placeholder="Select" - // @ts-ignore - components={ - type && - type?.length >= 2 && { - Menu: () => null, - MenuList: () => null, - DropdownIndicator: () => null, - IndicatorSeparator: () => null, - } + return ( + <section className="section"> + <h3 className="h3">Pokémon</h3> + <div className={styles.container}> + {data && ( + <h4 className={styles.subtitle}> + {data.length} Pokémon are{` `} + <span className="capitalize">{typeName}</span> type + </h4> + )} + <Select + value={type} + defaultValue={ + typeArray.some((t) => t.isFixed) + ? undefined + : (typeArray as PropsValue<IOptionsFixed>) + } + isMulti + isClearable={typeArray.some((t) => !t.isFixed)} + isSearchable={false} + styles={dropdownStyles} + name="type" + id="type" + className="dropdown selectOptions" + classNamePrefix="select" + options={typeArray} + placeholder="Select" + // @ts-ignore + components={ + type && + type?.length >= 2 && { + Menu: () => null, + MenuList: () => null, + DropdownIndicator: () => null, + IndicatorSeparator: () => null, } - onChange={(option) => option && setType(option as IOptionsFixed[])} - /> - </TypeListSubtitleContainer> - <TableContainer ref={tableContainerRef}> - {data.length > 0 && ( - <FullWidthTable> - {tableHeader()} - {tableBody()} - </FullWidthTable> - )} - </TableContainer> - </Section> - ); - } + } + onChange={(option) => option && setType(option as IOptionsFixed[])} + /> + </div> + <div className="tableContainer" ref={tableContainerRef}> + {data && data.length > 0 && ( + <table className="fullWidthTable"> + {tableHeader()} + {tableBody()} + </table> + )} + </div> + </section> + ); } - -export default PokemonType; diff --git a/src/modules/types/type/components/index.ts b/src/modules/types/type/components/index.ts new file mode 100644 index 00000000..700a8146 --- /dev/null +++ b/src/modules/types/type/components/index.ts @@ -0,0 +1,3 @@ +export * from './Damage'; +export * from './Moves'; +export * from './Pokemon'; diff --git a/src/modules/types/type/hooks/index.ts b/src/modules/types/type/hooks/index.ts new file mode 100644 index 00000000..48614907 --- /dev/null +++ b/src/modules/types/type/hooks/index.ts @@ -0,0 +1 @@ +export * from './useTypeQuery'; diff --git a/src/modules/types/type/hooks/useTypeQuery.tsx b/src/modules/types/type/hooks/useTypeQuery.tsx new file mode 100644 index 00000000..fb33248e --- /dev/null +++ b/src/modules/types/type/hooks/useTypeQuery.tsx @@ -0,0 +1,31 @@ +import { type UseQueryResult, useQuery } from '@tanstack/react-query'; + +import { getType, getTypeMoves, getTypePokemon } from '@/utils'; + +import type { IMove, IPokemon, IType } from '@/types'; + +export const useTypeQuery = (name: string) => { + const { + isLoading, + isError, + error, + data: type, + }: UseQueryResult<IType, Error> = useQuery({ + queryKey: [`type`, name], + queryFn: () => getType(`https://pokeapi.co/api/v2/type/${name}`), + }); + + const { data: pokemon }: UseQueryResult<IPokemon[]> = useQuery({ + queryKey: [`typePokemon`, name, type], + queryFn: () => type && getTypePokemon(type), + enabled: !!type, + }); + + const { data: moves }: UseQueryResult<IMove[]> = useQuery({ + queryKey: [`typeMoves`, name, type], + queryFn: () => type && getTypeMoves(type), + enabled: !!type, + }); + + return { type, pokemon, moves, isLoading, isError, error }; +}; diff --git a/src/modules/types/type/index.ts b/src/modules/types/type/index.ts new file mode 100644 index 00000000..54332a9c --- /dev/null +++ b/src/modules/types/type/index.ts @@ -0,0 +1,3 @@ +export * from './components'; +export * from './hooks'; +export * from './Heading'; diff --git a/src/pages/404.tsx b/src/pages/404.tsx index 679202fa..99b1103b 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,17 +1,15 @@ -import { - NotFoundImg, - NotFoundMain, - NotFoundText, -} from '@/components/pages/404/Styled.NotFound'; +import Image from 'next/image'; + +import styles from '@/modules/404/NotFound.module.scss'; function NotFound() { return ( - <NotFoundMain> - <NotFoundImg src={`/MissingNo.png`} alt="MissingNo" /> - <NotFoundText>Oops !</NotFoundText> - <NotFoundText>The URL entered does not exist</NotFoundText> - <NotFoundText>Use the links above to find your way back</NotFoundText> - </NotFoundMain> + <main className={styles.main}> + <Image className={styles.image} src={`/MissingNo.png`} alt="MissingNo" /> + <p className={styles.text}>Oops !</p> + <p className={styles.text}>The URL entered does not exist</p> + <p className={styles.text}>Use the links above to find your way back</p> + </main> ); } diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 21557ef4..0218cf03 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,18 +1,17 @@ -import { darkTheme, lightTheme } from '@/components/common/styles/Themes'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import type { AppProps } from 'next/app'; -import Head from 'next/head'; import { useState } from 'react'; -import { ErrorBoundary, FallbackProps } from 'react-error-boundary'; -import { ThemeProvider } from 'styled-components'; -import { Reset } from '@/components/common/styles/Reset'; -import Footer from '@/components/layout/Footer/Footer'; -import Header from '@/components/layout/Header/Header'; -import Nav from '@/components/layout/Nav/Nav'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import PlausibleProvider from 'next-plausible'; +import Head from 'next/head'; import NextNProgress from 'nextjs-progressbar'; +import { ErrorBoundary, type FallbackProps } from 'react-error-boundary'; import { Toaster } from 'react-hot-toast'; -import PlausibleProvider from 'next-plausible'; + +import { ThemeProvider } from '@/contexts'; +import '@/styles/styles.scss'; +import { Footer, Header, Nav } from '@/modules/layout'; + +import type { AppProps } from 'next/app'; const ErrorFallback = ({ error, resetErrorBoundary }: FallbackProps) => { return ( @@ -37,22 +36,6 @@ function MyApp({ Component, pageProps }: AppProps) { const [navOpen, setNavOpen] = useState(false); - const loadTheme: () => string = () => { - const localTheme = globalThis.window?.localStorage.getItem(`theme`); - return localTheme ?? `dark`; - }; - - const [theme, setTheme] = useState(loadTheme()); - - const setMode = (mode: string) => { - globalThis.window?.localStorage.setItem(`theme`, mode); - setTheme(mode); - }; - - const themeToggler = () => { - theme === `dark` ? setMode(`light`) : setMode(`dark`); - }; - return ( <> <Head> @@ -60,21 +43,15 @@ function MyApp({ Component, pageProps }: AppProps) { </Head> <ErrorBoundary FallbackComponent={ErrorFallback}> <QueryClientProvider client={queryClient}> - <ThemeProvider theme={theme === `dark` ? darkTheme : lightTheme}> + <ThemeProvider> <PlausibleProvider domain="pokeref.app" enabled={process.env.NODE_ENV === `production`} > <Toaster /> <NextNProgress /> - <Header - navOpen={navOpen} - setNavOpen={setNavOpen} - themeToggler={themeToggler} - theme={theme} - /> + <Header navOpen={navOpen} setNavOpen={setNavOpen} /> <Nav navOpen={navOpen} setNavOpen={setNavOpen} /> - <Reset /> <Component {...pageProps} /> <Footer /> </PlausibleProvider> diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx index 451128c3..f9da6806 100644 --- a/src/pages/_document.tsx +++ b/src/pages/_document.tsx @@ -1,64 +1,29 @@ -import Document, { - DocumentContext, - Head, - Html, - Main, - NextScript, -} from 'next/document'; -import { ServerStyleSheet } from 'styled-components'; +import { Head, Html, Main, NextScript } from 'next/document'; -export default class MyDocument extends Document { - static async getInitialProps(ctx: DocumentContext) { - const sheet = new ServerStyleSheet(); - const originalRenderPage = ctx.renderPage; - - try { - ctx.renderPage = () => - originalRenderPage({ - enhanceApp: (App) => (props) => - sheet.collectStyles(<App {...props} />), - }); - - const initialProps = await Document.getInitialProps(ctx); - return { - ...initialProps, - styles: ( - <> - {initialProps.styles} - {sheet.getStyleElement()} - </> - ), - }; - } finally { - sheet.seal(); - } - } - - render() { - return ( - <Html lang="en"> - <Head> - <meta name="theme-color" content="#c4c4c4" /> - <meta - name="keywords" - content="pokemon, Pokemon, info, pokedex, Pokedex, pokeinfo, database, pokeapi, moves, abilities, evolutions, locations, items, types" - /> - <meta name="googlebot-news" content="noindex, nosnippet" /> - <link rel="manifest" href="/manifest.json" /> - <link rel="apple-touch-icon" href="/icon-192x192.png" /> - <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> - <link rel="preconnect" href="https://fonts.googleapis.com" /> - <link rel="preconnect" href="https://fonts.gstatic.com" /> - <link - href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;600&family=Oswald:wght@600&display=swap" - rel="stylesheet" - /> - </Head> - <body> - <Main /> - <NextScript /> - </body> - </Html> - ); - } +export default function Document() { + return ( + <Html lang="en"> + <Head> + <meta name="theme-color" content="#c4c4c4" /> + <meta + name="keywords" + content="pokemon, Pokemon, info, pokedex, Pokedex, pokeinfo, database, pokeapi, moves, abilities, evolutions, locations, items, types" + /> + <meta name="googlebot-news" content="noindex, nosnippet" /> + <link rel="manifest" href="/manifest.json" /> + <link rel="apple-touch-icon" href="/icon-192x192.png" /> + <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> + <link rel="preconnect" href="https://fonts.googleapis.com" /> + <link rel="preconnect" href="https://fonts.gstatic.com" /> + <link + href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;600&family=Oswald:wght@600&display=swap" + rel="stylesheet" + /> + </Head> + <body> + <Main /> + <NextScript /> + </body> + </Html> + ); } diff --git a/src/pages/_offline.tsx b/src/pages/_offline.tsx index 926b5213..509bcc57 100644 --- a/src/pages/_offline.tsx +++ b/src/pages/_offline.tsx @@ -1,11 +1,8 @@ -import { H2 } from '@/components/common/styles/Headings'; -import { MainBig } from '@/components/common/styles/Sizing'; - function _offline() { return ( - <MainBig> - <H2>Sorry but this app can not be displayed offline</H2> - </MainBig> + <main className="mainBig"> + <h2 className="h2">Sorry but this app can not be displayed offline</h2> + </main> ); } diff --git a/src/pages/abilities.tsx b/src/pages/abilities.tsx index 2ce086f2..68fc247c 100644 --- a/src/pages/abilities.tsx +++ b/src/pages/abilities.tsx @@ -1,28 +1,16 @@ -import { LeftH2 } from '@/components/common/styles/Headings'; -import { MainBig } from '@/components/common/styles/Sizing'; -import { - FullWidthTable, - TableContainer, - TBold, - TEffect, - TLink, -} from '@/components/common/styles/Table'; -import Loader from '@/components/common/ui/Loader/Loader'; -import SearchAbilities from '@/components/pages/Abilities/Components/Search.Abilities'; -import { SearchContainer } from '@/components/pages/Moves/Styled.Moves'; -import { usePaginatedTableParams } from '@/hooks/usePaginatedTableParams'; -import { IAbility } from '@/types/Pokemon/Ability'; -import { getAbilities } from '@/utils/DataFetch'; -import { removeDash } from '@/utils/Typography'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; -import { ColumnDef } from '@tanstack/react-table'; -import dynamic from 'next/dynamic'; import { useMemo } from 'react'; -import toast from 'react-hot-toast'; -const HeadingAbilities = dynamic( - () => import(`@/components/pages/Abilities/Heading`), -); +import { type UseQueryResult, useQuery } from '@tanstack/react-query'; +import { type ColumnDef } from '@tanstack/react-table'; +import Link from 'next/link'; + +import { ErrorToast, Loader } from '@/components'; +import { usePaginatedTableParams } from '@/hooks'; +import { Heading, Search } from '@/modules/abilities'; +import moves from '@/modules/moves/Moves.module.scss'; +import { getAbilities, removeDash } from '@/utils'; + +import type { IAbility } from '@/types'; function AbilitiesPage() { const { @@ -44,16 +32,17 @@ function AbilitiesPage() { id: `sort`, header: `Name`, cell: (info) => ( - <TBold> - <TLink + <td className="tBold"> + <Link + className="tLink" href={{ pathname: `/ability/[name]`, query: { name: info.getValue<string>() }, }} > {removeDash(info.getValue<string>())} - </TLink> - </TBold> + </Link> + </td> ), }, { @@ -64,9 +53,9 @@ function AbilitiesPage() { id: `effect`, header: `Effect`, cell: (info) => ( - <TEffect> + <td className="tEffect"> <span>{info.getValue<string>()}</span> - </TEffect> + </td> ), }, ], @@ -77,11 +66,7 @@ function AbilitiesPage() { usePaginatedTableParams(data, columns); if (isError) { - return toast.error(`Something went wrong: ${error.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -90,20 +75,20 @@ function AbilitiesPage() { return ( <> - <HeadingAbilities /> - <MainBig> - <SearchContainer> - <LeftH2>Abilities</LeftH2> - <SearchAbilities abilities={abilities} /> - </SearchContainer> - <TableContainer ref={tableContainerRef}> - <FullWidthTable> + <Heading /> + <main className="mainBig"> + <div className={moves.search}> + <h2 className="leftH2">Abilities</h2> + <Search abilities={abilities} /> + </div> + <section className="tableContainer" ref={tableContainerRef}> + <table className="fullWidthTable"> {tableHeader()} {tableBody()} - </FullWidthTable> + </table> {tablePagination()} - </TableContainer> - </MainBig> + </section> + </main> </> ); } diff --git a/src/pages/ability/[name].tsx b/src/pages/ability/[name].tsx index 1a81a751..d5873576 100644 --- a/src/pages/ability/[name].tsx +++ b/src/pages/ability/[name].tsx @@ -1,44 +1,22 @@ -import { - Capitalize, - CardTitle, - H3, - H4, - Subtitle, -} from '@/components/common/styles/Headings'; -import { MainBig } from '@/components/common/styles/Sizing'; -import BackBtn from '@/components/common/ui/BackBtn'; -import { Divider } from '@/components/common/ui/Divider'; -import Loader from '@/components/common/ui/Loader/Loader'; -import HeadingAbility from '@/components/pages/Abilities/AbilityCard/Heading'; -import { useFilterAbility } from '@/components/pages/Abilities/AbilityCard/Hooks/useFilterAbility'; -import { - AbilityCardEffect, - AbilityCardSection, -} from '@/components/pages/Abilities/AbilityCard/Styled.AbilityCard'; -import { removeDash } from '@/utils/Typography'; -import { GetServerSidePropsContext } from 'next'; -import dynamic from 'next/dynamic'; +import { FaChevronLeft } from '@meronex/icons/fa'; +import { type GetServerSidePropsContext } from 'next'; import Link from 'next/link'; -import toast from 'react-hot-toast'; -const DescAbilityCard = dynamic( - () => - import( - `@/components/pages/Abilities/AbilityCard/Components/Desc.AbilityCard` - ), -); -const TableAbilityCard = dynamic( - () => - import( - `@/components/pages/Abilities/AbilityCard/Components/Table.AbilityCard` - ), -); +import { Button, ErrorToast, Loader, Separator } from '@/components'; +import { + Description, + Heading, + Table, + useFilterAbility, +} from '@/modules/abilities/ability'; +import styles from '@/modules/abilities/ability/Ability.module.scss'; +import { removeDash } from '@/utils'; type Props = { name: string; }; -function AbilityCard({ name }: Props) { +function Ability({ name }: Props) { const overworld = `Overworld`; const { @@ -53,11 +31,7 @@ function AbilityCard({ name }: Props) { } = useFilterAbility(name); if (isError) { - return toast.error(`Something went wrong: ${error?.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -66,45 +40,52 @@ function AbilityCard({ name }: Props) { return ( <> - <HeadingAbility name={name} /> - <MainBig> - <CardTitle>{ability && removeDash(ability?.name)}</CardTitle> - <Subtitle>{ability && removeDash(ability?.generation?.name)}</Subtitle> + <Heading name={name} /> + <main className="mainBig"> + <h2 className="pageTitle">{ability && removeDash(ability?.name)}</h2> + <h4 className="subtitle"> + {ability && removeDash(ability?.generation?.name)} + </h4> - <AbilityCardSection> - <AbilityCardEffect> - <H3>Effect</H3> + <section className={styles.section}> + <div className={styles.effect}> + <h3 className="h3">Effect</h3> <p>{filterEffect?.effect}</p> - </AbilityCardEffect> + </div> {filterOverworld && ( - <AbilityCardEffect> - <H4>Overworld</H4> + <div className={styles.effect}> + <h4 className="h4">Overworld</h4> <p> {filterOverworld?.effect .slice(filterOverworld.effect.indexOf(overworld)) .replace(`Overworld:`, ``)} </p> - </AbilityCardEffect> + </div> )} - </AbilityCardSection> - <DescAbilityCard filterDesc={filterDesc} /> - <Divider /> - <AbilityCardSection> - <H3> + </section> + <Description filterDesc={filterDesc} /> + <Separator /> + <section className={styles.section}> + <h3 className="h3"> Pokemon with{` `} - <Capitalize>{ability && removeDash(ability?.name)}</Capitalize> - </H3> - <TableAbilityCard ability={ability} pokemon={pokemon} /> - </AbilityCardSection> - <Link href="/abilities" passHref> - <BackBtn name="Abilities" /> - </Link> - </MainBig> + <span className="capitalize"> + {ability && removeDash(ability?.name)} + </span> + </h3> + <Table ability={ability} pokemon={pokemon} /> + </section> + <Button intent="back" asChild> + <Link href="/abilities"> + <FaChevronLeft /> + Back to Abilities + </Link> + </Button> + </main> </> ); } -export default AbilityCard; +export default Ability; export function getServerSideProps(context: GetServerSidePropsContext) { const { name } = context.query; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 056ca8ae..12b07066 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,24 +1,14 @@ -import { Pagination } from '@/components/common/styles/Pagination'; -import { MainBig } from '@/components/common/styles/Sizing'; -import { Divider } from '@/components/common/ui/Divider'; -import Loader from '@/components/common/ui/Loader/Loader'; -import HeadingPokedex from '@/components/pages/Pokemon/Heading'; -import { useScrollDir } from '@/components/pages/Pokemon/Hooks/useScrollDir'; -import { PokedexVerticalText } from '@/components/pages/Pokemon/Styled.Pokemon'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { IOptionsOffsetLimit } from '@/utils/DataArrays'; -import { getPokedex } from '@/utils/DataFetch'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; -import dynamic from 'next/dynamic'; import { useState } from 'react'; -import { toast } from 'react-hot-toast'; -const Filters = dynamic( - () => import(`@/components/pages/Pokemon/Components/Filters.Pokemon`), -); -const ListPokemon = dynamic( - () => import(`@/components/pages/Pokemon/Components/List.Pokemon`), -); +import { type UseQueryResult, useQuery } from '@tanstack/react-query'; +import ReactPaginate from 'react-paginate'; + +import { ErrorToast, Loader, Separator } from '@/components'; +import { Filters, Heading, List, useScrollDir } from '@/modules/pokedex'; +import styles from '@/modules/pokedex/Pokedex.module.scss'; +import { type IOptionsOffsetLimit, getPokedex } from '@/utils'; + +import type { IPokemon } from '@/types'; function Pokedex() { const [filteredPokedex, setFilteredPokedex] = useState<IPokemon[]>([]); @@ -57,11 +47,7 @@ function Pokedex() { }; if (isError) { - return toast.error(`Something went wrong: ${error.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -70,8 +56,8 @@ function Pokedex() { return ( <> - <HeadingPokedex /> - <MainBig> + <Heading /> + <main className="mainBig"> <Filters pokedex={pokedex} setFilteredPokedex={setFilteredPokedex} @@ -85,12 +71,13 @@ function Pokedex() { generation={generation} setGeneration={setGeneration} /> - <PokedexVerticalText>ポケモン</PokedexVerticalText> - <ListPokemon filteredPokedex={filteredPokedex} /> - <Divider /> + <p className={styles.verticalText}>ポケモン</p> + <List filteredPokedex={filteredPokedex} /> + <Separator /> {scrollBtn()} {!form && !generation && ( - <Pagination + <ReactPaginate + className="pagination" breakLabel="..." onPageChange={handlePageChange} nextLabel=">" @@ -101,7 +88,7 @@ function Pokedex() { renderOnZeroPageCount={() => null} /> )} - </MainBig> + </main> </> ); } diff --git a/src/pages/item/[name].tsx b/src/pages/item/[name].tsx index 57e970a0..95ea151a 100644 --- a/src/pages/item/[name].tsx +++ b/src/pages/item/[name].tsx @@ -1,33 +1,19 @@ -import { CardTitle, Subtitle } from '@/components/common/styles/Headings'; -import { MainBig } from '@/components/common/styles/Sizing'; -import BackBtn from '@/components/common/ui/BackBtn'; -import Loader from '@/components/common/ui/Loader/Loader'; -import HeadingItem from '@/components/pages/Items/ItemCard/Heading'; -import { useFilterItem } from '@/components/pages/Items/ItemCard/Hooks/useFilterItem'; -import { - ItemCardDataEffect, - ItemCardDataImage, - ItemCardDataSection, -} from '@/components/pages/Items/ItemCard/Styled.ItemCard'; -import { removeDash } from '@/utils/Typography'; -import { GetServerSidePropsContext } from 'next'; -import dynamic from 'next/dynamic'; +import { FaChevronLeft } from '@meronex/icons/fa'; +import { type GetServerSidePropsContext } from 'next'; import Image from 'next/image'; import Link from 'next/link'; -import toast from 'react-hot-toast'; -const DescItemcard = dynamic( - () => import(`@/components/pages/Items/ItemCard/Components/Desc.Itemcard`), -); -const FlingItemCard = dynamic( - () => import(`@/components/pages/Items/ItemCard/Components/Fling.ItemCard`), -); -const HeldItemcard = dynamic( - () => import(`@/components/pages/Items/ItemCard/Components/Held.Itemcard`), -); -const CostItemCard = dynamic( - () => import(`@/components/pages/Items/ItemCard/Components/Cost.ItemCard`), -); +import { Button, ErrorToast, Loader } from '@/components'; +import { + Cost, + Description, + Fling, + Heading, + Held, + useFilterItem, +} from '@/modules/items/item'; +import styles from '@/modules/items/item/Item.module.scss'; +import { removeDash } from '@/utils'; type Props = { name: string; @@ -37,11 +23,7 @@ function ItemCard({ name }: Props) { const { isLoading, isError, error, item, filterEffect } = useFilterItem(name); if (isError) { - return toast.error(`Something went wrong: ${error?.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -51,21 +33,21 @@ function ItemCard({ name }: Props) { if (item) { return ( <> - <HeadingItem name={name} /> - <MainBig> - <CardTitle>{removeDash(item?.name)}</CardTitle> - <Subtitle>{removeDash(item?.category.name)}</Subtitle> - <ItemCardDataSection> + <Heading name={name} /> + <main className="mainBig"> + <h2 className="pageTitle">{removeDash(item?.name)}</h2> + <h4 className="subtitle">{removeDash(item?.category.name)}</h4> + <section className={styles.section}> <div> - <ItemCardDataEffect> + <div className={styles.effect}> <h3>Effect</h3> <p>{filterEffect?.effect}</p> - </ItemCardDataEffect> - <CostItemCard item={item} /> - <HeldItemcard item={item} /> - <FlingItemCard item={item} /> + </div> + <Cost item={item} /> + <Held item={item} /> + <Fling item={item} /> </div> - <ItemCardDataImage> + <div className={styles.image}> {item && ( <Image src={item?.sprites?.default} @@ -74,13 +56,16 @@ function ItemCard({ name }: Props) { height={96} /> )} - </ItemCardDataImage> - </ItemCardDataSection> - <DescItemcard item={item} /> - <Link href="/items" passHref> - <BackBtn name="Items" /> - </Link> - </MainBig> + </div> + </section> + <Description item={item} /> + <Button intent="back" asChild> + <Link href="/items"> + <FaChevronLeft /> + Back to Items + </Link> + </Button> + </main> </> ); } diff --git a/src/pages/items.tsx b/src/pages/items.tsx index 57be1526..fb9c681f 100644 --- a/src/pages/items.tsx +++ b/src/pages/items.tsx @@ -1,19 +1,13 @@ -import { MethodNav } from '@/components/common/styles/Navbars'; -import { MainBig } from '@/components/common/styles/Sizing'; -import Loader from '@/components/common/ui/Loader/Loader'; -import HeadingItems from '@/components/pages/Items/Heading'; -import { useToggleTable } from '@/components/pages/Items/Hooks/useToggleTable'; -import toast from 'react-hot-toast'; +import * as Tabs from '@radix-ui/react-tabs'; + +import { ErrorToast, Loader } from '@/components'; +import { Berries, Heading, Items, useItemsQuery } from '@/modules/items'; function ItemsPage() { - const { items, berries, toggle, setToggle, pageShown } = useToggleTable(); + const { items, berries } = useItemsQuery(); if (items.status === `error` || berries.status === `error`) { - return toast.error(`Something went wrong`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast />; } if (items.status === `loading` || berries.status === `loading`) { @@ -22,24 +16,26 @@ function ItemsPage() { return ( <> - <HeadingItems /> - <MainBig> - <MethodNav> - <button - className={toggle === 1 ? `button_active` : ``} - onClick={() => setToggle(1)} - > - <p>Items</p> - </button> - <button - className={toggle === 2 ? `button_active` : ``} - onClick={() => setToggle(2)} - > - <p>Berries</p> - </button> - </MethodNav> - {pageShown()} - </MainBig> + <Heading /> + <Tabs.Root className="TabsRootMain" defaultValue="tab1"> + <Tabs.List + className="TabsList" + aria-label="Switch between items and berries" + > + <Tabs.Trigger value="tab1" className="TabsTrigger"> + Items + </Tabs.Trigger> + <Tabs.Trigger value="tab2" className="TabsTrigger"> + Berries + </Tabs.Trigger> + </Tabs.List> + <Tabs.Content className="TabsContent" value="tab1"> + <Items items={items.data} /> + </Tabs.Content> + <Tabs.Content className="TabsContent" value="tab2"> + <Berries berries={berries.data} /> + </Tabs.Content> + </Tabs.Root> </> ); } diff --git a/src/pages/location/[name].tsx b/src/pages/location/[name].tsx index 25da08ff..cdfb0ea9 100644 --- a/src/pages/location/[name].tsx +++ b/src/pages/location/[name].tsx @@ -1,33 +1,23 @@ -import { CardTitle, Subtitle } from '@/components/common/styles/Headings'; -import { MainBig, Section } from '@/components/common/styles/Sizing'; -import { TableContainer, TBold, TLink } from '@/components/common/styles/Table'; -import BackBtn from '@/components/common/ui/BackBtn'; -import Loader from '@/components/common/ui/Loader/Loader'; -import { useSwitchGame } from '@/components/pages/Locations/LocationCard/Hooks/useSwitchGame'; -import { LocationTable } from '@/components/pages/Locations/Styled.Locations'; -import { useTableParams } from '@/hooks/useTableParams'; -import { IEncounterConditionValue } from '@/types/Encounters/EncounterConditionValue'; -import { IEncounterMethod } from '@/types/Encounters/EncounterMethod'; -import { IPokemonEncounter } from '@/types/Locations/LocationArea'; -import { IEncounter, IName } from '@/types/Utility/CommonModels'; -import { removeDash } from '@/utils/Typography'; -import { ColumnDef } from '@tanstack/react-table'; -import { GetServerSidePropsContext } from 'next'; -import dynamic from 'next/dynamic'; +import { useCallback, useEffect, useMemo, useState } from 'react'; + +import { FaChevronLeft } from '@meronex/icons/fa'; +import { type ColumnDef } from '@tanstack/react-table'; +import { type GetServerSidePropsContext } from 'next'; import Link from 'next/link'; -import { useEffect, useMemo, useState, useCallback } from 'react'; -import toast from 'react-hot-toast'; - -const HeadingLocation = dynamic( - () => import(`@/components/pages/Locations/LocationCard/Heading`), -); -const Nav = dynamic(() => import(`@/components/common/ui/GenNav`)); -const AreaLocationCard = dynamic( - () => - import( - `@/components/pages/Locations/LocationCard/Components/Area.LocationCard` - ), -); + +import { Button, ErrorToast, GenNav, Loader } from '@/components'; +import { useTableParams } from '@/hooks'; +import { Area, Heading, useSwitchGame } from '@/modules/locations/location'; +import styles from '@/modules/locations/Locations.module.scss'; +import { removeDash } from '@/utils'; + +import type { + IEncounter, + IEncounterConditionValue, + IEncounterMethod, + IName, + IPokemonEncounter, +} from '@/types'; type Props = { name: string; @@ -92,16 +82,17 @@ function LocationCard({ name }: Props) { id: `name`, header: `Pokemon`, cell: (info) => ( - <TBold> - <TLink + <td className="tBold"> + <Link + className="tLink" href={{ pathname: `/pokemon/[name]`, query: { name: info.getValue<string>() }, }} > {removeDash(info.getValue<string>())} - </TLink> - </TBold> + </Link> + </td> ), }, { @@ -190,11 +181,7 @@ function LocationCard({ name }: Props) { ); if (isError) { - return toast.error(`Something went wrong: ${error?.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -203,27 +190,27 @@ function LocationCard({ name }: Props) { return ( <> - <HeadingLocation name={name} /> - <MainBig> - <CardTitle> + <Heading name={name} /> + <main className="mainBig"> + <h2 className="pageTitle"> {location && removeDash(location.data?.name).replace( /kanto|johto|hoenn|sinnoh|unova|kalos|alola|galar|hisui|paldea/g, ``, )} - </CardTitle> - <Subtitle> + </h2> + <h4 className="subtitle"> {game && `${location.data?.region.name} - ${removeDash(game)}`} - </Subtitle> - <AreaLocationCard + </h4> + <Area location={location.data} toggleState={toggleState} toggleTable={toggleTable} /> - <Nav setGame={setGame} setVersion={setVersion} /> - <Section> - <TableContainer ref={tableContainerRef}> - <LocationTable> + <GenNav setGame={setGame} setVersion={setVersion} /> + <section className="section"> + <div className="tableContainer" ref={tableContainerRef}> + <table className={styles.table}> {tableHeader()} {tableBody()} <tfoot> @@ -231,13 +218,16 @@ function LocationCard({ name }: Props) { <td colSpan={5}>This area is not present in this game</td> </tr> </tfoot> - </LocationTable> - </TableContainer> - </Section> - <Link href="/locations" passHref> - <BackBtn name="Locations" /> - </Link> - </MainBig> + </table> + </div> + </section> + <Button intent="back" asChild> + <Link href="/locations"> + <FaChevronLeft /> + Back to Locations + </Link> + </Button> + </main> </> ); } diff --git a/src/pages/locations.tsx b/src/pages/locations.tsx index 990dfe2b..0aed7003 100644 --- a/src/pages/locations.tsx +++ b/src/pages/locations.tsx @@ -1,22 +1,17 @@ -import { MainBig } from '@/components/common/styles/Sizing'; -import Loader from '@/components/common/ui/Loader/Loader'; -import HeadingLocations from '@/components/pages/Locations/Heading'; -import { LocationSection } from '@/components/pages/Locations/Styled.Locations'; -import { IRegion } from '@/types/Locations/Region'; -import { regions } from '@/utils/DataArrays'; -import { getRegions } from '@/utils/DataFetch'; -import { capitalize } from '@/utils/Typography'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; -import dynamic from 'next/dynamic'; import { useEffect, useState } from 'react'; -import toast from 'react-hot-toast'; -const ListLocations = dynamic( - () => import(`@/components/pages/Locations/Components/List.Locations`), -); +import * as Tabs from '@radix-ui/react-tabs'; +import { type UseQueryResult, useQuery } from '@tanstack/react-query'; +import dynamic from 'next/dynamic'; + +import { ErrorToast, Loader } from '@/components'; +import { Heading, List } from '@/modules/locations'; +import { getRegions, regions } from '@/utils'; + +import type { IRegion } from '@/types'; const RegionsMethod = dynamic(() => - import(`@/utils/ObjectsMap`).then((res) => res.RegionsMethod), + import(`@/utils`).then((res) => res.RegionsMethod), ); function LocationsPage() { @@ -37,11 +32,7 @@ function LocationsPage() { }, [toggle]); if (isError) { - return toast.error(`Something went wrong: ${error.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -50,16 +41,13 @@ function LocationsPage() { return ( <> - <HeadingLocations /> - <MainBig> - <RegionsMethod toggle={toggle} setToggle={setToggle} /> - <ListLocations location={location} locations={locations} /> - {location === `galar` || location === `hisui` ? ( - <LocationSection> - <p>No data for {capitalize(location)}</p> - </LocationSection> - ) : null} - </MainBig> + <Heading /> + <Tabs.Root className="TabsRootMain" defaultValue={String(toggle)}> + <RegionsMethod setToggle={setToggle} /> + <Tabs.Content value={String(toggle)}> + <List location={location} locations={locations} /> + </Tabs.Content> + </Tabs.Root> </> ); } diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 1149f6b8..e4fb2996 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -1,46 +1,25 @@ -import { H2 } from '@/components/common/styles/Headings'; -import { MainForm } from '@/components/common/styles/Sizing'; -import ResetPwd from '@/components/pages/Auth/ResetPwd'; -import { - AuthBtn, - AuthButtons, - AuthChoice, - AuthClose, - AuthContainer, - AuthForm, - AuthImage, - AuthInput, - AuthResetPwd, - AuthSecBtn, - AuthSwitch, - AuthTitle, -} from '@/components/pages/Auth/Styled.Auth'; -import { auth, signInWithGithub, signInWithGoogle } from '@/firebase-config'; -import { capitalize } from '@/utils/Typography'; +import { useState } from 'react'; + import { yupResolver } from '@hookform/resolvers/yup'; import { FiX } from '@meronex/icons/fi'; import { GrGithub, GrGoogle } from '@meronex/icons/gr'; -import { signInWithEmailAndPassword } from 'firebase/auth'; import Link from 'next/link'; import { useRouter } from 'next/router'; -import { useState } from 'react'; import { useForm } from 'react-hook-form'; -import { toast } from 'react-hot-toast'; import * as yup from 'yup'; -type FormInput = { - email: string; - password: string; - resetEmail: string; -}; +import { ErrorToast, Input, SuccessToast } from '@/components'; +import styles from '@/modules/auth/Auth.module.scss'; +import ResetPwd from '@/modules/auth/ResetPwd'; +import { capitalize } from '@/utils'; -const schema = yup - .object({ - email: yup.string().email().required(), - password: yup.string().min(6).required(), - resetEmail: yup.string().email().required(), - }) - .required(); +const schema = yup.object({ + email: yup.string().email().required(), + password: yup.string().min(6).required(), + resetEmail: yup.string().email().required(), +}); + +type FormInput = yup.Asserts<typeof schema>; function Login() { const router = useRouter(); @@ -55,56 +34,48 @@ function Login() { handleSubmit, formState: { errors }, } = useForm<FormInput>({ - resolver: yupResolver<yup.AnyObjectSchema>(schema), + resolver: yupResolver<FormInput>(schema), }); const submitForm = async (data: FormInput) => { try { - await signInWithEmailAndPassword(auth, data.email, data.password); - toast.success(`Welcome back 👋`, { - style: { - fontSize: `1.7rem`, - }, - }); + // will have the sign-in call router.push(`/`); + return <SuccessToast text="Welcome back 👋" />; } catch (error) { if (error instanceof Error) { - toast.error(error.message, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } } }; const googleConnect = () => { - signInWithGoogle(); + // will have the sign-in with google call router.push(`/`); }; const githubConnect = () => { - signInWithGithub(); + // will have the sign-in with github call router.push(`/`); }; return ( - <MainForm> - <AuthContainer> - <AuthClose href={`/`}> + <main className="mainForm"> + <div className={styles.container}> + <Link className={styles.close} href={`/`}> <FiX /> - </AuthClose> - <AuthImage /> - <AuthForm onSubmit={handleSubmit(submitForm)}> - <AuthTitle> - <H2>Login</H2> + </Link> + <div className={styles.image} /> + <form className={styles.form} onSubmit={handleSubmit(submitForm)}> + <div className={styles.title}> + <h2 className="h2">Login</h2> <p> Go to your profile to create teams and find your favorites pokémon </p> - </AuthTitle> - <AuthInput> + </div> + <div className={styles.input}> <div> - <input + <Input type="email" id="email" placeholder="Email" @@ -115,7 +86,7 @@ function Login() { )} </div> <div> - <input + <Input type="password" id="password" placeholder="Password" @@ -124,37 +95,51 @@ function Login() { {typeof errors.password?.message === `string` && ( <small>{capitalize(errors.password?.message)}</small> )} - <AuthResetPwd type="button" onClick={openModal}> + <button + className={styles.reset} + type="button" + onClick={openModal} + > J'ai oublié mon mot de passe - </AuthResetPwd> + </button> </div> - <AuthBtn type="submit">Login</AuthBtn> - </AuthInput> - <AuthChoice>OR</AuthChoice> - <AuthInput> - <AuthButtons> - <AuthSecBtn type="button" onClick={googleConnect}> + <button className={styles.button} type="submit"> + Login + </button> + </div> + <p className={styles.choice}>OR</p> + <div className={styles.input}> + <div className={styles.providers}> + <button + className={styles.secButton} + type="button" + onClick={googleConnect} + > Sign In with Google <span> <GrGoogle /> </span> - </AuthSecBtn> - <AuthSecBtn type="button" onClick={githubConnect}> + </button> + <button + className={styles.secButton} + type="button" + onClick={githubConnect} + > Sign In with Github <span> <GrGithub /> </span> - </AuthSecBtn> - </AuthButtons> - </AuthInput> - <AuthSwitch> + </button> + </div> + </div> + <p className={styles.switch}> Don't have an account yet ?{` `} <Link href="/register">Register</Link> - </AuthSwitch> - </AuthForm> - </AuthContainer> + </p> + </form> + </div> <ResetPwd modalIsOpen={modalIsOpen} setIsOpen={setIsOpen} /> - </MainForm> + </main> ); } diff --git a/src/pages/machines.tsx b/src/pages/machines.tsx index c86b72bd..b01aa3fc 100644 --- a/src/pages/machines.tsx +++ b/src/pages/machines.tsx @@ -1,27 +1,15 @@ -import { - Bold, - LeftH2, - LeftSubtitle, -} from '@/components/common/styles/Headings'; -import { MainBig } from '@/components/common/styles/Sizing'; -import { - FullWidthTable, - TableContainer, - TBold, - TLink, -} from '@/components/common/styles/Table'; -import Loader from '@/components/common/ui/Loader/Loader'; -import { useTableParams } from '@/hooks/useTableParams'; -import { IMachine } from '@/types/Machines/Machine'; -import { getMachines } from '@/utils/DataFetch'; -import { removeDash, uppercase } from '@/utils/Typography'; -import { useQuery, UseQueryResult } from '@tanstack/react-query'; -import { ColumnDef } from '@tanstack/react-table'; -import dynamic from 'next/dynamic'; import { useMemo, useState } from 'react'; -import toast from 'react-hot-toast'; -const Nav = dynamic(() => import(`@/components/common/ui/GenNav`)); +import { type UseQueryResult, useQuery } from '@tanstack/react-query'; +import { type ColumnDef } from '@tanstack/react-table'; +import Link from 'next/link'; + +import { ErrorToast, GenNav, Loader } from '@/components'; +import { useTableParams } from '@/hooks'; +import { Heading } from '@/modules/machines'; +import { getMachines, removeDash, uppercase } from '@/utils'; + +import type { IMachine } from '@/types'; function MachinesPage() { const [version, setVersion] = useState<string | null>(`red-blue`); @@ -47,7 +35,9 @@ function MachinesPage() { accessorKey: `item.name`, id: `sort`, header: `Name`, - cell: (info) => <TBold>{uppercase(info.getValue<string>())}</TBold>, + cell: (info) => ( + <td className="tBold">{uppercase(info.getValue<string>())}</td> + ), }, { accessorKey: `move.name`, @@ -55,14 +45,15 @@ function MachinesPage() { header: `Move`, cell: (info) => ( <td> - <TLink + <Link + className="tLink" href={{ pathname: `/move/[name]`, query: { name: info.getValue<string>() }, }} > {removeDash(info.getValue<string>())} - </TLink> + </Link> </td> ), }, @@ -76,11 +67,7 @@ function MachinesPage() { ); if (isError) { - return toast.error(`Something went wrong: ${error.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -89,14 +76,15 @@ function MachinesPage() { return ( <> - <MainBig> - <LeftH2>Machines</LeftH2> - <LeftSubtitle> - Game selected: <Bold>{game}</Bold> - </LeftSubtitle> - <Nav setGame={setGame} setVersion={setVersion} /> - <TableContainer ref={tableContainerRef}> - <FullWidthTable> + <Heading /> + <main className="mainBig"> + <h2 className="leftH2">Machines</h2> + <h4 className="leftSubtitle"> + Game selected: <span className="bold">{game}</span> + </h4> + <GenNav setGame={setGame} setVersion={setVersion} /> + <section className="tableContainer" ref={tableContainerRef}> + <table className="fullWidthTable"> {tableHeader()} {tableBody()} <tfoot> @@ -104,9 +92,9 @@ function MachinesPage() { <td colSpan={2}>There is no data for this game</td> </tr> </tfoot> - </FullWidthTable> - </TableContainer> - </MainBig> + </table> + </section> + </main> </> ); } diff --git a/src/pages/move/[name].tsx b/src/pages/move/[name].tsx index 85901c23..4a4f9553 100644 --- a/src/pages/move/[name].tsx +++ b/src/pages/move/[name].tsx @@ -1,28 +1,18 @@ -import { CardTitle, Subtitle } from '@/components/common/styles/Headings'; -import BackBtn from '@/components/common/ui/BackBtn'; -import { Divider } from '@/components/common/ui/Divider'; -import Loader from '@/components/common/ui/Loader/Loader'; -import HeadingMove from '@/components/pages/Moves/MoveCard/Heading'; -import { useFetchMove } from '@/components/pages/Moves/MoveCard/Hooks/useFetchMove'; -import { MoveMainBig } from '@/components/pages/Moves/MoveCard/Styled.MoveCard'; -import { removeDash } from '@/utils/Typography'; -import { GetServerSidePropsContext } from 'next'; +import { useState } from 'react'; + +import { FaChevronLeft } from '@meronex/icons/fa'; +import * as Tabs from '@radix-ui/react-tabs'; +import { type GetServerSidePropsContext } from 'next'; import dynamic from 'next/dynamic'; import Link from 'next/link'; -import { useState } from 'react'; -import toast from 'react-hot-toast'; -const Nav = dynamic( - () => import(`@/components/pages/Moves/MoveCard/Nav/Nav.MoveCard`), -); -const Data = dynamic( - () => import(`@/components/pages/Moves/MoveCard/Data/Data.MoveCard`), -); -const List = dynamic( - () => import(`@/components/pages/Moves/MoveCard/List/List.MoveCard`), -); +import { Button, ErrorToast, Loader, Separator } from '@/components'; +import { Data, Heading, List, Nav, useFetchMove } from '@/modules/moves/move'; +import styles from '@/modules/moves/move/Move.module.scss'; +import { removeDash } from '@/utils'; + const LearnMethod = dynamic(() => - import(`@/utils/ObjectsMap`).then((res) => res.LearnMethod), + import(`@/utils`).then((res) => res.LearnMethod), ); type Props = { @@ -47,11 +37,7 @@ function MoveCard({ name }: Props) { } = useFetchMove(name); if (isError) { - toast.error(`Something went wrong: ${error?.message}`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast error={error} />; } if (isLoading) { @@ -60,23 +46,20 @@ function MoveCard({ name }: Props) { return ( <> - <HeadingMove name={name} /> + <Heading name={name} /> {move && ( - <MoveMainBig> - <CardTitle>{removeDash(move.name)}</CardTitle> - <Subtitle>{removeDash(move.generation.name)}</Subtitle> + <main className={styles.main}> + <h2 className="pageTitle">{removeDash(move.name)}</h2> + <h4 className="subtitle">{removeDash(move.generation.name)}</h4> <Nav move={move} setVersion={setVersion} /> <Data move={move} machine={machine} version={version} /> - <Divider /> - - <LearnMethod - toggle={toggle} - setToggle={setToggle} - setLearn={setLearn} - /> + <Separator /> + <Tabs.Root className="TabsRootSection" defaultValue={String(toggle)}> + <LearnMethod setToggle={setToggle} setLearn={setLearn} /> + </Tabs.Root> <List pokemon={pokemon} @@ -86,10 +69,13 @@ function MoveCard({ name }: Props) { version={version} /> - <Link href="/moves" passHref> - <BackBtn name="Moves" /> - </Link> - </MoveMainBig> + <Button intent="back" asChild> + <Link href="/moves"> + <FaChevronLeft /> + Back to Moves + </Link> + </Button> + </main> )} </> ); diff --git a/src/pages/moves.tsx b/src/pages/moves.tsx index d0a1081a..43ea56d9 100644 --- a/src/pages/moves.tsx +++ b/src/pages/moves.tsx @@ -1,24 +1,17 @@ -import { MethodNav } from '@/components/common/styles/Navbars'; -import { MainBig } from '@/components/common/styles/Sizing'; -import Loader from '@/components/common/ui/Loader/Loader'; -import HeadingMoves from '@/components/pages/Moves/Heading'; -import { useToggleTable } from '@/components/pages/Moves/Hooks/useToggleTable'; -import toast from 'react-hot-toast'; +import * as Tabs from '@radix-ui/react-tabs'; + +import { ErrorToast, Loader } from '@/components'; +import { Heading, Moves, Stats, Status, useMovesQuery } from '@/modules/moves'; function MovesPage() { - const { moves, status, stats, toggle, setToggle, pageShown } = - useToggleTable(); + const { moves, status, stats } = useMovesQuery(); if ( moves.status === `error` || status.status === `error` || stats.status === `error` ) { - return toast.error(`Something went wrong`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast />; } if ( @@ -31,30 +24,32 @@ function MovesPage() { return ( <> - <HeadingMoves /> - <MainBig> - <MethodNav> - <button - className={toggle === 1 ? `button_active` : ``} - onClick={() => setToggle(1)} - > - <p>Moves</p> - </button> - <button - className={toggle === 2 ? `button_active` : ``} - onClick={() => setToggle(2)} - > - <p>Status</p> - </button> - <button - className={toggle === 3 ? `button_active` : ``} - onClick={() => setToggle(3)} - > - <p>Stats</p> - </button> - </MethodNav> - {pageShown()} - </MainBig> + <Heading /> + <Tabs.Root className="TabsRootMain" defaultValue="tab1"> + <Tabs.List + className="TabsList" + aria-label="Switch between moves, status and stats" + > + <Tabs.Trigger value="tab1" className="TabsTrigger"> + Moves + </Tabs.Trigger> + <Tabs.Trigger value="tab2" className="TabsTrigger"> + Status + </Tabs.Trigger> + <Tabs.Trigger value="tab3" className="TabsTrigger"> + Stats + </Tabs.Trigger> + </Tabs.List> + <Tabs.Content className="TabsContent" value="tab1"> + <Moves moves={moves.data} /> + </Tabs.Content> + <Tabs.Content className="TabsContent" value="tab2"> + <Status status={status.data} /> + </Tabs.Content> + <Tabs.Content className="TabsContent" value="tab3"> + <Stats stats={stats.data} /> + </Tabs.Content> + </Tabs.Root> </> ); } diff --git a/src/pages/pokemon/[name].tsx b/src/pages/pokemon/[name].tsx index d66032e8..00db23da 100644 --- a/src/pages/pokemon/[name].tsx +++ b/src/pages/pokemon/[name].tsx @@ -1,100 +1,30 @@ -import { Subtitle, Title } from '@/components/common/styles/Headings'; -import { MainBig } from '@/components/common/styles/Sizing'; -import BackBtn from '@/components/common/ui/BackBtn'; -import { Divider } from '@/components/common/ui/Divider'; -import Loader from '@/components/common/ui/Loader/Loader'; -import Contents from '@/components/pages/Pokemon/PokemonCard/Contents/Contents.PokemonCard'; -import HeadingPokemon from '@/components/pages/Pokemon/PokemonCard/Heading'; -import { useFetchPokemon } from '@/components/pages/Pokemon/PokemonCard/Hooks/useFetchPokemon'; -import { PokemonTitle } from '@/components/pages/Pokemon/Styled.Pokemon'; -import { IEvolutionChain } from '@/types/Evolution/EvolutionChain'; -import { IPokemon } from '@/types/Pokemon/Pokemon'; -import { pokemonFilters } from '@/utils/DataArrays'; -import { removeDash, removeLongName } from '@/utils/Typography'; -import { HiOutlineSpeakerphone } from '@meronex/icons/hi'; -import { GetServerSidePropsContext } from 'next'; -import dynamic from 'next/dynamic'; -import Link from 'next/link'; import { useEffect, useRef, useState } from 'react'; -import toast from 'react-hot-toast'; - -interface IEvolutionProps { - evolution: IEvolutionChain; - name: string; -} - -interface IMovesProps { - pokemon: IPokemon; - version: string; - name: string; -} - -interface ICompetitiveProps { - format: string; - name: string; -} -interface IFormsProps { - pokemon: IPokemon; -} +import { FaChevronLeft } from '@meronex/icons/fa'; +import { HiOutlineSpeakerphone } from '@meronex/icons/hi'; +import { type GetServerSidePropsContext } from 'next'; +import Link from 'next/link'; -const Nav = dynamic( - () => import(`@/components/pages/Pokemon/PokemonCard/Nav/Nav.PokemonCard`), -); -const Data = dynamic( - () => import(`@/components/pages/Pokemon/PokemonCard/Data/Data.PokemonCard`), -); -const Evolution = dynamic<IEvolutionProps>( - () => - import( - `@/components/pages/Pokemon/PokemonCard/Evolution/Evolution.PokemonCard` - ) as any, -); -const Info = dynamic( - () => import(`@/components/pages/Pokemon/PokemonCard/Info/Info.PokemonCard`), -); -const Stats = dynamic( - () => - import(`@/components/pages/Pokemon/PokemonCard/Stats/Stats.PokemonCard`), -); -const Typing = dynamic( - () => - import(`@/components/pages/Pokemon/PokemonCard/Types/Types.PokemonCard`), -); -const Moves = dynamic<IMovesProps>( - () => - import( - `@/components/pages/Pokemon/PokemonCard/Moves/Moves.PokemonCard` - ) as any, -); -const Locations = dynamic( - () => - import( - `@/components/pages/Pokemon/PokemonCard/Locations/Locations.PokemonCard` - ), -); -const Competitive = dynamic<ICompetitiveProps>( - () => - import( - `@/components/pages/Pokemon/PokemonCard/Competitive/Competitive.PokemonCard` - ) as any, -); -const Forms = dynamic<IFormsProps>( - () => - import( - `@/components/pages/Pokemon/PokemonCard/Forms/Forms.PokemonCard` - ) as any, -); -const Sprites = dynamic( - () => - import( - `@/components/pages/Pokemon/PokemonCard/Sprites/Sprites.PokemonCard` - ), -); -const Cards = dynamic( - () => - import(`@/components/pages/Pokemon/PokemonCard/Cards/Cards.PokemonCard`), -); +import { Button, ErrorToast, Loader, Separator } from '@/components'; +import styles from '@/modules/pokedex/Pokedex.module.scss'; +import { + Cards, + Competitive, + Content, + Data, + Evolution, + Forms, + Heading, + Info, + Locations, + Moves, + Nav, + Sprites, + Stats, + Types, + useFetchPokemon, +} from '@/modules/pokedex/pokemon'; +import { pokemonFilters, removeDash, removeLongName } from '@/utils'; type Props = { name: string; @@ -138,11 +68,7 @@ function PokemonCard({ name }: Props) { types.status === `error` || location.status === `error` ) { - return toast.error(`Something went wrong`, { - style: { - fontSize: `1.7rem`, - }, - }); + return <ErrorToast />; } if ( @@ -157,15 +83,18 @@ function PokemonCard({ name }: Props) { return ( <> - <HeadingPokemon name={name} /> - <MainBig> - <PokemonTitle> + <Heading name={name} /> + <main className="mainBig"> + <section className={styles.section}> {pokemon.data?.name?.includes(`mega`) ? ( - <Title> - {removeDash(pokemon.data?.name).split(` `).reverse().join(` `)} - +

    + {removeDash(pokemon.data?.name) + .split(` `) + .reverse() + .join(` `)} +

    ) : ( - {removeLongName(removeDash(name))} +

    {removeLongName(removeDash(name))}

    )} {pokemon.data?.id < 722 && (
    @@ -178,9 +107,11 @@ function PokemonCard({ name }: Props) { />
    )} - + {species.data && ( - {removeDash(species.data?.generation?.name)} +

    + {removeDash(species.data?.generation?.name)} +

    )}