Weapon stories
This commit is contained in:
		
							parent
							
								
									df8a7f820d
								
							
						
					
					
						commit
						7aeb85e4f9
					
				
							
								
								
									
										302
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										302
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -15,7 +15,7 @@ | ||||
|         "autoprefixer": "^10.4.13", | ||||
|         "cuid": "^2.1.8", | ||||
|         "intl-messageformat": "^10.3.0", | ||||
|         "isomorphic-dompurify": "^0.26.0", | ||||
|         "isomorphic-dompurify": "^1.0.0", | ||||
|         "jotai": "^2.0.1", | ||||
|         "markdown-to-jsx": "^7.1.9", | ||||
|         "marked": "^4.2.12", | ||||
| @ -28,7 +28,7 @@ | ||||
|         "react-dom": "18.2.0", | ||||
|         "react-hotkeys-hook": "^3.4.7", | ||||
|         "react-swipeable": "^7.0.0", | ||||
|         "react-zoom-pan-pinch": "^2.5.0", | ||||
|         "react-zoom-pan-pinch": "^2.6.1", | ||||
|         "string-natural-compare": "^3.0.1", | ||||
|         "throttle-debounce": "^5.0.0", | ||||
|         "tippy.js": "^6.3.7", | ||||
| @ -46,25 +46,25 @@ | ||||
|         "@types/marked": "^4.0.8", | ||||
|         "@types/node": "18.13.0", | ||||
|         "@types/nodemailer": "^6.4.7", | ||||
|         "@types/react": "^18.0.27", | ||||
|         "@types/react-dom": "^18.0.10", | ||||
|         "@types/react": "^18.0.28", | ||||
|         "@types/react-dom": "^18.0.11", | ||||
|         "@types/string-natural-compare": "^3.0.2", | ||||
|         "@types/throttle-debounce": "^5.0.0", | ||||
|         "@types/turndown": "^5.0.1", | ||||
|         "@types/ua-parser-js": "^0.7.36", | ||||
|         "@typescript-eslint/eslint-plugin": "^5.51.0", | ||||
|         "@typescript-eslint/parser": "^5.51.0", | ||||
|         "@typescript-eslint/eslint-plugin": "^5.52.0", | ||||
|         "@typescript-eslint/parser": "^5.52.0", | ||||
|         "dotenv": "^16.0.3", | ||||
|         "eslint": "^8.33.0", | ||||
|         "eslint": "^8.34.0", | ||||
|         "eslint-config-next": "13.1.6", | ||||
|         "eslint-plugin-import": "^2.27.5", | ||||
|         "graphql": "^16.6.0", | ||||
|         "graphql-request": "^5.1.0", | ||||
|         "next-sitemap": "^3.1.52", | ||||
|         "prettier": "^2.8.4", | ||||
|         "prettier-plugin-tailwindcss": "^0.2.2", | ||||
|         "prettier-plugin-tailwindcss": "^0.2.3", | ||||
|         "tailwindcss": "^3.2.6", | ||||
|         "ts-unused-exports": "^9.0.3", | ||||
|         "ts-unused-exports": "^9.0.4", | ||||
|         "typescript": "^4.9.5" | ||||
|       } | ||||
|     }, | ||||
| @ -3690,9 +3690,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/@types/react": { | ||||
|       "version": "18.0.27", | ||||
|       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", | ||||
|       "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", | ||||
|       "version": "18.0.28", | ||||
|       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", | ||||
|       "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@types/prop-types": "*", | ||||
| @ -3701,9 +3701,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@types/react-dom": { | ||||
|       "version": "18.0.10", | ||||
|       "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", | ||||
|       "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", | ||||
|       "version": "18.0.11", | ||||
|       "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", | ||||
|       "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@types/react": "*" | ||||
| @ -3760,14 +3760,14 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/eslint-plugin": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz", | ||||
|       "integrity": "sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", | ||||
|       "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/scope-manager": "5.51.0", | ||||
|         "@typescript-eslint/type-utils": "5.51.0", | ||||
|         "@typescript-eslint/utils": "5.51.0", | ||||
|         "@typescript-eslint/scope-manager": "5.52.0", | ||||
|         "@typescript-eslint/type-utils": "5.52.0", | ||||
|         "@typescript-eslint/utils": "5.52.0", | ||||
|         "debug": "^4.3.4", | ||||
|         "grapheme-splitter": "^1.0.4", | ||||
|         "ignore": "^5.2.0", | ||||
| @ -3794,14 +3794,14 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/parser": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz", | ||||
|       "integrity": "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", | ||||
|       "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/scope-manager": "5.51.0", | ||||
|         "@typescript-eslint/types": "5.51.0", | ||||
|         "@typescript-eslint/typescript-estree": "5.51.0", | ||||
|         "@typescript-eslint/scope-manager": "5.52.0", | ||||
|         "@typescript-eslint/types": "5.52.0", | ||||
|         "@typescript-eslint/typescript-estree": "5.52.0", | ||||
|         "debug": "^4.3.4" | ||||
|       }, | ||||
|       "engines": { | ||||
| @ -3821,13 +3821,13 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/scope-manager": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz", | ||||
|       "integrity": "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", | ||||
|       "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/types": "5.51.0", | ||||
|         "@typescript-eslint/visitor-keys": "5.51.0" | ||||
|         "@typescript-eslint/types": "5.52.0", | ||||
|         "@typescript-eslint/visitor-keys": "5.52.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | ||||
| @ -3838,13 +3838,13 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/type-utils": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz", | ||||
|       "integrity": "sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", | ||||
|       "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/typescript-estree": "5.51.0", | ||||
|         "@typescript-eslint/utils": "5.51.0", | ||||
|         "@typescript-eslint/typescript-estree": "5.52.0", | ||||
|         "@typescript-eslint/utils": "5.52.0", | ||||
|         "debug": "^4.3.4", | ||||
|         "tsutils": "^3.21.0" | ||||
|       }, | ||||
| @ -3865,9 +3865,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/types": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz", | ||||
|       "integrity": "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", | ||||
|       "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", | ||||
|       "dev": true, | ||||
|       "engines": { | ||||
|         "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | ||||
| @ -3878,13 +3878,13 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/typescript-estree": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz", | ||||
|       "integrity": "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", | ||||
|       "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/types": "5.51.0", | ||||
|         "@typescript-eslint/visitor-keys": "5.51.0", | ||||
|         "@typescript-eslint/types": "5.52.0", | ||||
|         "@typescript-eslint/visitor-keys": "5.52.0", | ||||
|         "debug": "^4.3.4", | ||||
|         "globby": "^11.1.0", | ||||
|         "is-glob": "^4.0.3", | ||||
| @ -3905,16 +3905,16 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/utils": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.51.0.tgz", | ||||
|       "integrity": "sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", | ||||
|       "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@types/json-schema": "^7.0.9", | ||||
|         "@types/semver": "^7.3.12", | ||||
|         "@typescript-eslint/scope-manager": "5.51.0", | ||||
|         "@typescript-eslint/types": "5.51.0", | ||||
|         "@typescript-eslint/typescript-estree": "5.51.0", | ||||
|         "@typescript-eslint/scope-manager": "5.52.0", | ||||
|         "@typescript-eslint/types": "5.52.0", | ||||
|         "@typescript-eslint/typescript-estree": "5.52.0", | ||||
|         "eslint-scope": "^5.1.1", | ||||
|         "eslint-utils": "^3.0.0", | ||||
|         "semver": "^7.3.7" | ||||
| @ -3953,12 +3953,12 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@typescript-eslint/visitor-keys": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz", | ||||
|       "integrity": "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", | ||||
|       "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@typescript-eslint/types": "5.51.0", | ||||
|         "@typescript-eslint/types": "5.52.0", | ||||
|         "eslint-visitor-keys": "^3.3.0" | ||||
|       }, | ||||
|       "engines": { | ||||
| @ -5297,9 +5297,9 @@ | ||||
|       "integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==" | ||||
|     }, | ||||
|     "node_modules/dompurify": { | ||||
|       "version": "2.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz", | ||||
|       "integrity": "sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA==" | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.0.tgz", | ||||
|       "integrity": "sha512-0g/yr2IJn4nTbxwL785YxS7/AvvgGFJw6LLWP+BzWzB1+BYOqPUT9Hy0rXrZh5HLdHnxH72aDdzvC9SdTjsuaA==" | ||||
|     }, | ||||
|     "node_modules/dot-case": { | ||||
|       "version": "3.0.4", | ||||
| @ -5624,9 +5624,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/eslint": { | ||||
|       "version": "8.33.0", | ||||
|       "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.33.0.tgz", | ||||
|       "integrity": "sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==", | ||||
|       "version": "8.34.0", | ||||
|       "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", | ||||
|       "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@eslint/eslintrc": "^1.4.1", | ||||
| @ -7467,13 +7467,13 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/isomorphic-dompurify": { | ||||
|       "version": "0.26.0", | ||||
|       "resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-0.26.0.tgz", | ||||
|       "integrity": "sha512-70gPadd/NJPTBuTtM5PsWimmc7S4fcBENzOFMHfBtIPacaygUvI9n63qFkUTc91WDDC9yB68mtmluW9/NhhTJw==", | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-1.0.0.tgz", | ||||
|       "integrity": "sha512-rxkJ2b2rwsgN/uvtaW+Z2JGfD9CYcixYMj0eTIa4V2hG47VDRMiehtUypi4lkpuwW41UrnOR65Dy0POiH3Lbjg==", | ||||
|       "dependencies": { | ||||
|         "@types/dompurify": "^2.3.4", | ||||
|         "dompurify": "^2.4.1", | ||||
|         "jsdom": "^21.0.0" | ||||
|         "@types/dompurify": "^2.4.0", | ||||
|         "dompurify": "^3.0.0", | ||||
|         "jsdom": "^21.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/isomorphic-fetch": { | ||||
| @ -7535,9 +7535,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/jsdom": { | ||||
|       "version": "21.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.0.0.tgz", | ||||
|       "integrity": "sha512-AIw+3ZakSUtDYvhwPwWHiZsUi3zHugpMEKlNPaurviseYoBqo0zBd3zqoUi3LPCNtPFlEP8FiW9MqCZdjb2IYA==", | ||||
|       "version": "21.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.1.0.tgz", | ||||
|       "integrity": "sha512-m0lzlP7qOtthD918nenK3hdItSd2I+V3W9IrBcB36sqDwG+KnUs66IF5GY7laGWUnlM9vTsD0W1QwSEBYWWcJg==", | ||||
|       "dependencies": { | ||||
|         "abab": "^2.0.6", | ||||
|         "acorn": "^8.8.1", | ||||
| @ -8860,14 +8860,15 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/prettier-plugin-tailwindcss": { | ||||
|       "version": "0.2.2", | ||||
|       "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.2.tgz", | ||||
|       "integrity": "sha512-5RjUbWRe305pUpc48MosoIp6uxZvZxrM6GyOgsbGLTce+ehePKNm7ziW2dLG2air9aXbGuXlHVSQQw4Lbosq3w==", | ||||
|       "version": "0.2.3", | ||||
|       "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.3.tgz", | ||||
|       "integrity": "sha512-s2N5Dh7Ao5KTV1mao5ZBnn8EKtUcDPJEkGViZIjI0Ij9TTI5zgTz4IHOxW33jOdjHKa8CSjM88scelUiC5TNRQ==", | ||||
|       "dev": true, | ||||
|       "engines": { | ||||
|         "node": ">=12.17.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@ianvs/prettier-plugin-sort-imports": "*", | ||||
|         "@prettier/plugin-php": "*", | ||||
|         "@prettier/plugin-pug": "*", | ||||
|         "@shopify/prettier-plugin-liquid": "*", | ||||
| @ -8885,6 +8886,9 @@ | ||||
|         "prettier-plugin-twig-melody": "*" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "@ianvs/prettier-plugin-sort-imports": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "@prettier/plugin-php": { | ||||
|           "optional": true | ||||
|         }, | ||||
| @ -9102,9 +9106,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/react-zoom-pan-pinch": { | ||||
|       "version": "2.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-2.5.0.tgz", | ||||
|       "integrity": "sha512-5o3DKACPRNXM5Yr1dfQ5sZsGpstEsam3ih3dNmaDUfpghwD7ENwCVAupbNiBHlJ1Jbowd6o9qamp/2FiWu2Jcg==", | ||||
|       "version": "2.6.1", | ||||
|       "resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-2.6.1.tgz", | ||||
|       "integrity": "sha512-4Cgdnn6OwN4DomY/E9NpAf0TyCtslEgwdYn96ZV/f5LKuw/FE3gcIBJiaKFmMGThDGV0yKN5mzO8noi34+UE4Q==", | ||||
|       "engines": { | ||||
|         "node": ">=8", | ||||
|         "npm": ">=5" | ||||
| @ -10042,9 +10046,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/ts-unused-exports": { | ||||
|       "version": "9.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.3.tgz", | ||||
|       "integrity": "sha512-LCGLYL0EVdXNj1O/cGfpP2Fx+zfqoV936iMyIhvSVnXk4RUjwmSjMzzCNXI9b1j9PCs946a2TbRMhJh7/XUyUA==", | ||||
|       "version": "9.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.4.tgz", | ||||
|       "integrity": "sha512-/PPy0B1zhOJkDTUd1XVyaCqE/yA3IL2FrQ8W5/6cQ2g0kKC/06q8LEoPeXI6ELfI6Bivmv3MMvsUup5u3WH+BQ==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "chalk": "^4.0.0", | ||||
| @ -13538,9 +13542,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "@types/react": { | ||||
|       "version": "18.0.27", | ||||
|       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", | ||||
|       "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", | ||||
|       "version": "18.0.28", | ||||
|       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", | ||||
|       "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@types/prop-types": "*", | ||||
| @ -13549,9 +13553,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@types/react-dom": { | ||||
|       "version": "18.0.10", | ||||
|       "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", | ||||
|       "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", | ||||
|       "version": "18.0.11", | ||||
|       "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", | ||||
|       "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@types/react": "*" | ||||
| @ -13608,14 +13612,14 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@typescript-eslint/eslint-plugin": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz", | ||||
|       "integrity": "sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", | ||||
|       "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@typescript-eslint/scope-manager": "5.51.0", | ||||
|         "@typescript-eslint/type-utils": "5.51.0", | ||||
|         "@typescript-eslint/utils": "5.51.0", | ||||
|         "@typescript-eslint/scope-manager": "5.52.0", | ||||
|         "@typescript-eslint/type-utils": "5.52.0", | ||||
|         "@typescript-eslint/utils": "5.52.0", | ||||
|         "debug": "^4.3.4", | ||||
|         "grapheme-splitter": "^1.0.4", | ||||
|         "ignore": "^5.2.0", | ||||
| @ -13626,53 +13630,53 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@typescript-eslint/parser": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz", | ||||
|       "integrity": "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", | ||||
|       "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@typescript-eslint/scope-manager": "5.51.0", | ||||
|         "@typescript-eslint/types": "5.51.0", | ||||
|         "@typescript-eslint/typescript-estree": "5.51.0", | ||||
|         "@typescript-eslint/scope-manager": "5.52.0", | ||||
|         "@typescript-eslint/types": "5.52.0", | ||||
|         "@typescript-eslint/typescript-estree": "5.52.0", | ||||
|         "debug": "^4.3.4" | ||||
|       } | ||||
|     }, | ||||
|     "@typescript-eslint/scope-manager": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz", | ||||
|       "integrity": "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", | ||||
|       "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@typescript-eslint/types": "5.51.0", | ||||
|         "@typescript-eslint/visitor-keys": "5.51.0" | ||||
|         "@typescript-eslint/types": "5.52.0", | ||||
|         "@typescript-eslint/visitor-keys": "5.52.0" | ||||
|       } | ||||
|     }, | ||||
|     "@typescript-eslint/type-utils": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz", | ||||
|       "integrity": "sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", | ||||
|       "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@typescript-eslint/typescript-estree": "5.51.0", | ||||
|         "@typescript-eslint/utils": "5.51.0", | ||||
|         "@typescript-eslint/typescript-estree": "5.52.0", | ||||
|         "@typescript-eslint/utils": "5.52.0", | ||||
|         "debug": "^4.3.4", | ||||
|         "tsutils": "^3.21.0" | ||||
|       } | ||||
|     }, | ||||
|     "@typescript-eslint/types": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz", | ||||
|       "integrity": "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", | ||||
|       "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "@typescript-eslint/typescript-estree": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz", | ||||
|       "integrity": "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", | ||||
|       "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@typescript-eslint/types": "5.51.0", | ||||
|         "@typescript-eslint/visitor-keys": "5.51.0", | ||||
|         "@typescript-eslint/types": "5.52.0", | ||||
|         "@typescript-eslint/visitor-keys": "5.52.0", | ||||
|         "debug": "^4.3.4", | ||||
|         "globby": "^11.1.0", | ||||
|         "is-glob": "^4.0.3", | ||||
| @ -13681,16 +13685,16 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@typescript-eslint/utils": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.51.0.tgz", | ||||
|       "integrity": "sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", | ||||
|       "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@types/json-schema": "^7.0.9", | ||||
|         "@types/semver": "^7.3.12", | ||||
|         "@typescript-eslint/scope-manager": "5.51.0", | ||||
|         "@typescript-eslint/types": "5.51.0", | ||||
|         "@typescript-eslint/typescript-estree": "5.51.0", | ||||
|         "@typescript-eslint/scope-manager": "5.52.0", | ||||
|         "@typescript-eslint/types": "5.52.0", | ||||
|         "@typescript-eslint/typescript-estree": "5.52.0", | ||||
|         "eslint-scope": "^5.1.1", | ||||
|         "eslint-utils": "^3.0.0", | ||||
|         "semver": "^7.3.7" | ||||
| @ -13715,12 +13719,12 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@typescript-eslint/visitor-keys": { | ||||
|       "version": "5.51.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz", | ||||
|       "integrity": "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==", | ||||
|       "version": "5.52.0", | ||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", | ||||
|       "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@typescript-eslint/types": "5.51.0", | ||||
|         "@typescript-eslint/types": "5.52.0", | ||||
|         "eslint-visitor-keys": "^3.3.0" | ||||
|       } | ||||
|     }, | ||||
| @ -14738,9 +14742,9 @@ | ||||
|       "integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==" | ||||
|     }, | ||||
|     "dompurify": { | ||||
|       "version": "2.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz", | ||||
|       "integrity": "sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA==" | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.0.tgz", | ||||
|       "integrity": "sha512-0g/yr2IJn4nTbxwL785YxS7/AvvgGFJw6LLWP+BzWzB1+BYOqPUT9Hy0rXrZh5HLdHnxH72aDdzvC9SdTjsuaA==" | ||||
|     }, | ||||
|     "dot-case": { | ||||
|       "version": "3.0.4", | ||||
| @ -15001,9 +15005,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "eslint": { | ||||
|       "version": "8.33.0", | ||||
|       "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.33.0.tgz", | ||||
|       "integrity": "sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==", | ||||
|       "version": "8.34.0", | ||||
|       "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", | ||||
|       "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "@eslint/eslintrc": "^1.4.1", | ||||
| @ -16358,13 +16362,13 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "isomorphic-dompurify": { | ||||
|       "version": "0.26.0", | ||||
|       "resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-0.26.0.tgz", | ||||
|       "integrity": "sha512-70gPadd/NJPTBuTtM5PsWimmc7S4fcBENzOFMHfBtIPacaygUvI9n63qFkUTc91WDDC9yB68mtmluW9/NhhTJw==", | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-1.0.0.tgz", | ||||
|       "integrity": "sha512-rxkJ2b2rwsgN/uvtaW+Z2JGfD9CYcixYMj0eTIa4V2hG47VDRMiehtUypi4lkpuwW41UrnOR65Dy0POiH3Lbjg==", | ||||
|       "requires": { | ||||
|         "@types/dompurify": "^2.3.4", | ||||
|         "dompurify": "^2.4.1", | ||||
|         "jsdom": "^21.0.0" | ||||
|         "@types/dompurify": "^2.4.0", | ||||
|         "dompurify": "^3.0.0", | ||||
|         "jsdom": "^21.1.0" | ||||
|       } | ||||
|     }, | ||||
|     "isomorphic-fetch": { | ||||
| @ -16411,9 +16415,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "jsdom": { | ||||
|       "version": "21.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.0.0.tgz", | ||||
|       "integrity": "sha512-AIw+3ZakSUtDYvhwPwWHiZsUi3zHugpMEKlNPaurviseYoBqo0zBd3zqoUi3LPCNtPFlEP8FiW9MqCZdjb2IYA==", | ||||
|       "version": "21.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.1.0.tgz", | ||||
|       "integrity": "sha512-m0lzlP7qOtthD918nenK3hdItSd2I+V3W9IrBcB36sqDwG+KnUs66IF5GY7laGWUnlM9vTsD0W1QwSEBYWWcJg==", | ||||
|       "requires": { | ||||
|         "abab": "^2.0.6", | ||||
|         "acorn": "^8.8.1", | ||||
| @ -17352,9 +17356,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "prettier-plugin-tailwindcss": { | ||||
|       "version": "0.2.2", | ||||
|       "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.2.tgz", | ||||
|       "integrity": "sha512-5RjUbWRe305pUpc48MosoIp6uxZvZxrM6GyOgsbGLTce+ehePKNm7ziW2dLG2air9aXbGuXlHVSQQw4Lbosq3w==", | ||||
|       "version": "0.2.3", | ||||
|       "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.3.tgz", | ||||
|       "integrity": "sha512-s2N5Dh7Ao5KTV1mao5ZBnn8EKtUcDPJEkGViZIjI0Ij9TTI5zgTz4IHOxW33jOdjHKa8CSjM88scelUiC5TNRQ==", | ||||
|       "dev": true, | ||||
|       "requires": {} | ||||
|     }, | ||||
| @ -17484,9 +17488,9 @@ | ||||
|       "requires": {} | ||||
|     }, | ||||
|     "react-zoom-pan-pinch": { | ||||
|       "version": "2.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-2.5.0.tgz", | ||||
|       "integrity": "sha512-5o3DKACPRNXM5Yr1dfQ5sZsGpstEsam3ih3dNmaDUfpghwD7ENwCVAupbNiBHlJ1Jbowd6o9qamp/2FiWu2Jcg==", | ||||
|       "version": "2.6.1", | ||||
|       "resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-2.6.1.tgz", | ||||
|       "integrity": "sha512-4Cgdnn6OwN4DomY/E9NpAf0TyCtslEgwdYn96ZV/f5LKuw/FE3gcIBJiaKFmMGThDGV0yKN5mzO8noi34+UE4Q==", | ||||
|       "requires": {} | ||||
|     }, | ||||
|     "read-cache": { | ||||
| @ -18202,9 +18206,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "ts-unused-exports": { | ||||
|       "version": "9.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.3.tgz", | ||||
|       "integrity": "sha512-LCGLYL0EVdXNj1O/cGfpP2Fx+zfqoV936iMyIhvSVnXk4RUjwmSjMzzCNXI9b1j9PCs946a2TbRMhJh7/XUyUA==", | ||||
|       "version": "9.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.4.tgz", | ||||
|       "integrity": "sha512-/PPy0B1zhOJkDTUd1XVyaCqE/yA3IL2FrQ8W5/6cQ2g0kKC/06q8LEoPeXI6ELfI6Bivmv3MMvsUup5u3WH+BQ==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "chalk": "^4.0.0", | ||||
|  | ||||
							
								
								
									
										18
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								package.json
									
									
									
									
									
								
							| @ -27,7 +27,7 @@ | ||||
|     "autoprefixer": "^10.4.13", | ||||
|     "cuid": "^2.1.8", | ||||
|     "intl-messageformat": "^10.3.0", | ||||
|     "isomorphic-dompurify": "^0.26.0", | ||||
|     "isomorphic-dompurify": "^1.0.0", | ||||
|     "jotai": "^2.0.1", | ||||
|     "markdown-to-jsx": "^7.1.9", | ||||
|     "marked": "^4.2.12", | ||||
| @ -40,7 +40,7 @@ | ||||
|     "react-dom": "18.2.0", | ||||
|     "react-hotkeys-hook": "^3.4.7", | ||||
|     "react-swipeable": "^7.0.0", | ||||
|     "react-zoom-pan-pinch": "^2.5.0", | ||||
|     "react-zoom-pan-pinch": "^2.6.1", | ||||
|     "string-natural-compare": "^3.0.1", | ||||
|     "throttle-debounce": "^5.0.0", | ||||
|     "tippy.js": "^6.3.7", | ||||
| @ -58,25 +58,25 @@ | ||||
|     "@types/marked": "^4.0.8", | ||||
|     "@types/node": "18.13.0", | ||||
|     "@types/nodemailer": "^6.4.7", | ||||
|     "@types/react": "^18.0.27", | ||||
|     "@types/react-dom": "^18.0.10", | ||||
|     "@types/react": "^18.0.28", | ||||
|     "@types/react-dom": "^18.0.11", | ||||
|     "@types/string-natural-compare": "^3.0.2", | ||||
|     "@types/throttle-debounce": "^5.0.0", | ||||
|     "@types/turndown": "^5.0.1", | ||||
|     "@types/ua-parser-js": "^0.7.36", | ||||
|     "@typescript-eslint/eslint-plugin": "^5.51.0", | ||||
|     "@typescript-eslint/parser": "^5.51.0", | ||||
|     "@typescript-eslint/eslint-plugin": "^5.52.0", | ||||
|     "@typescript-eslint/parser": "^5.52.0", | ||||
|     "dotenv": "^16.0.3", | ||||
|     "eslint": "^8.33.0", | ||||
|     "eslint": "^8.34.0", | ||||
|     "eslint-config-next": "13.1.6", | ||||
|     "eslint-plugin-import": "^2.27.5", | ||||
|     "graphql": "^16.6.0", | ||||
|     "graphql-request": "^5.1.0", | ||||
|     "next-sitemap": "^3.1.52", | ||||
|     "prettier": "^2.8.4", | ||||
|     "prettier-plugin-tailwindcss": "^0.2.2", | ||||
|     "prettier-plugin-tailwindcss": "^0.2.3", | ||||
|     "tailwindcss": "^3.2.6", | ||||
|     "ts-unused-exports": "^9.0.3", | ||||
|     "ts-unused-exports": "^9.0.4", | ||||
|     "typescript": "^4.9.5" | ||||
|   }, | ||||
|   "overrides": { | ||||
|  | ||||
| @ -180,7 +180,11 @@ | ||||
|           "definition_x": "Definition {x}", | ||||
|           "subitem_of_x": "Subitem of {x}", | ||||
|           "variant_of_x": "Variant of {x}", | ||||
|           "dark_mode_extension_warning": "This website offers a light and dark theme. If you are using a \"dark mode\" browser extension, make sure to disable it for an optimal experience." | ||||
|           "dark_mode_extension_warning": "This website offers a light and dark theme. If you are using a \"dark mode\" browser extension, make sure to disable it for an optimal experience.", | ||||
|           "weapon": "{ count, plural, =0 {No weapons} one {Weapon} other {Weapons} }", | ||||
|           "weapons_description": "A list of all the weapons across all of the games. All distinguished weapons come with an “account.” It’s a document with various details like how the weapon was forged and how it’s been used in the past.", | ||||
|           "level_x": "Level {x}", | ||||
|           "story_x": "Story {x}" | ||||
|         } | ||||
|       }, | ||||
|       { | ||||
| @ -362,7 +366,11 @@ | ||||
|           "definition_x": "Définition {x}", | ||||
|           "subitem_of_x": "Sous-item de {x}", | ||||
|           "variant_of_x": "Variante de {x}", | ||||
|           "dark_mode_extension_warning": "Ce site web propose un thème clair et un thème sombre. Si vous utilisez une extension de navigateur qui simule un thème sombre, veillez à la désactiver pour une expérience optimale." | ||||
|           "dark_mode_extension_warning": "Ce site web propose un thème clair et un thème sombre. Si vous utilisez une extension de navigateur qui simule un thème sombre, veillez à la désactiver pour une expérience optimale.", | ||||
|           "weapon": null, | ||||
|           "weapons_description": null, | ||||
|           "level_x": null, | ||||
|           "story_x": null | ||||
|         } | ||||
|       }, | ||||
|       { | ||||
| @ -544,7 +552,11 @@ | ||||
|           "definition_x": null, | ||||
|           "subitem_of_x": null, | ||||
|           "variant_of_x": null, | ||||
|           "dark_mode_extension_warning": null | ||||
|           "dark_mode_extension_warning": null, | ||||
|           "weapon": null, | ||||
|           "weapons_description": null, | ||||
|           "level_x": null, | ||||
|           "story_x": null | ||||
|         } | ||||
|       }, | ||||
|       { | ||||
| @ -726,7 +738,11 @@ | ||||
|           "definition_x": null, | ||||
|           "subitem_of_x": null, | ||||
|           "variant_of_x": null, | ||||
|           "dark_mode_extension_warning": null | ||||
|           "dark_mode_extension_warning": null, | ||||
|           "weapon": null, | ||||
|           "weapons_description": null, | ||||
|           "level_x": null, | ||||
|           "story_x": null | ||||
|         } | ||||
|       }, | ||||
|       { | ||||
| @ -908,7 +924,11 @@ | ||||
|           "definition_x": null, | ||||
|           "subitem_of_x": null, | ||||
|           "variant_of_x": null, | ||||
|           "dark_mode_extension_warning": null | ||||
|           "dark_mode_extension_warning": null, | ||||
|           "weapon": null, | ||||
|           "weapons_description": null, | ||||
|           "level_x": null, | ||||
|           "story_x": null | ||||
|         } | ||||
|       } | ||||
|     ] | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| import { useHotkeys } from "react-hotkeys-hook"; | ||||
| import { Ico } from "components/Ico"; | ||||
| import { PageSelector } from "components/Inputs/PageSelector"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| @ -21,8 +22,14 @@ export const Paginator = ({ | ||||
|   children, | ||||
| }: Props): JSX.Element => { | ||||
|   useScrollTopOnChange(Ids.ContentPanel, [page]); | ||||
|   useHotkeys("left", () => onPageChange(page - 1), { enabled: page > 1 }, [page]); | ||||
|   useHotkeys("right", () => onPageChange(page + 1), { enabled: page < (totalNumberOfPages ?? 0) }, [ | ||||
|     page, | ||||
|   ]); | ||||
| 
 | ||||
|   if (totalNumberOfPages === 0) return <DefaultRenderWhenEmpty />; | ||||
|   if (isUndefined(totalNumberOfPages) || totalNumberOfPages < 2) return <>{children}</>; | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <PageSelector | ||||
| @ -50,6 +57,7 @@ export const Paginator = ({ | ||||
| const DefaultRenderWhenEmpty = () => { | ||||
|   const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout); | ||||
|   const { format } = useFormat(); | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="grid h-full place-content-center"> | ||||
|       <div | ||||
|  | ||||
| @ -216,18 +216,12 @@ export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Eleme | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| interface TableOfContentsProps { | ||||
|   text: string; | ||||
|   title?: string; | ||||
|   toc: TocInterface; | ||||
|   onContentClicked?: MouseEventHandler<HTMLAnchorElement>; | ||||
| } | ||||
| 
 | ||||
| export const TableOfContents = ({ | ||||
|   text, | ||||
|   title, | ||||
|   onContentClicked, | ||||
| }: TableOfContentsProps): JSX.Element => { | ||||
| export const TableOfContents = ({ toc, onContentClicked }: TableOfContentsProps): JSX.Element => { | ||||
|   const { format } = useFormat(); | ||||
|   const toc = getTocFromMarkdawn(preprocessMarkDawn(text), title); | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
| @ -435,7 +429,14 @@ const markdawnHeadersParser = ( | ||||
| 
 | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| const getTocFromMarkdawn = (text: string, title?: string): TocInterface => { | ||||
| export const getTocFromMarkdawn = ( | ||||
|   markdawn: string | null | undefined, | ||||
|   title?: string | ||||
| ): TocInterface | undefined => { | ||||
|   if (isUndefined(markdawn)) return undefined; | ||||
| 
 | ||||
|   const text = preprocessMarkDawn(markdawn); | ||||
| 
 | ||||
|   const toc: TocInterface = { | ||||
|     title: title ?? "Return to top", | ||||
|     slug: slugify(title), | ||||
| @ -522,5 +523,6 @@ const getTocFromMarkdawn = (text: string, title?: string): TocInterface => { | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   if (toc.children.length === 0) return undefined; | ||||
|   return toc; | ||||
| }; | ||||
|  | ||||
| @ -14,6 +14,7 @@ import { | ||||
|   MeiliLibraryItem, | ||||
|   MeiliPost, | ||||
|   MeiliVideo, | ||||
|   MeiliWeapon, | ||||
|   MeiliWikiPage, | ||||
| } from "shared/meilisearch-graphql-typings/meiliTypes"; | ||||
| import { getVideoThumbnailURL } from "helpers/videos"; | ||||
| @ -43,6 +44,7 @@ export const SearchPopup = (): JSX.Element => { | ||||
|   const [videos, setVideos] = useState<CustomSearchResponse<MeiliVideo>>(); | ||||
|   const [posts, setPosts] = useState<CustomSearchResponse<MeiliPost>>(); | ||||
|   const [wikiPages, setWikiPages] = useState<CustomSearchResponse<MeiliWikiPage>>(); | ||||
|   const [weapons, setWeapons] = useState<CustomSearchResponse<MeiliWeapon>>(); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchLibraryItems = async () => { | ||||
| @ -129,6 +131,25 @@ export const SearchPopup = (): JSX.Element => { | ||||
|       setPosts(searchResult); | ||||
|     }; | ||||
| 
 | ||||
|     const fetchWeapons = async () => { | ||||
|       const searchResult = await meiliSearch(MeiliIndices.WEAPON, query, { | ||||
|         limit: SEARCH_LIMIT, | ||||
|         attributesToRetrieve: ["*"], | ||||
|         attributesToHighlight: ["translations.description", "translations.names"], | ||||
|         attributesToCrop: ["translations.description"], | ||||
|         sort: ["slug:asc"], | ||||
|       }); | ||||
|       searchResult.hits = searchResult.hits.map((item) => { | ||||
|         if (Object.keys(item._matchesPosition).some((match) => match.startsWith("translations"))) { | ||||
|           item._formatted.translations = filterDefined(item._formatted.translations).filter( | ||||
|             (translation) => JSON.stringify(translation).includes("</mark>") | ||||
|           ); | ||||
|         } | ||||
|         return item; | ||||
|       }); | ||||
|       setWeapons(searchResult); | ||||
|     }; | ||||
| 
 | ||||
|     const fetchWikiPages = async () => { | ||||
|       const searchResult = await meiliSearch(MeiliIndices.WIKI_PAGE, query, { | ||||
|         limit: SEARCH_LIMIT, | ||||
| @ -160,12 +181,14 @@ export const SearchPopup = (): JSX.Element => { | ||||
|       setContents(undefined); | ||||
|       setVideos(undefined); | ||||
|       setPosts(undefined); | ||||
|       setWeapons(undefined); | ||||
|     } else { | ||||
|       fetchWikiPages(); | ||||
|       fetchLibraryItems(); | ||||
|       fetchContents(); | ||||
|       fetchVideos(); | ||||
|       fetchPosts(); | ||||
|       fetchWeapons(); | ||||
|     } | ||||
|   }, [query]); | ||||
| 
 | ||||
| @ -411,6 +434,48 @@ export const SearchPopup = (): JSX.Element => { | ||||
|             </div> | ||||
|           </SearchResultSection> | ||||
|         )} | ||||
| 
 | ||||
|         {isDefined(weapons) && ( | ||||
|           <SearchResultSection | ||||
|             title={format("weapon", { count: Infinity })} | ||||
|             icon="shield" | ||||
|             href={`/wiki/weapons?page=1&query=${query}`} | ||||
|             totalHits={weapons.estimatedTotalHits}> | ||||
|             <div className="flex flex-wrap items-start gap-x-6 gap-y-8"> | ||||
|               {weapons.hits.map((item) => ( | ||||
|                 <TranslatedPreviewCard | ||||
|                   key={item.id} | ||||
|                   className="w-56" | ||||
|                   href={"/"} | ||||
|                   translations={filterHasAttributes(item._formatted.translations, [ | ||||
|                     "language.data.attributes.code", | ||||
|                   ] as const).map( | ||||
|                     ({ description, language, names: [primaryName, ...aliases] }) => ({ | ||||
|                       language: language.data.attributes.code, | ||||
|                       title: primaryName, | ||||
|                       subtitle: aliases.join("・"), | ||||
|                       description: containsHighlight(description) ? description : undefined, | ||||
|                     }) | ||||
|                   )} | ||||
|                   fallback={{ title: prettySlug(item.slug) }} | ||||
|                   thumbnail={item.thumbnail?.data?.attributes} | ||||
|                   thumbnailAspectRatio="1/1" | ||||
|                   thumbnailForceAspectRatio | ||||
|                   thumbnailFitMethod="contain" | ||||
|                   keepInfoVisible | ||||
|                   topChips={ | ||||
|                     item.type?.data?.attributes?.slug | ||||
|                       ? [prettySlug(item.type.data.attributes.slug)] | ||||
|                       : undefined | ||||
|                   } | ||||
|                   bottomChips={filterHasAttributes(item.categories, [ | ||||
|                     "attributes.short", | ||||
|                   ] as const).map((category) => category.attributes.short)} | ||||
|                 /> | ||||
|               ))} | ||||
|             </div> | ||||
|           </SearchResultSection> | ||||
|         )} | ||||
|       </div> | ||||
|     </Popup> | ||||
|   ); | ||||
| @ -442,7 +507,7 @@ const SearchResultSection = ({ | ||||
|               className="grid grid-cols-[auto_1fr] place-items-center gap-6 px-6 py-4" | ||||
|               href={href} | ||||
|               onClick={() => setSearchOpened(false)}> | ||||
|               <Ico icon={icon} className="!text-3xl" isFilled /> | ||||
|               <Ico icon={icon} className="!text-3xl" isFilled={false} /> | ||||
|               <div> | ||||
|                 <p className="font-headers text-lg">{title}</p> | ||||
|                 {isDefined(totalHits) && totalHits > SEARCH_LIMIT && ( | ||||
|  | ||||
| @ -2,7 +2,7 @@ import { Fragment, useCallback } from "react"; | ||||
| import { AppLayout, AppLayoutRequired } from "./AppLayout"; | ||||
| import { Chip } from "./Chip"; | ||||
| import { HorizontalLine } from "./HorizontalLine"; | ||||
| import { Markdawn, TableOfContents } from "./Markdown/Markdawn"; | ||||
| import { getTocFromMarkdawn, Markdawn, TableOfContents } from "./Markdown/Markdawn"; | ||||
| import { ReturnButton } from "./PanelComponents/ReturnButton"; | ||||
| import { ContentPanel } from "./Containers/ContentPanel"; | ||||
| import { SubPanel } from "./Containers/SubPanel"; | ||||
| @ -70,56 +70,55 @@ export const PostPage = ({ | ||||
|   const title = selectedTranslation?.title ?? prettySlug(post.slug); | ||||
|   const excerpt = selectedTranslation?.excerpt ?? ""; | ||||
| 
 | ||||
|   const subPanel = ( | ||||
|     <SubPanel> | ||||
|       <ElementsSeparator> | ||||
|         {[ | ||||
|           returnHref && returnTitle && !is1ColumnLayout && ( | ||||
|             <ReturnButton href={returnHref} title={returnTitle} /> | ||||
|           ), | ||||
|   const toc = getTocFromMarkdawn(body, title); | ||||
| 
 | ||||
|           displayCredits && ( | ||||
|             <> | ||||
|               {selectedTranslation && ( | ||||
|                 <div className="grid grid-flow-col place-content-center place-items-center gap-2"> | ||||
|                   <p className="font-headers font-bold">{format("status")}:</p> | ||||
|   const subPanelElems = [ | ||||
|     returnHref && returnTitle && !is1ColumnLayout && ( | ||||
|       <ReturnButton href={returnHref} title={returnTitle} /> | ||||
|     ), | ||||
| 
 | ||||
|                   <ToolTip | ||||
|                     content={formatStatusDescription(selectedTranslation.status)} | ||||
|                     maxWidth={"20rem"}> | ||||
|                     <Chip text={selectedTranslation.status} /> | ||||
|                   </ToolTip> | ||||
|                 </div> | ||||
|     displayCredits && ( | ||||
|       <> | ||||
|         {selectedTranslation && ( | ||||
|           <div className="grid grid-flow-col place-content-center place-items-center gap-2"> | ||||
|             <p className="font-headers font-bold">{format("status")}:</p> | ||||
| 
 | ||||
|             <ToolTip | ||||
|               content={formatStatusDescription(selectedTranslation.status)} | ||||
|               maxWidth={"20rem"}> | ||||
|               <Chip text={selectedTranslation.status} /> | ||||
|             </ToolTip> | ||||
|           </div> | ||||
|         )} | ||||
| 
 | ||||
|         {post.authors && post.authors.data.length > 0 && ( | ||||
|           <div> | ||||
|             <p className="font-headers font-bold">{"Authors"}:</p> | ||||
|             <div className="grid place-content-center place-items-center gap-2"> | ||||
|               {filterHasAttributes(post.authors.data, ["id", "attributes"] as const).map( | ||||
|                 (author) => ( | ||||
|                   <Fragment key={author.id}> | ||||
|                     <RecorderChip recorder={author.attributes} /> | ||||
|                   </Fragment> | ||||
|                 ) | ||||
|               )} | ||||
|             </div> | ||||
|           </div> | ||||
|         )} | ||||
|       </> | ||||
|     ), | ||||
| 
 | ||||
|               {post.authors && post.authors.data.length > 0 && ( | ||||
|                 <div> | ||||
|                   <p className="font-headers font-bold">{"Authors"}:</p> | ||||
|                   <div className="grid place-content-center place-items-center gap-2"> | ||||
|                     {filterHasAttributes(post.authors.data, ["id", "attributes"] as const).map( | ||||
|                       (author) => ( | ||||
|                         <Fragment key={author.id}> | ||||
|                           <RecorderChip recorder={author.attributes} /> | ||||
|                         </Fragment> | ||||
|                       ) | ||||
|                     )} | ||||
|                   </div> | ||||
|                 </div> | ||||
|               )} | ||||
|             </> | ||||
|           ), | ||||
|     displayToc && isDefined(toc) && ( | ||||
|       <TableOfContents toc={toc} onContentClicked={() => setSubPanelOpened(false)} /> | ||||
|     ), | ||||
|   ]; | ||||
| 
 | ||||
|           displayToc && ( | ||||
|             <TableOfContents | ||||
|               text={body} | ||||
|               title={title} | ||||
|               onContentClicked={() => setSubPanelOpened(false)} | ||||
|             /> | ||||
|           ), | ||||
|         ]} | ||||
|       </ElementsSeparator> | ||||
|     </SubPanel> | ||||
|   ); | ||||
|   const subPanel = | ||||
|     subPanelElems.filter(Boolean).length > 0 ? ( | ||||
|       <SubPanel> | ||||
|         <ElementsSeparator>{subPanelElems}</ElementsSeparator> | ||||
|       </SubPanel> | ||||
|     ) : undefined; | ||||
| 
 | ||||
|   const contentPanel = ( | ||||
|     <ContentPanel> | ||||
|  | ||||
| @ -24,6 +24,7 @@ interface Props { | ||||
|   thumbnail?: UploadImageFragment | string | null | undefined; | ||||
|   thumbnailAspectRatio?: string; | ||||
|   thumbnailForceAspectRatio?: boolean; | ||||
|   thumbnailFitMethod?: "contain" | "cover"; | ||||
|   thumbnailRounded?: boolean; | ||||
|   href: string; | ||||
|   pre_title?: string | null | undefined; | ||||
| @ -60,6 +61,7 @@ export const PreviewCard = ({ | ||||
|   thumbnail, | ||||
|   thumbnailAspectRatio = "4/3", | ||||
|   thumbnailForceAspectRatio = false, | ||||
|   thumbnailFitMethod = "cover", | ||||
|   thumbnailRounded = true, | ||||
|   pre_title, | ||||
|   title, | ||||
| @ -133,7 +135,12 @@ export const PreviewCard = ({ | ||||
|                   thumbnailRounded, | ||||
|                   cIf(keepInfoVisible, "rounded-t-md", "rounded-md notHoverable:rounded-b-none") | ||||
|                 ), | ||||
|                 cIf(thumbnailForceAspectRatio, "h-full w-full object-cover") | ||||
|                 cIf(thumbnailForceAspectRatio, "h-full w-full"), | ||||
|                 cIf( | ||||
|                   thumbnailForceAspectRatio && thumbnailFitMethod === "contain", | ||||
|                   "object-contain", | ||||
|                   "object-cover" | ||||
|                 ) | ||||
|               )} | ||||
|               src={thumbnail} | ||||
|               quality={ImageQuality.Medium} | ||||
|  | ||||
| @ -179,4 +179,8 @@ export interface ICUParams { | ||||
|   subitem_of_x: { x: Date | boolean | number | string }; | ||||
|   variant_of_x: { x: Date | boolean | number | string }; | ||||
|   dark_mode_extension_warning: never; | ||||
|   weapon: { count: number }; | ||||
|   weapons_description: never; | ||||
|   level_x: { x: Date | boolean | number | string }; | ||||
|   story_x: { x: Date | boolean | number | string }; | ||||
| } | ||||
|  | ||||
							
								
								
									
										92
									
								
								src/graphql/operations/getWeapon.graphql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/graphql/operations/getWeapon.graphql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| query getWeapon($slug: String, $language_code: String) { | ||||
|   weaponStories(filters: { slug: { eq: $slug } }) { | ||||
|     data { | ||||
|       attributes { | ||||
|         ...sharedWeaponFragment | ||||
|         stories(pagination: { limit: -1 }) { | ||||
|           id | ||||
|           categories(pagination: { limit: -1 }) { | ||||
|             data { | ||||
|               id | ||||
|               attributes { | ||||
|                 name | ||||
|                 short | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           translations(pagination: { limit: -1 }) { | ||||
|             id | ||||
|             description | ||||
|             level_1 | ||||
|             level_2 | ||||
|             level_3 | ||||
|             level_4 | ||||
|             status | ||||
|             language { | ||||
|               data { | ||||
|                 attributes { | ||||
|                   code | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|         weapon_group { | ||||
|           data { | ||||
|             attributes { | ||||
|               slug | ||||
|               weapons(pagination: { limit: -1 }, filters: { slug: { ne: $slug } }) { | ||||
|                 data { | ||||
|                   id | ||||
|                   attributes { | ||||
|                     ...sharedWeaponFragment | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| fragment sharedWeaponFragment on WeaponStory { | ||||
|   type { | ||||
|     data { | ||||
|       id | ||||
|       attributes { | ||||
|         slug | ||||
|         translations(filters: { language: { code: { eq: $language_code } } }) { | ||||
|           name | ||||
|           language { | ||||
|             data { | ||||
|               attributes { | ||||
|                 code | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   name(pagination: { limit: -1 }) { | ||||
|     id | ||||
|     name | ||||
|     language { | ||||
|       data { | ||||
|         attributes { | ||||
|           code | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   slug | ||||
|   thumbnail { | ||||
|     data { | ||||
|       attributes { | ||||
|         ...uploadImage | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										10
									
								
								src/graphql/operations/getWeaponsSlugs.graphql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/graphql/operations/getWeaponsSlugs.graphql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| query getWeaponsSlugs { | ||||
|   weaponStories(pagination: { limit: -1 }) { | ||||
|     data { | ||||
|       id | ||||
|       attributes { | ||||
|         slug | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -186,6 +186,10 @@ query localDataGetWebsiteInterfaces { | ||||
|         subitem_of_x | ||||
|         variant_of_x | ||||
|         dark_mode_extension_warning | ||||
|         weapon | ||||
|         weapons_description | ||||
|         level_x | ||||
|         story_x | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -59,7 +59,13 @@ export const useFormat = (): { | ||||
|       if (isDefinedAndNotEmpty(result)) { | ||||
|         return result; | ||||
|       } | ||||
|       return new IntlMessageFormat(fallbackLangui[key] ?? "").format(processedValues).toString(); | ||||
|       const fallback = new IntlMessageFormat(fallbackLangui[key] ?? "") | ||||
|         .format(processedValues) | ||||
|         .toString(); | ||||
|       if (isDefinedAndNotEmpty(fallback)) { | ||||
|         return fallback; | ||||
|       } | ||||
|       return key; | ||||
|     }, | ||||
|     [langui, fallbackLangui] | ||||
|   ); | ||||
|  | ||||
| @ -17,10 +17,10 @@ interface ReaderSettings extends FilterSettings { | ||||
| 
 | ||||
| const DEFAULT_READER_SETTINGS: ReaderSettings = { | ||||
|   bookFold: true, | ||||
|   lighting: true, | ||||
|   lighting: false, | ||||
|   paperTexture: true, | ||||
|   teint: 0.1, | ||||
|   dropShadow: true, | ||||
|   dropShadow: false, | ||||
|   pageQuality: ImageQuality.Large, | ||||
|   isSidePagesEnabled: true, | ||||
| }; | ||||
|  | ||||
| @ -4,7 +4,7 @@ import naturalCompare from "string-natural-compare"; | ||||
| import { AppLayout, AppLayoutRequired } from "components/AppLayout"; | ||||
| import { Chip } from "components/Chip"; | ||||
| import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs"; | ||||
| import { Markdawn, TableOfContents } from "components/Markdown/Markdawn"; | ||||
| import { getTocFromMarkdawn, Markdawn, TableOfContents } from "components/Markdown/Markdawn"; | ||||
| import { TranslatedReturnButton } from "components/PanelComponents/ReturnButton"; | ||||
| import { ContentPanel } from "components/Containers/ContentPanel"; | ||||
| import { SubPanel } from "components/Containers/SubPanel"; | ||||
| @ -91,6 +91,15 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
|     }, | ||||
|   }; | ||||
| 
 | ||||
|   const toc = getTocFromMarkdawn( | ||||
|     selectedTranslation?.text_set?.text, | ||||
|     prettyInlineTitle( | ||||
|       selectedTranslation?.pre_title, | ||||
|       selectedTranslation?.title, | ||||
|       selectedTranslation?.subtitle | ||||
|     ) | ||||
|   ); | ||||
| 
 | ||||
|   const subPanel = ( | ||||
|     <SubPanel> | ||||
|       <ElementsSeparator> | ||||
| @ -191,17 +200,7 @@ const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
|             </div> | ||||
|           ), | ||||
| 
 | ||||
|           selectedTranslation?.text_set?.text && ( | ||||
|             <TableOfContents | ||||
|               text={selectedTranslation.text_set.text} | ||||
|               title={prettyInlineTitle( | ||||
|                 selectedTranslation.pre_title, | ||||
|                 selectedTranslation.title, | ||||
|                 selectedTranslation.subtitle | ||||
|               )} | ||||
|               onContentClicked={() => setSubPanelOpened(false)} | ||||
|             /> | ||||
|           ), | ||||
|           toc && <TableOfContents toc={toc} onContentClicked={() => setSubPanelOpened(false)} />, | ||||
| 
 | ||||
|           content.ranged_contents?.data && content.ranged_contents.data.length > 0 && ( | ||||
|             <div> | ||||
|  | ||||
| @ -3,12 +3,13 @@ import { useCallback, useRef, useState } from "react"; | ||||
| import TurndownService from "turndown"; | ||||
| import { AppLayout, AppLayoutRequired } from "components/AppLayout"; | ||||
| import { Button } from "components/Inputs/Button"; | ||||
| import { Markdawn, TableOfContents } from "components/Markdown/Markdawn"; | ||||
| import { getTocFromMarkdawn, Markdawn, TableOfContents } from "components/Markdown/Markdawn"; | ||||
| import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel"; | ||||
| import { Popup } from "components/Containers/Popup"; | ||||
| import { ToolTip } from "components/ToolTip"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { getFormat } from "helpers/i18n"; | ||||
| import { isDefined } from "helpers/asserts"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -155,6 +156,8 @@ const Editor = (props: Props): JSX.Element => { | ||||
|     [transformationWrapper] | ||||
|   ); | ||||
| 
 | ||||
|   const toc = getTocFromMarkdawn(markdown); | ||||
| 
 | ||||
|   const contentPanel = ( | ||||
|     <ContentPanel width={ContentPanelWidthSizes.Full}> | ||||
|       <Popup isVisible={converterOpened} onCloseRequest={() => setConverterOpened(false)}> | ||||
| @ -388,9 +391,11 @@ const Editor = (props: Props): JSX.Element => { | ||||
|         </div> | ||||
|       </div> | ||||
| 
 | ||||
|       <div className="mt-8"> | ||||
|         <TableOfContents text={markdown} /> | ||||
|       </div> | ||||
|       {isDefined(toc) && ( | ||||
|         <div className="mt-8"> | ||||
|           <TableOfContents toc={toc} /> | ||||
|         </div> | ||||
|       )} | ||||
|     </ContentPanel> | ||||
|   ); | ||||
| 
 | ||||
|  | ||||
| @ -47,13 +47,13 @@ import { useSmartLanguage } from "hooks/useSmartLanguage"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { getDescription } from "helpers/description"; | ||||
| import { useIntersectionList } from "hooks/useIntersectionList"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { Ids } from "types/ids"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter, useAtomSetter } from "helpers/atoms"; | ||||
| import { Link } from "components/Inputs/Link"; | ||||
| import { useFormat } from "hooks/useFormat"; | ||||
| import { getFormat } from "helpers/i18n"; | ||||
| import { ElementsSeparator } from "helpers/component"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -99,59 +99,69 @@ const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => { | ||||
|     (content) => content.attributes?.scan_set && content.attributes.scan_set.length > 0 | ||||
|   ); | ||||
| 
 | ||||
|   const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout); | ||||
| 
 | ||||
|   const subPanel = ( | ||||
|     <SubPanel> | ||||
|       <ReturnButton href="/library/" title={format("library")} displayOnlyOn="3ColumnsLayout" /> | ||||
|       <ElementsSeparator> | ||||
|         {[ | ||||
|           is3ColumnsLayout && ( | ||||
|             <ReturnButton | ||||
|               key="ReturnButton" | ||||
|               href="/library/" | ||||
|               title={format("library")} | ||||
|               displayOnlyOn="3ColumnsLayout" | ||||
|             /> | ||||
|           ), | ||||
|           <div className="grid gap-4" key="NavOption"> | ||||
|             <NavOption | ||||
|               title={format("summary")} | ||||
|               url={`#${intersectionIds[0]}`} | ||||
|               border | ||||
|               active={currentIntersection === 0} | ||||
|               onClick={closeSubPanel} | ||||
|             /> | ||||
| 
 | ||||
|       <HorizontalLine /> | ||||
|             {item.gallery && item.gallery.data.length > 0 && ( | ||||
|               <NavOption | ||||
|                 title={format("gallery")} | ||||
|                 url={`#${intersectionIds[1]}`} | ||||
|                 border | ||||
|                 active={currentIntersection === 1} | ||||
|                 onClick={closeSubPanel} | ||||
|               /> | ||||
|             )} | ||||
| 
 | ||||
|       <div className="grid gap-4"> | ||||
|         <NavOption | ||||
|           title={format("summary")} | ||||
|           url={`#${intersectionIds[0]}`} | ||||
|           border | ||||
|           active={currentIntersection === 0} | ||||
|           onClick={closeSubPanel} | ||||
|         /> | ||||
|             <NavOption | ||||
|               title={format("details")} | ||||
|               url={`#${intersectionIds[2]}`} | ||||
|               border | ||||
|               active={currentIntersection === 2} | ||||
|               onClick={closeSubPanel} | ||||
|             /> | ||||
| 
 | ||||
|         {item.gallery && item.gallery.data.length > 0 && ( | ||||
|           <NavOption | ||||
|             title={format("gallery")} | ||||
|             url={`#${intersectionIds[1]}`} | ||||
|             border | ||||
|             active={currentIntersection === 1} | ||||
|             onClick={closeSubPanel} | ||||
|           /> | ||||
|         )} | ||||
|             {item.subitems && item.subitems.data.length > 0 && ( | ||||
|               <NavOption | ||||
|                 title={format(isVariantSet ? "variant" : "subitem", { count: Infinity })} | ||||
|                 url={`#${intersectionIds[3]}`} | ||||
|                 border | ||||
|                 active={currentIntersection === 3} | ||||
|                 onClick={closeSubPanel} | ||||
|               /> | ||||
|             )} | ||||
| 
 | ||||
|         <NavOption | ||||
|           title={format("details")} | ||||
|           url={`#${intersectionIds[2]}`} | ||||
|           border | ||||
|           active={currentIntersection === 2} | ||||
|           onClick={closeSubPanel} | ||||
|         /> | ||||
| 
 | ||||
|         {item.subitems && item.subitems.data.length > 0 && ( | ||||
|           <NavOption | ||||
|             title={format(isVariantSet ? "variant" : "subitem", { count: Infinity })} | ||||
|             url={`#${intersectionIds[3]}`} | ||||
|             border | ||||
|             active={currentIntersection === 3} | ||||
|             onClick={closeSubPanel} | ||||
|           /> | ||||
|         )} | ||||
| 
 | ||||
|         {item.contents && item.contents.data.length > 0 && ( | ||||
|           <NavOption | ||||
|             title={format("contents")} | ||||
|             url={`#${intersectionIds[4]}`} | ||||
|             border | ||||
|             active={currentIntersection === 4} | ||||
|             onClick={closeSubPanel} | ||||
|           /> | ||||
|         )} | ||||
|       </div> | ||||
|             {item.contents && item.contents.data.length > 0 && ( | ||||
|               <NavOption | ||||
|                 title={format("contents")} | ||||
|                 url={`#${intersectionIds[4]}`} | ||||
|                 border | ||||
|                 active={currentIntersection === 4} | ||||
|                 onClick={closeSubPanel} | ||||
|               /> | ||||
|             )} | ||||
|           </div>, | ||||
|         ]} | ||||
|       </ElementsSeparator> | ||||
|     </SubPanel> | ||||
|   ); | ||||
| 
 | ||||
|  | ||||
| @ -129,6 +129,7 @@ const News = ({ ...otherProps }: Props): JSX.Element => { | ||||
|         placeholder={format("search_title")} | ||||
|         value={query} | ||||
|         onChange={(name) => { | ||||
|           setPage(1); | ||||
|           setQuery(name); | ||||
|           if (isDefinedAndNotEmpty(name)) { | ||||
|             sendAnalytics("News", "Change search term"); | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { GetStaticProps } from "next"; | ||||
| import { Fragment, useCallback } from "react"; | ||||
| import { Fragment, useCallback, useMemo } from "react"; | ||||
| import { useRouter } from "next/router"; | ||||
| import { AppLayout, AppLayoutRequired } from "components/AppLayout"; | ||||
| import { InsetBox } from "components/Containers/InsetBox"; | ||||
| @ -27,6 +27,8 @@ import { useIntersectionList } from "hooks/useIntersectionList"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { useFormat } from "hooks/useFormat"; | ||||
| import { getFormat } from "helpers/i18n"; | ||||
| import { useAtomSetter } from "helpers/atoms"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -40,8 +42,14 @@ interface Props extends AppLayoutRequired { | ||||
| 
 | ||||
| const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props): JSX.Element => { | ||||
|   const { format } = useFormat(); | ||||
|   const ids = filterHasAttributes(chronologyEras, ["attributes"] as const).map( | ||||
|     (era) => era.attributes.slug | ||||
|   const setSubPanelOpened = useAtomSetter(atoms.layout.subPanelOpened); | ||||
|   const closeSubPanel = useCallback(() => setSubPanelOpened(false), [setSubPanelOpened]); | ||||
|   const ids = useMemo( | ||||
|     () => | ||||
|       filterHasAttributes(chronologyEras, ["attributes"] as const).map( | ||||
|         (era) => era.attributes.slug | ||||
|       ), | ||||
|     [chronologyEras] | ||||
|   ); | ||||
| 
 | ||||
|   const currentIntersection = useIntersectionList(ids); | ||||
| @ -69,6 +77,7 @@ const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props): | ||||
|             url={`#${era.attributes.slug}`} | ||||
|             border | ||||
|             active={currentIntersection === index} | ||||
|             onClick={closeSubPanel} | ||||
|           /> | ||||
|         </Fragment> | ||||
|       ))} | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| import { GetStaticProps } from "next"; | ||||
| import { useEffect, useState } from "react"; | ||||
| import { useCallback, useEffect, useState } from "react"; | ||||
| import { useBoolean } from "usehooks-ts"; | ||||
| import { z } from "zod"; | ||||
| import { AppLayout, AppLayoutRequired } from "components/AppLayout"; | ||||
| @ -24,6 +24,8 @@ import { containsHighlight, CustomSearchResponse, meiliSearch } from "helpers/se | ||||
| import { Paginator } from "components/Containers/Paginator"; | ||||
| import { useFormat } from "hooks/useFormat"; | ||||
| import { getFormat } from "helpers/i18n"; | ||||
| import { useAtomSetter } from "helpers/atoms"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -50,6 +52,8 @@ interface Props extends AppLayoutRequired {} | ||||
| 
 | ||||
| const Wiki = (props: Props): JSX.Element => { | ||||
|   const hoverable = useDeviceSupportsHover(); | ||||
|   const setSubPanelOpened = useAtomSetter(atoms.layout.subPanelOpened); | ||||
|   const closeSubPanel = useCallback(() => setSubPanelOpened(false), [setSubPanelOpened]); | ||||
|   const { format } = useFormat(); | ||||
|   const router = useTypedRouter(queryParamSchema); | ||||
|   const [query, setQuery] = useState(router.query.query ?? DEFAULT_FILTERS_STATE.query); | ||||
| @ -151,7 +155,18 @@ const Wiki = (props: Props): JSX.Element => { | ||||
| 
 | ||||
|       <p className="mb-4 font-headers text-xl font-bold">{format("special_pages")}</p> | ||||
| 
 | ||||
|       <NavOption title={format("chronology")} url="/wiki/chronology" border /> | ||||
|       <NavOption | ||||
|         title={format("chronology")} | ||||
|         url="/wiki/chronology" | ||||
|         onClick={closeSubPanel} | ||||
|         border | ||||
|       /> | ||||
|       <NavOption | ||||
|         title={format("weapon", { count: Infinity })} | ||||
|         url="/wiki/weapons" | ||||
|         onClick={closeSubPanel} | ||||
|         border | ||||
|       /> | ||||
|     </SubPanel> | ||||
|   ); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										297
									
								
								src/pages/wiki/weapons/[slug].tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										297
									
								
								src/pages/wiki/weapons/[slug].tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,297 @@ | ||||
| import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next"; | ||||
| import { Fragment, useCallback, useMemo } from "react"; | ||||
| import { AppLayout, AppLayoutRequired } from "components/AppLayout"; | ||||
| import { getReadySdk } from "graphql/sdk"; | ||||
| import { filterDefined, filterHasAttributes, isDefinedAndNotEmpty } from "helpers/asserts"; | ||||
| import { getFormat } from "helpers/i18n"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { ContentPanel } from "components/Containers/ContentPanel"; | ||||
| import { ReturnButton } from "components/PanelComponents/ReturnButton"; | ||||
| import { useFormat } from "hooks/useFormat"; | ||||
| import { SubPanel } from "components/Containers/SubPanel"; | ||||
| import { ThumbnailHeader } from "components/ThumbnailHeader"; | ||||
| import { getDefaultPreferredLanguages } from "helpers/locales"; | ||||
| import { prettySlug } from "helpers/formatters"; | ||||
| import { useSmartLanguage } from "hooks/useSmartLanguage"; | ||||
| import { Weapon, WeaponGroupPreview, WeaponStoryWithTranslations } from "types/types"; | ||||
| import { InsetBox } from "components/Containers/InsetBox"; | ||||
| import { Chip } from "components/Chip"; | ||||
| import { Markdawn } from "components/Markdown/Markdawn"; | ||||
| import { NavOption } from "components/PanelComponents/NavOption"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { useIntersectionList } from "hooks/useIntersectionList"; | ||||
| import { ElementsSeparator } from "helpers/component"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { TranslatedPreviewCard } from "components/PreviewCard"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
|  * ──────────────────────────────────────────╯  PAGE  ╰───────────────────────────────────────────── | ||||
|  */ | ||||
| 
 | ||||
| interface Props extends AppLayoutRequired { | ||||
|   weapon: Weapon; | ||||
|   primaryName: string; | ||||
|   aliases: string[]; | ||||
| } | ||||
| 
 | ||||
| interface WeaponPreviewProps { | ||||
|   weapon: WeaponGroupPreview; | ||||
| } | ||||
| 
 | ||||
| const WeaponPreview = ({ weapon }: WeaponPreviewProps): JSX.Element => ( | ||||
|   <TranslatedPreviewCard | ||||
|     href={`/wiki/weapons/${weapon.slug}`} | ||||
|     translations={filterHasAttributes(weapon.name, ["language.data.attributes.code"] as const).map( | ||||
|       ({ name, language }) => ({ | ||||
|         language: language.data.attributes.code, | ||||
|         title: name, | ||||
|       }) | ||||
|     )} | ||||
|     fallback={{ title: prettySlug(weapon.slug) }} | ||||
|     thumbnail={weapon.thumbnail?.data?.attributes} | ||||
|     thumbnailAspectRatio="1/1" | ||||
|     thumbnailForceAspectRatio | ||||
|     thumbnailFitMethod="contain" | ||||
|     keepInfoVisible | ||||
|     topChips={ | ||||
|       weapon.type?.data?.attributes?.slug | ||||
|         ? [prettySlug(weapon.type.data.attributes.slug)] | ||||
|         : undefined | ||||
|     } | ||||
|   /> | ||||
| ); | ||||
| 
 | ||||
| const WeaponPage = ({ weapon, primaryName, aliases, ...otherProps }: Props): JSX.Element => { | ||||
|   const { format } = useFormat(); | ||||
| 
 | ||||
|   const intersectionIds = useMemo( | ||||
|     () => filterDefined(weapon.stories).map(({ id }) => `story-${id}`), | ||||
|     [weapon.stories] | ||||
|   ); | ||||
|   const currentIntersection = useIntersectionList(intersectionIds); | ||||
|   const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout); | ||||
| 
 | ||||
|   const subPanel = ( | ||||
|     <SubPanel> | ||||
|       <ElementsSeparator> | ||||
|         {[ | ||||
|           is3ColumnsLayout && ( | ||||
|             <ReturnButton | ||||
|               key="return-button" | ||||
|               href="/wiki/weapons" | ||||
|               title={format("weapon", { count: Infinity })} | ||||
|             /> | ||||
|           ), | ||||
| 
 | ||||
|           <Fragment key="nav-options"> | ||||
|             {intersectionIds.map((id, index) => ( | ||||
|               <NavOption | ||||
|                 key={index} | ||||
|                 url={`#${id}`} | ||||
|                 title={`Story ${index + 1}`} | ||||
|                 subtitle={weapon.stories?.[index]?.categories?.data | ||||
|                   .map((category) => category.attributes?.name) | ||||
|                   .join("・")} | ||||
|                 active={currentIntersection === index} | ||||
|                 border | ||||
|               /> | ||||
|             ))} | ||||
|           </Fragment>, | ||||
| 
 | ||||
|           weapon.weapon_group?.data?.attributes?.weapons?.data && ( | ||||
|             <> | ||||
|               <h3>Weapon group</h3> | ||||
|               <p className="mb-8">{`${ | ||||
|                 weapon.weapon_group.data.attributes.weapons.data.length | ||||
|               } other weapons part of the ${prettySlug( | ||||
|                 weapon.weapon_group.data.attributes.slug | ||||
|               )}'s group`}</p>
 | ||||
|               <div className="grid gap-8"> | ||||
|                 {filterHasAttributes(weapon.weapon_group.data.attributes.weapons.data, [ | ||||
|                   "attributes", | ||||
|                 ] as const).map((groupWeapon) => ( | ||||
|                   <WeaponPreview key={groupWeapon.id} weapon={groupWeapon.attributes} /> | ||||
|                 ))} | ||||
|               </div> | ||||
|             </> | ||||
|           ), | ||||
|         ]} | ||||
|       </ElementsSeparator> | ||||
|     </SubPanel> | ||||
|   ); | ||||
| 
 | ||||
|   const contentPanel = ( | ||||
|     <ContentPanel> | ||||
|       <ReturnButton | ||||
|         href="/wiki/weapons" | ||||
|         title={format("weapon", { count: Infinity })} | ||||
|         displayOnlyOn="1ColumnLayout" | ||||
|         className="mb-10" | ||||
|       /> | ||||
|       <ThumbnailHeader | ||||
|         title={primaryName} | ||||
|         subtitle={aliases.join("・")} | ||||
|         thumbnail={weapon.thumbnail?.data?.attributes} | ||||
|       /> | ||||
| 
 | ||||
|       <HorizontalLine className="mb-12" /> | ||||
| 
 | ||||
|       <div className="grid gap-8"> | ||||
|         <ElementsSeparator> | ||||
|           {filterHasAttributes(weapon.stories, ["translations"] as const).map((story, index) => ( | ||||
|             <WeaponStory | ||||
|               key={story.id} | ||||
|               id={intersectionIds[index]} | ||||
|               story={story} | ||||
|               storyNumber={index + 1} | ||||
|             /> | ||||
|           ))} | ||||
|         </ElementsSeparator> | ||||
|       </div> | ||||
|     </ContentPanel> | ||||
|   ); | ||||
| 
 | ||||
|   return <AppLayout contentPanel={contentPanel} subPanel={subPanel} {...otherProps} />; | ||||
| }; | ||||
| export default WeaponPage; | ||||
| 
 | ||||
| /* | ||||
|  *                                    ╭──────────────────────╮ | ||||
|  * ───────────────────────────────────╯  NEXT DATA FETCHING  ╰────────────────────────────────────── | ||||
|  */ | ||||
| 
 | ||||
| export const getStaticProps: GetStaticProps = async (context) => { | ||||
|   const sdk = getReadySdk(); | ||||
|   const { format } = getFormat(context.locale); | ||||
|   const slug = context.params?.slug ? context.params.slug.toString() : ""; | ||||
|   const weaponResp = await sdk.getWeapon({ | ||||
|     slug: slug, | ||||
|     language_code: context.locale ?? "en", | ||||
|   }); | ||||
| 
 | ||||
|   const weapon = weaponResp.weaponStories?.data[0]?.attributes; | ||||
| 
 | ||||
|   if (!weapon?.stories || !context.locale || !context.locales) { | ||||
|     return { notFound: true }; | ||||
|   } | ||||
| 
 | ||||
|   const names = weapon.name; | ||||
|   const preferredLanguages = getDefaultPreferredLanguages(context.locale, context.locales); | ||||
| 
 | ||||
|   const [primaryName, ...aliases] = getFilteredNames(names, preferredLanguages); | ||||
| 
 | ||||
|   const props: Props = { | ||||
|     primaryName: primaryName ?? prettySlug(slug), | ||||
|     aliases, | ||||
|     // eslint-disable-next-line id-denylist
 | ||||
|     weapon, | ||||
|     openGraph: getOpenGraph(format, undefined, undefined, weapon.thumbnail?.data?.attributes), | ||||
|   }; | ||||
| 
 | ||||
|   return { | ||||
|     props: props, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|   const sdk = getReadySdk(); | ||||
|   const weapons = await sdk.getWeaponsSlugs(); | ||||
|   const paths: GetStaticPathsResult["paths"] = []; | ||||
|   filterHasAttributes(weapons.weaponStories?.data, ["attributes"] as const).map((item) => { | ||||
|     context.locales?.map((local) => { | ||||
|       paths.push({ | ||||
|         params: { slug: item.attributes.slug }, | ||||
|         locale: local, | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
|   return { | ||||
|     paths, | ||||
|     fallback: "blocking", | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| /* | ||||
|  *                                    ╭──────────────────────╮ | ||||
|  * ───────────────────────────────────╯  PRIVATE COMPONENTS  ╰────────────────────────────────────── | ||||
|  */ | ||||
| 
 | ||||
| interface WeaponStoryProps { | ||||
|   story: WeaponStoryWithTranslations; | ||||
|   storyNumber: number; | ||||
|   id?: string; | ||||
| } | ||||
| 
 | ||||
| const WeaponStory = ({ story, storyNumber, id }: WeaponStoryProps): JSX.Element => { | ||||
|   const { format } = useFormat(); | ||||
|   const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({ | ||||
|     items: story.translations, | ||||
|     languageExtractor: useCallback( | ||||
|       (item: WeaponStoryProps["story"]["translations"][number]) => | ||||
|         item?.language?.data?.attributes?.code, | ||||
|       [] | ||||
|     ), | ||||
|   }); | ||||
| 
 | ||||
|   if (!selectedTranslation) return <></>; | ||||
| 
 | ||||
|   return ( | ||||
|     <InsetBox id={id} className="formatted"> | ||||
|       <h2 className="!mt-4 !mb-4">{format("story_x", { x: storyNumber })}</h2> | ||||
| 
 | ||||
|       {languageSwitcherProps.locales.size > 1 && <LanguageSwitcher {...languageSwitcherProps} />} | ||||
| 
 | ||||
|       {story.categories && story.categories.data.length > 0 && ( | ||||
|         <div className="mb-12 flex flex-row flex-wrap place-content-center gap-2"> | ||||
|           {filterHasAttributes(story.categories.data, ["attributes.name"] as const).map( | ||||
|             (category) => ( | ||||
|               <Chip key={category.id} text={category.attributes.name} /> | ||||
|             ) | ||||
|           )} | ||||
|         </div> | ||||
|       )} | ||||
| 
 | ||||
|       {isDefinedAndNotEmpty(selectedTranslation.description) && ( | ||||
|         <div className="mb-8"> | ||||
|           <h3>{format("description")}</h3> | ||||
|           {selectedTranslation.description} | ||||
|         </div> | ||||
|       )} | ||||
|       <h3>{format("level_x", { x: 1 })}</h3> | ||||
|       <Markdawn text={selectedTranslation.level_1 ?? "To be added"} /> | ||||
| 
 | ||||
|       <h3>{format("level_x", { x: 2 })}</h3> | ||||
|       <Markdawn text={selectedTranslation.level_2 ?? "To be added"} /> | ||||
| 
 | ||||
|       <h3>{format("level_x", { x: 3 })}</h3> | ||||
|       <Markdawn text={selectedTranslation.level_3 ?? "To be added"} /> | ||||
| 
 | ||||
|       <h3>{format("level_x", { x: 4 })}</h3> | ||||
|       <Markdawn text={selectedTranslation.level_4 ?? "To be added"} /> | ||||
|     </InsetBox> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| /* | ||||
|  *                                      ╭───────────────────╮ | ||||
|  * ─────────────────────────────────────╯  PRIVATE METHODS  ╰─────────────────────────────────────── | ||||
|  */ | ||||
| 
 | ||||
| export const getFilteredNames = ( | ||||
|   names: Props["weapon"]["name"], | ||||
|   preferredLanguages: string[] | ||||
| ): string[] => { | ||||
|   for (const language of preferredLanguages) { | ||||
|     const filteredNames = filterHasAttributes(names, ["name"] as const).filter( | ||||
|       (name) => name.language?.data?.attributes?.code === language | ||||
|     ); | ||||
|     if (filteredNames.length > 0) { | ||||
|       return filteredNames.map((name) => name.name); | ||||
|     } | ||||
|   } | ||||
|   return []; | ||||
| }; | ||||
							
								
								
									
										237
									
								
								src/pages/wiki/weapons/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								src/pages/wiki/weapons/index.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,237 @@ | ||||
| import { GetStaticProps } from "next"; | ||||
| import { z } from "zod"; | ||||
| import { useEffect, useState } from "react"; | ||||
| import { useBoolean } from "usehooks-ts"; | ||||
| import { AppLayout, AppLayoutRequired } from "components/AppLayout"; | ||||
| import { getFormat } from "helpers/i18n"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { SubPanel } from "components/Containers/SubPanel"; | ||||
| import { PanelHeader } from "components/PanelComponents/PanelHeader"; | ||||
| import { TextInput } from "components/Inputs/TextInput"; | ||||
| import { useTypedRouter } from "hooks/useTypedRouter"; | ||||
| import { useFormat } from "hooks/useFormat"; | ||||
| import { | ||||
|   filterDefined, | ||||
|   filterHasAttributes, | ||||
|   isDefined, | ||||
|   isDefinedAndNotEmpty, | ||||
| } from "helpers/asserts"; | ||||
| import { sendAnalytics } from "helpers/analytics"; | ||||
| import { Button } from "components/Inputs/Button"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { containsHighlight, CustomSearchResponse, meiliSearch } from "helpers/search"; | ||||
| import { MeiliIndices, MeiliWeapon } from "shared/meilisearch-graphql-typings/meiliTypes"; | ||||
| import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel"; | ||||
| import { Paginator } from "components/Containers/Paginator"; | ||||
| import { TranslatedPreviewCard } from "components/PreviewCard"; | ||||
| import { prettySlug } from "helpers/formatters"; | ||||
| import { useDeviceSupportsHover } from "hooks/useMediaQuery"; | ||||
| import { WithLabel } from "components/Inputs/WithLabel"; | ||||
| import { Switch } from "components/Inputs/Switch"; | ||||
| import { ReturnButton } from "components/PanelComponents/ReturnButton"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
|  * ────────────────────────────────────────╯  CONSTANTS  ╰────────────────────────────────────────── | ||||
|  */ | ||||
| 
 | ||||
| const DEFAULT_FILTERS_STATE = { | ||||
|   query: "", | ||||
|   keepInfoVisible: true, | ||||
|   page: 1, | ||||
| }; | ||||
| 
 | ||||
| const queryParamSchema = z.object({ | ||||
|   query: z.coerce.string().optional(), | ||||
|   page: z.coerce.number().positive().optional(), | ||||
| }); | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
|  * ──────────────────────────────────────────╯  PAGE  ╰───────────────────────────────────────────── | ||||
|  */ | ||||
| 
 | ||||
| interface Props extends AppLayoutRequired {} | ||||
| 
 | ||||
| const Weapons = (props: Props): JSX.Element => { | ||||
|   const { format } = useFormat(); | ||||
|   const hoverable = useDeviceSupportsHover(); | ||||
|   const router = useTypedRouter(queryParamSchema); | ||||
| 
 | ||||
|   const [query, setQuery] = useState(router.query.query ?? DEFAULT_FILTERS_STATE.query); | ||||
|   const [page, setPage] = useState<number>(router.query.page ?? DEFAULT_FILTERS_STATE.page); | ||||
| 
 | ||||
|   const { | ||||
|     value: keepInfoVisible, | ||||
|     toggle: toggleKeepInfoVisible, | ||||
|     setValue: setKeepInfoVisible, | ||||
|   } = useBoolean(DEFAULT_FILTERS_STATE.keepInfoVisible); | ||||
| 
 | ||||
|   const [weapons, setWeapons] = useState<CustomSearchResponse<MeiliWeapon>>(); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const fetchPosts = async () => { | ||||
|       const searchResult = await meiliSearch(MeiliIndices.WEAPON, query, { | ||||
|         hitsPerPage: 25, | ||||
|         page, | ||||
|         attributesToRetrieve: ["*"], | ||||
|         attributesToHighlight: ["translations.description", "translations.names"], | ||||
|         attributesToCrop: ["translations.description"], | ||||
|         sort: ["slug:asc"], | ||||
|       }); | ||||
| 
 | ||||
|       searchResult.hits = searchResult.hits.map((item) => { | ||||
|         if (Object.keys(item._matchesPosition).some((match) => match.startsWith("translations"))) { | ||||
|           item._formatted.translations = filterDefined(item._formatted.translations).filter( | ||||
|             (translation) => JSON.stringify(translation).includes("</mark>") | ||||
|           ); | ||||
|         } | ||||
|         return item; | ||||
|       }); | ||||
| 
 | ||||
|       setWeapons(searchResult); | ||||
|     }; | ||||
|     fetchPosts(); | ||||
|   }, [query, page]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (router.isReady) | ||||
|       router.updateQuery({ | ||||
|         page, | ||||
|         query, | ||||
|       }); | ||||
|     // eslint-disable-next-line react-hooks/exhaustive-deps
 | ||||
|   }, [page, query, router.isReady]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (router.isReady) { | ||||
|       if (isDefined(router.query.page)) setPage(router.query.page); | ||||
|       if (isDefined(router.query.query)) setQuery(router.query.query); | ||||
|     } | ||||
|     // eslint-disable-next-line react-hooks/exhaustive-deps
 | ||||
|   }, [router.isReady]); | ||||
| 
 | ||||
|   const subPanel = ( | ||||
|     <SubPanel> | ||||
|       <ReturnButton | ||||
|         href="/wiki" | ||||
|         title={format("wiki")} | ||||
|         displayOnlyOn="3ColumnsLayout" | ||||
|         className="mb-10" | ||||
|       /> | ||||
| 
 | ||||
|       <PanelHeader | ||||
|         icon="shield" | ||||
|         title={format("weapon", { count: Infinity })} | ||||
|         description={format("weapons_description")} | ||||
|       /> | ||||
|       <HorizontalLine /> | ||||
| 
 | ||||
|       <TextInput | ||||
|         className="mb-6 w-full" | ||||
|         placeholder={format("search_title")} | ||||
|         value={query} | ||||
|         onChange={(name) => { | ||||
|           setPage(1); | ||||
|           setQuery(name); | ||||
|           if (isDefinedAndNotEmpty(name)) { | ||||
|             sendAnalytics("Weapons", "Change search term"); | ||||
|           } else { | ||||
|             sendAnalytics("Weapons", "Clear search term"); | ||||
|           } | ||||
|         }} | ||||
|       /> | ||||
| 
 | ||||
|       {hoverable && ( | ||||
|         <WithLabel label={format("always_show_info")}> | ||||
|           <Switch | ||||
|             value={keepInfoVisible} | ||||
|             onClick={() => { | ||||
|               toggleKeepInfoVisible(); | ||||
|               sendAnalytics("Weapons", `Always ${keepInfoVisible ? "hide" : "show"} info`); | ||||
|             }} | ||||
|           /> | ||||
|         </WithLabel> | ||||
|       )} | ||||
| 
 | ||||
|       <Button | ||||
|         className="mt-8" | ||||
|         text={format("reset_all_filters")} | ||||
|         icon="settings_backup_restore" | ||||
|         onClick={() => { | ||||
|           setQuery(DEFAULT_FILTERS_STATE.query); | ||||
|           setKeepInfoVisible(DEFAULT_FILTERS_STATE.keepInfoVisible); | ||||
|           sendAnalytics("Weapons", "Reset all filters"); | ||||
|         }} | ||||
|       /> | ||||
|     </SubPanel> | ||||
|   ); | ||||
| 
 | ||||
|   const contentPanel = ( | ||||
|     <ContentPanel width={ContentPanelWidthSizes.Full}> | ||||
|       <ReturnButton | ||||
|         href="/wiki" | ||||
|         title={format("wiki")} | ||||
|         displayOnlyOn="1ColumnLayout" | ||||
|         className="mb-10" | ||||
|       /> | ||||
| 
 | ||||
|       <Paginator page={page} onPageChange={setPage} totalNumberOfPages={weapons?.totalPages}> | ||||
|         <div | ||||
|           className="grid grid-cols-[repeat(auto-fill,_minmax(12rem,1fr))] items-start | ||||
|           gap-x-6 gap-y-8"> | ||||
|           {weapons?.hits.map((item) => ( | ||||
|             <TranslatedPreviewCard | ||||
|               key={item.id} | ||||
|               href={`/wiki/weapons/${item.slug}`} | ||||
|               translations={filterHasAttributes(item._formatted.translations, [ | ||||
|                 "language.data.attributes.code", | ||||
|               ] as const).map(({ description, language, names: [primaryName, ...aliases] }) => ({ | ||||
|                 language: language.data.attributes.code, | ||||
|                 title: primaryName, | ||||
|                 subtitle: aliases.join("・"), | ||||
|                 description: containsHighlight(description) ? description : undefined, | ||||
|               }))} | ||||
|               fallback={{ title: prettySlug(item.slug) }} | ||||
|               thumbnail={item.thumbnail?.data?.attributes} | ||||
|               thumbnailAspectRatio="1/1" | ||||
|               thumbnailForceAspectRatio | ||||
|               thumbnailFitMethod="contain" | ||||
|               keepInfoVisible={keepInfoVisible} | ||||
|               topChips={ | ||||
|                 item.type?.data?.attributes?.slug | ||||
|                   ? [prettySlug(item.type.data.attributes.slug)] | ||||
|                   : undefined | ||||
|               } | ||||
|               bottomChips={filterHasAttributes(item.categories, ["attributes.short"] as const).map( | ||||
|                 (category) => category.attributes.short | ||||
|               )} | ||||
|             /> | ||||
|           ))} | ||||
|         </div> | ||||
|       </Paginator> | ||||
|     </ContentPanel> | ||||
|   ); | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <AppLayout contentPanel={contentPanel} subPanel={subPanel} {...props} /> | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
| export default Weapons; | ||||
| 
 | ||||
| /* | ||||
|  *                                    ╭──────────────────────╮ | ||||
|  * ───────────────────────────────────╯  NEXT DATA FETCHING  ╰────────────────────────────────────── | ||||
|  */ | ||||
| 
 | ||||
| export const getStaticProps: GetStaticProps = (context) => { | ||||
|   const { format } = getFormat(context.locale); | ||||
|   const props: Props = { | ||||
|     openGraph: getOpenGraph(format, format("weapon", { count: Infinity })), | ||||
|   }; | ||||
|   return { | ||||
|     props: props, | ||||
|   }; | ||||
| }; | ||||
| @ -4715,7 +4715,7 @@ export type WeaponStory = { | ||||
|   __typename?: "WeaponStory"; | ||||
|   createdAt?: Maybe<Scalars["DateTime"]>; | ||||
|   name?: Maybe<Array<Maybe<ComponentTranslationsWeaponStory>>>; | ||||
|   slug?: Maybe<Scalars["String"]>; | ||||
|   slug: Scalars["String"]; | ||||
|   stories?: Maybe<Array<Maybe<ComponentCollectionsComponentWeaponStory>>>; | ||||
|   thumbnail?: Maybe<UploadFileEntityResponse>; | ||||
|   type?: Maybe<WeaponStoryTypeEntityResponse>; | ||||
| @ -4772,10 +4772,18 @@ export type WeaponStoryGroup = { | ||||
|   __typename?: "WeaponStoryGroup"; | ||||
|   createdAt?: Maybe<Scalars["DateTime"]>; | ||||
|   slug: Scalars["String"]; | ||||
|   subgroup_of?: Maybe<WeaponStoryGroupEntityResponse>; | ||||
|   subgroups?: Maybe<WeaponStoryGroupRelationResponseCollection>; | ||||
|   updatedAt?: Maybe<Scalars["DateTime"]>; | ||||
|   weapons?: Maybe<WeaponStoryRelationResponseCollection>; | ||||
| }; | ||||
| 
 | ||||
| export type WeaponStoryGroupSubgroupsArgs = { | ||||
|   filters?: InputMaybe<WeaponStoryGroupFiltersInput>; | ||||
|   pagination?: InputMaybe<PaginationArg>; | ||||
|   sort?: InputMaybe<Array<InputMaybe<Scalars["String"]>>>; | ||||
| }; | ||||
| 
 | ||||
| export type WeaponStoryGroupWeaponsArgs = { | ||||
|   filters?: InputMaybe<WeaponStoryFiltersInput>; | ||||
|   pagination?: InputMaybe<PaginationArg>; | ||||
| @ -4806,15 +4814,24 @@ export type WeaponStoryGroupFiltersInput = { | ||||
|   not?: InputMaybe<WeaponStoryGroupFiltersInput>; | ||||
|   or?: InputMaybe<Array<InputMaybe<WeaponStoryGroupFiltersInput>>>; | ||||
|   slug?: InputMaybe<StringFilterInput>; | ||||
|   subgroup_of?: InputMaybe<WeaponStoryGroupFiltersInput>; | ||||
|   subgroups?: InputMaybe<WeaponStoryGroupFiltersInput>; | ||||
|   updatedAt?: InputMaybe<DateTimeFilterInput>; | ||||
|   weapons?: InputMaybe<WeaponStoryFiltersInput>; | ||||
| }; | ||||
| 
 | ||||
| export type WeaponStoryGroupInput = { | ||||
|   slug?: InputMaybe<Scalars["String"]>; | ||||
|   subgroup_of?: InputMaybe<Scalars["ID"]>; | ||||
|   subgroups?: InputMaybe<Array<InputMaybe<Scalars["ID"]>>>; | ||||
|   weapons?: InputMaybe<Array<InputMaybe<Scalars["ID"]>>>; | ||||
| }; | ||||
| 
 | ||||
| export type WeaponStoryGroupRelationResponseCollection = { | ||||
|   __typename?: "WeaponStoryGroupRelationResponseCollection"; | ||||
|   data: Array<WeaponStoryGroupEntity>; | ||||
| }; | ||||
| 
 | ||||
| export type WeaponStoryInput = { | ||||
|   name?: InputMaybe<Array<InputMaybe<ComponentTranslationsWeaponStoryInput>>>; | ||||
|   slug?: InputMaybe<Scalars["String"]>; | ||||
| @ -4962,7 +4979,6 @@ export type WebsiteInterface = { | ||||
|   binding?: Maybe<Scalars["String"]>; | ||||
|   book_fold?: Maybe<Scalars["String"]>; | ||||
|   calculated?: Maybe<Scalars["String"]>; | ||||
|   categories?: Maybe<Scalars["String"]>; | ||||
|   category?: Maybe<Scalars["String"]>; | ||||
|   change_language?: Maybe<Scalars["String"]>; | ||||
|   channel?: Maybe<Scalars["String"]>; | ||||
| @ -4984,8 +5000,9 @@ export type WebsiteInterface = { | ||||
|   createdAt?: Maybe<Scalars["DateTime"]>; | ||||
|   currency?: Maybe<Scalars["String"]>; | ||||
|   dark?: Maybe<Scalars["String"]>; | ||||
|   dark_mode_extension_warning?: Maybe<Scalars["String"]>; | ||||
|   default_description?: Maybe<Scalars["String"]>; | ||||
|   definition?: Maybe<Scalars["String"]>; | ||||
|   definition_x?: Maybe<Scalars["String"]>; | ||||
|   description?: Maybe<Scalars["String"]>; | ||||
|   details?: Maybe<Scalars["String"]>; | ||||
|   display_all_items?: Maybe<Scalars["String"]>; | ||||
| @ -5001,7 +5018,6 @@ export type WebsiteInterface = { | ||||
|   font_size?: Maybe<Scalars["String"]>; | ||||
|   front_matter?: Maybe<Scalars["String"]>; | ||||
|   gallery?: Maybe<Scalars["String"]>; | ||||
|   gallery_description?: Maybe<Scalars["String"]>; | ||||
|   game?: Maybe<Scalars["String"]>; | ||||
|   group?: Maybe<Scalars["String"]>; | ||||
|   group_by?: Maybe<Scalars["String"]>; | ||||
| @ -5011,10 +5027,7 @@ export type WebsiteInterface = { | ||||
|   incomplete?: Maybe<Scalars["String"]>; | ||||
|   item?: Maybe<Scalars["String"]>; | ||||
|   item_not_available?: Maybe<Scalars["String"]>; | ||||
|   items?: Maybe<Scalars["String"]>; | ||||
|   language?: Maybe<Scalars["String"]>; | ||||
|   language_switch_message?: Maybe<Scalars["String"]>; | ||||
|   languages?: Maybe<Scalars["String"]>; | ||||
|   least_popular?: Maybe<Scalars["String"]>; | ||||
|   left_to_right?: Maybe<Scalars["String"]>; | ||||
|   legality?: Maybe<Scalars["String"]>; | ||||
| @ -5026,9 +5039,6 @@ export type WebsiteInterface = { | ||||
|   lighting?: Maybe<Scalars["String"]>; | ||||
|   listen_content?: Maybe<Scalars["String"]>; | ||||
|   longest?: Maybe<Scalars["String"]>; | ||||
|   members?: Maybe<Scalars["String"]>; | ||||
|   merch?: Maybe<Scalars["String"]>; | ||||
|   merch_description?: Maybe<Scalars["String"]>; | ||||
|   message?: Maybe<Scalars["String"]>; | ||||
|   most_popular?: Maybe<Scalars["String"]>; | ||||
|   name?: Maybe<Scalars["String"]>; | ||||
| @ -5036,11 +5046,8 @@ export type WebsiteInterface = { | ||||
|   news?: Maybe<Scalars["String"]>; | ||||
|   news_description?: Maybe<Scalars["String"]>; | ||||
|   night_reader?: Maybe<Scalars["String"]>; | ||||
|   no_category?: Maybe<Scalars["String"]>; | ||||
|   no_results_message?: Maybe<Scalars["String"]>; | ||||
|   no_source_warning?: Maybe<Scalars["String"]>; | ||||
|   no_type?: Maybe<Scalars["String"]>; | ||||
|   no_year?: Maybe<Scalars["String"]>; | ||||
|   notes?: Maybe<Scalars["String"]>; | ||||
|   oldest?: Maybe<Scalars["String"]>; | ||||
|   only_display_items_i_have?: Maybe<Scalars["String"]>; | ||||
| @ -5055,7 +5062,6 @@ export type WebsiteInterface = { | ||||
|   page?: Maybe<Scalars["String"]>; | ||||
|   page_not_found?: Maybe<Scalars["String"]>; | ||||
|   page_order?: Maybe<Scalars["String"]>; | ||||
|   pages?: Maybe<Scalars["String"]>; | ||||
|   paper_texture?: Maybe<Scalars["String"]>; | ||||
|   paperback?: Maybe<Scalars["String"]>; | ||||
|   player_name?: Maybe<Scalars["String"]>; | ||||
| @ -5074,9 +5080,7 @@ export type WebsiteInterface = { | ||||
|   response_email_success?: Maybe<Scalars["String"]>; | ||||
|   response_invalid_code?: Maybe<Scalars["String"]>; | ||||
|   response_invalid_email?: Maybe<Scalars["String"]>; | ||||
|   result?: Maybe<Scalars["String"]>; | ||||
|   results?: Maybe<Scalars["String"]>; | ||||
|   return_to?: Maybe<Scalars["String"]>; | ||||
|   return_to_x?: Maybe<Scalars["String"]>; | ||||
|   review?: Maybe<Scalars["String"]>; | ||||
|   right_to_left?: Maybe<Scalars["String"]>; | ||||
|   scan?: Maybe<Scalars["String"]>; | ||||
| @ -5095,6 +5099,7 @@ export type WebsiteInterface = { | ||||
|   show_primary_items?: Maybe<Scalars["String"]>; | ||||
|   show_secondary_items?: Maybe<Scalars["String"]>; | ||||
|   show_subitems?: Maybe<Scalars["String"]>; | ||||
|   showing_x_out_of_y_results?: Maybe<Scalars["String"]>; | ||||
|   side_pages?: Maybe<Scalars["String"]>; | ||||
|   single_page_view?: Maybe<Scalars["String"]>; | ||||
|   size?: Maybe<Scalars["String"]>; | ||||
| @ -5107,8 +5112,7 @@ export type WebsiteInterface = { | ||||
|   status_incomplete?: Maybe<Scalars["String"]>; | ||||
|   status_review?: Maybe<Scalars["String"]>; | ||||
|   subitem?: Maybe<Scalars["String"]>; | ||||
|   subitem_of?: Maybe<Scalars["String"]>; | ||||
|   subitems?: Maybe<Scalars["String"]>; | ||||
|   subitem_of_x?: Maybe<Scalars["String"]>; | ||||
|   subscribers?: Maybe<Scalars["String"]>; | ||||
|   summary?: Maybe<Scalars["String"]>; | ||||
|   switch_to_folder_view?: Maybe<Scalars["String"]>; | ||||
| @ -5128,8 +5132,7 @@ export type WebsiteInterface = { | ||||
|   ui_language?: Maybe<LanguageEntityResponse>; | ||||
|   updatedAt?: Maybe<Scalars["DateTime"]>; | ||||
|   variant?: Maybe<Scalars["String"]>; | ||||
|   variant_of?: Maybe<Scalars["String"]>; | ||||
|   variants?: Maybe<Scalars["String"]>; | ||||
|   variant_of_x?: Maybe<Scalars["String"]>; | ||||
|   video?: Maybe<Scalars["String"]>; | ||||
|   videos?: Maybe<Scalars["String"]>; | ||||
|   view_on?: Maybe<Scalars["String"]>; | ||||
| @ -5140,6 +5143,7 @@ export type WebsiteInterface = { | ||||
|   wiki?: Maybe<Scalars["String"]>; | ||||
|   wiki_description?: Maybe<Scalars["String"]>; | ||||
|   wiki_short_description?: Maybe<Scalars["String"]>; | ||||
|   x_results?: Maybe<Scalars["String"]>; | ||||
| }; | ||||
| 
 | ||||
| export type WebsiteInterfaceEntity = { | ||||
| @ -5176,7 +5180,6 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   binding?: InputMaybe<StringFilterInput>; | ||||
|   book_fold?: InputMaybe<StringFilterInput>; | ||||
|   calculated?: InputMaybe<StringFilterInput>; | ||||
|   categories?: InputMaybe<StringFilterInput>; | ||||
|   category?: InputMaybe<StringFilterInput>; | ||||
|   change_language?: InputMaybe<StringFilterInput>; | ||||
|   channel?: InputMaybe<StringFilterInput>; | ||||
| @ -5198,8 +5201,9 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   createdAt?: InputMaybe<DateTimeFilterInput>; | ||||
|   currency?: InputMaybe<StringFilterInput>; | ||||
|   dark?: InputMaybe<StringFilterInput>; | ||||
|   dark_mode_extension_warning?: InputMaybe<StringFilterInput>; | ||||
|   default_description?: InputMaybe<StringFilterInput>; | ||||
|   definition?: InputMaybe<StringFilterInput>; | ||||
|   definition_x?: InputMaybe<StringFilterInput>; | ||||
|   description?: InputMaybe<StringFilterInput>; | ||||
|   details?: InputMaybe<StringFilterInput>; | ||||
|   display_all_items?: InputMaybe<StringFilterInput>; | ||||
| @ -5215,7 +5219,6 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   font_size?: InputMaybe<StringFilterInput>; | ||||
|   front_matter?: InputMaybe<StringFilterInput>; | ||||
|   gallery?: InputMaybe<StringFilterInput>; | ||||
|   gallery_description?: InputMaybe<StringFilterInput>; | ||||
|   game?: InputMaybe<StringFilterInput>; | ||||
|   group?: InputMaybe<StringFilterInput>; | ||||
|   group_by?: InputMaybe<StringFilterInput>; | ||||
| @ -5226,10 +5229,7 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   incomplete?: InputMaybe<StringFilterInput>; | ||||
|   item?: InputMaybe<StringFilterInput>; | ||||
|   item_not_available?: InputMaybe<StringFilterInput>; | ||||
|   items?: InputMaybe<StringFilterInput>; | ||||
|   language?: InputMaybe<StringFilterInput>; | ||||
|   language_switch_message?: InputMaybe<StringFilterInput>; | ||||
|   languages?: InputMaybe<StringFilterInput>; | ||||
|   least_popular?: InputMaybe<StringFilterInput>; | ||||
|   left_to_right?: InputMaybe<StringFilterInput>; | ||||
|   legality?: InputMaybe<StringFilterInput>; | ||||
| @ -5241,9 +5241,6 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   lighting?: InputMaybe<StringFilterInput>; | ||||
|   listen_content?: InputMaybe<StringFilterInput>; | ||||
|   longest?: InputMaybe<StringFilterInput>; | ||||
|   members?: InputMaybe<StringFilterInput>; | ||||
|   merch?: InputMaybe<StringFilterInput>; | ||||
|   merch_description?: InputMaybe<StringFilterInput>; | ||||
|   message?: InputMaybe<StringFilterInput>; | ||||
|   most_popular?: InputMaybe<StringFilterInput>; | ||||
|   name?: InputMaybe<StringFilterInput>; | ||||
| @ -5251,11 +5248,8 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   news?: InputMaybe<StringFilterInput>; | ||||
|   news_description?: InputMaybe<StringFilterInput>; | ||||
|   night_reader?: InputMaybe<StringFilterInput>; | ||||
|   no_category?: InputMaybe<StringFilterInput>; | ||||
|   no_results_message?: InputMaybe<StringFilterInput>; | ||||
|   no_source_warning?: InputMaybe<StringFilterInput>; | ||||
|   no_type?: InputMaybe<StringFilterInput>; | ||||
|   no_year?: InputMaybe<StringFilterInput>; | ||||
|   not?: InputMaybe<WebsiteInterfaceFiltersInput>; | ||||
|   notes?: InputMaybe<StringFilterInput>; | ||||
|   oldest?: InputMaybe<StringFilterInput>; | ||||
| @ -5272,7 +5266,6 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   page?: InputMaybe<StringFilterInput>; | ||||
|   page_not_found?: InputMaybe<StringFilterInput>; | ||||
|   page_order?: InputMaybe<StringFilterInput>; | ||||
|   pages?: InputMaybe<StringFilterInput>; | ||||
|   paper_texture?: InputMaybe<StringFilterInput>; | ||||
|   paperback?: InputMaybe<StringFilterInput>; | ||||
|   player_name?: InputMaybe<StringFilterInput>; | ||||
| @ -5291,9 +5284,7 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   response_email_success?: InputMaybe<StringFilterInput>; | ||||
|   response_invalid_code?: InputMaybe<StringFilterInput>; | ||||
|   response_invalid_email?: InputMaybe<StringFilterInput>; | ||||
|   result?: InputMaybe<StringFilterInput>; | ||||
|   results?: InputMaybe<StringFilterInput>; | ||||
|   return_to?: InputMaybe<StringFilterInput>; | ||||
|   return_to_x?: InputMaybe<StringFilterInput>; | ||||
|   review?: InputMaybe<StringFilterInput>; | ||||
|   right_to_left?: InputMaybe<StringFilterInput>; | ||||
|   scan?: InputMaybe<StringFilterInput>; | ||||
| @ -5312,6 +5303,7 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   show_primary_items?: InputMaybe<StringFilterInput>; | ||||
|   show_secondary_items?: InputMaybe<StringFilterInput>; | ||||
|   show_subitems?: InputMaybe<StringFilterInput>; | ||||
|   showing_x_out_of_y_results?: InputMaybe<StringFilterInput>; | ||||
|   side_pages?: InputMaybe<StringFilterInput>; | ||||
|   single_page_view?: InputMaybe<StringFilterInput>; | ||||
|   size?: InputMaybe<StringFilterInput>; | ||||
| @ -5324,8 +5316,7 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   status_incomplete?: InputMaybe<StringFilterInput>; | ||||
|   status_review?: InputMaybe<StringFilterInput>; | ||||
|   subitem?: InputMaybe<StringFilterInput>; | ||||
|   subitem_of?: InputMaybe<StringFilterInput>; | ||||
|   subitems?: InputMaybe<StringFilterInput>; | ||||
|   subitem_of_x?: InputMaybe<StringFilterInput>; | ||||
|   subscribers?: InputMaybe<StringFilterInput>; | ||||
|   summary?: InputMaybe<StringFilterInput>; | ||||
|   switch_to_folder_view?: InputMaybe<StringFilterInput>; | ||||
| @ -5345,8 +5336,7 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   ui_language?: InputMaybe<LanguageFiltersInput>; | ||||
|   updatedAt?: InputMaybe<DateTimeFilterInput>; | ||||
|   variant?: InputMaybe<StringFilterInput>; | ||||
|   variant_of?: InputMaybe<StringFilterInput>; | ||||
|   variants?: InputMaybe<StringFilterInput>; | ||||
|   variant_of_x?: InputMaybe<StringFilterInput>; | ||||
|   video?: InputMaybe<StringFilterInput>; | ||||
|   videos?: InputMaybe<StringFilterInput>; | ||||
|   view_on?: InputMaybe<StringFilterInput>; | ||||
| @ -5357,6 +5347,7 @@ export type WebsiteInterfaceFiltersInput = { | ||||
|   wiki?: InputMaybe<StringFilterInput>; | ||||
|   wiki_description?: InputMaybe<StringFilterInput>; | ||||
|   wiki_short_description?: InputMaybe<StringFilterInput>; | ||||
|   x_results?: InputMaybe<StringFilterInput>; | ||||
| }; | ||||
| 
 | ||||
| export type WebsiteInterfaceInput = { | ||||
| @ -5375,7 +5366,6 @@ export type WebsiteInterfaceInput = { | ||||
|   binding?: InputMaybe<Scalars["String"]>; | ||||
|   book_fold?: InputMaybe<Scalars["String"]>; | ||||
|   calculated?: InputMaybe<Scalars["String"]>; | ||||
|   categories?: InputMaybe<Scalars["String"]>; | ||||
|   category?: InputMaybe<Scalars["String"]>; | ||||
|   change_language?: InputMaybe<Scalars["String"]>; | ||||
|   channel?: InputMaybe<Scalars["String"]>; | ||||
| @ -5396,8 +5386,9 @@ export type WebsiteInterfaceInput = { | ||||
|   cover?: InputMaybe<Scalars["String"]>; | ||||
|   currency?: InputMaybe<Scalars["String"]>; | ||||
|   dark?: InputMaybe<Scalars["String"]>; | ||||
|   dark_mode_extension_warning?: InputMaybe<Scalars["String"]>; | ||||
|   default_description?: InputMaybe<Scalars["String"]>; | ||||
|   definition?: InputMaybe<Scalars["String"]>; | ||||
|   definition_x?: InputMaybe<Scalars["String"]>; | ||||
|   description?: InputMaybe<Scalars["String"]>; | ||||
|   details?: InputMaybe<Scalars["String"]>; | ||||
|   display_all_items?: InputMaybe<Scalars["String"]>; | ||||
| @ -5413,7 +5404,6 @@ export type WebsiteInterfaceInput = { | ||||
|   font_size?: InputMaybe<Scalars["String"]>; | ||||
|   front_matter?: InputMaybe<Scalars["String"]>; | ||||
|   gallery?: InputMaybe<Scalars["String"]>; | ||||
|   gallery_description?: InputMaybe<Scalars["String"]>; | ||||
|   game?: InputMaybe<Scalars["String"]>; | ||||
|   group?: InputMaybe<Scalars["String"]>; | ||||
|   group_by?: InputMaybe<Scalars["String"]>; | ||||
| @ -5423,10 +5413,7 @@ export type WebsiteInterfaceInput = { | ||||
|   incomplete?: InputMaybe<Scalars["String"]>; | ||||
|   item?: InputMaybe<Scalars["String"]>; | ||||
|   item_not_available?: InputMaybe<Scalars["String"]>; | ||||
|   items?: InputMaybe<Scalars["String"]>; | ||||
|   language?: InputMaybe<Scalars["String"]>; | ||||
|   language_switch_message?: InputMaybe<Scalars["String"]>; | ||||
|   languages?: InputMaybe<Scalars["String"]>; | ||||
|   least_popular?: InputMaybe<Scalars["String"]>; | ||||
|   left_to_right?: InputMaybe<Scalars["String"]>; | ||||
|   legality?: InputMaybe<Scalars["String"]>; | ||||
| @ -5438,9 +5425,6 @@ export type WebsiteInterfaceInput = { | ||||
|   lighting?: InputMaybe<Scalars["String"]>; | ||||
|   listen_content?: InputMaybe<Scalars["String"]>; | ||||
|   longest?: InputMaybe<Scalars["String"]>; | ||||
|   members?: InputMaybe<Scalars["String"]>; | ||||
|   merch?: InputMaybe<Scalars["String"]>; | ||||
|   merch_description?: InputMaybe<Scalars["String"]>; | ||||
|   message?: InputMaybe<Scalars["String"]>; | ||||
|   most_popular?: InputMaybe<Scalars["String"]>; | ||||
|   name?: InputMaybe<Scalars["String"]>; | ||||
| @ -5448,11 +5432,8 @@ export type WebsiteInterfaceInput = { | ||||
|   news?: InputMaybe<Scalars["String"]>; | ||||
|   news_description?: InputMaybe<Scalars["String"]>; | ||||
|   night_reader?: InputMaybe<Scalars["String"]>; | ||||
|   no_category?: InputMaybe<Scalars["String"]>; | ||||
|   no_results_message?: InputMaybe<Scalars["String"]>; | ||||
|   no_source_warning?: InputMaybe<Scalars["String"]>; | ||||
|   no_type?: InputMaybe<Scalars["String"]>; | ||||
|   no_year?: InputMaybe<Scalars["String"]>; | ||||
|   notes?: InputMaybe<Scalars["String"]>; | ||||
|   oldest?: InputMaybe<Scalars["String"]>; | ||||
|   only_display_items_i_have?: InputMaybe<Scalars["String"]>; | ||||
| @ -5467,7 +5448,6 @@ export type WebsiteInterfaceInput = { | ||||
|   page?: InputMaybe<Scalars["String"]>; | ||||
|   page_not_found?: InputMaybe<Scalars["String"]>; | ||||
|   page_order?: InputMaybe<Scalars["String"]>; | ||||
|   pages?: InputMaybe<Scalars["String"]>; | ||||
|   paper_texture?: InputMaybe<Scalars["String"]>; | ||||
|   paperback?: InputMaybe<Scalars["String"]>; | ||||
|   player_name?: InputMaybe<Scalars["String"]>; | ||||
| @ -5486,9 +5466,7 @@ export type WebsiteInterfaceInput = { | ||||
|   response_email_success?: InputMaybe<Scalars["String"]>; | ||||
|   response_invalid_code?: InputMaybe<Scalars["String"]>; | ||||
|   response_invalid_email?: InputMaybe<Scalars["String"]>; | ||||
|   result?: InputMaybe<Scalars["String"]>; | ||||
|   results?: InputMaybe<Scalars["String"]>; | ||||
|   return_to?: InputMaybe<Scalars["String"]>; | ||||
|   return_to_x?: InputMaybe<Scalars["String"]>; | ||||
|   review?: InputMaybe<Scalars["String"]>; | ||||
|   right_to_left?: InputMaybe<Scalars["String"]>; | ||||
|   scan?: InputMaybe<Scalars["String"]>; | ||||
| @ -5507,6 +5485,7 @@ export type WebsiteInterfaceInput = { | ||||
|   show_primary_items?: InputMaybe<Scalars["String"]>; | ||||
|   show_secondary_items?: InputMaybe<Scalars["String"]>; | ||||
|   show_subitems?: InputMaybe<Scalars["String"]>; | ||||
|   showing_x_out_of_y_results?: InputMaybe<Scalars["String"]>; | ||||
|   side_pages?: InputMaybe<Scalars["String"]>; | ||||
|   single_page_view?: InputMaybe<Scalars["String"]>; | ||||
|   size?: InputMaybe<Scalars["String"]>; | ||||
| @ -5519,8 +5498,7 @@ export type WebsiteInterfaceInput = { | ||||
|   status_incomplete?: InputMaybe<Scalars["String"]>; | ||||
|   status_review?: InputMaybe<Scalars["String"]>; | ||||
|   subitem?: InputMaybe<Scalars["String"]>; | ||||
|   subitem_of?: InputMaybe<Scalars["String"]>; | ||||
|   subitems?: InputMaybe<Scalars["String"]>; | ||||
|   subitem_of_x?: InputMaybe<Scalars["String"]>; | ||||
|   subscribers?: InputMaybe<Scalars["String"]>; | ||||
|   summary?: InputMaybe<Scalars["String"]>; | ||||
|   switch_to_folder_view?: InputMaybe<Scalars["String"]>; | ||||
| @ -5539,8 +5517,7 @@ export type WebsiteInterfaceInput = { | ||||
|   typesetters?: InputMaybe<Scalars["String"]>; | ||||
|   ui_language?: InputMaybe<Scalars["ID"]>; | ||||
|   variant?: InputMaybe<Scalars["String"]>; | ||||
|   variant_of?: InputMaybe<Scalars["String"]>; | ||||
|   variants?: InputMaybe<Scalars["String"]>; | ||||
|   variant_of_x?: InputMaybe<Scalars["String"]>; | ||||
|   video?: InputMaybe<Scalars["String"]>; | ||||
|   videos?: InputMaybe<Scalars["String"]>; | ||||
|   view_on?: InputMaybe<Scalars["String"]>; | ||||
| @ -5551,6 +5528,7 @@ export type WebsiteInterfaceInput = { | ||||
|   wiki?: InputMaybe<Scalars["String"]>; | ||||
|   wiki_description?: InputMaybe<Scalars["String"]>; | ||||
|   wiki_short_description?: InputMaybe<Scalars["String"]>; | ||||
|   x_results?: InputMaybe<Scalars["String"]>; | ||||
| }; | ||||
| 
 | ||||
| export type WikiPage = { | ||||
| @ -6005,6 +5983,88 @@ export type VideoAttributesFragment = { | ||||
|   } | null; | ||||
| }; | ||||
| 
 | ||||
| export type WeaponAttributesFragment = { | ||||
|   __typename?: "WeaponStory"; | ||||
|   slug: string; | ||||
|   thumbnail?: { | ||||
|     __typename?: "UploadFileEntityResponse"; | ||||
|     data?: { | ||||
|       __typename?: "UploadFileEntity"; | ||||
|       attributes?: { | ||||
|         __typename?: "UploadFile"; | ||||
|         name: string; | ||||
|         alternativeText?: string | null; | ||||
|         caption?: string | null; | ||||
|         width?: number | null; | ||||
|         height?: number | null; | ||||
|         url: string; | ||||
|       } | null; | ||||
|     } | null; | ||||
|   } | null; | ||||
|   type?: { | ||||
|     __typename?: "WeaponStoryTypeEntityResponse"; | ||||
|     data?: { | ||||
|       __typename?: "WeaponStoryTypeEntity"; | ||||
|       id?: string | null; | ||||
|       attributes?: { | ||||
|         __typename?: "WeaponStoryType"; | ||||
|         slug: string; | ||||
|         translations?: Array<{ | ||||
|           __typename?: "ComponentTranslationsWeaponStoryType"; | ||||
|           name?: string | null; | ||||
|           language?: { | ||||
|             __typename?: "LanguageEntityResponse"; | ||||
|             data?: { | ||||
|               __typename?: "LanguageEntity"; | ||||
|               attributes?: { __typename?: "Language"; code: string } | null; | ||||
|             } | null; | ||||
|           } | null; | ||||
|         } | null> | null; | ||||
|       } | null; | ||||
|     } | null; | ||||
|   } | null; | ||||
|   name?: Array<{ | ||||
|     __typename?: "ComponentTranslationsWeaponStory"; | ||||
|     id: string; | ||||
|     name?: string | null; | ||||
|     language?: { | ||||
|       __typename?: "LanguageEntityResponse"; | ||||
|       data?: { | ||||
|         __typename?: "LanguageEntity"; | ||||
|         attributes?: { __typename?: "Language"; code: string } | null; | ||||
|       } | null; | ||||
|     } | null; | ||||
|   } | null> | null; | ||||
|   stories?: Array<{ | ||||
|     __typename?: "ComponentCollectionsComponentWeaponStory"; | ||||
|     id: string; | ||||
|     categories?: { | ||||
|       __typename?: "CategoryRelationResponseCollection"; | ||||
|       data: Array<{ | ||||
|         __typename?: "CategoryEntity"; | ||||
|         id?: string | null; | ||||
|         attributes?: { __typename?: "Category"; short: string } | null; | ||||
|       }>; | ||||
|     } | null; | ||||
|     translations?: Array<{ | ||||
|       __typename?: "ComponentTranslationsWeaponStoryStory"; | ||||
|       description?: string | null; | ||||
|       level_1?: string | null; | ||||
|       level_2?: string | null; | ||||
|       level_3?: string | null; | ||||
|       level_4?: string | null; | ||||
|       status: Enum_Componenttranslationsweaponstorystory_Status; | ||||
|       language?: { | ||||
|         __typename?: "LanguageEntityResponse"; | ||||
|         data?: { | ||||
|           __typename?: "LanguageEntity"; | ||||
|           attributes?: { __typename?: "Language"; code: string } | null; | ||||
|         } | null; | ||||
|       } | null; | ||||
|     } | null> | null; | ||||
|   } | null> | null; | ||||
| }; | ||||
| 
 | ||||
| export type WikiPageAttributesFragment = { | ||||
|   __typename?: "WikiPage"; | ||||
|   slug: string; | ||||
| @ -6804,6 +6864,196 @@ export type GetVideosQuery = { | ||||
|   } | null; | ||||
| }; | ||||
| 
 | ||||
| export type GetWeaponQueryVariables = Exact<{ | ||||
|   id?: InputMaybe<Scalars["ID"]>; | ||||
| }>; | ||||
| 
 | ||||
| export type GetWeaponQuery = { | ||||
|   __typename?: "Query"; | ||||
|   weaponStory?: { | ||||
|     __typename?: "WeaponStoryEntityResponse"; | ||||
|     data?: { | ||||
|       __typename?: "WeaponStoryEntity"; | ||||
|       id?: string | null; | ||||
|       attributes?: { | ||||
|         __typename?: "WeaponStory"; | ||||
|         slug: string; | ||||
|         thumbnail?: { | ||||
|           __typename?: "UploadFileEntityResponse"; | ||||
|           data?: { | ||||
|             __typename?: "UploadFileEntity"; | ||||
|             attributes?: { | ||||
|               __typename?: "UploadFile"; | ||||
|               name: string; | ||||
|               alternativeText?: string | null; | ||||
|               caption?: string | null; | ||||
|               width?: number | null; | ||||
|               height?: number | null; | ||||
|               url: string; | ||||
|             } | null; | ||||
|           } | null; | ||||
|         } | null; | ||||
|         type?: { | ||||
|           __typename?: "WeaponStoryTypeEntityResponse"; | ||||
|           data?: { | ||||
|             __typename?: "WeaponStoryTypeEntity"; | ||||
|             id?: string | null; | ||||
|             attributes?: { | ||||
|               __typename?: "WeaponStoryType"; | ||||
|               slug: string; | ||||
|               translations?: Array<{ | ||||
|                 __typename?: "ComponentTranslationsWeaponStoryType"; | ||||
|                 name?: string | null; | ||||
|                 language?: { | ||||
|                   __typename?: "LanguageEntityResponse"; | ||||
|                   data?: { | ||||
|                     __typename?: "LanguageEntity"; | ||||
|                     attributes?: { __typename?: "Language"; code: string } | null; | ||||
|                   } | null; | ||||
|                 } | null; | ||||
|               } | null> | null; | ||||
|             } | null; | ||||
|           } | null; | ||||
|         } | null; | ||||
|         name?: Array<{ | ||||
|           __typename?: "ComponentTranslationsWeaponStory"; | ||||
|           id: string; | ||||
|           name?: string | null; | ||||
|           language?: { | ||||
|             __typename?: "LanguageEntityResponse"; | ||||
|             data?: { | ||||
|               __typename?: "LanguageEntity"; | ||||
|               attributes?: { __typename?: "Language"; code: string } | null; | ||||
|             } | null; | ||||
|           } | null; | ||||
|         } | null> | null; | ||||
|         stories?: Array<{ | ||||
|           __typename?: "ComponentCollectionsComponentWeaponStory"; | ||||
|           id: string; | ||||
|           categories?: { | ||||
|             __typename?: "CategoryRelationResponseCollection"; | ||||
|             data: Array<{ | ||||
|               __typename?: "CategoryEntity"; | ||||
|               id?: string | null; | ||||
|               attributes?: { __typename?: "Category"; short: string } | null; | ||||
|             }>; | ||||
|           } | null; | ||||
|           translations?: Array<{ | ||||
|             __typename?: "ComponentTranslationsWeaponStoryStory"; | ||||
|             description?: string | null; | ||||
|             level_1?: string | null; | ||||
|             level_2?: string | null; | ||||
|             level_3?: string | null; | ||||
|             level_4?: string | null; | ||||
|             status: Enum_Componenttranslationsweaponstorystory_Status; | ||||
|             language?: { | ||||
|               __typename?: "LanguageEntityResponse"; | ||||
|               data?: { | ||||
|                 __typename?: "LanguageEntity"; | ||||
|                 attributes?: { __typename?: "Language"; code: string } | null; | ||||
|               } | null; | ||||
|             } | null; | ||||
|           } | null> | null; | ||||
|         } | null> | null; | ||||
|       } | null; | ||||
|     } | null; | ||||
|   } | null; | ||||
| }; | ||||
| 
 | ||||
| export type GetWeaponsQueryVariables = Exact<{ [key: string]: never }>; | ||||
| 
 | ||||
| export type GetWeaponsQuery = { | ||||
|   __typename?: "Query"; | ||||
|   weaponStories?: { | ||||
|     __typename?: "WeaponStoryEntityResponseCollection"; | ||||
|     data: Array<{ | ||||
|       __typename?: "WeaponStoryEntity"; | ||||
|       id?: string | null; | ||||
|       attributes?: { | ||||
|         __typename?: "WeaponStory"; | ||||
|         slug: string; | ||||
|         thumbnail?: { | ||||
|           __typename?: "UploadFileEntityResponse"; | ||||
|           data?: { | ||||
|             __typename?: "UploadFileEntity"; | ||||
|             attributes?: { | ||||
|               __typename?: "UploadFile"; | ||||
|               name: string; | ||||
|               alternativeText?: string | null; | ||||
|               caption?: string | null; | ||||
|               width?: number | null; | ||||
|               height?: number | null; | ||||
|               url: string; | ||||
|             } | null; | ||||
|           } | null; | ||||
|         } | null; | ||||
|         type?: { | ||||
|           __typename?: "WeaponStoryTypeEntityResponse"; | ||||
|           data?: { | ||||
|             __typename?: "WeaponStoryTypeEntity"; | ||||
|             id?: string | null; | ||||
|             attributes?: { | ||||
|               __typename?: "WeaponStoryType"; | ||||
|               slug: string; | ||||
|               translations?: Array<{ | ||||
|                 __typename?: "ComponentTranslationsWeaponStoryType"; | ||||
|                 name?: string | null; | ||||
|                 language?: { | ||||
|                   __typename?: "LanguageEntityResponse"; | ||||
|                   data?: { | ||||
|                     __typename?: "LanguageEntity"; | ||||
|                     attributes?: { __typename?: "Language"; code: string } | null; | ||||
|                   } | null; | ||||
|                 } | null; | ||||
|               } | null> | null; | ||||
|             } | null; | ||||
|           } | null; | ||||
|         } | null; | ||||
|         name?: Array<{ | ||||
|           __typename?: "ComponentTranslationsWeaponStory"; | ||||
|           id: string; | ||||
|           name?: string | null; | ||||
|           language?: { | ||||
|             __typename?: "LanguageEntityResponse"; | ||||
|             data?: { | ||||
|               __typename?: "LanguageEntity"; | ||||
|               attributes?: { __typename?: "Language"; code: string } | null; | ||||
|             } | null; | ||||
|           } | null; | ||||
|         } | null> | null; | ||||
|         stories?: Array<{ | ||||
|           __typename?: "ComponentCollectionsComponentWeaponStory"; | ||||
|           id: string; | ||||
|           categories?: { | ||||
|             __typename?: "CategoryRelationResponseCollection"; | ||||
|             data: Array<{ | ||||
|               __typename?: "CategoryEntity"; | ||||
|               id?: string | null; | ||||
|               attributes?: { __typename?: "Category"; short: string } | null; | ||||
|             }>; | ||||
|           } | null; | ||||
|           translations?: Array<{ | ||||
|             __typename?: "ComponentTranslationsWeaponStoryStory"; | ||||
|             description?: string | null; | ||||
|             level_1?: string | null; | ||||
|             level_2?: string | null; | ||||
|             level_3?: string | null; | ||||
|             level_4?: string | null; | ||||
|             status: Enum_Componenttranslationsweaponstorystory_Status; | ||||
|             language?: { | ||||
|               __typename?: "LanguageEntityResponse"; | ||||
|               data?: { | ||||
|                 __typename?: "LanguageEntity"; | ||||
|                 attributes?: { __typename?: "Language"; code: string } | null; | ||||
|               } | null; | ||||
|             } | null; | ||||
|           } | null> | null; | ||||
|         } | null> | null; | ||||
|       } | null; | ||||
|     }>; | ||||
|   } | null; | ||||
| }; | ||||
| 
 | ||||
| export type GetWikiPageQueryVariables = Exact<{ | ||||
|   id?: InputMaybe<Scalars["ID"]>; | ||||
| }>; | ||||
| @ -7289,6 +7539,74 @@ export const VideoAttributesFragmentDoc = gql` | ||||
|     duration | ||||
|   } | ||||
| `;
 | ||||
| export const WeaponAttributesFragmentDoc = gql` | ||||
|   fragment weaponAttributes on WeaponStory { | ||||
|     thumbnail { | ||||
|       data { | ||||
|         attributes { | ||||
|           ...uploadImage | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     type { | ||||
|       data { | ||||
|         id | ||||
|         attributes { | ||||
|           slug | ||||
|           translations(filters: { language: { code: { eq: "en" } } }) { | ||||
|             name | ||||
|             language { | ||||
|               data { | ||||
|                 attributes { | ||||
|                   code | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     name(pagination: { limit: -1 }) { | ||||
|       id | ||||
|       name | ||||
|       language { | ||||
|         data { | ||||
|           attributes { | ||||
|             code | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     slug | ||||
|     stories(pagination: { limit: -1 }) { | ||||
|       id | ||||
|       categories(pagination: { limit: -1 }) { | ||||
|         data { | ||||
|           id | ||||
|           attributes { | ||||
|             short | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       translations(pagination: { limit: -1 }) { | ||||
|         description | ||||
|         level_1 | ||||
|         level_2 | ||||
|         level_3 | ||||
|         level_4 | ||||
|         status | ||||
|         language { | ||||
|           data { | ||||
|             attributes { | ||||
|               code | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   ${UploadImageFragmentDoc} | ||||
| `;
 | ||||
| export const WikiPageAttributesFragmentDoc = gql` | ||||
|   fragment wikiPageAttributes on WikiPage { | ||||
|     slug | ||||
| @ -7462,6 +7780,32 @@ export const GetVideosDocument = gql` | ||||
|   } | ||||
|   ${VideoAttributesFragmentDoc} | ||||
| `;
 | ||||
| export const GetWeaponDocument = gql` | ||||
|   query getWeapon($id: ID) { | ||||
|     weaponStory(id: $id) { | ||||
|       data { | ||||
|         id | ||||
|         attributes { | ||||
|           ...weaponAttributes | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   ${WeaponAttributesFragmentDoc} | ||||
| `;
 | ||||
| export const GetWeaponsDocument = gql` | ||||
|   query getWeapons { | ||||
|     weaponStories(pagination: { limit: -1 }) { | ||||
|       data { | ||||
|         id | ||||
|         attributes { | ||||
|           ...weaponAttributes | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   ${WeaponAttributesFragmentDoc} | ||||
| `;
 | ||||
| export const GetWikiPageDocument = gql` | ||||
|   query getWikiPage($id: ID) { | ||||
|     wikiPage(id: $id) { | ||||
| @ -7611,6 +7955,34 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper = | ||||
|         "query" | ||||
|       ); | ||||
|     }, | ||||
|     getWeapon( | ||||
|       variables?: GetWeaponQueryVariables, | ||||
|       requestHeaders?: Dom.RequestInit["headers"] | ||||
|     ): Promise<GetWeaponQuery> { | ||||
|       return withWrapper( | ||||
|         (wrappedRequestHeaders) => | ||||
|           client.request<GetWeaponQuery>(GetWeaponDocument, variables, { | ||||
|             ...requestHeaders, | ||||
|             ...wrappedRequestHeaders, | ||||
|           }), | ||||
|         "getWeapon", | ||||
|         "query" | ||||
|       ); | ||||
|     }, | ||||
|     getWeapons( | ||||
|       variables?: GetWeaponsQueryVariables, | ||||
|       requestHeaders?: Dom.RequestInit["headers"] | ||||
|     ): Promise<GetWeaponsQuery> { | ||||
|       return withWrapper( | ||||
|         (wrappedRequestHeaders) => | ||||
|           client.request<GetWeaponsQuery>(GetWeaponsDocument, variables, { | ||||
|             ...requestHeaders, | ||||
|             ...wrappedRequestHeaders, | ||||
|           }), | ||||
|         "getWeapons", | ||||
|         "query" | ||||
|       ); | ||||
|     }, | ||||
|     getWikiPage( | ||||
|       variables?: GetWikiPageQueryVariables, | ||||
|       requestHeaders?: Dom.RequestInit["headers"] | ||||
|  | ||||
| @ -4,10 +4,12 @@ import { | ||||
|   GetLibraryItemQuery, | ||||
|   GetPostQuery, | ||||
|   GetVideoQuery, | ||||
|   GetWeaponQuery, | ||||
|   GetWikiPageQuery, | ||||
|   LibraryItemAttributesFragment, | ||||
|   PostAttributesFragment, | ||||
|   VideoAttributesFragment, | ||||
|   WeaponAttributesFragment, | ||||
|   WikiPageAttributesFragment, | ||||
| } from "./generated"; | ||||
| 
 | ||||
| @ -24,7 +26,7 @@ export interface MeiliContent | ||||
|   id: string; | ||||
|   translations: (Omit< | ||||
|     NonNullable<NonNullable<ContentAttributesFragment["translations"]>[number]>, | ||||
|     "text_set" | "description" | ||||
|     "description" | "text_set" | ||||
|   > & { | ||||
|     displayable_description?: string | null; | ||||
|   })[]; | ||||
| @ -52,35 +54,60 @@ export interface MeiliWikiPage extends Omit<WikiPageAttributesFragment, "transla | ||||
|   })[]; | ||||
| } | ||||
| 
 | ||||
| type WeaponAttributesTranslation = NonNullable< | ||||
|   NonNullable< | ||||
|     NonNullable<NonNullable<WeaponAttributesFragment["stories"]>[number]>["translations"] | ||||
|   >[number] | ||||
| >; | ||||
| 
 | ||||
| export interface MeiliWeapon extends Omit<WeaponAttributesFragment, "name" | "stories"> { | ||||
|   id: string; | ||||
|   categories: NonNullable< | ||||
|     NonNullable<NonNullable<WeaponAttributesFragment["stories"]>[number]>["categories"] | ||||
|   >["data"]; | ||||
|   translations: { | ||||
|     id: NonNullable<NonNullable<WeaponAttributesFragment["stories"]>[number]>["id"]; | ||||
|     names: string[]; | ||||
|     description: string; | ||||
|     language: WeaponAttributesTranslation["language"]; | ||||
|   }[]; | ||||
| } | ||||
| 
 | ||||
| export enum MeiliIndices { | ||||
|   LIBRARY_ITEM = "library-item", | ||||
|   CONTENT = "content", | ||||
|   VIDEOS = "video", | ||||
|   POST = "post", | ||||
|   WIKI_PAGE = "wiki-page", | ||||
|   WEAPON = "weapon-story", | ||||
| } | ||||
| 
 | ||||
| export type MeiliDocumentsType = | ||||
|   | { | ||||
|       index: MeiliIndices.LIBRARY_ITEM; | ||||
|       documents: MeiliLibraryItem; | ||||
|       strapi: GetLibraryItemQuery["libraryItem"]; | ||||
|     } | ||||
|   | { | ||||
|       index: MeiliIndices.CONTENT; | ||||
|       documents: MeiliContent; | ||||
|       strapi: GetContentQuery["content"]; | ||||
|     } | ||||
|   | { | ||||
|       index: MeiliIndices.VIDEOS; | ||||
|       documents: MeiliVideo; | ||||
|       strapi: GetVideoQuery["video"]; | ||||
|       index: MeiliIndices.LIBRARY_ITEM; | ||||
|       documents: MeiliLibraryItem; | ||||
|       strapi: GetLibraryItemQuery["libraryItem"]; | ||||
|     } | ||||
|   | { | ||||
|       index: MeiliIndices.POST; | ||||
|       documents: MeiliPost; | ||||
|       strapi: GetPostQuery["post"]; | ||||
|     } | ||||
|   | { | ||||
|       index: MeiliIndices.VIDEOS; | ||||
|       documents: MeiliVideo; | ||||
|       strapi: GetVideoQuery["video"]; | ||||
|     } | ||||
|   | { | ||||
|       index: MeiliIndices.WEAPON; | ||||
|       documents: MeiliWeapon; | ||||
|       strapi: GetWeaponQuery["weaponStory"]; | ||||
|     } | ||||
|   | { | ||||
|       index: MeiliIndices.WIKI_PAGE; | ||||
|       documents: MeiliWikiPage; | ||||
|  | ||||
| @ -2,6 +2,7 @@ import { | ||||
|   GetChronicleQuery, | ||||
|   GetContentTextQuery, | ||||
|   GetPostQuery, | ||||
|   GetWeaponQuery, | ||||
|   GetWikiPageQuery, | ||||
| } from "graphql/generated"; | ||||
| 
 | ||||
| @ -45,6 +46,28 @@ export interface ChronicleWithTranslations extends Omit<Chronicle, "translations | ||||
| 
 | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export type Weapon = NonNullable< | ||||
|   NonNullable<NonNullable<GetWeaponQuery["weaponStories"]>["data"][number]>["attributes"] | ||||
| >; | ||||
| 
 | ||||
| type WeaponStory = NonNullable<NonNullable<Weapon["stories"]>[number]>; | ||||
| 
 | ||||
| export interface WeaponStoryWithTranslations extends Omit<WeaponStory, "translations"> { | ||||
|   translations: NonNullable<NonNullable<WeaponStory>["translations"]>; | ||||
| } | ||||
| 
 | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export type WeaponGroupPreview = NonNullable< | ||||
|   NonNullable< | ||||
|     NonNullable< | ||||
|       NonNullable<NonNullable<NonNullable<Weapon["weapon_group"]>["data"]>["attributes"]>["weapons"] | ||||
|     >["data"][number]["attributes"] | ||||
|   > | ||||
| >; | ||||
| 
 | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export enum LibraryItemUserStatus { | ||||
|   None = 0, | ||||
|   Want = 1, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint