Use Jotai instead of React Context (#65)
* Turn React Context into Jotai * Finish converting the remaining contexts into Jotai * Changed the readme * Fixed build * Provider hell be gone * Fixed build
This commit is contained in:
		
							parent
							
								
									f4ff30e279
								
							
						
					
					
						commit
						35b58982d0
					
				| @ -39,7 +39,8 @@ | ||||
|   - Support for Container Queries (media queries at the element level) | ||||
|   - The website has a three-column layout, which turns into one-column + 2 toggleable side-menus if the screen is too narrow. | ||||
|   - Check out our [Design System Showcase](https://accords-library.com/dev/showcase/design-system) | ||||
| - State Management: [React Context](https://reactjs.org/docs/context.html) | ||||
| - State Management: [Jōtai](https://jotai.org/) | ||||
|   - Jōtai is a small-weighted library for atomic state management | ||||
|   - Persistent app state using LocalStorage and SessionStorage | ||||
| - Accessibility | ||||
|   - Gestures using [react-swipeable](https://www.npmjs.com/package/react-swipeable) | ||||
|  | ||||
							
								
								
									
										232
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										232
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -16,6 +16,7 @@ | ||||
|         "autoprefixer": "^10.4.13", | ||||
|         "cuid": "^2.1.8", | ||||
|         "graphql-request": "^5.0.0", | ||||
|         "jotai": "^1.9.0", | ||||
|         "markdown-to-jsx": "^7.1.7", | ||||
|         "next": "^12.3.1", | ||||
|         "nodemailer": "^6.8.0", | ||||
| @ -65,7 +66,7 @@ | ||||
|       "version": "2.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", | ||||
|       "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@jridgewell/gen-mapping": "^0.1.0", | ||||
|         "@jridgewell/trace-mapping": "^0.3.9" | ||||
| @ -78,7 +79,7 @@ | ||||
|       "version": "0.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", | ||||
|       "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@jridgewell/set-array": "^1.0.0", | ||||
|         "@jridgewell/sourcemap-codec": "^1.4.10" | ||||
| @ -134,7 +135,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", | ||||
|       "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/highlight": "^7.18.6" | ||||
|       }, | ||||
| @ -146,7 +147,7 @@ | ||||
|       "version": "7.19.4", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", | ||||
|       "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=6.9.0" | ||||
|       } | ||||
| @ -155,7 +156,7 @@ | ||||
|       "version": "7.19.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", | ||||
|       "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@ampproject/remapping": "^2.1.0", | ||||
|         "@babel/code-frame": "^7.18.6", | ||||
| @ -185,7 +186,7 @@ | ||||
|       "version": "2.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", | ||||
|       "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "bin": { | ||||
|         "json5": "lib/cli.js" | ||||
|       }, | ||||
| @ -197,7 +198,7 @@ | ||||
|       "version": "6.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", | ||||
|       "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "bin": { | ||||
|         "semver": "bin/semver.js" | ||||
|       } | ||||
| @ -206,7 +207,7 @@ | ||||
|       "version": "7.19.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", | ||||
|       "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/types": "^7.19.4", | ||||
|         "@jridgewell/gen-mapping": "^0.3.2", | ||||
| @ -232,7 +233,7 @@ | ||||
|       "version": "7.19.3", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", | ||||
|       "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/compat-data": "^7.19.3", | ||||
|         "@babel/helper-validator-option": "^7.18.6", | ||||
| @ -250,7 +251,7 @@ | ||||
|       "version": "6.3.0", | ||||
|       "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", | ||||
|       "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "bin": { | ||||
|         "semver": "bin/semver.js" | ||||
|       } | ||||
| @ -280,7 +281,7 @@ | ||||
|       "version": "7.18.9", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", | ||||
|       "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=6.9.0" | ||||
|       } | ||||
| @ -289,7 +290,7 @@ | ||||
|       "version": "7.19.0", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", | ||||
|       "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/template": "^7.18.10", | ||||
|         "@babel/types": "^7.19.0" | ||||
| @ -302,7 +303,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", | ||||
|       "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/types": "^7.18.6" | ||||
|       }, | ||||
| @ -326,7 +327,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", | ||||
|       "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/types": "^7.18.6" | ||||
|       }, | ||||
| @ -338,7 +339,7 @@ | ||||
|       "version": "7.19.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", | ||||
|       "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/helper-environment-visitor": "^7.18.9", | ||||
|         "@babel/helper-module-imports": "^7.18.6", | ||||
| @ -394,7 +395,7 @@ | ||||
|       "version": "7.19.4", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", | ||||
|       "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/types": "^7.19.4" | ||||
|       }, | ||||
| @ -418,7 +419,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", | ||||
|       "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/types": "^7.18.6" | ||||
|       }, | ||||
| @ -430,7 +431,7 @@ | ||||
|       "version": "7.19.4", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", | ||||
|       "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=6.9.0" | ||||
|       } | ||||
| @ -439,7 +440,7 @@ | ||||
|       "version": "7.19.1", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", | ||||
|       "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=6.9.0" | ||||
|       } | ||||
| @ -448,7 +449,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", | ||||
|       "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=6.9.0" | ||||
|       } | ||||
| @ -457,7 +458,7 @@ | ||||
|       "version": "7.19.4", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", | ||||
|       "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/template": "^7.18.10", | ||||
|         "@babel/traverse": "^7.19.4", | ||||
| @ -471,7 +472,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", | ||||
|       "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/helper-validator-identifier": "^7.18.6", | ||||
|         "chalk": "^2.0.0", | ||||
| @ -485,7 +486,7 @@ | ||||
|       "version": "3.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", | ||||
|       "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "color-convert": "^1.9.0" | ||||
|       }, | ||||
| @ -497,7 +498,7 @@ | ||||
|       "version": "2.4.2", | ||||
|       "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", | ||||
|       "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "ansi-styles": "^3.2.1", | ||||
|         "escape-string-regexp": "^1.0.5", | ||||
| @ -511,7 +512,7 @@ | ||||
|       "version": "1.9.3", | ||||
|       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", | ||||
|       "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "color-name": "1.1.3" | ||||
|       } | ||||
| @ -520,13 +521,13 @@ | ||||
|       "version": "1.1.3", | ||||
|       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", | ||||
|       "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "node_modules/@babel/highlight/node_modules/escape-string-regexp": { | ||||
|       "version": "1.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", | ||||
|       "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=0.8.0" | ||||
|       } | ||||
| @ -535,7 +536,7 @@ | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", | ||||
|       "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=4" | ||||
|       } | ||||
| @ -544,7 +545,7 @@ | ||||
|       "version": "5.5.0", | ||||
|       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", | ||||
|       "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "has-flag": "^3.0.0" | ||||
|       }, | ||||
| @ -556,7 +557,7 @@ | ||||
|       "version": "7.19.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", | ||||
|       "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "bin": { | ||||
|         "parser": "bin/babel-parser.js" | ||||
|       }, | ||||
| @ -1000,7 +1001,7 @@ | ||||
|       "version": "7.18.10", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", | ||||
|       "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/code-frame": "^7.18.6", | ||||
|         "@babel/parser": "^7.18.10", | ||||
| @ -1014,7 +1015,7 @@ | ||||
|       "version": "7.19.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", | ||||
|       "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/code-frame": "^7.18.6", | ||||
|         "@babel/generator": "^7.19.6", | ||||
| @ -1035,7 +1036,7 @@ | ||||
|       "version": "7.19.4", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", | ||||
|       "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@babel/helper-string-parser": "^7.19.4", | ||||
|         "@babel/helper-validator-identifier": "^7.19.1", | ||||
| @ -2160,7 +2161,7 @@ | ||||
|       "version": "0.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", | ||||
|       "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@jridgewell/set-array": "^1.0.1", | ||||
|         "@jridgewell/sourcemap-codec": "^1.4.10", | ||||
| @ -2174,7 +2175,7 @@ | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", | ||||
|       "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=6.0.0" | ||||
|       } | ||||
| @ -2183,7 +2184,7 @@ | ||||
|       "version": "1.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", | ||||
|       "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=6.0.0" | ||||
|       } | ||||
| @ -2192,13 +2193,13 @@ | ||||
|       "version": "1.4.14", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", | ||||
|       "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "node_modules/@jridgewell/trace-mapping": { | ||||
|       "version": "0.3.15", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", | ||||
|       "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "@jridgewell/resolve-uri": "^3.0.3", | ||||
|         "@jridgewell/sourcemap-codec": "^1.4.10" | ||||
| @ -3844,7 +3845,7 @@ | ||||
|       "version": "1.9.0", | ||||
|       "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", | ||||
|       "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "node_modules/core-js-pure": { | ||||
|       "version": "3.21.1", | ||||
| @ -3971,7 +3972,7 @@ | ||||
|       "version": "4.3.4", | ||||
|       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", | ||||
|       "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "dependencies": { | ||||
|         "ms": "2.1.2" | ||||
|       }, | ||||
| @ -5463,7 +5464,7 @@ | ||||
|       "version": "1.0.0-beta.2", | ||||
|       "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", | ||||
|       "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=6.9.0" | ||||
|       } | ||||
| @ -5543,7 +5544,7 @@ | ||||
|       "version": "11.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", | ||||
|       "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=4" | ||||
|       } | ||||
| @ -6298,6 +6299,51 @@ | ||||
|         "ws": "*" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/jotai": { | ||||
|       "version": "1.9.0", | ||||
|       "resolved": "https://registry.npmjs.org/jotai/-/jotai-1.9.0.tgz", | ||||
|       "integrity": "sha512-XYpSlxbxujUCTA8PNkzfj3+zF6XVyzo6XMZIEic3gXQCpTDPfmqhUj2FR8kwUACK5weosFrSBhesrjwfILUCoQ==", | ||||
|       "engines": { | ||||
|         "node": ">=12.7.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "@babel/core": "*", | ||||
|         "@babel/template": "*", | ||||
|         "immer": "*", | ||||
|         "jotai-tanstack-query": "*", | ||||
|         "jotai-urql": "*", | ||||
|         "optics-ts": "*", | ||||
|         "react": ">=16.8", | ||||
|         "valtio": "*", | ||||
|         "xstate": "*" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "@babel/core": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "@babel/template": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "immer": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "jotai-tanstack-query": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "jotai-urql": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "optics-ts": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "valtio": { | ||||
|           "optional": true | ||||
|         }, | ||||
|         "xstate": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/js-sdsl": { | ||||
|       "version": "4.1.4", | ||||
|       "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", | ||||
| @ -6325,7 +6371,7 @@ | ||||
|       "version": "2.5.2", | ||||
|       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", | ||||
|       "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "bin": { | ||||
|         "jsesc": "bin/jsesc" | ||||
|       }, | ||||
| @ -6825,7 +6871,7 @@ | ||||
|       "version": "2.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | ||||
|       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "node_modules/nanoid": { | ||||
|       "version": "3.3.4", | ||||
| @ -8541,7 +8587,7 @@ | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", | ||||
|       "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "engines": { | ||||
|         "node": ">=4" | ||||
|       } | ||||
| @ -9219,7 +9265,7 @@ | ||||
|       "version": "2.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", | ||||
|       "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@jridgewell/gen-mapping": "^0.1.0", | ||||
|         "@jridgewell/trace-mapping": "^0.3.9" | ||||
| @ -9229,7 +9275,7 @@ | ||||
|           "version": "0.1.1", | ||||
|           "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", | ||||
|           "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", | ||||
|           "dev": true, | ||||
|           "devOptional": true, | ||||
|           "requires": { | ||||
|             "@jridgewell/set-array": "^1.0.0", | ||||
|             "@jridgewell/sourcemap-codec": "^1.4.10" | ||||
| @ -9275,7 +9321,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", | ||||
|       "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/highlight": "^7.18.6" | ||||
|       } | ||||
| @ -9284,13 +9330,13 @@ | ||||
|       "version": "7.19.4", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", | ||||
|       "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "@babel/core": { | ||||
|       "version": "7.19.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", | ||||
|       "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@ampproject/remapping": "^2.1.0", | ||||
|         "@babel/code-frame": "^7.18.6", | ||||
| @ -9313,13 +9359,13 @@ | ||||
|           "version": "2.2.1", | ||||
|           "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", | ||||
|           "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", | ||||
|           "dev": true | ||||
|           "devOptional": true | ||||
|         }, | ||||
|         "semver": { | ||||
|           "version": "6.3.0", | ||||
|           "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", | ||||
|           "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", | ||||
|           "dev": true | ||||
|           "devOptional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
| @ -9327,7 +9373,7 @@ | ||||
|       "version": "7.19.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", | ||||
|       "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/types": "^7.19.4", | ||||
|         "@jridgewell/gen-mapping": "^0.3.2", | ||||
| @ -9347,7 +9393,7 @@ | ||||
|       "version": "7.19.3", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", | ||||
|       "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/compat-data": "^7.19.3", | ||||
|         "@babel/helper-validator-option": "^7.18.6", | ||||
| @ -9359,7 +9405,7 @@ | ||||
|           "version": "6.3.0", | ||||
|           "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", | ||||
|           "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", | ||||
|           "dev": true | ||||
|           "devOptional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
| @ -9382,13 +9428,13 @@ | ||||
|       "version": "7.18.9", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", | ||||
|       "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "@babel/helper-function-name": { | ||||
|       "version": "7.19.0", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", | ||||
|       "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/template": "^7.18.10", | ||||
|         "@babel/types": "^7.19.0" | ||||
| @ -9398,7 +9444,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", | ||||
|       "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/types": "^7.18.6" | ||||
|       } | ||||
| @ -9416,7 +9462,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", | ||||
|       "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/types": "^7.18.6" | ||||
|       } | ||||
| @ -9425,7 +9471,7 @@ | ||||
|       "version": "7.19.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", | ||||
|       "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/helper-environment-visitor": "^7.18.9", | ||||
|         "@babel/helper-module-imports": "^7.18.6", | ||||
| @ -9469,7 +9515,7 @@ | ||||
|       "version": "7.19.4", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", | ||||
|       "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/types": "^7.19.4" | ||||
|       } | ||||
| @ -9487,7 +9533,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", | ||||
|       "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/types": "^7.18.6" | ||||
|       } | ||||
| @ -9496,25 +9542,25 @@ | ||||
|       "version": "7.19.4", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", | ||||
|       "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "@babel/helper-validator-identifier": { | ||||
|       "version": "7.19.1", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", | ||||
|       "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "@babel/helper-validator-option": { | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", | ||||
|       "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "@babel/helpers": { | ||||
|       "version": "7.19.4", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", | ||||
|       "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/template": "^7.18.10", | ||||
|         "@babel/traverse": "^7.19.4", | ||||
| @ -9525,7 +9571,7 @@ | ||||
|       "version": "7.18.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", | ||||
|       "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/helper-validator-identifier": "^7.18.6", | ||||
|         "chalk": "^2.0.0", | ||||
| @ -9536,7 +9582,7 @@ | ||||
|           "version": "3.2.1", | ||||
|           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", | ||||
|           "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", | ||||
|           "dev": true, | ||||
|           "devOptional": true, | ||||
|           "requires": { | ||||
|             "color-convert": "^1.9.0" | ||||
|           } | ||||
| @ -9545,7 +9591,7 @@ | ||||
|           "version": "2.4.2", | ||||
|           "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", | ||||
|           "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", | ||||
|           "dev": true, | ||||
|           "devOptional": true, | ||||
|           "requires": { | ||||
|             "ansi-styles": "^3.2.1", | ||||
|             "escape-string-regexp": "^1.0.5", | ||||
| @ -9556,7 +9602,7 @@ | ||||
|           "version": "1.9.3", | ||||
|           "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", | ||||
|           "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", | ||||
|           "dev": true, | ||||
|           "devOptional": true, | ||||
|           "requires": { | ||||
|             "color-name": "1.1.3" | ||||
|           } | ||||
| @ -9565,25 +9611,25 @@ | ||||
|           "version": "1.1.3", | ||||
|           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", | ||||
|           "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", | ||||
|           "dev": true | ||||
|           "devOptional": true | ||||
|         }, | ||||
|         "escape-string-regexp": { | ||||
|           "version": "1.0.5", | ||||
|           "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", | ||||
|           "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", | ||||
|           "dev": true | ||||
|           "devOptional": true | ||||
|         }, | ||||
|         "has-flag": { | ||||
|           "version": "3.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", | ||||
|           "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", | ||||
|           "dev": true | ||||
|           "devOptional": true | ||||
|         }, | ||||
|         "supports-color": { | ||||
|           "version": "5.5.0", | ||||
|           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", | ||||
|           "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", | ||||
|           "dev": true, | ||||
|           "devOptional": true, | ||||
|           "requires": { | ||||
|             "has-flag": "^3.0.0" | ||||
|           } | ||||
| @ -9594,7 +9640,7 @@ | ||||
|       "version": "7.19.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", | ||||
|       "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "@babel/plugin-proposal-class-properties": { | ||||
|       "version": "7.18.6", | ||||
| @ -9876,7 +9922,7 @@ | ||||
|       "version": "7.18.10", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", | ||||
|       "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/code-frame": "^7.18.6", | ||||
|         "@babel/parser": "^7.18.10", | ||||
| @ -9887,7 +9933,7 @@ | ||||
|       "version": "7.19.6", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", | ||||
|       "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/code-frame": "^7.18.6", | ||||
|         "@babel/generator": "^7.19.6", | ||||
| @ -9905,7 +9951,7 @@ | ||||
|       "version": "7.19.4", | ||||
|       "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", | ||||
|       "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@babel/helper-string-parser": "^7.19.4", | ||||
|         "@babel/helper-validator-identifier": "^7.19.1", | ||||
| @ -10885,7 +10931,7 @@ | ||||
|       "version": "0.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", | ||||
|       "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@jridgewell/set-array": "^1.0.1", | ||||
|         "@jridgewell/sourcemap-codec": "^1.4.10", | ||||
| @ -10896,25 +10942,25 @@ | ||||
|       "version": "3.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", | ||||
|       "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "@jridgewell/set-array": { | ||||
|       "version": "1.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", | ||||
|       "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "@jridgewell/sourcemap-codec": { | ||||
|       "version": "1.4.14", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", | ||||
|       "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "@jridgewell/trace-mapping": { | ||||
|       "version": "0.3.15", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", | ||||
|       "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "@jridgewell/resolve-uri": "^3.0.3", | ||||
|         "@jridgewell/sourcemap-codec": "^1.4.10" | ||||
| @ -12104,7 +12150,7 @@ | ||||
|       "version": "1.9.0", | ||||
|       "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", | ||||
|       "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "core-js-pure": { | ||||
|       "version": "3.21.1", | ||||
| @ -12205,7 +12251,7 @@ | ||||
|       "version": "4.3.4", | ||||
|       "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", | ||||
|       "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", | ||||
|       "dev": true, | ||||
|       "devOptional": true, | ||||
|       "requires": { | ||||
|         "ms": "2.1.2" | ||||
|       } | ||||
| @ -13250,7 +13296,7 @@ | ||||
|       "version": "1.0.0-beta.2", | ||||
|       "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", | ||||
|       "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "get-caller-file": { | ||||
|       "version": "2.0.5", | ||||
| @ -13306,7 +13352,7 @@ | ||||
|       "version": "11.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", | ||||
|       "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "globby": { | ||||
|       "version": "11.1.0", | ||||
| @ -13856,6 +13902,12 @@ | ||||
|       "dev": true, | ||||
|       "requires": {} | ||||
|     }, | ||||
|     "jotai": { | ||||
|       "version": "1.9.0", | ||||
|       "resolved": "https://registry.npmjs.org/jotai/-/jotai-1.9.0.tgz", | ||||
|       "integrity": "sha512-XYpSlxbxujUCTA8PNkzfj3+zF6XVyzo6XMZIEic3gXQCpTDPfmqhUj2FR8kwUACK5weosFrSBhesrjwfILUCoQ==", | ||||
|       "requires": {} | ||||
|     }, | ||||
|     "js-sdsl": { | ||||
|       "version": "4.1.4", | ||||
|       "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", | ||||
| @ -13880,7 +13932,7 @@ | ||||
|       "version": "2.5.2", | ||||
|       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", | ||||
|       "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "json-parse-even-better-errors": { | ||||
|       "version": "2.3.1", | ||||
| @ -14280,7 +14332,7 @@ | ||||
|       "version": "2.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | ||||
|       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "nanoid": { | ||||
|       "version": "3.3.4", | ||||
| @ -15513,7 +15565,7 @@ | ||||
|       "version": "2.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", | ||||
|       "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", | ||||
|       "dev": true | ||||
|       "devOptional": true | ||||
|     }, | ||||
|     "to-regex-range": { | ||||
|       "version": "5.0.1", | ||||
|  | ||||
| @ -27,6 +27,7 @@ | ||||
|     "autoprefixer": "^10.4.13", | ||||
|     "cuid": "^2.1.8", | ||||
|     "graphql-request": "^5.0.0", | ||||
|     "jotai": "^1.9.0", | ||||
|     "markdown-to-jsx": "^7.1.7", | ||||
|     "next": "^12.3.1", | ||||
|     "nodemailer": "^6.8.0", | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| import { Ico, Icon } from "./Ico"; | ||||
| import { ToolTip } from "./ToolTip"; | ||||
| import { cJoin } from "helpers/className"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -16,7 +17,7 @@ interface Props { | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export const AnchorShare = ({ id, className }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   return ( | ||||
|     <ToolTip content={langui.copy_anchor_link} trigger="mouseenter" className="text-sm"> | ||||
|       <ToolTip content={langui.anchor_link_copied} trigger="click" className="text-sm"> | ||||
|  | ||||
| @ -7,11 +7,10 @@ import { MainPanel } from "./Panels/MainPanel"; | ||||
| import { SafariPopup } from "./Panels/SafariPopup"; | ||||
| import { isDefined, isUndefined } from "helpers/others"; | ||||
| import { cIf, cJoin } from "helpers/className"; | ||||
| import { useAppLayout } from "contexts/AppLayoutContext"; | ||||
| import { OpenGraph, TITLE_PREFIX, TITLE_SEPARATOR } from "helpers/openGraph"; | ||||
| import { Ids } from "types/ids"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter, useAtomPair } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -45,39 +44,34 @@ export const AppLayout = ({ | ||||
|   subPanelIcon = Icon.Tune, | ||||
|   contentPanelScroolbar = true, | ||||
| }: Props): JSX.Element => { | ||||
|   const { | ||||
|     mainPanelOpen, | ||||
|     mainPanelReduced, | ||||
|     menuGestures, | ||||
|     subPanelOpen, | ||||
|     setMainPanelOpen, | ||||
|     setSubPanelOpen, | ||||
|     toggleMainPanelOpen, | ||||
|     toggleSubPanelOpen, | ||||
|   } = useAppLayout(); | ||||
|   const isMainPanelReduced = useAtomGetter(atoms.layout.mainPanelReduced); | ||||
|   const [isSubPanelOpened, setSubPanelOpened] = useAtomPair(atoms.layout.subPanelOpened); | ||||
|   const [isMainPanelOpened, setMainPanelOpened] = useAtomPair(atoms.layout.mainPanelOpened); | ||||
|   const isMenuGesturesEnabled = useAtomGetter(atoms.layout.menuGesturesEnabled); | ||||
| 
 | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
| 
 | ||||
|   const { is1ColumnLayout, isScreenAtLeastXs } = useContainerQueries(); | ||||
|   const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout); | ||||
|   const isScreenAtLeastXs = useAtomGetter(atoms.containerQueries.isScreenAtLeastXs); | ||||
| 
 | ||||
|   const handlers = useSwipeable({ | ||||
|     onSwipedLeft: (SwipeEventData) => { | ||||
|       if (menuGestures) { | ||||
|       if (isMenuGesturesEnabled) { | ||||
|         if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return; | ||||
|         if (mainPanelOpen) { | ||||
|           setMainPanelOpen(false); | ||||
|         if (isMainPanelOpened) { | ||||
|           setMainPanelOpened(false); | ||||
|         } else if (isDefined(subPanel) && isDefined(contentPanel)) { | ||||
|           setSubPanelOpen(true); | ||||
|           setSubPanelOpened(true); | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     onSwipedRight: (SwipeEventData) => { | ||||
|       if (menuGestures) { | ||||
|       if (isMenuGesturesEnabled) { | ||||
|         if (SwipeEventData.velocity < SENSIBILITY_SWIPE) return; | ||||
|         if (subPanelOpen) { | ||||
|           setSubPanelOpen(false); | ||||
|         if (isSubPanelOpened) { | ||||
|           setSubPanelOpened(false); | ||||
|         } else { | ||||
|           setMainPanelOpen(true); | ||||
|           setMainPanelOpened(true); | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
| @ -99,7 +93,7 @@ export const AppLayout = ({ | ||||
|       style={{ | ||||
|         gridTemplateColumns: is1ColumnLayout | ||||
|           ? "1fr" | ||||
|           : `${mainPanelReduced ? layout.mainMenuReduced : layout.mainMenu}rem ${ | ||||
|           : `${isMainPanelReduced ? layout.mainMenuReduced : layout.mainMenu}rem ${ | ||||
|               isDefined(subPanel) ? layout.subMenu : 0 | ||||
|             }rem 1fr`,
 | ||||
|       }}> | ||||
| @ -128,7 +122,7 @@ export const AppLayout = ({ | ||||
|           `absolute inset-0 transition-filter duration-500
 | ||||
|             [grid-area:content]`,
 | ||||
|           cIf( | ||||
|             (mainPanelOpen || subPanelOpen) && is1ColumnLayout, | ||||
|             (isMainPanelOpened || isSubPanelOpened) && is1ColumnLayout, | ||||
|             "z-10 backdrop-blur", | ||||
|             "pointer-events-none touch-none" | ||||
|           ) | ||||
| @ -136,11 +130,15 @@ export const AppLayout = ({ | ||||
|         <div | ||||
|           className={cJoin( | ||||
|             "absolute inset-0 bg-shade transition-opacity duration-500", | ||||
|             cIf((mainPanelOpen || subPanelOpen) && is1ColumnLayout, "opacity-60", "opacity-0") | ||||
|             cIf( | ||||
|               (isMainPanelOpened || isSubPanelOpened) && is1ColumnLayout, | ||||
|               "opacity-60", | ||||
|               "opacity-0" | ||||
|             ) | ||||
|           )} | ||||
|           onClick={() => { | ||||
|             setMainPanelOpen(false); | ||||
|             setSubPanelOpen(false); | ||||
|             setMainPanelOpened(false); | ||||
|             setSubPanelOpened(false); | ||||
|           }} | ||||
|         /> | ||||
|       </div> | ||||
| @ -175,7 +173,7 @@ export const AppLayout = ({ | ||||
|               "[grid-area:sub]" | ||||
|             ), | ||||
|             cIf(is1ColumnLayout && isScreenAtLeastXs, "w-[min(30rem,90%)] border-l"), | ||||
|             cIf(is1ColumnLayout && !subPanelOpen && !turnSubIntoContent, "translate-x-[100vw]"), | ||||
|             cIf(is1ColumnLayout && !isSubPanelOpened && !turnSubIntoContent, "translate-x-[100vw]"), | ||||
|             cIf(is1ColumnLayout && turnSubIntoContent, "w-full border-l-0") | ||||
|           )}> | ||||
|           {subPanel} | ||||
| @ -189,7 +187,7 @@ export const AppLayout = ({ | ||||
|             transition-transform duration-300 scrollbar-none texture-paper-dots`,
 | ||||
|           cIf(is1ColumnLayout, "justify-self-start [grid-area:content]", "[grid-area:main]"), | ||||
|           cIf(is1ColumnLayout && isScreenAtLeastXs, "w-[min(30rem,90%)]"), | ||||
|           cIf(!mainPanelOpen && is1ColumnLayout, "-translate-x-full") | ||||
|           cIf(!isMainPanelOpened && is1ColumnLayout, "-translate-x-full") | ||||
|         )}> | ||||
|         <MainPanel /> | ||||
|       </div> | ||||
| @ -202,11 +200,11 @@ export const AppLayout = ({ | ||||
|           cIf(!is1ColumnLayout, "hidden") | ||||
|         )}> | ||||
|         <Ico | ||||
|           icon={mainPanelOpen ? Icon.Close : Icon.Menu} | ||||
|           icon={isMainPanelOpened ? Icon.Close : Icon.Menu} | ||||
|           className="cursor-pointer !text-2xl" | ||||
|           onClick={() => { | ||||
|             toggleMainPanelOpen(); | ||||
|             setSubPanelOpen(false); | ||||
|             setMainPanelOpened((current) => !current); | ||||
|             setSubPanelOpened(false); | ||||
|           }} | ||||
|         /> | ||||
|         <p | ||||
| @ -220,11 +218,11 @@ export const AppLayout = ({ | ||||
|         </p> | ||||
|         {isDefined(subPanel) && !turnSubIntoContent && ( | ||||
|           <Ico | ||||
|             icon={subPanelOpen ? Icon.Close : subPanelIcon} | ||||
|             icon={isSubPanelOpened ? Icon.Close : subPanelIcon} | ||||
|             className="cursor-pointer !text-2xl" | ||||
|             onClick={() => { | ||||
|               toggleSubPanelOpen(); | ||||
|               setMainPanelOpen(false); | ||||
|               setSubPanelOpened((current) => !current); | ||||
|               setMainPanelOpened(false); | ||||
|             }} | ||||
|           /> | ||||
|         )} | ||||
|  | ||||
| @ -1,9 +1,9 @@ | ||||
| import { useCallback, useEffect, useMemo, useRef, useState } from "react"; | ||||
| import { useRouter } from "next/router"; | ||||
| import { cJoin, cIf } from "helpers/className"; | ||||
| import { useTerminalContext } from "contexts/TerminalContext"; | ||||
| import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; | ||||
| import { useUserSettings } from "contexts/UserSettingsContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomSetter, useAtomPair } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -31,9 +31,11 @@ export const Terminal = ({ | ||||
|   content, | ||||
| }: Props): JSX.Element => { | ||||
|   const [childrenPaths, setChildrenPaths] = useState(propsChildrenPaths); | ||||
|   const { darkMode, setPlayerName } = useUserSettings(); | ||||
|   const { previousCommands, previousLines, setPreviousCommands, setPreviousLines } = | ||||
|     useTerminalContext(); | ||||
|   const setPlayerName = useAtomSetter(atoms.settings.playerName); | ||||
| 
 | ||||
|   const [previousCommands, setPreviousCommands] = useAtomPair(atoms.terminal.previousCommands); | ||||
|   const [previousLines, setPreviousLines] = useAtomPair(atoms.terminal.previousLines); | ||||
| 
 | ||||
|   const [line, setLine] = useState(""); | ||||
|   const [displayCurrentLine, setDisplayCurrentLine] = useState(true); | ||||
|   const [previousCommandIndex, setPreviousCommandIndex] = useState(0); | ||||
| @ -232,11 +234,7 @@ export const Terminal = ({ | ||||
|   }, [line]); | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|       className={cJoin( | ||||
|         "h-screen overflow-hidden bg-light set-theme-font-standard", | ||||
|         cIf(darkMode, "set-theme-dark", "set-theme-light") | ||||
|       )}> | ||||
|     <div className={cJoin("h-screen overflow-hidden bg-light set-theme-font-standard")}> | ||||
|       <div | ||||
|         ref={terminalWindowRef} | ||||
|         className="h-full overflow-scroll scroll-auto p-6 scrollbar-none"> | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| import { cIf, cJoin } from "helpers/className"; | ||||
| 
 | ||||
| /* | ||||
| @ -25,7 +26,7 @@ export const ContentPanel = ({ | ||||
|   children, | ||||
|   className, | ||||
| }: Props): JSX.Element => { | ||||
|   const { isContentPanelAtLeast3xl } = useContainerQueries(); | ||||
|   const isContentPanelAtLeast3xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast3xl); | ||||
|   return ( | ||||
|     <div className="grid h-full"> | ||||
|       <main | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| import { useEffect } from "react"; | ||||
| import { useHotkeys } from "react-hotkeys-hook"; | ||||
| import { useAppLayout } from "contexts/AppLayoutContext"; | ||||
| import { cIf, cJoin } from "helpers/className"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomSetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -27,13 +28,13 @@ export const Popup = ({ | ||||
|   hideBackground = false, | ||||
|   padding = true, | ||||
| }: Props): JSX.Element => { | ||||
|   const { setMenuGestures } = useAppLayout(); | ||||
|   const setMenuGesturesEnabled = useAtomSetter(atoms.layout.menuGesturesEnabled); | ||||
| 
 | ||||
|   useHotkeys("escape", () => onCloseRequest?.(), {}, [onCloseRequest]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setMenuGestures(!isVisible); | ||||
|   }, [setMenuGestures, isVisible]); | ||||
|     setMenuGesturesEnabled(!isVisible); | ||||
|   }, [isVisible, setMenuGesturesEnabled]); | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| import { cIf, cJoin } from "helpers/className"; | ||||
| 
 | ||||
| /* | ||||
| @ -13,7 +14,7 @@ interface Props { | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export const SubPanel = ({ children }: Props): JSX.Element => { | ||||
|   const { isSubPanelAtLeastXs } = useContainerQueries(); | ||||
|   const isSubPanelAtLeastXs = useAtomGetter(atoms.containerQueries.isSubPanelAtLeastXs); | ||||
|   return ( | ||||
|     <div | ||||
|       className={cJoin( | ||||
|  | ||||
| @ -6,7 +6,8 @@ import { cJoin } from "helpers/className"; | ||||
| import { prettyLanguage } from "helpers/formatters"; | ||||
| import { iterateMap } from "helpers/others"; | ||||
| import { sendAnalytics } from "helpers/analytics"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -32,7 +33,7 @@ export const LanguageSwitcher = ({ | ||||
|   onLanguageChanged, | ||||
|   showBadge = true, | ||||
| }: Props): JSX.Element => { | ||||
|   const { languages } = useLocalData(); | ||||
|   const languages = useAtomGetter(atoms.localData.languages); | ||||
|   return ( | ||||
|     <ToolTip | ||||
|       content={ | ||||
|  | ||||
| @ -3,8 +3,9 @@ import { Button } from "components/Inputs/Button"; | ||||
| import { ToolTip } from "components/ToolTip"; | ||||
| import { LibraryItemUserStatus } from "types/types"; | ||||
| import { cIf, cJoin } from "helpers/className"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useLibraryItemUserStatus } from "hooks/useLibraryItemUserStatus"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -20,7 +21,7 @@ interface Props { | ||||
| 
 | ||||
| export const PreviewCardCTAs = ({ id, expand = false }: Props): JSX.Element => { | ||||
|   const { libraryItemUserStatus, setLibraryItemUserStatus } = useLibraryItemUserStatus(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|  | ||||
| @ -10,7 +10,8 @@ import { Ids } from "types/ids"; | ||||
| import { UploadImageFragment } from "graphql/generated"; | ||||
| import { ImageQuality } from "helpers/img"; | ||||
| import { isDefined } from "helpers/others"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| 
 | ||||
| interface Props { | ||||
|   onCloseRequest: () => void; | ||||
| @ -138,7 +139,7 @@ const ControlButtons = ({ | ||||
|   onCloseRequest, | ||||
|   toggleFullscreen, | ||||
| }: ControlButtonsProps): JSX.Element => { | ||||
|   const { is1ColumnLayout } = useContainerQueries(); | ||||
|   const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout); | ||||
| 
 | ||||
|   const PreviousButton = () => ( | ||||
|     <Button | ||||
|  | ||||
| @ -13,10 +13,8 @@ import { AnchorShare } from "components/AnchorShare"; | ||||
| import { useIntersectionList } from "hooks/useIntersectionList"; | ||||
| import { Ico, Icon } from "components/Ico"; | ||||
| import { useDeviceSupportsHover } from "hooks/useMediaQuery"; | ||||
| import { useUserSettings } from "contexts/UserSettingsContext"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { useLightBox } from "contexts/LightBoxContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -31,10 +29,10 @@ interface MarkdawnProps { | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Element => { | ||||
|   const { playerName } = useUserSettings(); | ||||
|   const playerName = useAtomGetter(atoms.settings.playerName); | ||||
|   const router = useRouter(); | ||||
|   const { isContentPanelAtLeastLg } = useContainerQueries(); | ||||
|   const { showLightBox } = useLightBox(); | ||||
|   const isContentPanelAtLeastLg = useAtomGetter(atoms.containerQueries.isContentPanelAtLeastLg); | ||||
|   const { showLightBox } = useAtomGetter(atoms.lightBox); | ||||
| 
 | ||||
|   /* eslint-disable no-irregular-whitespace */ | ||||
|   const text = useMemo( | ||||
| @ -232,7 +230,7 @@ export const TableOfContents = ({ | ||||
|   horizontalLine = false, | ||||
| }: TableOfContentsProps): JSX.Element => { | ||||
|   const router = useRouter(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const toc = useMemo(() => getTocFromMarkdawn(preprocessMarkDawn(text), title), [text, title]); | ||||
| 
 | ||||
|   return ( | ||||
|  | ||||
| @ -1,12 +1,11 @@ | ||||
| import { useCallback } from "react"; | ||||
| import { Icon } from "components/Ico"; | ||||
| import { Button } from "components/Inputs/Button"; | ||||
| import { useAppLayout } from "contexts/AppLayoutContext"; | ||||
| import { TranslatedProps } from "types/TranslatedProps"; | ||||
| import { useSmartLanguage } from "hooks/useSmartLanguage"; | ||||
| import { isDefined } from "helpers/others"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -24,9 +23,8 @@ interface Props { | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export const ReturnButton = ({ href, title, displayOnlyOn, className }: Props): JSX.Element => { | ||||
|   const { setSubPanelOpen } = useAppLayout(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const { is3ColumnsLayout } = useContainerQueries(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout); | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
| @ -34,12 +32,7 @@ export const ReturnButton = ({ href, title, displayOnlyOn, className }: Props): | ||||
|         (!is3ColumnsLayout && displayOnlyOn === "1ColumnLayout") || | ||||
|         !isDefined(displayOnlyOn)) && ( | ||||
|         <div className={className}> | ||||
|           <Button | ||||
|             onClick={() => setSubPanelOpen(false)} | ||||
|             href={href} | ||||
|             text={`${langui.return_to} ${title}`} | ||||
|             icon={Icon.NavigateBefore} | ||||
|           /> | ||||
|           <Button href={href} text={`${langui.return_to} ${title}`} icon={Icon.NavigateBefore} /> | ||||
|         </div> | ||||
|       )} | ||||
|     </> | ||||
|  | ||||
| @ -3,15 +3,14 @@ import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { Button } from "components/Inputs/Button"; | ||||
| import { NavOption } from "components/PanelComponents/NavOption"; | ||||
| import { ToolTip } from "components/ToolTip"; | ||||
| import { useAppLayout } from "contexts/AppLayoutContext"; | ||||
| import { Icon } from "components/Ico"; | ||||
| import { cIf, cJoin } from "helpers/className"; | ||||
| import { isDefinedAndNotEmpty } from "helpers/others"; | ||||
| import { Link } from "components/Inputs/Link"; | ||||
| import { sendAnalytics } from "helpers/analytics"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { ColoredSvg } from "components/ColoredSvg"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter, useAtomPair, useAtomSetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -19,34 +18,35 @@ import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
|  */ | ||||
| 
 | ||||
| export const MainPanel = (): JSX.Element => { | ||||
|   const { is3ColumnsLayout } = useContainerQueries(); | ||||
|   const { mainPanelReduced, toggleMainPanelReduced, setConfigPanelOpen } = useAppLayout(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const [isMainPanelReduced, setMainPanelReduced] = useAtomPair(atoms.layout.mainPanelReduced); | ||||
|   const setSettingsOpened = useAtomSetter(atoms.layout.settingsOpened); | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|       className={cJoin( | ||||
|         "grid content-start justify-center gap-y-2 p-8 text-center", | ||||
|         cIf(mainPanelReduced && is3ColumnsLayout, "px-4") | ||||
|         cIf(isMainPanelReduced && is3ColumnsLayout, "px-4") | ||||
|       )}> | ||||
|       {/* Reduce/expand main menu */} | ||||
|       {is3ColumnsLayout && ( | ||||
|         <div | ||||
|           className={cJoin( | ||||
|             "fixed top-1/2", | ||||
|             cIf(mainPanelReduced, "left-[4.65rem]", "left-[18.65rem]") | ||||
|             cIf(isMainPanelReduced, "left-[4.65rem]", "left-[18.65rem]") | ||||
|           )}> | ||||
|           <Button | ||||
|             onClick={() => { | ||||
|               if (mainPanelReduced) { | ||||
|               if (isMainPanelReduced) { | ||||
|                 sendAnalytics("MainPanel", "Expand"); | ||||
|               } else { | ||||
|                 sendAnalytics("MainPanel", "Reduce"); | ||||
|               } | ||||
|               toggleMainPanelReduced(); | ||||
|               setMainPanelReduced((current) => !current); | ||||
|             }} | ||||
|             className="z-50 bg-light !px-2" | ||||
|             icon={mainPanelReduced ? Icon.ChevronRight : Icon.ChevronLeft} | ||||
|             icon={isMainPanelReduced ? Icon.ChevronRight : Icon.ChevronLeft} | ||||
|           /> | ||||
|         </div> | ||||
|       )} | ||||
| @ -57,28 +57,28 @@ export const MainPanel = (): JSX.Element => { | ||||
|               src="/icons/accords.svg" | ||||
|               className={cJoin( | ||||
|                 "mb-4 aspect-square bg-black hover:bg-dark", | ||||
|                 cIf(mainPanelReduced && is3ColumnsLayout, "w-12", "w-1/2") | ||||
|                 cIf(isMainPanelReduced && is3ColumnsLayout, "w-12", "w-1/2") | ||||
|               )} | ||||
|             /> | ||||
|           </Link> | ||||
| 
 | ||||
|           {(!mainPanelReduced || !is3ColumnsLayout) && ( | ||||
|           {(!isMainPanelReduced || !is3ColumnsLayout) && ( | ||||
|             <h2 className="mb-4 text-3xl">Accord’s Library</h2> | ||||
|           )} | ||||
| 
 | ||||
|           <div | ||||
|             className={cJoin( | ||||
|               "flex flex-wrap gap-2", | ||||
|               cIf(mainPanelReduced && is3ColumnsLayout, "flex-col gap-3", "flex-row") | ||||
|               cIf(isMainPanelReduced && is3ColumnsLayout, "flex-col gap-3", "flex-row") | ||||
|             )}> | ||||
|             <ToolTip | ||||
|               content={<h3 className="text-2xl">{langui.open_settings}</h3>} | ||||
|               placement="right" | ||||
|               className="text-left" | ||||
|               disabled={!mainPanelReduced}> | ||||
|               disabled={!isMainPanelReduced}> | ||||
|               <Button | ||||
|                 onClick={() => { | ||||
|                   setConfigPanelOpen(true); | ||||
|                   setSettingsOpened(true); | ||||
|                   sendAnalytics("Settings", "Open settings"); | ||||
|                 }} | ||||
|                 icon={Icon.Settings} | ||||
| @ -95,7 +95,7 @@ export const MainPanel = (): JSX.Element => { | ||||
|         icon={Icon.LibraryBooks} | ||||
|         title={langui.library} | ||||
|         subtitle={langui.library_short_description} | ||||
|         reduced={mainPanelReduced && is3ColumnsLayout} | ||||
|         reduced={isMainPanelReduced && is3ColumnsLayout} | ||||
|       /> | ||||
| 
 | ||||
|       <NavOption | ||||
| @ -103,7 +103,7 @@ export const MainPanel = (): JSX.Element => { | ||||
|         icon={Icon.Workspaces} | ||||
|         title={langui.contents} | ||||
|         subtitle={langui.contents_short_description} | ||||
|         reduced={mainPanelReduced && is3ColumnsLayout} | ||||
|         reduced={isMainPanelReduced && is3ColumnsLayout} | ||||
|       /> | ||||
| 
 | ||||
|       <NavOption | ||||
| @ -111,7 +111,7 @@ export const MainPanel = (): JSX.Element => { | ||||
|         icon={Icon.TravelExplore} | ||||
|         title={langui.wiki} | ||||
|         subtitle={langui.wiki_short_description} | ||||
|         reduced={mainPanelReduced && is3ColumnsLayout} | ||||
|         reduced={isMainPanelReduced && is3ColumnsLayout} | ||||
|       /> | ||||
| 
 | ||||
|       <NavOption | ||||
| @ -119,7 +119,7 @@ export const MainPanel = (): JSX.Element => { | ||||
|         icon={Icon.WatchLater} | ||||
|         title={langui.chronicles} | ||||
|         subtitle={langui.chronicles_short_description} | ||||
|         reduced={mainPanelReduced && is3ColumnsLayout} | ||||
|         reduced={isMainPanelReduced && is3ColumnsLayout} | ||||
|       /> | ||||
| 
 | ||||
|       <HorizontalLine /> | ||||
| @ -128,7 +128,7 @@ export const MainPanel = (): JSX.Element => { | ||||
|         url="/news" | ||||
|         icon={Icon.Feed} | ||||
|         title={langui.news} | ||||
|         reduced={mainPanelReduced && is3ColumnsLayout} | ||||
|         reduced={isMainPanelReduced && is3ColumnsLayout} | ||||
|       /> | ||||
| 
 | ||||
|       {/* | ||||
| @ -136,7 +136,7 @@ export const MainPanel = (): JSX.Element => { | ||||
|         url="/merch" | ||||
|         icon={Icon.Store} | ||||
|         title={langui.merch} | ||||
|         reduced={mainPanelReduced && is3ColumnsLayout} | ||||
|         reduced={isMainPanelReduced && is3ColumnsLayout} | ||||
|       /> | ||||
|       */} | ||||
| 
 | ||||
| @ -144,26 +144,26 @@ export const MainPanel = (): JSX.Element => { | ||||
|         url="https://gallery.accords-library.com/posts/" | ||||
|         icon={Icon.Collections} | ||||
|         title={langui.gallery} | ||||
|         reduced={mainPanelReduced && is3ColumnsLayout} | ||||
|         reduced={isMainPanelReduced && is3ColumnsLayout} | ||||
|       /> | ||||
| 
 | ||||
|       <NavOption | ||||
|         url="/archives" | ||||
|         icon={Icon.Inventory2} | ||||
|         title={langui.archives} | ||||
|         reduced={mainPanelReduced && is3ColumnsLayout} | ||||
|         reduced={isMainPanelReduced && is3ColumnsLayout} | ||||
|       /> | ||||
| 
 | ||||
|       <NavOption | ||||
|         url="/about-us" | ||||
|         icon={Icon.Info} | ||||
|         title={langui.about_us} | ||||
|         reduced={mainPanelReduced && is3ColumnsLayout} | ||||
|         reduced={isMainPanelReduced && is3ColumnsLayout} | ||||
|       /> | ||||
| 
 | ||||
|       {(!mainPanelReduced || !is3ColumnsLayout) && <HorizontalLine />} | ||||
|       {(!isMainPanelReduced || !is3ColumnsLayout) && <HorizontalLine />} | ||||
| 
 | ||||
|       <div className={cJoin("text-center", cIf(mainPanelReduced && is3ColumnsLayout, "hidden"))}> | ||||
|       <div className={cJoin("text-center", cIf(isMainPanelReduced && is3ColumnsLayout, "hidden"))}> | ||||
|         {isDefinedAndNotEmpty(langui.licensing_notice) && ( | ||||
|           <p> | ||||
|             <Markdown>{langui.licensing_notice}</Markdown> | ||||
|  | ||||
| @ -7,37 +7,32 @@ import { OrderableList } from "components/Inputs/OrderableList"; | ||||
| import { Select } from "components/Inputs/Select"; | ||||
| import { TextInput } from "components/Inputs/TextInput"; | ||||
| import { Popup } from "components/Containers/Popup"; | ||||
| import { useAppLayout } from "contexts/AppLayoutContext"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useUserSettings } from "contexts/UserSettingsContext"; | ||||
| import { sendAnalytics } from "helpers/analytics"; | ||||
| import { cJoin, cIf } from "helpers/className"; | ||||
| import { prettyLanguage } from "helpers/formatters"; | ||||
| import { filterHasAttributes, isDefined } from "helpers/others"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter, useAtomPair } from "helpers/atoms"; | ||||
| import { ThemeMode } from "contexts/settings"; | ||||
| 
 | ||||
| export const SettingsPopup = (): JSX.Element => { | ||||
|   const { | ||||
|     currency, | ||||
|     darkMode, | ||||
|     dyslexic, | ||||
|     fontSize, | ||||
|     playerName, | ||||
|     preferredLanguages, | ||||
|     selectedThemeMode, | ||||
|     setCurrency, | ||||
|     setDarkMode, | ||||
|     setDyslexic, | ||||
|     setFontSize, | ||||
|     setPlayerName, | ||||
|     setPreferredLanguages, | ||||
|     setSelectedThemeMode, | ||||
|   } = useUserSettings(); | ||||
|   const [preferredLanguages, setPreferredLanguages] = useAtomPair( | ||||
|     atoms.settings.preferredLanguages | ||||
|   ); | ||||
|   const [isSettingsOpened, setSettingsOpened] = useAtomPair(atoms.layout.settingsOpened); | ||||
|   const [currency, setCurrency] = useAtomPair(atoms.settings.currency); | ||||
|   const [isDyslexic, setDyslexic] = useAtomPair(atoms.settings.dyslexic); | ||||
|   const [fontSize, setFontSize] = useAtomPair(atoms.settings.fontSize); | ||||
|   const [playerName, setPlayerName] = useAtomPair(atoms.settings.playerName); | ||||
|   const [themeMode, setThemeMode] = useAtomPair(atoms.settings.themeMode); | ||||
| 
 | ||||
|   const languages = useAtomGetter(atoms.localData.languages); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const currencies = useAtomGetter(atoms.localData.currencies); | ||||
| 
 | ||||
|   const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout); | ||||
| 
 | ||||
|   const { langui, currencies, languages } = useLocalData(); | ||||
|   const { is1ColumnLayout } = useContainerQueries(); | ||||
|   const router = useRouter(); | ||||
|   const { configPanelOpen, setConfigPanelOpen } = useAppLayout(); | ||||
| 
 | ||||
|   const currencyOptions = useMemo( | ||||
|     () => | ||||
| @ -59,9 +54,9 @@ export const SettingsPopup = (): JSX.Element => { | ||||
| 
 | ||||
|   return ( | ||||
|     <Popup | ||||
|       isVisible={configPanelOpen} | ||||
|       isVisible={isSettingsOpened} | ||||
|       onCloseRequest={() => { | ||||
|         setConfigPanelOpen(false); | ||||
|         setSettingsOpened(false); | ||||
|         sendAnalytics("Settings", "Close settings"); | ||||
|       }}> | ||||
|       <h2 className="text-2xl">{langui.settings}</h2> | ||||
| @ -110,28 +105,26 @@ export const SettingsPopup = (): JSX.Element => { | ||||
|               buttonsProps={[ | ||||
|                 { | ||||
|                   onClick: () => { | ||||
|                     setDarkMode(false); | ||||
|                     setSelectedThemeMode(true); | ||||
|                     setThemeMode(ThemeMode.Light); | ||||
|                     sendAnalytics("Settings", "Change theme (light)"); | ||||
|                   }, | ||||
|                   active: selectedThemeMode && !darkMode, | ||||
|                   active: themeMode === ThemeMode.Light, | ||||
|                   text: langui.light, | ||||
|                 }, | ||||
|                 { | ||||
|                   onClick: () => { | ||||
|                     setSelectedThemeMode(false); | ||||
|                     setThemeMode(ThemeMode.Auto); | ||||
|                     sendAnalytics("Settings", "Change theme (auto)"); | ||||
|                   }, | ||||
|                   active: !selectedThemeMode, | ||||
|                   active: themeMode === ThemeMode.Auto, | ||||
|                   text: langui.auto, | ||||
|                 }, | ||||
|                 { | ||||
|                   onClick: () => { | ||||
|                     setDarkMode(true); | ||||
|                     setSelectedThemeMode(true); | ||||
|                     setThemeMode(ThemeMode.Dark); | ||||
|                     sendAnalytics("Settings", "Change theme (dark)"); | ||||
|                   }, | ||||
|                   active: selectedThemeMode && darkMode, | ||||
|                   active: themeMode === ThemeMode.Dark, | ||||
|                   text: langui.dark, | ||||
|                 }, | ||||
|               ]} | ||||
| @ -198,7 +191,7 @@ export const SettingsPopup = (): JSX.Element => { | ||||
|             <h3 className="text-xl">{langui.font}</h3> | ||||
|             <div className="grid gap-2"> | ||||
|               <Button | ||||
|                 active={!dyslexic} | ||||
|                 active={!isDyslexic} | ||||
|                 onClick={() => { | ||||
|                   setDyslexic(false); | ||||
|                   sendAnalytics("Settings", "Change font (Zen Maru Gothic)"); | ||||
| @ -207,7 +200,7 @@ export const SettingsPopup = (): JSX.Element => { | ||||
|                 text="Zen Maru Gothic" | ||||
|               /> | ||||
|               <Button | ||||
|                 active={dyslexic} | ||||
|                 active={isDyslexic} | ||||
|                 onClick={() => { | ||||
|                   setDyslexic(true); | ||||
|                   sendAnalytics("Settings", "Change font (OpenDyslexic)"); | ||||
|  | ||||
| @ -13,7 +13,8 @@ import { useSmartLanguage } from "hooks/useSmartLanguage"; | ||||
| import { PostWithTranslations } from "types/types"; | ||||
| import { filterHasAttributes, getStatusDescription } from "helpers/others"; | ||||
| import { prettySlug } from "helpers/formatters"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -48,7 +49,7 @@ export const PostPage = ({ | ||||
|   displayTitle = true, | ||||
|   ...otherProps | ||||
| }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({ | ||||
|     items: post.translations, | ||||
|     languageExtractor: useCallback( | ||||
|  | ||||
| @ -11,8 +11,8 @@ import { ImageQuality } from "helpers/img"; | ||||
| import { useDeviceSupportsHover } from "hooks/useMediaQuery"; | ||||
| import { useSmartLanguage } from "hooks/useSmartLanguage"; | ||||
| import { TranslatedProps } from "types/TranslatedProps"; | ||||
| import { useUserSettings } from "contexts/UserSettingsContext"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -70,8 +70,8 @@ export const PreviewCard = ({ | ||||
|   infoAppend, | ||||
|   disabled = false, | ||||
| }: Props): JSX.Element => { | ||||
|   const { currency } = useUserSettings(); | ||||
|   const { currencies } = useLocalData(); | ||||
|   const currency = useAtomGetter(atoms.settings.currency); | ||||
|   const currencies = useAtomGetter(atoms.localData.currencies); | ||||
|   const isHoverable = useDeviceSupportsHover(); | ||||
|   const router = useRouter(); | ||||
| 
 | ||||
|  | ||||
| @ -6,7 +6,8 @@ import { Chip } from "components/Chip"; | ||||
| import { RecorderChipFragment } from "graphql/generated"; | ||||
| import { ImageQuality } from "helpers/img"; | ||||
| import { filterHasAttributes } from "helpers/others"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -21,7 +22,7 @@ interface Props { | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export const RecorderChip = ({ recorder }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
| 
 | ||||
|   return ( | ||||
|     <ToolTip | ||||
|  | ||||
| @ -8,8 +8,8 @@ import { cJoin } from "helpers/className"; | ||||
| import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; | ||||
| import { useScrollTopOnChange } from "hooks/useScrollTopOnChange"; | ||||
| import { Ids } from "types/ids"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| interface Group<T> { | ||||
|   name: string; | ||||
| @ -71,7 +71,7 @@ export const SmartList = <T,>({ | ||||
|   className, | ||||
| }: Props<T>): JSX.Element => { | ||||
|   const [page, setPage] = useState(0); | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   useScrollTopOnChange(Ids.ContentPanel, [page], paginationScroolTop); | ||||
|   useEffect(() => setPage(0), [searchingTerm, groupingFunction, groupSortingFunction, items]); | ||||
| 
 | ||||
| @ -228,8 +228,8 @@ export const SmartList = <T,>({ | ||||
|  */ | ||||
| 
 | ||||
| const DefaultRenderWhenEmpty = () => { | ||||
|   const { is3ColumnsLayout } = useContainerQueries(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   return ( | ||||
|     <div className="grid h-full place-content-center"> | ||||
|       <div | ||||
|  | ||||
| @ -6,8 +6,8 @@ import { GetContentTextQuery, UploadImageFragment } from "graphql/generated"; | ||||
| import { prettyInlineTitle, prettySlug, slugify } from "helpers/formatters"; | ||||
| import { ImageQuality } from "helpers/img"; | ||||
| import { filterHasAttributes } from "helpers/others"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useLightBox } from "contexts/LightBoxContext"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -42,8 +42,8 @@ export const ThumbnailHeader = ({ | ||||
|   description, | ||||
|   languageSwitcher, | ||||
| }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const { showLightBox } = useLightBox(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const { showLightBox } = useAtomGetter(atoms.lightBox); | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|  | ||||
| @ -5,8 +5,8 @@ import { getStatusDescription } from "helpers/others"; | ||||
| import { useSmartLanguage } from "hooks/useSmartLanguage"; | ||||
| import { Button } from "components/Inputs/Button"; | ||||
| import { cIf, cJoin } from "helpers/className"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                        ╭─────────────╮ | ||||
| @ -30,8 +30,8 @@ interface Props { | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| const DefinitionCard = ({ source, translations = [], index, categories }: Props): JSX.Element => { | ||||
|   const { isContentPanelAtLeastMd } = useContainerQueries(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const isContentPanelAtLeastMd = useAtomGetter(atoms.containerQueries.isContentPanelAtLeastMd); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({ | ||||
|     items: translations, | ||||
|     languageExtractor: useCallback((item: Props["translations"][number]) => item.language, []), | ||||
|  | ||||
| @ -1,152 +0,0 @@ | ||||
| import React, { | ||||
|   createContext, | ||||
|   Dispatch, | ||||
|   ReactNode, | ||||
|   SetStateAction, | ||||
|   useContext, | ||||
|   useEffect, | ||||
|   useState, | ||||
| } from "react"; | ||||
| import { useRouter } from "next/router"; | ||||
| import { useLocalStorage } from "usehooks-ts"; | ||||
| import { isDefined } from "helpers/others"; | ||||
| import { RequiredNonNullable } from "types/types"; | ||||
| import { useStateWithLocalStorage } from "hooks/useStateWithLocalStorage"; | ||||
| import { useScrollIntoView } from "hooks/useScrollIntoView"; | ||||
| 
 | ||||
| interface AppLayoutState { | ||||
|   subPanelOpen: boolean; | ||||
|   toggleSubPanelOpen: () => void; | ||||
|   setSubPanelOpen: Dispatch<SetStateAction<AppLayoutState["subPanelOpen"]>>; | ||||
| 
 | ||||
|   configPanelOpen: boolean; | ||||
|   toggleConfigPanelOpen: () => void; | ||||
|   setConfigPanelOpen: Dispatch<SetStateAction<AppLayoutState["configPanelOpen"]>>; | ||||
| 
 | ||||
|   mainPanelReduced: boolean; | ||||
|   toggleMainPanelReduced: () => void; | ||||
|   setMainPanelReduced: Dispatch<SetStateAction<AppLayoutState["mainPanelReduced"]>>; | ||||
| 
 | ||||
|   mainPanelOpen: boolean; | ||||
|   toggleMainPanelOpen: () => void; | ||||
|   setMainPanelOpen: Dispatch<SetStateAction<AppLayoutState["mainPanelOpen"]>>; | ||||
| 
 | ||||
|   menuGestures: boolean; | ||||
|   toggleMenuGestures: () => void; | ||||
|   setMenuGestures: Dispatch<SetStateAction<AppLayoutState["menuGestures"]>>; | ||||
| } | ||||
| 
 | ||||
| const initialState: RequiredNonNullable<AppLayoutState> = { | ||||
|   subPanelOpen: false, | ||||
|   toggleSubPanelOpen: () => null, | ||||
|   setSubPanelOpen: () => null, | ||||
| 
 | ||||
|   configPanelOpen: false, | ||||
|   setConfigPanelOpen: () => null, | ||||
|   toggleConfigPanelOpen: () => null, | ||||
| 
 | ||||
|   mainPanelReduced: false, | ||||
|   setMainPanelReduced: () => null, | ||||
|   toggleMainPanelReduced: () => null, | ||||
| 
 | ||||
|   mainPanelOpen: false, | ||||
|   toggleMainPanelOpen: () => null, | ||||
|   setMainPanelOpen: () => null, | ||||
| 
 | ||||
|   menuGestures: true, | ||||
|   toggleMenuGestures: () => null, | ||||
|   setMenuGestures: () => null, | ||||
| }; | ||||
| 
 | ||||
| const AppLayoutContext = createContext<AppLayoutState>(initialState); | ||||
| 
 | ||||
| export const useAppLayout = (): AppLayoutState => useContext(AppLayoutContext); | ||||
| 
 | ||||
| interface Props { | ||||
|   children: ReactNode; | ||||
| } | ||||
| 
 | ||||
| export const AppContextProvider = ({ children }: Props): JSX.Element => { | ||||
|   const router = useRouter(); | ||||
| 
 | ||||
|   const [subPanelOpen, setSubPanelOpen] = useStateWithLocalStorage( | ||||
|     "subPanelOpen", | ||||
|     initialState.subPanelOpen | ||||
|   ); | ||||
| 
 | ||||
|   const [configPanelOpen, setConfigPanelOpen] = useLocalStorage( | ||||
|     "configPanelOpen", | ||||
|     initialState.configPanelOpen | ||||
|   ); | ||||
| 
 | ||||
|   const [mainPanelReduced, setMainPanelReduced] = useLocalStorage( | ||||
|     "mainPanelReduced", | ||||
|     initialState.mainPanelReduced | ||||
|   ); | ||||
| 
 | ||||
|   const [mainPanelOpen, setMainPanelOpen] = useStateWithLocalStorage( | ||||
|     "mainPanelOpen", | ||||
|     initialState.mainPanelOpen | ||||
|   ); | ||||
| 
 | ||||
|   const [menuGestures, setMenuGestures] = useState(false); | ||||
| 
 | ||||
|   const toggleSubPanelOpen = () => { | ||||
|     setSubPanelOpen((current) => (isDefined(current) ? !current : current)); | ||||
|   }; | ||||
| 
 | ||||
|   const toggleConfigPanelOpen = () => { | ||||
|     setConfigPanelOpen((current) => (isDefined(current) ? !current : current)); | ||||
|   }; | ||||
| 
 | ||||
|   const toggleMainPanelReduced = () => { | ||||
|     setMainPanelReduced((current) => (isDefined(current) ? !current : current)); | ||||
|   }; | ||||
| 
 | ||||
|   const toggleMainPanelOpen = () => { | ||||
|     setMainPanelOpen((current) => (isDefined(current) ? !current : current)); | ||||
|   }; | ||||
| 
 | ||||
|   const toggleMenuGestures = () => { | ||||
|     setMenuGestures((current) => !current); | ||||
|   }; | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     router.events.on("routeChangeStart", () => { | ||||
|       console.log("[Router Events] on routeChangeStart"); | ||||
|       setConfigPanelOpen(false); | ||||
|       setMainPanelOpen(false); | ||||
|       setSubPanelOpen(false); | ||||
|     }); | ||||
| 
 | ||||
|     router.events.on("hashChangeStart", () => { | ||||
|       console.log("[Router Events] on hashChangeStart"); | ||||
|       setSubPanelOpen(false); | ||||
|     }); | ||||
|   }, [router.events, setConfigPanelOpen, setMainPanelOpen, setSubPanelOpen]); | ||||
| 
 | ||||
|   useScrollIntoView(); | ||||
| 
 | ||||
|   return ( | ||||
|     <AppLayoutContext.Provider | ||||
|       value={{ | ||||
|         subPanelOpen, | ||||
|         configPanelOpen, | ||||
|         mainPanelReduced, | ||||
|         mainPanelOpen, | ||||
|         menuGestures, | ||||
|         setSubPanelOpen, | ||||
|         setConfigPanelOpen, | ||||
|         setMainPanelReduced, | ||||
|         setMainPanelOpen, | ||||
|         setMenuGestures, | ||||
|         toggleSubPanelOpen, | ||||
|         toggleConfigPanelOpen, | ||||
|         toggleMainPanelReduced, | ||||
|         toggleMainPanelOpen, | ||||
|         toggleMenuGestures, | ||||
|       }}> | ||||
|       {children} | ||||
|     </AppLayoutContext.Provider> | ||||
|   ); | ||||
| }; | ||||
| @ -1,315 +0,0 @@ | ||||
| import React, { createContext, ReactNode, useContext, useMemo, useState } from "react"; | ||||
| import { useUserSettings } from "./UserSettingsContext"; | ||||
| import { useOnResize } from "hooks/useOnResize"; | ||||
| import { Ids } from "types/ids"; | ||||
| import { RequiredNonNullable } from "types/types"; | ||||
| 
 | ||||
| type Size = | ||||
|   | "2xl" | ||||
|   | "2xs" | ||||
|   | "3xl" | ||||
|   | "4xl" | ||||
|   | "5xl" | ||||
|   | "6xl" | ||||
|   | "7xl" | ||||
|   | "lg" | ||||
|   | "md" | ||||
|   | "sm" | ||||
|   | "xl" | ||||
|   | "xs"; | ||||
| 
 | ||||
| const sizes: Record<Size, number> = { | ||||
|   "2xl": 42, | ||||
|   "3xl": 48, | ||||
|   "4xl": 56, | ||||
|   "5xl": 64, | ||||
|   "6xl": 72, | ||||
|   "7xl": 80, | ||||
|   lg: 32, | ||||
|   md: 28, | ||||
|   sm: 24, | ||||
|   xl: 36, | ||||
|   xs: 19, | ||||
|   "2xs": 16, | ||||
| }; | ||||
| 
 | ||||
| type ContainerQueriesContainers = "contentPanel" | "screen" | "subPanel"; | ||||
| 
 | ||||
| type ContainerQueriesKeys = | ||||
|   | "is1ColumnLayout" | ||||
|   | "is3ColumnsLayout" | ||||
|   | `is${Capitalize<ContainerQueriesContainers>}AtLeast${Capitalize<Size>}`; | ||||
| 
 | ||||
| type ContainerQueriesState = Record<ContainerQueriesKeys, boolean>; | ||||
| 
 | ||||
| const initialState: RequiredNonNullable<ContainerQueriesState> = { | ||||
|   is1ColumnLayout: false, | ||||
|   is3ColumnsLayout: false, | ||||
|   isContentPanelAtLeast2xl: false, | ||||
|   isContentPanelAtLeast2xs: false, | ||||
|   isContentPanelAtLeast3xl: false, | ||||
|   isContentPanelAtLeast4xl: false, | ||||
|   isContentPanelAtLeast5xl: false, | ||||
|   isContentPanelAtLeast6xl: false, | ||||
|   isContentPanelAtLeast7xl: false, | ||||
|   isContentPanelAtLeastLg: false, | ||||
|   isContentPanelAtLeastMd: false, | ||||
|   isContentPanelAtLeastSm: false, | ||||
|   isContentPanelAtLeastXl: false, | ||||
|   isContentPanelAtLeastXs: false, | ||||
|   isScreenAtLeast2xl: false, | ||||
|   isScreenAtLeast2xs: false, | ||||
|   isScreenAtLeast3xl: false, | ||||
|   isScreenAtLeast4xl: false, | ||||
|   isScreenAtLeast5xl: false, | ||||
|   isScreenAtLeast6xl: false, | ||||
|   isScreenAtLeast7xl: false, | ||||
|   isScreenAtLeastLg: false, | ||||
|   isScreenAtLeastMd: false, | ||||
|   isScreenAtLeastSm: false, | ||||
|   isScreenAtLeastXl: false, | ||||
|   isScreenAtLeastXs: false, | ||||
|   isSubPanelAtLeast2xl: false, | ||||
|   isSubPanelAtLeast2xs: false, | ||||
|   isSubPanelAtLeast3xl: false, | ||||
|   isSubPanelAtLeast4xl: false, | ||||
|   isSubPanelAtLeast5xl: false, | ||||
|   isSubPanelAtLeast6xl: false, | ||||
|   isSubPanelAtLeast7xl: false, | ||||
|   isSubPanelAtLeastLg: false, | ||||
|   isSubPanelAtLeastMd: false, | ||||
|   isSubPanelAtLeastSm: false, | ||||
|   isSubPanelAtLeastXl: false, | ||||
|   isSubPanelAtLeastXs: false, | ||||
| }; | ||||
| 
 | ||||
| const ContainerQueriesContext = createContext<ContainerQueriesState>(initialState); | ||||
| 
 | ||||
| export const useContainerQueries = (): ContainerQueriesState => useContext(ContainerQueriesContext); | ||||
| 
 | ||||
| interface Props { | ||||
|   children: ReactNode; | ||||
| } | ||||
| 
 | ||||
| export const ContainerQueriesContextProvider = ({ children }: Props): JSX.Element => { | ||||
|   const [screenWidth, setScreenWidth] = useState(0); | ||||
|   const [contentPanelWidth, setContentPanelWidth] = useState(0); | ||||
|   const [subPanelWidth, setSubPanelWidth] = useState(0); | ||||
| 
 | ||||
|   useOnResize(Ids.Body, (width) => setScreenWidth(width)); | ||||
|   useOnResize(Ids.ContentPanel, (width) => setContentPanelWidth(width)); | ||||
|   useOnResize(Ids.SubPanel, (width) => setSubPanelWidth(width)); | ||||
| 
 | ||||
|   const { fontSize } = useUserSettings(); | ||||
| 
 | ||||
|   const screenAtLeasts = useMemo( | ||||
|     () => ({ | ||||
|       isScreenAtLeast2xs: applyContainerQuery( | ||||
|         fontSize, | ||||
|         screenWidth, | ||||
|         createAtLeastMediaQuery("2xs") | ||||
|       ), | ||||
|       isScreenAtLeastXs: applyContainerQuery(fontSize, screenWidth, createAtLeastMediaQuery("xs")), | ||||
|       isScreenAtLeastSm: applyContainerQuery(fontSize, screenWidth, createAtLeastMediaQuery("sm")), | ||||
|       isScreenAtLeastMd: applyContainerQuery(fontSize, screenWidth, createAtLeastMediaQuery("md")), | ||||
|       isScreenAtLeastLg: applyContainerQuery(fontSize, screenWidth, createAtLeastMediaQuery("lg")), | ||||
|       isScreenAtLeastXl: applyContainerQuery(fontSize, screenWidth, createAtLeastMediaQuery("xl")), | ||||
|       isScreenAtLeast2xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         screenWidth, | ||||
|         createAtLeastMediaQuery("2xl") | ||||
|       ), | ||||
|       isScreenAtLeast3xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         screenWidth, | ||||
|         createAtLeastMediaQuery("3xl") | ||||
|       ), | ||||
|       isScreenAtLeast4xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         screenWidth, | ||||
|         createAtLeastMediaQuery("4xl") | ||||
|       ), | ||||
|       isScreenAtLeast5xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         screenWidth, | ||||
|         createAtLeastMediaQuery("5xl") | ||||
|       ), | ||||
|       isScreenAtLeast6xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         screenWidth, | ||||
|         createAtLeastMediaQuery("6xl") | ||||
|       ), | ||||
|       isScreenAtLeast7xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         screenWidth, | ||||
|         createAtLeastMediaQuery("7xl") | ||||
|       ), | ||||
|     }), | ||||
|     [screenWidth, fontSize] | ||||
|   ); | ||||
| 
 | ||||
|   const columnLayouts = useMemo( | ||||
|     () => ({ | ||||
|       is1ColumnLayout: !screenAtLeasts.isScreenAtLeast5xl, | ||||
|       is3ColumnsLayout: screenAtLeasts.isScreenAtLeast5xl, | ||||
|     }), | ||||
|     [screenAtLeasts.isScreenAtLeast5xl] | ||||
|   ); | ||||
| 
 | ||||
|   const subPanelAtLeasts = useMemo( | ||||
|     () => ({ | ||||
|       isSubPanelAtLeast2xs: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("2xs") | ||||
|       ), | ||||
|       isSubPanelAtLeastXs: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("xs") | ||||
|       ), | ||||
|       isSubPanelAtLeastSm: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("sm") | ||||
|       ), | ||||
|       isSubPanelAtLeastMd: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("md") | ||||
|       ), | ||||
|       isSubPanelAtLeastLg: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("lg") | ||||
|       ), | ||||
|       isSubPanelAtLeastXl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("xl") | ||||
|       ), | ||||
|       isSubPanelAtLeast2xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("2xl") | ||||
|       ), | ||||
|       isSubPanelAtLeast3xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("3xl") | ||||
|       ), | ||||
|       isSubPanelAtLeast4xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("4xl") | ||||
|       ), | ||||
|       isSubPanelAtLeast5xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("5xl") | ||||
|       ), | ||||
|       isSubPanelAtLeast6xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("6xl") | ||||
|       ), | ||||
|       isSubPanelAtLeast7xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         subPanelWidth, | ||||
|         createAtLeastMediaQuery("7xl") | ||||
|       ), | ||||
|     }), | ||||
|     [subPanelWidth, fontSize] | ||||
|   ); | ||||
| 
 | ||||
|   const contentPanelAtLeasts = useMemo( | ||||
|     () => ({ | ||||
|       isContentPanelAtLeast2xs: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("2xs") | ||||
|       ), | ||||
|       isContentPanelAtLeastXs: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("xs") | ||||
|       ), | ||||
|       isContentPanelAtLeastSm: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("sm") | ||||
|       ), | ||||
|       isContentPanelAtLeastMd: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("md") | ||||
|       ), | ||||
|       isContentPanelAtLeastLg: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("lg") | ||||
|       ), | ||||
|       isContentPanelAtLeastXl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("xl") | ||||
|       ), | ||||
|       isContentPanelAtLeast2xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("2xl") | ||||
|       ), | ||||
|       isContentPanelAtLeast3xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("3xl") | ||||
|       ), | ||||
|       isContentPanelAtLeast4xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("4xl") | ||||
|       ), | ||||
|       isContentPanelAtLeast5xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("5xl") | ||||
|       ), | ||||
|       isContentPanelAtLeast6xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("6xl") | ||||
|       ), | ||||
|       isContentPanelAtLeast7xl: applyContainerQuery( | ||||
|         fontSize, | ||||
|         contentPanelWidth, | ||||
|         createAtLeastMediaQuery("7xl") | ||||
|       ), | ||||
|     }), | ||||
|     [contentPanelWidth, fontSize] | ||||
|   ); | ||||
| 
 | ||||
|   return ( | ||||
|     <ContainerQueriesContext.Provider | ||||
|       value={{ | ||||
|         ...screenAtLeasts, | ||||
|         ...contentPanelAtLeasts, | ||||
|         ...subPanelAtLeasts, | ||||
|         ...columnLayouts, | ||||
|       }}> | ||||
|       {children} | ||||
|     </ContainerQueriesContext.Provider> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| type MediaQuery = { value: number; unit: "px" | "rem"; rule: "max" | "min" }; | ||||
| 
 | ||||
| const createAtLeastMediaQuery = (size: Size): MediaQuery => ({ | ||||
|   value: sizes[size], | ||||
|   unit: "rem", | ||||
|   rule: "min", | ||||
| }); | ||||
| 
 | ||||
| const applyContainerQuery = (fontSize: number, width: number, query: MediaQuery): boolean => { | ||||
|   const breakpoint = query.value * (query.unit === "rem" ? 16 : 1) * fontSize; | ||||
|   return query.rule === "min" ? width >= breakpoint : width < breakpoint; | ||||
| }; | ||||
| @ -1,58 +0,0 @@ | ||||
| import React, { createContext, ReactNode, useCallback, useContext, useState } from "react"; | ||||
| import { UploadImageFragment } from "graphql/generated"; | ||||
| import { RequiredNonNullable } from "types/types"; | ||||
| import { LightBox } from "components/LightBox"; | ||||
| import { filterDefined } from "helpers/others"; | ||||
| 
 | ||||
| type LightBoxImagesNullable = (UploadImageFragment | string | null | undefined)[]; | ||||
| type LightBoxImages = (UploadImageFragment | string)[]; | ||||
| 
 | ||||
| interface LightBoxState { | ||||
|   showLightBox: (images: LightBoxImagesNullable, index?: number) => void; | ||||
| } | ||||
| 
 | ||||
| const initialState: RequiredNonNullable<LightBoxState> = { | ||||
|   showLightBox: () => null, | ||||
| }; | ||||
| 
 | ||||
| const LightBoxContext = createContext<LightBoxState>(initialState); | ||||
| 
 | ||||
| export const useLightBox = (): LightBoxState => useContext(LightBoxContext); | ||||
| 
 | ||||
| interface Props { | ||||
|   children: ReactNode; | ||||
| } | ||||
| 
 | ||||
| export const LightBoxContextProvider = ({ children }: Props): JSX.Element => { | ||||
|   const [isLightBoxVisible, setLightBoxVisibility] = useState(false); | ||||
|   const [lightBoxImages, setLightBoxImages] = useState<LightBoxImages>([]); | ||||
|   const [lightBoxIndex, setLightBoxIndex] = useState(0); | ||||
| 
 | ||||
|   const showLightBox = useCallback((images: LightBoxImagesNullable, index = 0) => { | ||||
|     const filteredImages = filterDefined(images); | ||||
|     setLightBoxIndex(index); | ||||
|     setLightBoxImages(filteredImages); | ||||
|     setLightBoxVisibility(true); | ||||
|   }, []); | ||||
| 
 | ||||
|   const closeLightBox = useCallback(() => { | ||||
|     setLightBoxVisibility(false); | ||||
|     setTimeout(() => setLightBoxImages([]), 100); | ||||
|   }, []); | ||||
| 
 | ||||
|   return ( | ||||
|     <LightBoxContext.Provider value={{ showLightBox }}> | ||||
|       <LightBox | ||||
|         isVisible={isLightBoxVisible} | ||||
|         onCloseRequest={closeLightBox} | ||||
|         image={lightBoxImages[lightBoxIndex]} | ||||
|         isNextImageAvailable={lightBoxIndex < lightBoxImages.length - 1} | ||||
|         isPreviousImageAvailable={lightBoxIndex > 0} | ||||
|         onPressNext={() => setLightBoxIndex((current) => current + 1)} | ||||
|         onPressPrevious={() => setLightBoxIndex((current) => current - 1)} | ||||
|       /> | ||||
| 
 | ||||
|       {children} | ||||
|     </LightBoxContext.Provider> | ||||
|   ); | ||||
| }; | ||||
							
								
								
									
										54
									
								
								src/contexts/LightBoxProvider.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/contexts/LightBoxProvider.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| import React, { useCallback, useState } from "react"; | ||||
| import { useEffectOnce } from "usehooks-ts"; | ||||
| import { atom } from "jotai"; | ||||
| import { UploadImageFragment } from "graphql/generated"; | ||||
| import { LightBox } from "components/LightBox"; | ||||
| import { filterDefined } from "helpers/others"; | ||||
| import { atomPairing, useAtomSetter } from "helpers/atoms"; | ||||
| 
 | ||||
| const lightBoxAtom = atomPairing( | ||||
|   atom<{ | ||||
|     showLightBox: ( | ||||
|       images: (UploadImageFragment | string | null | undefined)[], | ||||
|       index?: number | ||||
|     ) => void; | ||||
|   }>({ showLightBox: () => null }) | ||||
| ); | ||||
| 
 | ||||
| export const lightBox = lightBoxAtom[0]; | ||||
| 
 | ||||
| export const LightBoxProvider = (): JSX.Element => { | ||||
|   const [isLightBoxVisible, setLightBoxVisibility] = useState(false); | ||||
|   const [lightBoxImages, setLightBoxImages] = useState<(UploadImageFragment | string)[]>([]); | ||||
|   const [lightBoxIndex, setLightBoxIndex] = useState(0); | ||||
| 
 | ||||
|   const setShowLightBox = useAtomSetter(lightBoxAtom); | ||||
| 
 | ||||
|   useEffectOnce(() => | ||||
|     setShowLightBox({ | ||||
|       showLightBox: (images, index = 0) => { | ||||
|         const filteredImages = filterDefined(images); | ||||
|         setLightBoxIndex(index); | ||||
|         setLightBoxImages(filteredImages); | ||||
|         setLightBoxVisibility(true); | ||||
|       }, | ||||
|     }) | ||||
|   ); | ||||
| 
 | ||||
|   const closeLightBox = useCallback(() => { | ||||
|     setLightBoxVisibility(false); | ||||
|     setTimeout(() => setLightBoxImages([]), 100); | ||||
|   }, []); | ||||
| 
 | ||||
|   return ( | ||||
|     <LightBox | ||||
|       isVisible={isLightBoxVisible} | ||||
|       onCloseRequest={closeLightBox} | ||||
|       image={lightBoxImages[lightBoxIndex]} | ||||
|       isNextImageAvailable={lightBoxIndex < lightBoxImages.length - 1} | ||||
|       isPreviousImageAvailable={lightBoxIndex > 0} | ||||
|       onPressNext={() => setLightBoxIndex((current) => current + 1)} | ||||
|       onPressPrevious={() => setLightBoxIndex((current) => current - 1)} | ||||
|     /> | ||||
|   ); | ||||
| }; | ||||
| @ -1,70 +0,0 @@ | ||||
| import React, { createContext, ReactNode, useContext, useMemo } from "react"; | ||||
| import { useRouter } from "next/router"; | ||||
| import { useFetch } from "usehooks-ts"; | ||||
| import { | ||||
|   Langui, | ||||
|   Languages, | ||||
|   Currencies, | ||||
|   processCurrencies, | ||||
|   processLanguages, | ||||
|   processLangui, | ||||
| } from "helpers/localData"; | ||||
| import { RequiredNonNullable } from "types/types"; | ||||
| import { LocalDataFile } from "graphql/fetchLocalData"; | ||||
| import { | ||||
|   LocalDataGetCurrenciesQuery, | ||||
|   LocalDataGetLanguagesQuery, | ||||
|   LocalDataGetWebsiteInterfacesQuery, | ||||
| } from "graphql/generated"; | ||||
| 
 | ||||
| interface LocalDataState { | ||||
|   langui: Langui; | ||||
|   languages: Languages; | ||||
|   currencies: Currencies; | ||||
| } | ||||
| 
 | ||||
| const initialState: RequiredNonNullable<LocalDataState> = { | ||||
|   currencies: [], | ||||
|   languages: [], | ||||
|   langui: {}, | ||||
| }; | ||||
| 
 | ||||
| const LocalDataContext = createContext<LocalDataState>(initialState); | ||||
| 
 | ||||
| export const useLocalData = (): LocalDataState => useContext(LocalDataContext); | ||||
| 
 | ||||
| interface Props { | ||||
|   children: ReactNode; | ||||
| } | ||||
| 
 | ||||
| export const LocalDataContextProvider = ({ children }: Props): JSX.Element => { | ||||
|   const langui = useLangui(); | ||||
|   const languages = useLanguages(); | ||||
|   const currencies = useCurrencies(); | ||||
| 
 | ||||
|   return ( | ||||
|     <LocalDataContext.Provider value={{ langui, languages, currencies }}> | ||||
|       {children} | ||||
|     </LocalDataContext.Provider> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| const getFileName = (name: LocalDataFile): string => `/local-data/${name}.json`; | ||||
| 
 | ||||
| const useLangui = (): Langui => { | ||||
|   const { locale } = useRouter(); | ||||
|   const { data: websiteInterfaces } = useFetch<LocalDataGetWebsiteInterfacesQuery>( | ||||
|     getFileName("websiteInterfaces") | ||||
|   ); | ||||
|   return useMemo(() => processLangui(websiteInterfaces, locale), [websiteInterfaces, locale]); | ||||
| }; | ||||
| 
 | ||||
| const useCurrencies = (): Currencies => { | ||||
|   const { data: currencies } = useFetch<LocalDataGetCurrenciesQuery>(getFileName("currencies")); | ||||
|   return useMemo(() => processCurrencies(currencies), [currencies]); | ||||
| }; | ||||
| 
 | ||||
| const useLanguages = (): Languages => { | ||||
|   const { data: languages } = useFetch<LocalDataGetLanguagesQuery>(getFileName("languages")); | ||||
|   return useMemo(() => processLanguages(languages), [languages]); | ||||
| }; | ||||
| @ -1,42 +0,0 @@ | ||||
| import React, { | ||||
|   createContext, | ||||
|   Dispatch, | ||||
|   ReactNode, | ||||
|   SetStateAction, | ||||
|   useContext, | ||||
|   useState, | ||||
| } from "react"; | ||||
| import { RequiredNonNullable } from "types/types"; | ||||
| 
 | ||||
| interface TerminalState { | ||||
|   previousLines: string[]; | ||||
|   previousCommands: string[]; | ||||
|   setPreviousLines: Dispatch<SetStateAction<TerminalState["previousLines"]>>; | ||||
|   setPreviousCommands: Dispatch<SetStateAction<TerminalState["previousCommands"]>>; | ||||
| } | ||||
| 
 | ||||
| const initialState: RequiredNonNullable<TerminalState> = { | ||||
|   previousLines: [], | ||||
|   previousCommands: [], | ||||
|   setPreviousLines: () => null, | ||||
|   setPreviousCommands: () => null, | ||||
| }; | ||||
| 
 | ||||
| const TerminalContext = createContext<TerminalState>(initialState); | ||||
| 
 | ||||
| export const useTerminalContext = (): TerminalState => useContext(TerminalContext); | ||||
| 
 | ||||
| interface Props { | ||||
|   children: ReactNode; | ||||
| } | ||||
| 
 | ||||
| export const TerminalContextProvider = ({ children }: Props): JSX.Element => { | ||||
|   const [previousLines, setPreviousLines] = useState(initialState.previousLines); | ||||
|   const [previousCommands, setPreviousCommands] = useState(initialState.previousCommands); | ||||
|   return ( | ||||
|     <TerminalContext.Provider | ||||
|       value={{ previousCommands, previousLines, setPreviousCommands, setPreviousLines }}> | ||||
|       {children} | ||||
|     </TerminalContext.Provider> | ||||
|   ); | ||||
| }; | ||||
| @ -1,189 +0,0 @@ | ||||
| import { useLocalStorage } from "usehooks-ts"; | ||||
| import React, { | ||||
|   createContext, | ||||
|   Dispatch, | ||||
|   ReactNode, | ||||
|   SetStateAction, | ||||
|   useContext, | ||||
|   useEffect, | ||||
|   useLayoutEffect, | ||||
| } from "react"; | ||||
| import { useRouter } from "next/router"; | ||||
| import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; | ||||
| import { RequiredNonNullable } from "types/types"; | ||||
| import { getDefaultPreferredLanguages } from "helpers/locales"; | ||||
| import { useDarkMode } from "hooks/useDarkMode"; | ||||
| import { SettingsPopup } from "components/Panels/SettingsPopup"; | ||||
| 
 | ||||
| interface UserSettingsState { | ||||
|   fontSize: number; | ||||
|   setFontSize: Dispatch<SetStateAction<UserSettingsState["fontSize"]>>; | ||||
| 
 | ||||
|   darkMode: boolean; | ||||
|   toggleDarkMode: () => void; | ||||
|   setDarkMode: Dispatch<SetStateAction<UserSettingsState["darkMode"]>>; | ||||
| 
 | ||||
|   selectedThemeMode: boolean; | ||||
|   toggleSelectedThemeMode: () => void; | ||||
|   setSelectedThemeMode: Dispatch<SetStateAction<UserSettingsState["selectedThemeMode"]>>; | ||||
| 
 | ||||
|   dyslexic: boolean; | ||||
|   toggleDyslexic: () => void; | ||||
|   setDyslexic: Dispatch<SetStateAction<UserSettingsState["dyslexic"]>>; | ||||
| 
 | ||||
|   currency: string; | ||||
|   setCurrency: Dispatch<SetStateAction<UserSettingsState["currency"]>>; | ||||
| 
 | ||||
|   playerName: string; | ||||
|   setPlayerName: Dispatch<SetStateAction<UserSettingsState["playerName"]>>; | ||||
| 
 | ||||
|   preferredLanguages: string[]; | ||||
|   setPreferredLanguages: Dispatch<SetStateAction<UserSettingsState["preferredLanguages"]>>; | ||||
| } | ||||
| 
 | ||||
| const initialState: RequiredNonNullable<UserSettingsState> = { | ||||
|   fontSize: 1, | ||||
|   setFontSize: () => null, | ||||
| 
 | ||||
|   darkMode: false, | ||||
|   toggleDarkMode: () => null, | ||||
|   setDarkMode: () => null, | ||||
| 
 | ||||
|   selectedThemeMode: false, | ||||
|   toggleSelectedThemeMode: () => null, | ||||
|   setSelectedThemeMode: () => null, | ||||
| 
 | ||||
|   dyslexic: false, | ||||
|   toggleDyslexic: () => null, | ||||
|   setDyslexic: () => null, | ||||
| 
 | ||||
|   currency: "USD", | ||||
|   setCurrency: () => null, | ||||
| 
 | ||||
|   playerName: "", | ||||
|   setPlayerName: () => null, | ||||
| 
 | ||||
|   preferredLanguages: [], | ||||
|   setPreferredLanguages: () => null, | ||||
| }; | ||||
| 
 | ||||
| const UserSettingsContext = createContext<UserSettingsState>(initialState); | ||||
| 
 | ||||
| export const useUserSettings = (): UserSettingsState => useContext(UserSettingsContext); | ||||
| 
 | ||||
| interface Props { | ||||
|   children: ReactNode; | ||||
| } | ||||
| 
 | ||||
| export const UserSettingsProvider = ({ children }: Props): JSX.Element => { | ||||
|   const router = useRouter(); | ||||
| 
 | ||||
|   const [fontSize, setFontSize] = useLocalStorage("fontSize", initialState.fontSize); | ||||
| 
 | ||||
|   const [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode] = useDarkMode( | ||||
|     "darkMode", | ||||
|     initialState.darkMode | ||||
|   ); | ||||
| 
 | ||||
|   const [dyslexic, setDyslexic] = useLocalStorage("dyslexic", initialState.dyslexic); | ||||
| 
 | ||||
|   const [currency, setCurrency] = useLocalStorage("currency", initialState.currency); | ||||
| 
 | ||||
|   const [playerName, setPlayerName] = useLocalStorage("playerName", initialState.playerName); | ||||
| 
 | ||||
|   const [preferredLanguages, setPreferredLanguages] = useLocalStorage( | ||||
|     "preferredLanguages", | ||||
|     initialState.preferredLanguages | ||||
|   ); | ||||
| 
 | ||||
|   const toggleDarkMode = () => { | ||||
|     setDarkMode((current) => (isDefined(current) ? !current : current)); | ||||
|   }; | ||||
| 
 | ||||
|   const toggleSelectedThemeMode = () => { | ||||
|     setSelectedThemeMode((current) => (isDefined(current) ? !current : current)); | ||||
|   }; | ||||
| 
 | ||||
|   const toggleDyslexic = () => { | ||||
|     setDyslexic((current) => (isDefined(current) ? !current : current)); | ||||
|   }; | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (preferredLanguages.length === 0) { | ||||
|       if (isDefinedAndNotEmpty(router.locale) && router.locales) { | ||||
|         setPreferredLanguages(getDefaultPreferredLanguages(router.locale, router.locales)); | ||||
|       } | ||||
|     } else if (router.locale !== preferredLanguages[0]) { | ||||
|       /* | ||||
|        * Using a timeout to the code getting stuck into a loop when reaching the website with a | ||||
|        * different preferredLanguages[0] from router.locale | ||||
|        */ | ||||
|       setTimeout( | ||||
|         async () => | ||||
|           router.replace(router.asPath, router.asPath, { | ||||
|             locale: preferredLanguages[0], | ||||
|           }), | ||||
|         250 | ||||
|       ); | ||||
|     } | ||||
|   }, [preferredLanguages, router, router.locale, router.locales, setPreferredLanguages]); | ||||
| 
 | ||||
|   useLayoutEffect(() => { | ||||
|     const html = document.getElementsByTagName("html")[0]; | ||||
|     if (isDefined(html)) { | ||||
|       html.style.fontSize = `${fontSize * 100}%`; | ||||
|     } | ||||
|   }, [fontSize]); | ||||
| 
 | ||||
|   useLayoutEffect(() => { | ||||
|     const next = document.getElementById("__next"); | ||||
|     if (isDefined(next)) { | ||||
|       if (darkMode) { | ||||
|         next.classList.add("set-theme-dark"); | ||||
|         next.classList.remove("set-theme-light"); | ||||
|       } else { | ||||
|         next.classList.add("set-theme-light"); | ||||
|         next.classList.remove("set-theme-dark"); | ||||
|       } | ||||
|     } | ||||
|   }, [darkMode]); | ||||
| 
 | ||||
|   useLayoutEffect(() => { | ||||
|     const next = document.getElementById("__next"); | ||||
|     if (isDefined(next)) { | ||||
|       if (dyslexic) { | ||||
|         next.classList.add("set-theme-font-dyslexic"); | ||||
|         next.classList.remove("set-theme-font-standard"); | ||||
|       } else { | ||||
|         next.classList.add("set-theme-font-standard"); | ||||
|         next.classList.remove("set-theme-font-dyslexic"); | ||||
|       } | ||||
|     } | ||||
|   }, [dyslexic]); | ||||
| 
 | ||||
|   return ( | ||||
|     <UserSettingsContext.Provider | ||||
|       value={{ | ||||
|         fontSize, | ||||
|         darkMode, | ||||
|         selectedThemeMode, | ||||
|         dyslexic, | ||||
|         currency, | ||||
|         playerName, | ||||
|         preferredLanguages, | ||||
|         setFontSize, | ||||
|         setDarkMode, | ||||
|         setSelectedThemeMode, | ||||
|         setDyslexic, | ||||
|         setCurrency, | ||||
|         setPlayerName, | ||||
|         setPreferredLanguages, | ||||
|         toggleDarkMode, | ||||
|         toggleSelectedThemeMode, | ||||
|         toggleDyslexic, | ||||
|       }}> | ||||
|       <SettingsPopup /> | ||||
|       {children} | ||||
|     </UserSettingsContext.Provider> | ||||
|   ); | ||||
| }; | ||||
							
								
								
									
										29
									
								
								src/contexts/appLayout.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/contexts/appLayout.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| import { useRouter } from "next/router"; | ||||
| import { useEffect } from "react"; | ||||
| import { useScrollIntoView } from "hooks/useScrollIntoView"; | ||||
| import { useAtomSetter } from "helpers/atoms"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| 
 | ||||
| export const useAppLayout = (): void => { | ||||
|   const router = useRouter(); | ||||
| 
 | ||||
|   const setSettingsOpened = useAtomSetter(atoms.layout.settingsOpened); | ||||
|   const setMainPanelOpened = useAtomSetter(atoms.layout.mainPanelOpened); | ||||
|   const setSubPanelOpened = useAtomSetter(atoms.layout.subPanelOpened); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     router.events.on("routeChangeStart", () => { | ||||
|       console.log("[Router Events] on routeChangeStart"); | ||||
|       setSettingsOpened(false); | ||||
|       setMainPanelOpened(false); | ||||
|       setSubPanelOpened(false); | ||||
|     }); | ||||
| 
 | ||||
|     router.events.on("hashChangeStart", () => { | ||||
|       console.log("[Router Events] on hashChangeStart"); | ||||
|       setSubPanelOpened(false); | ||||
|     }); | ||||
|   }, [router, setSettingsOpened, setMainPanelOpened, setSubPanelOpened]); | ||||
| 
 | ||||
|   useScrollIntoView(); | ||||
| }; | ||||
							
								
								
									
										49
									
								
								src/contexts/atoms.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/contexts/atoms.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| import { atom } from "jotai"; | ||||
| import { atomWithStorage } from "jotai/utils"; | ||||
| import { localData } from "contexts/localData"; | ||||
| import { containerQueries } from "contexts/containerQueries"; | ||||
| import { atomPairing } from "helpers/atoms"; | ||||
| import { settings } from "contexts/settings"; | ||||
| import { lightBox } from "contexts/LightBoxProvider"; | ||||
| 
 | ||||
| /* | ||||
|  * I'm getting a weird error if I put those atoms in appLayout.ts | ||||
|  * So I'm putting the atoms here. Sucks, I know. | ||||
|  */ | ||||
| 
 | ||||
| /* [ APPLAYOUT ATOMS ] */ | ||||
| 
 | ||||
| const mainPanelReduced = atomPairing(atomWithStorage("isMainPanelReduced", false)); | ||||
| const settingsOpened = atomPairing(atomWithStorage("isSettingsOpened", false)); | ||||
| const subPanelOpened = atomPairing(atomWithStorage("isSubPanelOpened", false)); | ||||
| const mainPanelOpened = atomPairing(atomWithStorage("isMainPanelOpened", false)); | ||||
| const menuGesturesEnabled = atomPairing(atomWithStorage("isMenuGesturesEnabled", false)); | ||||
| const terminalMode = atom((get) => get(settings.playerName[0]) === "root"); | ||||
| 
 | ||||
| const layout = { | ||||
|   mainPanelReduced, | ||||
|   settingsOpened, | ||||
|   subPanelOpened, | ||||
|   mainPanelOpened, | ||||
|   menuGesturesEnabled, | ||||
|   terminalMode, | ||||
| }; | ||||
| 
 | ||||
| /* [ TERMINAL ATOMS ] */ | ||||
| 
 | ||||
| const previousLines = atomPairing(atom<string[]>([])); | ||||
| const previousCommands = atomPairing(atom<string[]>([])); | ||||
| 
 | ||||
| const terminal = { | ||||
|   previousLines, | ||||
|   previousCommands, | ||||
| }; | ||||
| 
 | ||||
| export const atoms = { | ||||
|   settings, | ||||
|   layout, | ||||
|   terminal, | ||||
|   localData, | ||||
|   lightBox, | ||||
|   containerQueries, | ||||
| }; | ||||
							
								
								
									
										146
									
								
								src/contexts/containerQueries.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								src/contexts/containerQueries.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,146 @@ | ||||
| import { atom, Getter } from "jotai"; | ||||
| import { atomPairing, useAtomSetter } from "helpers/atoms"; | ||||
| import { useOnResize } from "hooks/useOnResize"; | ||||
| import { Ids } from "types/ids"; | ||||
| import { settings } from "contexts/settings"; | ||||
| 
 | ||||
| type Size = | ||||
|   | "2xl" | ||||
|   | "2xs" | ||||
|   | "3xl" | ||||
|   | "4xl" | ||||
|   | "5xl" | ||||
|   | "6xl" | ||||
|   | "7xl" | ||||
|   | "lg" | ||||
|   | "md" | ||||
|   | "sm" | ||||
|   | "xl" | ||||
|   | "xs"; | ||||
| 
 | ||||
| const sizes: Record<Size, number> = { | ||||
|   "2xl": 42, | ||||
|   "3xl": 48, | ||||
|   "4xl": 56, | ||||
|   "5xl": 64, | ||||
|   "6xl": 72, | ||||
|   "7xl": 80, | ||||
|   lg: 32, | ||||
|   md: 28, | ||||
|   sm: 24, | ||||
|   xl: 36, | ||||
|   xs: 19, | ||||
|   "2xs": 16, | ||||
| }; | ||||
| 
 | ||||
| const isAtLeastContainerQuery = (width: number, size: Size, fontSize: number): boolean => | ||||
|   width >= sizes[size] * 16 * fontSize; | ||||
| 
 | ||||
| const screenWidth = atomPairing(atom(0)); | ||||
| const contentPanelWidth = atomPairing(atom(0)); | ||||
| const subPanelWidth = atomPairing(atom(0)); | ||||
| 
 | ||||
| const screenGetter = (get: Getter, size: Size) => | ||||
|   isAtLeastContainerQuery(get(screenWidth[0]), size, get(settings.fontSize[0])); | ||||
| 
 | ||||
| const isScreenAtLeast2xs = atom((get) => screenGetter(get, "2xs")); | ||||
| const isScreenAtLeastXs = atom((get) => screenGetter(get, "xs")); | ||||
| const isScreenAtLeastSm = atom((get) => screenGetter(get, "sm")); | ||||
| const isScreenAtLeastMd = atom((get) => screenGetter(get, "md")); | ||||
| const isScreenAtLeastLg = atom((get) => screenGetter(get, "lg")); | ||||
| const isScreenAtLeastXl = atom((get) => screenGetter(get, "xl")); | ||||
| const isScreenAtLeast2xl = atom((get) => screenGetter(get, "2xl")); | ||||
| const isScreenAtLeast3xl = atom((get) => screenGetter(get, "3xl")); | ||||
| const isScreenAtLeast4xl = atom((get) => screenGetter(get, "4xl")); | ||||
| const isScreenAtLeast5xl = atom((get) => screenGetter(get, "5xl")); | ||||
| const isScreenAtLeast6xl = atom((get) => screenGetter(get, "6xl")); | ||||
| const isScreenAtLeast7xl = atom((get) => screenGetter(get, "7xl")); | ||||
| 
 | ||||
| const is1ColumnLayout = atom((get) => !get(isScreenAtLeast5xl)); | ||||
| const is3ColumnsLayout = atom((get) => get(isScreenAtLeast5xl)); | ||||
| 
 | ||||
| const contentPanelGetter = (get: Getter, size: Size) => | ||||
|   isAtLeastContainerQuery(get(contentPanelWidth[0]), size, get(settings.fontSize[0])); | ||||
| 
 | ||||
| const isContentPanelAtLeast2xs = atom((get) => contentPanelGetter(get, "2xs")); | ||||
| const isContentPanelAtLeastXs = atom((get) => contentPanelGetter(get, "xs")); | ||||
| const isContentPanelAtLeastSm = atom((get) => contentPanelGetter(get, "sm")); | ||||
| const isContentPanelAtLeastMd = atom((get) => contentPanelGetter(get, "md")); | ||||
| const isContentPanelAtLeastLg = atom((get) => contentPanelGetter(get, "lg")); | ||||
| const isContentPanelAtLeastXl = atom((get) => contentPanelGetter(get, "xl")); | ||||
| const isContentPanelAtLeast2xl = atom((get) => contentPanelGetter(get, "2xl")); | ||||
| const isContentPanelAtLeast3xl = atom((get) => contentPanelGetter(get, "3xl")); | ||||
| const isContentPanelAtLeast4xl = atom((get) => contentPanelGetter(get, "4xl")); | ||||
| const isContentPanelAtLeast5xl = atom((get) => contentPanelGetter(get, "5xl")); | ||||
| const isContentPanelAtLeast6xl = atom((get) => contentPanelGetter(get, "6xl")); | ||||
| const isContentPanelAtLeast7xl = atom((get) => contentPanelGetter(get, "7xl")); | ||||
| 
 | ||||
| const subPanelGetter = (get: Getter, size: Size) => | ||||
|   isAtLeastContainerQuery(get(subPanelWidth[0]), size, get(settings.fontSize[0])); | ||||
| 
 | ||||
| const isSubPanelAtLeast2xs = atom((get) => subPanelGetter(get, "2xs")); | ||||
| const isSubPanelAtLeastXs = atom((get) => subPanelGetter(get, "xs")); | ||||
| const isSubPanelAtLeastSm = atom((get) => subPanelGetter(get, "sm")); | ||||
| const isSubPanelAtLeastMd = atom((get) => subPanelGetter(get, "md")); | ||||
| const isSubPanelAtLeastLg = atom((get) => subPanelGetter(get, "lg")); | ||||
| const isSubPanelAtLeastXl = atom((get) => subPanelGetter(get, "xl")); | ||||
| const isSubPanelAtLeast2xl = atom((get) => subPanelGetter(get, "2xl")); | ||||
| const isSubPanelAtLeast3xl = atom((get) => subPanelGetter(get, "3xl")); | ||||
| const isSubPanelAtLeast4xl = atom((get) => subPanelGetter(get, "4xl")); | ||||
| const isSubPanelAtLeast5xl = atom((get) => subPanelGetter(get, "5xl")); | ||||
| const isSubPanelAtLeast6xl = atom((get) => subPanelGetter(get, "6xl")); | ||||
| const isSubPanelAtLeast7xl = atom((get) => subPanelGetter(get, "7xl")); | ||||
| 
 | ||||
| export const containerQueries = { | ||||
|   is1ColumnLayout, | ||||
|   is3ColumnsLayout, | ||||
| 
 | ||||
|   isScreenAtLeast2xs, | ||||
|   isScreenAtLeastXs, | ||||
|   isScreenAtLeastSm, | ||||
|   isScreenAtLeastMd, | ||||
|   isScreenAtLeastLg, | ||||
|   isScreenAtLeastXl, | ||||
|   isScreenAtLeast2xl, | ||||
|   isScreenAtLeast3xl, | ||||
|   isScreenAtLeast4xl, | ||||
|   isScreenAtLeast5xl, | ||||
|   isScreenAtLeast6xl, | ||||
|   isScreenAtLeast7xl, | ||||
| 
 | ||||
|   isContentPanelAtLeast2xs, | ||||
|   isContentPanelAtLeastXs, | ||||
|   isContentPanelAtLeastSm, | ||||
|   isContentPanelAtLeastMd, | ||||
|   isContentPanelAtLeastLg, | ||||
|   isContentPanelAtLeastXl, | ||||
|   isContentPanelAtLeast2xl, | ||||
|   isContentPanelAtLeast3xl, | ||||
|   isContentPanelAtLeast4xl, | ||||
|   isContentPanelAtLeast5xl, | ||||
|   isContentPanelAtLeast6xl, | ||||
|   isContentPanelAtLeast7xl, | ||||
| 
 | ||||
|   isSubPanelAtLeast2xs, | ||||
|   isSubPanelAtLeastXs, | ||||
|   isSubPanelAtLeastSm, | ||||
|   isSubPanelAtLeastMd, | ||||
|   isSubPanelAtLeastLg, | ||||
|   isSubPanelAtLeastXl, | ||||
|   isSubPanelAtLeast2xl, | ||||
|   isSubPanelAtLeast3xl, | ||||
|   isSubPanelAtLeast4xl, | ||||
|   isSubPanelAtLeast5xl, | ||||
|   isSubPanelAtLeast6xl, | ||||
|   isSubPanelAtLeast7xl, | ||||
| }; | ||||
| 
 | ||||
| export const useContainerQueries = (): void => { | ||||
|   const setScreenWidth = useAtomSetter(screenWidth); | ||||
|   const setContentPanelWidth = useAtomSetter(contentPanelWidth); | ||||
|   const setSubPanelWidth = useAtomSetter(subPanelWidth); | ||||
| 
 | ||||
|   useOnResize(Ids.Body, (width) => setScreenWidth(width)); | ||||
|   useOnResize(Ids.ContentPanel, (width) => setContentPanelWidth(width)); | ||||
|   useOnResize(Ids.SubPanel, (width) => setSubPanelWidth(width)); | ||||
| }; | ||||
							
								
								
									
										59
									
								
								src/contexts/localData.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/contexts/localData.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| import { atom } from "jotai"; | ||||
| import { useRouter } from "next/router"; | ||||
| import { useEffect } from "react"; | ||||
| import { useFetch } from "usehooks-ts"; | ||||
| import { atomPairing, useAtomSetter } from "helpers/atoms"; | ||||
| import { | ||||
|   Languages, | ||||
|   Currencies, | ||||
|   Langui, | ||||
|   processLangui, | ||||
|   processCurrencies, | ||||
|   processLanguages, | ||||
| } from "helpers/localData"; | ||||
| import { | ||||
|   LocalDataGetWebsiteInterfacesQuery, | ||||
|   LocalDataGetCurrenciesQuery, | ||||
|   LocalDataGetLanguagesQuery, | ||||
| } from "graphql/generated"; | ||||
| import { LocalDataFile } from "graphql/fetchLocalData"; | ||||
| 
 | ||||
| const languages = atomPairing(atom<Languages>([])); | ||||
| const currencies = atomPairing(atom<Currencies>([])); | ||||
| const langui = atomPairing(atom<Langui>({})); | ||||
| 
 | ||||
| export const localData = { | ||||
|   languages: languages[0], | ||||
|   currencies: currencies[0], | ||||
|   langui: langui[0], | ||||
| }; | ||||
| 
 | ||||
| const getFileName = (name: LocalDataFile): string => `/local-data/${name}.json`; | ||||
| 
 | ||||
| export const useLocalData = (): void => { | ||||
|   const setLanguages = useAtomSetter(languages); | ||||
|   const setCurrencies = useAtomSetter(currencies); | ||||
|   const setLangui = useAtomSetter(langui); | ||||
| 
 | ||||
|   const { locale } = useRouter(); | ||||
|   const { data: rawLanguages } = useFetch<LocalDataGetLanguagesQuery>(getFileName("languages")); | ||||
|   const { data: rawCurrencies } = useFetch<LocalDataGetCurrenciesQuery>(getFileName("currencies")); | ||||
|   const { data: rawLangui } = useFetch<LocalDataGetWebsiteInterfacesQuery>( | ||||
|     getFileName("websiteInterfaces") | ||||
|   ); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     console.log("[useLocalData] Refresh languages"); | ||||
|     setLanguages(processLanguages(rawLanguages)); | ||||
|   }, [rawLanguages, setLanguages]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     console.log("[useLocalData] Refresh currencies"); | ||||
|     setCurrencies(processCurrencies(rawCurrencies)); | ||||
|   }, [rawCurrencies, setCurrencies]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     console.log("[useLocalData] Refresh langui"); | ||||
|     setLangui(processLangui(rawLangui, locale)); | ||||
|   }, [locale, rawLangui, setLangui]); | ||||
| }; | ||||
							
								
								
									
										103
									
								
								src/contexts/settings.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/contexts/settings.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | ||||
| import { useRouter } from "next/router"; | ||||
| import { useLayoutEffect, useEffect } from "react"; | ||||
| import { atom } from "jotai"; | ||||
| import { atomWithStorage } from "jotai/utils"; | ||||
| import { atomPairing, useAtomGetter, useAtomPair } from "helpers/atoms"; | ||||
| import { getDefaultPreferredLanguages } from "helpers/locales"; | ||||
| import { isDefined, isDefinedAndNotEmpty } from "helpers/others"; | ||||
| import { usePrefersDarkMode } from "hooks/useMediaQuery"; | ||||
| 
 | ||||
| export enum ThemeMode { | ||||
|   Dark = "dark", | ||||
|   Auto = "auto", | ||||
|   Light = "light", | ||||
| } | ||||
| 
 | ||||
| const preferredLanguagesAtom = atomPairing(atomWithStorage<string[]>("preferredLanguages", [])); | ||||
| const themeModeAtom = atomPairing(atomWithStorage<ThemeMode>("themeMode", ThemeMode.Auto)); | ||||
| const darkModeAtom = atomPairing(atom(false)); | ||||
| const fontSizeAtom = atomPairing(atomWithStorage("fontSize", 1)); | ||||
| const dyslexicAtom = atomPairing(atomWithStorage("isDyslexic", false)); | ||||
| const currencyAtom = atomPairing(atomWithStorage("currency", "USD")); | ||||
| const playerNameAtom = atomPairing(atomWithStorage("playerName", "")); | ||||
| 
 | ||||
| export const settings = { | ||||
|   preferredLanguages: preferredLanguagesAtom, | ||||
|   themeMode: themeModeAtom, | ||||
|   darkMode: darkModeAtom, | ||||
|   fontSize: fontSizeAtom, | ||||
|   dyslexic: dyslexicAtom, | ||||
|   currency: currencyAtom, | ||||
|   playerName: playerNameAtom, | ||||
| }; | ||||
| 
 | ||||
| export const useSettings = (): void => { | ||||
|   const router = useRouter(); | ||||
|   const [preferredLanguages, setPreferredLanguages] = useAtomPair(preferredLanguagesAtom); | ||||
|   const fontSize = useAtomGetter(fontSizeAtom); | ||||
|   const isDyslexic = useAtomGetter(dyslexicAtom); | ||||
|   const [isDarkMode, setDarkMode] = useAtomPair(darkModeAtom); | ||||
|   const themeMode = useAtomGetter(themeModeAtom); | ||||
| 
 | ||||
|   useLayoutEffect(() => { | ||||
|     const html = document.getElementsByTagName("html")[0]; | ||||
|     if (isDefined(html)) { | ||||
|       html.style.fontSize = `${fontSize * 100}%`; | ||||
|     } | ||||
|   }, [fontSize]); | ||||
| 
 | ||||
|   useLayoutEffect(() => { | ||||
|     const next = document.getElementById("__next"); | ||||
|     if (isDefined(next)) { | ||||
|       if (isDyslexic) { | ||||
|         next.classList.add("set-theme-font-dyslexic"); | ||||
|         next.classList.remove("set-theme-font-standard"); | ||||
|       } else { | ||||
|         next.classList.add("set-theme-font-standard"); | ||||
|         next.classList.remove("set-theme-font-dyslexic"); | ||||
|       } | ||||
|     } | ||||
|   }, [isDyslexic]); | ||||
| 
 | ||||
|   /* DARK MODE */ | ||||
|   const prefersDarkMode = usePrefersDarkMode(); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     setDarkMode(themeMode === ThemeMode.Auto ? prefersDarkMode : themeMode === ThemeMode.Dark); | ||||
|   }, [prefersDarkMode, setDarkMode, themeMode]); | ||||
| 
 | ||||
|   useLayoutEffect(() => { | ||||
|     const next = document.getElementById("__next"); | ||||
|     if (isDefined(next)) { | ||||
|       if (isDarkMode) { | ||||
|         next.classList.add("set-theme-dark"); | ||||
|         next.classList.remove("set-theme-light"); | ||||
|       } else { | ||||
|         next.classList.add("set-theme-light"); | ||||
|         next.classList.remove("set-theme-dark"); | ||||
|       } | ||||
|     } | ||||
|   }, [isDarkMode]); | ||||
| 
 | ||||
|   /* PREFERRED LANGUAGES */ | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (preferredLanguages.length === 0) { | ||||
|       if (isDefinedAndNotEmpty(router.locale) && router.locales) { | ||||
|         setPreferredLanguages(getDefaultPreferredLanguages(router.locale, router.locales)); | ||||
|       } | ||||
|     } else if (router.locale !== preferredLanguages[0]) { | ||||
|       /* | ||||
|        * Using a timeout to the code getting stuck into a loop when reaching the website with a | ||||
|        * different preferredLanguages[0] from router.locale | ||||
|        */ | ||||
|       setTimeout( | ||||
|         async () => | ||||
|           router.replace(router.asPath, router.asPath, { | ||||
|             locale: preferredLanguages[0], | ||||
|           }), | ||||
|         250 | ||||
|       ); | ||||
|     } | ||||
|   }, [preferredLanguages, router, setPreferredLanguages]); | ||||
| }; | ||||
| @ -2,6 +2,7 @@ export const sendAnalytics = (category: string, event: string): void => { | ||||
|   try { | ||||
|     umami(`[${category}] ${event}`); | ||||
|   } catch (error) { | ||||
|     if (error instanceof ReferenceError) return; | ||||
|     console.log(error); | ||||
|   } | ||||
| }; | ||||
|  | ||||
							
								
								
									
										26
									
								
								src/helpers/atoms.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/helpers/atoms.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| import { atom, PrimitiveAtom, Atom, WritableAtom, useAtom } from "jotai"; | ||||
| import { Dispatch, SetStateAction } from "react"; | ||||
| 
 | ||||
| type AtomPair<T> = [Atom<T>, WritableAtom<null, T>]; | ||||
| 
 | ||||
| export const atomPairing = <T>(anAtom: PrimitiveAtom<T>): AtomPair<T> => { | ||||
|   const getter = atom((get) => get(anAtom)); | ||||
|   const setter = atom(null, (_get, set, newText: T) => set(anAtom, newText)); | ||||
|   return [getter, setter]; | ||||
| }; | ||||
| 
 | ||||
| export const useAtomSetter = <T>(atomPair: AtomPair<T>): Dispatch<SetStateAction<T>> => { | ||||
|   const [, setter] = useAtom(atomPair[1]); | ||||
|   return setter as Dispatch<SetStateAction<T>>; | ||||
| }; | ||||
| 
 | ||||
| export const useAtomGetter = <T>(atomPair: Atom<T> | AtomPair<T>): T => { | ||||
|   const atomGet = Array.isArray(atomPair) ? atomPair[0] : atomPair; | ||||
|   const [getter] = useAtom(atomGet); | ||||
|   return getter; | ||||
| }; | ||||
| 
 | ||||
| export const useAtomPair = <T>(atomPair: AtomPair<T>): [T, Dispatch<SetStateAction<T>>] => [ | ||||
|   useAtomGetter(atomPair), | ||||
|   useAtomSetter(atomPair), | ||||
| ]; | ||||
| @ -1,18 +0,0 @@ | ||||
| import { Dispatch, SetStateAction, useEffect } from "react"; | ||||
| import { useLocalStorage } from "usehooks-ts"; | ||||
| import { usePrefersDarkMode } from "./useMediaQuery"; | ||||
| 
 | ||||
| export const useDarkMode = ( | ||||
|   key: string, | ||||
|   initialValue: boolean | ||||
| ): [boolean, boolean, Dispatch<SetStateAction<boolean>>, Dispatch<SetStateAction<boolean>>] => { | ||||
|   const [darkMode, setDarkMode] = useLocalStorage(key, initialValue); | ||||
|   const prefersDarkMode = usePrefersDarkMode(); | ||||
|   const [selectedThemeMode, setSelectedThemeMode] = useLocalStorage("selectedThemeMode", false); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (!selectedThemeMode) setDarkMode(prefersDarkMode); | ||||
|   }, [selectedThemeMode, prefersDarkMode, setDarkMode]); | ||||
| 
 | ||||
|   return [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode]; | ||||
| }; | ||||
| @ -1,6 +0,0 @@ | ||||
| import { useUserSettings } from "contexts/UserSettingsContext"; | ||||
| 
 | ||||
| export const useIsTerminalMode = (): boolean => { | ||||
|   const { playerName } = useUserSettings(); | ||||
|   return playerName === "root"; | ||||
| }; | ||||
| @ -3,8 +3,8 @@ import { useEffect, useMemo, useState } from "react"; | ||||
| import { LanguageSwitcher } from "components/Inputs/LanguageSwitcher"; | ||||
| import { filterDefined, isDefined } from "helpers/others"; | ||||
| import { getPreferredLanguage } from "helpers/locales"; | ||||
| import { useUserSettings } from "contexts/UserSettingsContext"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| interface Props<T> { | ||||
|   items: T[]; | ||||
| @ -17,8 +17,8 @@ export const useSmartLanguage = <T>({ | ||||
|   languageExtractor, | ||||
|   transform = (item) => item, | ||||
| }: Props<T>): [T | undefined, typeof LanguageSwitcher, Parameters<typeof LanguageSwitcher>[0]] => { | ||||
|   const { preferredLanguages } = useUserSettings(); | ||||
|   const { languages } = useLocalData(); | ||||
|   const preferredLanguages = useAtomGetter(atoms.settings.preferredLanguages); | ||||
|   const languages = useAtomGetter(atoms.localData.languages); | ||||
|   const router = useRouter(); | ||||
| 
 | ||||
|   const availableLocales = useMemo(() => { | ||||
|  | ||||
| @ -1,31 +0,0 @@ | ||||
| import { Dispatch, SetStateAction, useEffect, useState } from "react"; | ||||
| import { isDefined } from "helpers/others"; | ||||
| 
 | ||||
| export const useStateWithLocalStorage = <T>( | ||||
|   key: string, | ||||
|   initialValue: T | ||||
| ): [T, Dispatch<SetStateAction<T>>] => { | ||||
|   const [value, setValue] = useState<T>(initialValue); | ||||
|   const [isFromLocaleStorage, setFromLocaleStorage] = useState<boolean>(false); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     try { | ||||
|       const item = localStorage.getItem(key); | ||||
|       if (isDefined(item)) { | ||||
|         setValue(JSON.parse(item) as T); | ||||
|       } else { | ||||
|         setValue(initialValue); | ||||
|       } | ||||
|       setFromLocaleStorage(true); | ||||
|     } catch (error) { | ||||
|       console.warn(`Error reading localStorage key “${key}”:`, error); | ||||
|       setValue(initialValue); | ||||
|     } | ||||
|   }, [initialValue, key]); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (isFromLocaleStorage) localStorage.setItem(key, JSON.stringify(value)); | ||||
|   }, [value, key, isFromLocaleStorage]); | ||||
| 
 | ||||
|   return [value, setValue]; | ||||
| }; | ||||
| @ -5,7 +5,8 @@ import { ContentPanel } from "components/Containers/ContentPanel"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { Img } from "components/Img"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -15,7 +16,7 @@ import { useLocalData } from "contexts/LocalDataContext"; | ||||
| interface Props extends AppLayoutRequired {} | ||||
| 
 | ||||
| const FourOhFour = ({ openGraph, ...otherProps }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       contentPanel={ | ||||
|  | ||||
| @ -5,7 +5,8 @@ import { ContentPanel } from "components/Containers/ContentPanel"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { Img } from "components/Img"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -15,7 +16,7 @@ import { useLocalData } from "contexts/LocalDataContext"; | ||||
| interface Props extends AppLayoutRequired {} | ||||
| 
 | ||||
| const FiveHundred = ({ openGraph, ...otherProps }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       contentPanel={ | ||||
|  | ||||
| @ -9,7 +9,6 @@ import "@fontsource/zen-maru-gothic/900.css"; | ||||
| 
 | ||||
| import type { AppProps } from "next/app"; | ||||
| import Script from "next/script"; | ||||
| import { AppContextProvider } from "contexts/AppLayoutContext"; | ||||
| 
 | ||||
| import "styles/debug.css"; | ||||
| import "styles/formatted.css"; | ||||
| @ -17,31 +16,31 @@ import "styles/others.css"; | ||||
| import "styles/rc-slider.css"; | ||||
| import "styles/tippy.css"; | ||||
| 
 | ||||
| import { TerminalContextProvider } from "contexts/TerminalContext"; | ||||
| import { UserSettingsProvider as UserSettingsContextProvider } from "contexts/UserSettingsContext"; | ||||
| import { LocalDataContextProvider } from "contexts/LocalDataContext"; | ||||
| import { ContainerQueriesContextProvider } from "contexts/ContainerQueriesContext"; | ||||
| import { LightBoxContextProvider } from "contexts/LightBoxContext"; | ||||
| import { useLocalData } from "contexts/localData"; | ||||
| import { useAppLayout } from "contexts/appLayout"; | ||||
| import { LightBoxProvider } from "contexts/LightBoxProvider"; | ||||
| import { SettingsPopup } from "components/Panels/SettingsPopup"; | ||||
| import { useSettings } from "contexts/settings"; | ||||
| import { useContainerQueries } from "contexts/containerQueries"; | ||||
| 
 | ||||
| const AccordsLibraryApp = (props: AppProps): JSX.Element => ( | ||||
|   <LocalDataContextProvider> | ||||
|     <AppContextProvider> | ||||
|       <UserSettingsContextProvider> | ||||
|         <ContainerQueriesContextProvider> | ||||
|           <TerminalContextProvider> | ||||
|             <LightBoxContextProvider> | ||||
|               <Script | ||||
|                 async | ||||
|                 defer | ||||
|                 data-website-id={process.env.NEXT_PUBLIC_UMAMI_ID} | ||||
|                 src={`${process.env.NEXT_PUBLIC_UMAMI_URL}/umami.js`} | ||||
|               /> | ||||
|               <props.Component {...props.pageProps} /> | ||||
|             </LightBoxContextProvider> | ||||
|           </TerminalContextProvider> | ||||
|         </ContainerQueriesContextProvider> | ||||
|       </UserSettingsContextProvider> | ||||
|     </AppContextProvider> | ||||
|   </LocalDataContextProvider> | ||||
| ); | ||||
| const AccordsLibraryApp = (props: AppProps): JSX.Element => { | ||||
|   useLocalData(); | ||||
|   useAppLayout(); | ||||
|   useSettings(); | ||||
|   useContainerQueries(); | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <SettingsPopup /> | ||||
|       <LightBoxProvider /> | ||||
|       <Script | ||||
|         async | ||||
|         defer | ||||
|         data-website-id={process.env.NEXT_PUBLIC_UMAMI_ID} | ||||
|         src={`${process.env.NEXT_PUBLIC_UMAMI_URL}/umami.js`} | ||||
|       /> | ||||
|       <props.Component {...props.pageProps} /> | ||||
|     </> | ||||
|   ); | ||||
| }; | ||||
| export default AccordsLibraryApp; | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| import { PostPage } from "components/PostPage"; | ||||
| import { getPostStaticProps, PostStaticProps } from "graphql/getPostStaticProps"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -8,7 +9,7 @@ import { useLocalData } from "contexts/LocalDataContext"; | ||||
|  */ | ||||
| 
 | ||||
| const AccordsHandbook = (props: PostStaticProps): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   return ( | ||||
|     <PostPage | ||||
|       {...props} | ||||
|  | ||||
| @ -7,8 +7,8 @@ import { cIf, cJoin } from "helpers/className"; | ||||
| import { randomInt } from "helpers/numbers"; | ||||
| import { RequestMailProps, ResponseMailProps } from "pages/api/mail"; | ||||
| import { sendAnalytics } from "helpers/analytics"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -17,8 +17,8 @@ import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| 
 | ||||
| const AboutUs = (props: PostStaticProps): JSX.Element => { | ||||
|   const router = useRouter(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const { is1ColumnLayout } = useContainerQueries(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout); | ||||
|   const [formResponse, setFormResponse] = useState(""); | ||||
|   const [formState, setFormState] = useState<"completed" | "ongoing" | "stale">("stale"); | ||||
| 
 | ||||
|  | ||||
| @ -7,7 +7,8 @@ import { SubPanel } from "components/Containers/SubPanel"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -17,7 +18,7 @@ import { useLocalData } from "contexts/LocalDataContext"; | ||||
| interface Props extends AppLayoutRequired {} | ||||
| 
 | ||||
| const AboutUs = (props: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       subPanel={ | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| import { PostPage } from "components/PostPage"; | ||||
| import { getPostStaticProps, PostStaticProps } from "graphql/getPostStaticProps"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -8,7 +9,7 @@ import { useLocalData } from "contexts/LocalDataContext"; | ||||
|  */ | ||||
| 
 | ||||
| const Legality = (props: PostStaticProps): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   return ( | ||||
|     <PostPage | ||||
|       {...props} | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| import { PostPage } from "components/PostPage"; | ||||
| import { getPostStaticProps, PostStaticProps } from "graphql/getPostStaticProps"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -8,7 +9,7 @@ import { useLocalData } from "contexts/LocalDataContext"; | ||||
|  */ | ||||
| 
 | ||||
| const SharingPolicy = (props: PostStaticProps): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   return ( | ||||
|     <PostPage | ||||
|       {...props} | ||||
|  | ||||
| @ -8,7 +8,8 @@ import { Icon } from "components/Ico"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -18,7 +19,7 @@ import { useLocalData } from "contexts/LocalDataContext"; | ||||
| interface Props extends AppLayoutRequired {} | ||||
| 
 | ||||
| const Archives = (props: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const subPanel = useMemo( | ||||
|     () => ( | ||||
|       <SubPanel> | ||||
|  | ||||
| @ -22,8 +22,8 @@ import { SmartList } from "components/SmartList"; | ||||
| import { cIf } from "helpers/className"; | ||||
| import { TextInput } from "components/Inputs/TextInput"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -45,9 +45,9 @@ interface Props extends AppLayoutRequired { | ||||
| 
 | ||||
| const Channel = ({ channel, ...otherProps }: Props): JSX.Element => { | ||||
|   const { value: keepInfoVisible, toggle: toggleKeepInfoVisible } = useBoolean(true); | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const hoverable = useDeviceSupportsHover(); | ||||
|   const { isContentPanelAtLeast4xl } = useContainerQueries(); | ||||
|   const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl); | ||||
| 
 | ||||
|   const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName); | ||||
| 
 | ||||
|  | ||||
| @ -22,8 +22,8 @@ import { compareDate } from "helpers/date"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { cIf } from "helpers/className"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -44,9 +44,9 @@ interface Props extends AppLayoutRequired { | ||||
| } | ||||
| 
 | ||||
| const Videos = ({ videos, ...otherProps }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const hoverable = useDeviceSupportsHover(); | ||||
|   const { isContentPanelAtLeast4xl } = useContainerQueries(); | ||||
|   const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl); | ||||
| 
 | ||||
|   const { value: keepInfoVisible, toggle: toggleKeepInfoVisible } = useBoolean(true); | ||||
| 
 | ||||
|  | ||||
| @ -10,7 +10,6 @@ import { NavOption } from "components/PanelComponents/NavOption"; | ||||
| import { ReturnButton } from "components/PanelComponents/ReturnButton"; | ||||
| import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel"; | ||||
| import { SubPanel } from "components/Containers/SubPanel"; | ||||
| import { useAppLayout } from "contexts/AppLayoutContext"; | ||||
| import { GetVideoQuery } from "graphql/generated"; | ||||
| import { getReadySdk } from "graphql/sdk"; | ||||
| import { prettyDate, prettyShortenNumber } from "helpers/formatters"; | ||||
| @ -18,8 +17,8 @@ import { filterHasAttributes, isDefined } from "helpers/others"; | ||||
| import { getVideoFile } from "helpers/videos"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -31,9 +30,8 @@ interface Props extends AppLayoutRequired { | ||||
| } | ||||
| 
 | ||||
| const Video = ({ video, ...otherProps }: Props): JSX.Element => { | ||||
|   const { isContentPanelAtLeast4xl } = useContainerQueries(); | ||||
|   const { setSubPanelOpen } = useAppLayout(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const router = useRouter(); | ||||
| 
 | ||||
|   const subPanel = useMemo( | ||||
| @ -47,29 +45,12 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => { | ||||
| 
 | ||||
|         <HorizontalLine /> | ||||
| 
 | ||||
|         <NavOption | ||||
|           title={langui.video} | ||||
|           url="#video" | ||||
|           border | ||||
|           onClick={() => setSubPanelOpen(false)} | ||||
|         /> | ||||
| 
 | ||||
|         <NavOption | ||||
|           title={langui.channel} | ||||
|           url="#channel" | ||||
|           border | ||||
|           onClick={() => setSubPanelOpen(false)} | ||||
|         /> | ||||
| 
 | ||||
|         <NavOption | ||||
|           title={langui.description} | ||||
|           url="#description" | ||||
|           border | ||||
|           onClick={() => setSubPanelOpen(false)} | ||||
|         /> | ||||
|         <NavOption title={langui.video} url="#video" border /> | ||||
|         <NavOption title={langui.channel} url="#channel" border /> | ||||
|         <NavOption title={langui.description} url="#description" border /> | ||||
|       </SubPanel> | ||||
|     ), | ||||
|     [setSubPanelOpen, langui] | ||||
|     [langui] | ||||
|   ); | ||||
| 
 | ||||
|   const contentPanel = useMemo( | ||||
|  | ||||
| @ -19,7 +19,8 @@ import { getDefaultPreferredLanguages, staticSmartLanguage } from "helpers/local | ||||
| import { getDescription } from "helpers/description"; | ||||
| import { TranslatedChroniclesList } from "components/Chronicles/ChroniclesList"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -32,7 +33,7 @@ interface Props extends AppLayoutRequired { | ||||
| } | ||||
| 
 | ||||
| const Chronicle = ({ chronicle, chapters, ...otherProps }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({ | ||||
|     items: chronicle.translations, | ||||
|     languageExtractor: useCallback( | ||||
|  | ||||
| @ -12,7 +12,8 @@ import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { TranslatedChroniclesList } from "components/Chronicles/ChroniclesList"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -24,7 +25,7 @@ interface Props extends AppLayoutRequired { | ||||
| } | ||||
| 
 | ||||
| const Chronicles = ({ chapters, ...otherProps }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const subPanel = useMemo( | ||||
|     () => ( | ||||
|       <SubPanel> | ||||
|  | ||||
| @ -32,8 +32,8 @@ import { TranslatedPreviewLine } from "components/PreviewLine"; | ||||
| import { cIf } from "helpers/className"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { Ids } from "types/ids"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -45,8 +45,11 @@ interface Props extends AppLayoutRequired { | ||||
| } | ||||
| 
 | ||||
| const Content = ({ content, ...otherProps }: Props): JSX.Element => { | ||||
|   const { isContentPanelAtLeast2xl, is1ColumnLayout } = useContainerQueries(); | ||||
|   const { langui, languages } = useLocalData(); | ||||
|   const isContentPanelAtLeast2xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast2xl); | ||||
|   const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout); | ||||
| 
 | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const languages = useAtomGetter(atoms.localData.languages); | ||||
| 
 | ||||
|   const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({ | ||||
|     items: content.translations, | ||||
|  | ||||
| @ -25,8 +25,8 @@ import { TranslatedPreviewCard } from "components/PreviewCard"; | ||||
| import { cJoin, cIf } from "helpers/className"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { sendAnalytics } from "helpers/analytics"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -50,8 +50,8 @@ interface Props extends AppLayoutRequired { | ||||
| 
 | ||||
| const Contents = ({ contents, ...otherProps }: Props): JSX.Element => { | ||||
|   const hoverable = useDeviceSupportsHover(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const { isContentPanelAtLeast4xl } = useContainerQueries(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl); | ||||
| 
 | ||||
|   const [groupingMethod, setGroupingMethod] = useState<number>( | ||||
|     DEFAULT_FILTERS_STATE.groupingMethod | ||||
|  | ||||
| @ -18,8 +18,8 @@ import { TranslatedPreviewCard } from "components/PreviewCard"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { cJoin, cIf } from "helpers/className"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| import { TranslatedPreviewFolder } from "components/Contents/PreviewFolder"; | ||||
| 
 | ||||
| /* | ||||
| @ -34,8 +34,8 @@ interface Props extends AppLayoutRequired { | ||||
| } | ||||
| 
 | ||||
| const ContentsFolder = ({ openGraph, folder, ...otherProps }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const { isContentPanelAtLeast4xl } = useContainerQueries(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl); | ||||
| 
 | ||||
|   const subPanel = useMemo( | ||||
|     () => ( | ||||
| @ -273,7 +273,7 @@ export const getStaticPaths: GetStaticPaths = async (context) => { | ||||
|  */ | ||||
| 
 | ||||
| const NoContentNorFolderMessage = () => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   return ( | ||||
|     <div className="grid place-content-center"> | ||||
|       <div | ||||
|  | ||||
| @ -2,8 +2,8 @@ import { PostPage } from "components/PostPage"; | ||||
| import { getPostStaticProps, PostStaticProps } from "graphql/getPostStaticProps"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { Terminal } from "components/Cli/Terminal"; | ||||
| import { useIsTerminalMode } from "hooks/useIsTerminalMode"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -11,8 +11,8 @@ import { useLocalData } from "contexts/LocalDataContext"; | ||||
|  */ | ||||
| 
 | ||||
| const Home = ({ ...otherProps }: PostStaticProps): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const isTerminalMode = useIsTerminalMode(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const isTerminalMode = useAtomGetter(atoms.layout.terminalMode); | ||||
| 
 | ||||
|   if (isTerminalMode) { | ||||
|     return ( | ||||
|  | ||||
| @ -51,10 +51,8 @@ import { useIntersectionList } from "hooks/useIntersectionList"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { Ids } from "types/ids"; | ||||
| import { useUserSettings } from "contexts/UserSettingsContext"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { useLightBox } from "contexts/LightBoxContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -74,14 +72,18 @@ interface Props extends AppLayoutRequired { | ||||
| } | ||||
| 
 | ||||
| const LibrarySlug = ({ item, itemId, ...otherProps }: Props): JSX.Element => { | ||||
|   const { currency } = useUserSettings(); | ||||
|   const { langui, currencies } = useLocalData(); | ||||
|   const { isContentPanelAtLeast3xl, isContentPanelAtLeastSm } = useContainerQueries(); | ||||
|   const currency = useAtomGetter(atoms.settings.currency); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const currencies = useAtomGetter(atoms.localData.currencies); | ||||
| 
 | ||||
|   const isContentPanelAtLeast3xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast3xl); | ||||
|   const isContentPanelAtLeastSm = useAtomGetter(atoms.containerQueries.isContentPanelAtLeastSm); | ||||
| 
 | ||||
|   const hoverable = useDeviceSupportsHover(); | ||||
|   const router = useRouter(); | ||||
|   const { value: keepInfoVisible, toggle: toggleKeepInfoVisible } = useBoolean(false); | ||||
| 
 | ||||
|   const { showLightBox } = useLightBox(); | ||||
|   const { showLightBox } = useAtomGetter(atoms.lightBox); | ||||
| 
 | ||||
|   useScrollTopOnChange(Ids.ContentPanel, [item]); | ||||
|   const currentIntersection = useIntersectionList(intersectionIds); | ||||
| @ -692,7 +694,7 @@ const ContentLine = ({ | ||||
|   parentSlug, | ||||
|   condensed, | ||||
| }: ContentLineProps): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const { value: isOpened, toggle: toggleOpened } = useBoolean(false); | ||||
|   const [selectedTranslation] = useSmartLanguage({ | ||||
|     items: content?.translations ?? [], | ||||
|  | ||||
| @ -41,14 +41,13 @@ import { useSmartLanguage } from "hooks/useSmartLanguage"; | ||||
| import { TranslatedProps } from "types/TranslatedProps"; | ||||
| import { prettyInlineTitle, prettySlug } from "helpers/formatters"; | ||||
| import { useFullscreen } from "hooks/useFullscreen"; | ||||
| import { useUserSettings } from "contexts/UserSettingsContext"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| import { FilterSettings, useReaderSettings } from "hooks/useReaderSettings"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| 
 | ||||
| const CUSTOM_DARK_DROPSHADOW = ` | ||||
| drop-shadow(0 0    0.5em rgb(var(--theme-color-shade) / 30%)) | ||||
| drop-shadow(0 1em    1em rgb(var(--theme-color-shade) / 40%)) | ||||
|   drop-shadow(0 0    0.5em rgb(var(--theme-color-shade) / 30%)) | ||||
|   drop-shadow(0 1em    1em rgb(var(--theme-color-shade) / 40%)) | ||||
|   drop-shadow(0 2em    2em rgb(var(--theme-color-shade) / 60%)) | ||||
|   drop-shadow(0 12em  12em rgb(var(--theme-color-shade) / 80%))`;
 | ||||
| 
 | ||||
| @ -90,9 +89,9 @@ const LibrarySlug = ({ | ||||
|   item, | ||||
|   ...otherProps | ||||
| }: Props): JSX.Element => { | ||||
|   const { is1ColumnLayout } = useContainerQueries(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const { darkMode } = useUserSettings(); | ||||
|   const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const isDarkMode = useAtomGetter(atoms.settings.darkMode); | ||||
|   const { | ||||
|     filterSettings, | ||||
|     isSidePagesEnabled, | ||||
| @ -453,7 +452,7 @@ const LibrarySlug = ({ | ||||
|                 display: "grid", | ||||
|                 placeContent: "center", | ||||
|                 filter: filterSettings.dropShadow | ||||
|                   ? darkMode | ||||
|                   ? isDarkMode | ||||
|                     ? CUSTOM_DARK_DROPSHADOW | ||||
|                     : CUSTOM_LIGHT_DROPSHADOW | ||||
|                   : undefined, | ||||
| @ -631,7 +630,7 @@ const LibrarySlug = ({ | ||||
|       is1ColumnLayout, | ||||
|       currentZoom, | ||||
|       filterSettings, | ||||
|       darkMode, | ||||
|       isDarkMode, | ||||
|       pageHeight, | ||||
|       effectiveDisplayMode, | ||||
|       firstPage, | ||||
| @ -798,7 +797,7 @@ interface PageFiltersProps { | ||||
| } | ||||
| 
 | ||||
| const PageFilters = ({ page, bookType, options }: PageFiltersProps) => { | ||||
|   const { darkMode } = useUserSettings(); | ||||
|   const isDarkMode = useAtomGetter(atoms.settings.darkMode); | ||||
|   const commonCss = useMemo( | ||||
|     () => cJoin("absolute inset-0", cIf(page === "right", "[background-position-x:-100%]")), | ||||
|     [page] | ||||
| @ -823,7 +822,7 @@ const PageFilters = ({ page, bookType, options }: PageFiltersProps) => { | ||||
|             commonCss, | ||||
|             `bg-blend-lighten mix-blend-multiply [background-image:url(/reader/book-fold.webp)]
 | ||||
|           [background-size:200%_100%]`,
 | ||||
|             cIf(!darkMode, "bg-[#FFF]/50") | ||||
|             cIf(!isDarkMode, "bg-[#FFF]/50") | ||||
|           )} | ||||
|         /> | ||||
|       )} | ||||
| @ -834,7 +833,7 @@ const PageFilters = ({ page, bookType, options }: PageFiltersProps) => { | ||||
|             className={cJoin( | ||||
|               commonCss, | ||||
|               `bg-blend-lighten mix-blend-multiply [background-size:200%_100%]`, | ||||
|               cIf(!darkMode, "bg-[#FFF]/50"), | ||||
|               cIf(!isDarkMode, "bg-[#FFF]/50"), | ||||
|               cIf( | ||||
|                 page === "single", | ||||
|                 "[background-image:url(/reader/lighting-single-page.webp)]", | ||||
| @ -846,7 +845,7 @@ const PageFilters = ({ page, bookType, options }: PageFiltersProps) => { | ||||
|             className={cJoin( | ||||
|               commonCss, | ||||
|               `bg-blend-lighten mix-blend-soft-light [background-size:200%_100%]`, | ||||
|               cIf(!darkMode, "bg-[#FFF]/30"), | ||||
|               cIf(!isDarkMode, "bg-[#FFF]/30"), | ||||
|               cIf( | ||||
|                 page === "single", | ||||
|                 "[background-image:url(/reader/specular-single-page.webp)]", | ||||
| @ -889,8 +888,8 @@ interface ScanSetProps { | ||||
| } | ||||
| 
 | ||||
| const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps): JSX.Element => { | ||||
|   const { is1ColumnLayout } = useContainerQueries(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const [selectedScan, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({ | ||||
|     items: scanSet, | ||||
|     languageExtractor: useCallback( | ||||
|  | ||||
| @ -31,9 +31,9 @@ import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { cIf, cJoin } from "helpers/className"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { sendAnalytics } from "helpers/analytics"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| import { useLibraryItemUserStatus } from "hooks/useLibraryItemUserStatus"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -62,9 +62,11 @@ interface Props extends AppLayoutRequired { | ||||
| 
 | ||||
| const Library = ({ items, ...otherProps }: Props): JSX.Element => { | ||||
|   const hoverable = useDeviceSupportsHover(); | ||||
|   const { langui, currencies } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const currencies = useAtomGetter(atoms.localData.currencies); | ||||
| 
 | ||||
|   const { libraryItemUserStatus } = useLibraryItemUserStatus(); | ||||
|   const { isContentPanelAtLeast4xl } = useContainerQueries(); | ||||
|   const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl); | ||||
| 
 | ||||
|   const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName); | ||||
| 
 | ||||
|  | ||||
| @ -5,7 +5,8 @@ import { SubPanel } from "components/Containers/SubPanel"; | ||||
| import { Icon } from "components/Ico"; | ||||
| import { getOpenGraph } from "helpers/openGraph"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -14,7 +15,7 @@ import { useLocalData } from "contexts/LocalDataContext"; | ||||
| 
 | ||||
| interface Props extends AppLayoutRequired {} | ||||
| const Merch = (props: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   return ( | ||||
|     <AppLayout | ||||
|       subPanel={ | ||||
|  | ||||
| @ -4,14 +4,13 @@ import { PostPage } from "components/PostPage"; | ||||
| import { getPostStaticProps, PostStaticProps } from "graphql/getPostStaticProps"; | ||||
| import { getReadySdk } from "graphql/sdk"; | ||||
| import { filterHasAttributes, isDefined, isDefinedAndNotEmpty } from "helpers/others"; | ||||
| import { useIsTerminalMode } from "hooks/useIsTerminalMode"; | ||||
| import { Terminal } from "components/Cli/Terminal"; | ||||
| import { PostWithTranslations } from "types/types"; | ||||
| import { getDefaultPreferredLanguages, staticSmartLanguage } from "helpers/locales"; | ||||
| import { prettyTerminalBoxedTitle } from "helpers/terminal"; | ||||
| import { prettyMarkdown } from "helpers/description"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| 
 | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
|  * ──────────────────────────────────────────╯  PAGE  ╰───────────────────────────────────────────── | ||||
| @ -20,8 +19,8 @@ import { useLocalData } from "contexts/LocalDataContext"; | ||||
| interface Props extends PostStaticProps {} | ||||
| 
 | ||||
| const LibrarySlug = (props: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const isTerminalMode = useIsTerminalMode(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const isTerminalMode = useAtomGetter(atoms.layout.terminalMode); | ||||
|   const router = useRouter(); | ||||
| 
 | ||||
|   if (isTerminalMode) { | ||||
|  | ||||
| @ -23,10 +23,9 @@ import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { cIf } from "helpers/className"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { sendAnalytics } from "helpers/analytics"; | ||||
| import { useIsTerminalMode } from "hooks/useIsTerminalMode"; | ||||
| import { Terminal } from "components/Cli/Terminal"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -48,8 +47,8 @@ interface Props extends AppLayoutRequired { | ||||
| } | ||||
| 
 | ||||
| const News = ({ posts, ...otherProps }: Props): JSX.Element => { | ||||
|   const { isContentPanelAtLeast4xl } = useContainerQueries(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const hoverable = useDeviceSupportsHover(); | ||||
|   const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName); | ||||
|   const { | ||||
| @ -57,7 +56,7 @@ const News = ({ posts, ...otherProps }: Props): JSX.Element => { | ||||
|     toggle: toggleKeepInfoVisible, | ||||
|     setValue: setKeepInfoVisible, | ||||
|   } = useBoolean(DEFAULT_FILTERS_STATE.keepInfoVisible); | ||||
|   const isTerminalMode = useIsTerminalMode(); | ||||
|   const isTerminalMode = useAtomGetter(atoms.layout.terminalMode); | ||||
| 
 | ||||
|   const subPanel = useMemo( | ||||
|     () => ( | ||||
|  | ||||
| @ -22,10 +22,8 @@ import { cIf, cJoin } from "helpers/className"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { Terminal } from "components/Cli/Terminal"; | ||||
| import { prettyTerminalBoxedTitle, prettyTerminalUnderlinedTitle } from "helpers/terminal"; | ||||
| import { useIsTerminalMode } from "hooks/useIsTerminalMode"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { useLightBox } from "contexts/LightBoxContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -37,10 +35,10 @@ interface Props extends AppLayoutRequired { | ||||
| } | ||||
| 
 | ||||
| const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const router = useRouter(); | ||||
|   const isTerminalMode = useIsTerminalMode(); | ||||
|   const { showLightBox } = useLightBox(); | ||||
|   const isTerminalMode = useAtomGetter(atoms.layout.terminalMode); | ||||
|   const { showLightBox } = useAtomGetter(atoms.lightBox); | ||||
|   const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({ | ||||
|     items: page.translations, | ||||
|     languageExtractor: useCallback( | ||||
| @ -49,7 +47,7 @@ const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => { | ||||
|       [] | ||||
|     ), | ||||
|   }); | ||||
|   const { is3ColumnsLayout } = useContainerQueries(); | ||||
|   const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout); | ||||
| 
 | ||||
|   const subPanel = useMemo( | ||||
|     () => ( | ||||
|  | ||||
| @ -31,7 +31,8 @@ import { TranslatedNavOption } from "components/PanelComponents/NavOption"; | ||||
| import { useIntersectionList } from "hooks/useIntersectionList"; | ||||
| import { HorizontalLine } from "components/HorizontalLine"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                           ╭────────╮ | ||||
| @ -44,7 +45,7 @@ interface Props extends AppLayoutRequired { | ||||
| } | ||||
| 
 | ||||
| const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const ids = useMemo( | ||||
|     () => | ||||
|       filterHasAttributes(chronologyEras, ["attributes"] as const).map( | ||||
| @ -315,7 +316,7 @@ interface ChronologyEventProps { | ||||
| } | ||||
| 
 | ||||
| export const ChronologyEvent = ({ event, id }: ChronologyEventProps): JSX.Element => { | ||||
|   const { langui } = useLocalData(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({ | ||||
|     items: event.translations ?? [], | ||||
|     languageExtractor: useCallback( | ||||
|  | ||||
| @ -26,9 +26,8 @@ import { cIf } from "helpers/className"; | ||||
| import { getLangui } from "graphql/fetchLocalData"; | ||||
| import { sendAnalytics } from "helpers/analytics"; | ||||
| import { Terminal } from "components/Cli/Terminal"; | ||||
| import { useIsTerminalMode } from "hooks/useIsTerminalMode"; | ||||
| import { useLocalData } from "contexts/LocalDataContext"; | ||||
| import { useContainerQueries } from "contexts/ContainerQueriesContext"; | ||||
| import { atoms } from "contexts/atoms"; | ||||
| import { useAtomGetter } from "helpers/atoms"; | ||||
| 
 | ||||
| /* | ||||
|  *                                         ╭─────────────╮ | ||||
| @ -52,9 +51,9 @@ interface Props extends AppLayoutRequired { | ||||
| 
 | ||||
| const Wiki = ({ pages, ...otherProps }: Props): JSX.Element => { | ||||
|   const hoverable = useDeviceSupportsHover(); | ||||
|   const { langui } = useLocalData(); | ||||
|   const { isContentPanelAtLeast4xl } = useContainerQueries(); | ||||
|   const isTerminalMode = useIsTerminalMode(); | ||||
|   const langui = useAtomGetter(atoms.localData.langui); | ||||
|   const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl); | ||||
|   const isTerminalMode = useAtomGetter(atoms.layout.terminalMode); | ||||
| 
 | ||||
|   const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName); | ||||
| 
 | ||||
|  | ||||
| @ -45,12 +45,6 @@ export interface ChronicleWithTranslations extends Omit<Chronicle, "translations | ||||
| 
 | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export type RequiredNonNullable<T> = { | ||||
|   [P in keyof T]-?: NonNullable<T[P]>; | ||||
| }; | ||||
| 
 | ||||
| // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
 | ||||
| 
 | ||||
| export enum LibraryItemUserStatus { | ||||
|   None = 0, | ||||
|   Want = 1, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 DrMint
						DrMint