@scrabble-solver/scrabble-solver 2.17.0 → 2.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +22 -20
  3. package/.next/cache/.previewinfo +1 -1
  4. package/.next/cache/.rscinfo +1 -1
  5. package/.next/cache/.tsbuildinfo +1 -1
  6. package/.next/cache/webpack/client-production/0.pack +0 -0
  7. package/.next/cache/webpack/client-production/index.pack +0 -0
  8. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  9. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  10. package/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
  11. package/.next/cache/webpack/server-production/0.pack +0 -0
  12. package/.next/cache/webpack/server-production/index.pack +0 -0
  13. package/.next/cache/webpack/server-production/index.pack.old +0 -0
  14. package/.next/diagnostics/framework.json +1 -1
  15. package/.next/dynamic-css-manifest.json +8 -1
  16. package/.next/next-minimal-server.js.nft.json +1 -1
  17. package/.next/next-server.js.nft.json +1 -1
  18. package/.next/prerender-manifest.json +4 -4
  19. package/.next/react-loadable-manifest.json +176 -1
  20. package/.next/routes-manifest.json +1 -1
  21. package/.next/server/chunks/309.js +1 -0
  22. package/.next/server/chunks/{785.js → 316.js} +1 -1
  23. package/.next/server/chunks/344.js +1 -0
  24. package/.next/server/chunks/371.js +1 -0
  25. package/.next/server/chunks/465.js +1 -0
  26. package/.next/server/chunks/546.js +1 -0
  27. package/.next/server/chunks/623.js +1 -0
  28. package/.next/server/chunks/624.js +1 -0
  29. package/.next/server/chunks/641.js +1 -0
  30. package/.next/server/chunks/671.js +1 -1
  31. package/.next/server/chunks/692.js +1 -0
  32. package/.next/server/chunks/705.js +1 -0
  33. package/.next/server/chunks/712.js +1 -1
  34. package/.next/server/chunks/846.js +1 -0
  35. package/.next/server/chunks/853.js +15 -0
  36. package/.next/server/chunks/886.js +1 -0
  37. package/.next/server/chunks/916.js +1 -0
  38. package/.next/server/chunks/953.js +1 -0
  39. package/.next/server/chunks/961.js +1 -0
  40. package/.next/server/chunks/968.js +1 -0
  41. package/.next/server/dynamic-css-manifest.js +1 -1
  42. package/.next/server/middleware-build-manifest.js +1 -1
  43. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  44. package/.next/server/pages/404.html +29 -1
  45. package/.next/server/pages/500.html +29 -1
  46. package/.next/server/pages/_app.js +1 -1
  47. package/.next/server/pages/_app.js.nft.json +1 -1
  48. package/.next/server/pages/_document.js +28 -1
  49. package/.next/server/pages/_document.js.nft.json +1 -1
  50. package/.next/server/pages/_error.js +28 -1
  51. package/.next/server/pages/_error.js.nft.json +1 -1
  52. package/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  53. package/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  54. package/.next/server/pages/api/solve.js +1 -1
  55. package/.next/server/pages/api/solve.js.nft.json +1 -1
  56. package/.next/server/pages/api/verify.js.nft.json +1 -1
  57. package/.next/server/pages/api/visit.js.nft.json +1 -1
  58. package/.next/server/pages/index.html +29 -1
  59. package/.next/server/pages/index.js +30 -1
  60. package/.next/server/pages/index.js.nft.json +1 -1
  61. package/.next/server/pages/index.json +1 -1
  62. package/.next/server/pages/not-found.html +29 -1
  63. package/.next/server/pages/not-found.js.nft.json +1 -1
  64. package/.next/server/pages-manifest.json +1 -1
  65. package/.next/server/webpack-api-runtime.js +1 -1
  66. package/.next/server/webpack-runtime.js +1 -1
  67. package/.next/static/5KOWzYqfY1Z2rjrzptr8D/_buildManifest.js +1 -0
  68. package/.next/static/chunks/101-829ab8a8d310e7a0.js +3 -0
  69. package/.next/static/chunks/106.e414e88694add27f.js +1 -0
  70. package/.next/static/chunks/127.125d896a19061d71.js +1 -0
  71. package/.next/static/chunks/18.8b91e137d239e15c.js +1 -0
  72. package/.next/static/chunks/277.6785dfaf22fdb0b7.js +1 -0
  73. package/.next/static/chunks/307.67f52f13e3d60d4e.js +1 -0
  74. package/.next/static/chunks/341.79535ba85bf1986f.js +1 -0
  75. package/.next/static/chunks/363.01eed3233f92b6a4.js +1 -0
  76. package/.next/static/chunks/422.1559ae6756912ca5.js +1 -0
  77. package/.next/static/chunks/541.dcd9e8b804f88da5.js +1 -0
  78. package/.next/static/chunks/631.98d42abad0a60af6.js +1 -0
  79. package/.next/static/chunks/663.d2c9ca36b26695b8.js +1 -0
  80. package/.next/static/chunks/711.ba7b8f900dfd40d0.js +1 -0
  81. package/.next/static/chunks/744.b06c9a3de4a1d877.js +1 -0
  82. package/.next/static/chunks/820.97b82f751ca49579.js +1 -0
  83. package/.next/static/chunks/865.a9b563a45848a83c.js +1 -0
  84. package/.next/static/chunks/912.ff8037ba9d4db5c8.js +1 -0
  85. package/.next/static/chunks/939.19b33a3d3c351d73.js +1 -0
  86. package/.next/static/chunks/990.61296e5870b91f11.js +1 -0
  87. package/.next/static/chunks/framework-626cbd48ac5aca57.js +1 -0
  88. package/.next/static/chunks/main-b92e08f3fc96dd8d.js +5 -0
  89. package/.next/static/chunks/pages/_app-2e607dcd4135f340.js +1 -0
  90. package/.next/static/chunks/pages/{_error-afeda7c5231b6c3c.js → _error-f0290a98eb3ed0ec.js} +1 -1
  91. package/.next/static/chunks/pages/index-e0087247c995328d.js +1 -0
  92. package/.next/static/chunks/pages/not-found-a59f9deeeff63d17.js +1 -0
  93. package/.next/static/chunks/webpack-cfb34d175e081981.js +1 -0
  94. package/.next/static/css/2d03f0da2c678dfc.css +1 -0
  95. package/.next/static/css/4dbcacc1122ac6b9.css +2 -0
  96. package/.next/static/css/7b6724d2df70f48f.css +1 -0
  97. package/.next/static/css/b736be3bd02b5d99.css +1 -0
  98. package/.next/static/css/b74cd7de82dabcdd.css +1 -0
  99. package/.next/static/css/c403ce739a9c0d83.css +1 -0
  100. package/.next/static/css/ca311e6c030663d4.css +1 -0
  101. package/.next/static/css/dee878eb64099d92.css +1 -0
  102. package/.next/static/css/fbfdce70731d0d2b.css +1 -0
  103. package/.next/trace +21 -21
  104. package/.next/trace-build +1 -1
  105. package/empty-module.js +2 -0
  106. package/next.config.js +13 -2
  107. package/package.json +43 -17
  108. package/public/llms.txt +11 -0
  109. package/public/robots.txt +5 -0
  110. package/public/site.webmanifest +14 -0
  111. package/scripts/generate-scss-types.ts +112 -0
  112. package/src/@types/scss.d.ts +6 -9
  113. package/src/@types/svg.d.ts +1 -1
  114. package/src/components/Alert/Alert.module.scss.d.ts +13 -0
  115. package/src/components/Alert/Alert.tsx +4 -1
  116. package/src/components/Badge/Badge.module.scss.d.ts +6 -0
  117. package/src/components/Board/Board.module.scss +10 -0
  118. package/src/components/Board/Board.module.scss.d.ts +17 -0
  119. package/src/components/Board/Board.tsx +14 -26
  120. package/src/components/Board/BoardPure.tsx +54 -49
  121. package/src/components/Board/components/Actions/Actions.module.scss +18 -18
  122. package/src/components/Board/components/Actions/Actions.module.scss.d.ts +7 -0
  123. package/src/components/Board/components/Actions/Actions.tsx +6 -3
  124. package/src/components/Board/components/Actions/lib.ts +3 -1
  125. package/src/components/Board/components/Cell/Cell.module.scss.d.ts +13 -0
  126. package/src/components/Board/components/Cell/Cell.tsx +28 -33
  127. package/src/components/Board/components/InputPrompt/InputPrompt.module.scss.d.ts +10 -0
  128. package/src/components/Board/components/InputPrompt/InputPrompt.tsx +1 -1
  129. package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.module.scss.d.ts +8 -0
  130. package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.tsx +2 -2
  131. package/src/components/Board/getBoardBackground.ts +175 -0
  132. package/src/components/Board/hooks/index.ts +0 -1
  133. package/src/components/Board/hooks/useBoardStyle.ts +10 -20
  134. package/src/components/Board/hooks/useFloatingActions.ts +3 -6
  135. package/src/components/Board/hooks/useGrid.ts +6 -3
  136. package/src/components/Board/selectors.ts +1 -1
  137. package/src/components/Button/Button.module.scss.d.ts +12 -0
  138. package/src/components/Dictionary/Dictionary.module.scss +1 -0
  139. package/src/components/Dictionary/Dictionary.module.scss.d.ts +14 -0
  140. package/src/components/Dictionary/Dictionary.tsx +1 -3
  141. package/src/components/DictionaryInput/DictionaryInput.module.scss.d.ts +7 -0
  142. package/src/components/DictionaryInput/DictionaryInput.tsx +1 -1
  143. package/src/components/EmptyState/EmptyState.module.scss.d.ts +7 -0
  144. package/src/components/EmptyState/EmptyState.tsx +1 -1
  145. package/src/components/IconButton/IconButton.module.scss.d.ts +8 -0
  146. package/src/components/Key/Key.module.scss.d.ts +6 -0
  147. package/src/components/Keys/Arrows/Arrows.module.scss.d.ts +11 -0
  148. package/src/components/Keys/Arrows/Arrows.tsx +4 -1
  149. package/src/components/Keys/index.tsx +1 -1
  150. package/src/components/Loading/Loading.module.scss.d.ts +9 -0
  151. package/src/components/Loading/Loading.tsx +1 -1
  152. package/src/components/Logo/Logo.tsx +4 -9
  153. package/src/components/Logo/LogoBlueprint.tsx +1 -0
  154. package/src/components/Modal/Modal.module.scss.d.ts +15 -0
  155. package/src/components/Modal/Modal.tsx +16 -3
  156. package/src/components/Modal/components/Section/Section.module.scss.d.ts +7 -0
  157. package/src/components/NavButtons/NavButtons.module.scss +20 -0
  158. package/src/components/NavButtons/NavButtons.module.scss.d.ts +13 -0
  159. package/src/components/NavButtons/NavButtons.tsx +29 -45
  160. package/src/components/NotFound/NotFound.module.scss.d.ts +9 -0
  161. package/src/components/NotFound/NotFound.tsx +1 -1
  162. package/src/components/PlainTiles/PlainTiles.module.scss.d.ts +11 -0
  163. package/src/components/PlainTiles/PlainTiles.tsx +0 -1
  164. package/src/components/PlainTiles/Tile.tsx +3 -4
  165. package/src/components/PlainTiles/lib.ts +4 -19
  166. package/src/components/PlainTiles/types.ts +0 -1
  167. package/src/components/Progress/Progress.module.scss +7 -0
  168. package/src/components/Progress/Progress.module.scss.d.ts +6 -0
  169. package/src/components/Progress/Progress.tsx +2 -11
  170. package/src/components/Rack/Rack.module.scss +3 -0
  171. package/src/components/Rack/Rack.module.scss.d.ts +10 -0
  172. package/src/components/Rack/Rack.tsx +8 -11
  173. package/src/components/Rack/components/InputPrompt/InputPrompt.module.scss +2 -0
  174. package/src/components/Rack/components/InputPrompt/InputPrompt.module.scss.d.ts +7 -0
  175. package/src/components/Rack/components/InputPrompt/InputPrompt.tsx +1 -13
  176. package/src/components/Rack/components/InputPrompt/lib.ts +1 -1
  177. package/src/components/Rack/components/RackTile/RackTile.module.scss.d.ts +6 -0
  178. package/src/components/Rack/components/RackTile/RackTile.tsx +5 -4
  179. package/src/components/Rack/selectors.ts +1 -1
  180. package/src/components/Radio/Radio.module.scss.d.ts +12 -0
  181. package/src/components/Results/Cell.tsx +3 -12
  182. package/src/components/Results/Header.tsx +9 -18
  183. package/src/components/Results/HeaderButton.tsx +4 -5
  184. package/src/components/Results/Result.tsx +4 -12
  185. package/src/components/Results/Results.module.scss +4 -6
  186. package/src/components/Results/Results.module.scss.d.ts +27 -0
  187. package/src/components/Results/Results.tsx +4 -3
  188. package/src/components/Results/SolveButton.tsx +1 -1
  189. package/src/components/ResultsInput/ResultsInput.module.scss.d.ts +7 -0
  190. package/src/components/ResultsInput/ResultsInput.tsx +1 -1
  191. package/src/components/Solver/Solver.module.scss +6 -5
  192. package/src/components/Solver/Solver.module.scss.d.ts +20 -0
  193. package/src/components/Solver/Solver.tsx +19 -21
  194. package/src/components/Solver/components/InsertButton/InsertButton.module.scss.d.ts +7 -0
  195. package/src/components/Solver/components/InsertButton/InsertButton.tsx +1 -1
  196. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss.d.ts +18 -0
  197. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +3 -1
  198. package/src/components/Spinner/Spinner.module.scss.d.ts +10 -0
  199. package/src/components/Tile/Tile.module.scss +3 -0
  200. package/src/components/Tile/Tile.module.scss.d.ts +19 -0
  201. package/src/components/Tile/Tile.tsx +5 -14
  202. package/src/components/Tile/TilePure.tsx +2 -12
  203. package/src/components/Tooltip/Tooltip.module.scss.d.ts +7 -0
  204. package/src/components/Tooltip/Tooltip.tsx +14 -3
  205. package/src/components/Tooltip/useTooltip.ts +1 -0
  206. package/src/hooks/useColumns.ts +4 -7
  207. package/src/hooks/useDeferredRender.ts +20 -0
  208. package/src/hooks/useDirection.ts +4 -3
  209. package/src/hooks/useLanguage.ts +2 -2
  210. package/src/hooks/useLocalStorage.ts +32 -8
  211. package/src/hooks/useMedia.ts +26 -26
  212. package/src/i18n/constants.ts +2 -15
  213. package/src/i18n/i18n.ts +18 -17
  214. package/src/i18n/languages/english.json +0 -1
  215. package/src/i18n/languages/french.json +0 -1
  216. package/src/i18n/languages/german.json +0 -1
  217. package/src/i18n/languages/persian.json +0 -1
  218. package/src/i18n/languages/polish.json +0 -1
  219. package/src/i18n/languages/romanian.json +0 -1
  220. package/src/i18n/languages/spanish.json +0 -1
  221. package/src/i18n/languages/turkish.json +0 -1
  222. package/src/i18n/localeIcons.ts +24 -0
  223. package/src/lib/localeTransliterate.test.ts +5 -0
  224. package/src/lib/localeTransliterate.ts +26 -6
  225. package/src/lib/waitForIdleOrFirstIntent.ts +44 -0
  226. package/src/modals/DictionaryModal/DictionaryModal.module.scss.d.ts +8 -0
  227. package/src/modals/DictionaryModal/DictionaryModal.tsx +3 -1
  228. package/src/modals/KeyMapModal/KeyMapModal.tsx +3 -1
  229. package/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss.d.ts +11 -0
  230. package/src/modals/MenuModal/MenuModal.module.scss +5 -0
  231. package/src/modals/MenuModal/MenuModal.module.scss.d.ts +10 -0
  232. package/src/modals/MenuModal/MenuModal.tsx +16 -5
  233. package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss +4 -1
  234. package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss.d.ts +9 -0
  235. package/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +4 -6
  236. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss +1 -0
  237. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss.d.ts +12 -0
  238. package/src/modals/RemainingTilesModal/components/Character/Character.tsx +5 -12
  239. package/src/modals/ResultsModal/ResultsModal.module.scss.d.ts +8 -0
  240. package/src/modals/ResultsModal/ResultsModal.tsx +8 -4
  241. package/src/modals/SettingsModal/SettingsModal.tsx +2 -2
  242. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.module.scss.d.ts +7 -0
  243. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +1 -1
  244. package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.module.scss.d.ts +7 -0
  245. package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +1 -1
  246. package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.module.scss.d.ts +7 -0
  247. package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.tsx +1 -1
  248. package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.module.scss.d.ts +7 -0
  249. package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.tsx +1 -1
  250. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss.d.ts +8 -0
  251. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +24 -21
  252. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.module.scss.d.ts +7 -0
  253. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.tsx +1 -1
  254. package/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.module.scss.d.ts +7 -0
  255. package/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.tsx +1 -5
  256. package/src/modals/WordsModal/WordsModal.module.scss.d.ts +11 -0
  257. package/src/modals/WordsModal/WordsModal.tsx +4 -2
  258. package/src/modals/preload.ts +24 -0
  259. package/src/pages/_app.tsx +37 -76
  260. package/src/pages/_document.tsx +112 -24
  261. package/src/pages/api/solve.ts +1 -1
  262. package/src/pages/index.module.scss +1 -0
  263. package/src/pages/index.module.scss.d.ts +11 -0
  264. package/src/pages/index.tsx +127 -40
  265. package/src/pages/not-found.tsx +14 -3
  266. package/src/parameters/index.ts +31 -93
  267. package/src/serviceWorkerManager.ts +5 -2
  268. package/src/state/actions.ts +1 -1
  269. package/src/state/app/index.ts +4 -0
  270. package/src/state/app/initialState.ts +6 -0
  271. package/src/state/app/selectors.ts +5 -0
  272. package/src/state/app/slice.ts +20 -0
  273. package/src/state/app/types.ts +4 -0
  274. package/src/state/board/initialState.ts +1 -2
  275. package/src/state/i18n/index.ts +4 -0
  276. package/src/state/i18n/initialState.ts +5 -0
  277. package/src/state/i18n/selectors.ts +3 -0
  278. package/src/state/i18n/slice.ts +16 -0
  279. package/src/state/i18n/types.ts +7 -0
  280. package/src/state/index.ts +2 -0
  281. package/src/state/lib.ts +1 -1
  282. package/src/state/localStorage.ts +86 -29
  283. package/src/state/rack/initialState.ts +1 -2
  284. package/src/state/rack/slice.ts +4 -1
  285. package/src/state/results/lib.ts +5 -5
  286. package/src/state/results/selectors.ts +1 -1
  287. package/src/state/sagas.ts +125 -9
  288. package/src/state/selectors.ts +1 -1
  289. package/src/state/settings/initialState.ts +7 -10
  290. package/src/state/settings/selectors.ts +7 -2
  291. package/src/state/settings/slice.ts +5 -2
  292. package/src/state/store.ts +4 -0
  293. package/src/state/types.ts +4 -0
  294. package/src/styles/_tokens.scss +1 -0
  295. package/src/styles/global.scss +9 -0
  296. package/src/styles/variables.module.scss +0 -21
  297. package/src/styles/variables.module.scss.d.ts +27 -0
  298. package/src/styles/variables.scss +46 -2
  299. package/src/types/index.ts +1 -2
  300. package/tsconfig.tsbuildinfo +1 -1
  301. package/.next/server/chunks/129.js +0 -1
  302. package/.next/server/chunks/318.js +0 -3
  303. package/.next/server/chunks/791.js +0 -15
  304. package/.next/static/OLE8_ZInlGH7ENU0NIOpf/_buildManifest.js +0 -1
  305. package/.next/static/chunks/830.661816bf0de8c2f1.js +0 -1
  306. package/.next/static/chunks/framework-3cf15b8041c59dd3.js +0 -1
  307. package/.next/static/chunks/main-5b999f3f24ebfa84.js +0 -5
  308. package/.next/static/chunks/pages/_app-7024e7a27ffbb2fa.js +0 -7
  309. package/.next/static/chunks/pages/index-8b398b0a5d870773.js +0 -1
  310. package/.next/static/chunks/pages/not-found-9e076427bad69d90.js +0 -1
  311. package/.next/static/chunks/webpack-3943d624bbb47a64.js +0 -1
  312. package/.next/static/css/a78e04fe95452380.css +0 -1
  313. package/.next/static/css/aedeaada218d7280.css +0 -2
  314. package/src/app-layout/AppLayoutContext.tsx +0 -25
  315. package/src/app-layout/index.ts +0 -1
  316. package/src/app-layout/useAppLayoutValue.ts +0 -112
  317. package/src/components/Board/hooks/useBackgroundImage.tsx +0 -279
  318. package/src/components/SeoMessage/SeoMessage.tsx +0 -18
  319. package/src/components/SeoMessage/index.ts +0 -1
  320. package/src/components/index.ts +0 -26
  321. package/src/hooks/index.ts +0 -12
  322. package/src/hooks/useOnWindowResize.ts +0 -11
  323. package/src/hooks/useViewportSize.ts +0 -17
  324. package/src/i18n/index.ts +0 -2
  325. package/src/icons/Flag.svg +0 -4
  326. package/src/icons/Star.svg +0 -4
  327. package/src/icons/index.ts +0 -49
  328. package/src/lib/getTileSizes.ts +0 -13
  329. package/src/lib/index.ts +0 -24
  330. package/src/modals/index.ts +0 -7
  331. /package/.next/static/{OLE8_ZInlGH7ENU0NIOpf → 5KOWzYqfY1Z2rjrzptr8D}/_ssgManifest.js +0 -0
@@ -3,8 +3,9 @@ import classNames from 'classnames';
3
3
  import { type ChangeEvent, type FunctionComponent } from 'react';
4
4
  import { useDispatch } from 'react-redux';
5
5
 
6
- import { Radio } from '@/components';
7
- import { LOCALE_FEATURES } from '@/i18n';
6
+ import { Radio } from '@/components/Radio';
7
+ import { LOCALE_FEATURES } from '@/i18n/constants';
8
+ import { LOCALE_ICONS } from '@/i18n/localeIcons';
8
9
  import { selectLocale, settingsSlice, useTypedSelector } from '@/state';
9
10
 
10
11
  import styles from './LocaleSetting.module.scss';
@@ -27,25 +28,27 @@ export const LocaleSetting: FunctionComponent<Props> = ({ className, disabled })
27
28
 
28
29
  return (
29
30
  <div className={className}>
30
- {OPTIONS.map(({ Icon, ...option }) => (
31
- <Radio
32
- checked={locale === option.locale}
33
- className={classNames(styles.option, className, {
34
- [styles.checked]: locale === option.locale,
35
- })}
36
- disabled={disabled}
37
- key={option.locale}
38
- name="locale"
39
- value={option.locale}
40
- onChange={handleChange}
41
- >
42
- <span className={styles.label}>
43
- <Icon aria-hidden="true" className={styles.flag} role="img" />
44
-
45
- <span>{option.label}</span>
46
- </span>
47
- </Radio>
48
- ))}
31
+ {OPTIONS.map((option) => {
32
+ const Icon = LOCALE_ICONS[option.locale];
33
+
34
+ return (
35
+ <Radio
36
+ checked={locale === option.locale}
37
+ className={classNames(styles.option, className)}
38
+ disabled={disabled}
39
+ key={option.locale}
40
+ name="locale"
41
+ value={option.locale}
42
+ onChange={handleChange}
43
+ >
44
+ <span className={styles.label}>
45
+ <Icon aria-hidden="true" className={styles.flag} role="img" />
46
+
47
+ <span>{option.label}</span>
48
+ </span>
49
+ </Radio>
50
+ );
51
+ })}
49
52
  </div>
50
53
  );
51
54
  };
@@ -0,0 +1,7 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly label: string;
4
+ readonly option: string;
5
+ };
6
+
7
+ export default styles;
@@ -1,7 +1,7 @@
1
1
  import { type ChangeEvent, type FunctionComponent } from 'react';
2
2
  import { useDispatch } from 'react-redux';
3
3
 
4
- import { Radio } from '@/components';
4
+ import { Radio } from '@/components/Radio';
5
5
  import { selectRemoveCellFilters, settingsSlice, useTranslate, useTypedSelector } from '@/state';
6
6
 
7
7
  import { parseValue } from './lib';
@@ -0,0 +1,7 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly label: string;
4
+ readonly option: string;
5
+ };
6
+
7
+ export default styles;
@@ -2,7 +2,7 @@ import { type ShowCoordinates } from '@scrabble-solver/types';
2
2
  import { type ChangeEvent, type FunctionComponent } from 'react';
3
3
  import { useDispatch } from 'react-redux';
4
4
 
5
- import { Radio } from '@/components';
5
+ import { Radio } from '@/components/Radio';
6
6
  import { selectShowCoordinates, settingsSlice, useTranslate, useTypedSelector } from '@/state';
7
7
 
8
8
  import styles from './ShowCoordinatesSetting.module.scss';
@@ -18,10 +18,6 @@ export const ShowCoordinatesSetting: FunctionComponent<Props> = ({ className, di
18
18
  const value = useTypedSelector(selectShowCoordinates);
19
19
 
20
20
  const options = [
21
- {
22
- label: translate('settings.showCoordinates.hidden'),
23
- value: 'hidden',
24
- },
25
21
  {
26
22
  label: translate('settings.showCoordinates.original'),
27
23
  value: 'original',
@@ -0,0 +1,11 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly badge: string;
4
+ readonly icon: string;
5
+ readonly invalid: string;
6
+ readonly title: string;
7
+ readonly valid: string;
8
+ readonly word: string;
9
+ };
10
+
11
+ export default styles;
@@ -1,8 +1,10 @@
1
1
  import classNames from 'classnames';
2
2
  import { type FunctionComponent, memo } from 'react';
3
3
 
4
- import { Badge, Modal } from '@/components';
5
- import { Check, Cross } from '@/icons';
4
+ import { Badge } from '@/components/Badge';
5
+ import { Modal } from '@/components/Modal';
6
+ import Check from '@/icons/Check.svg';
7
+ import Cross from '@/icons/Cross.svg';
6
8
  import { selectInvalidWords, selectLocale, selectValidWords, useTranslate, useTypedSelector } from '@/state';
7
9
 
8
10
  import styles from './WordsModal.module.scss';
@@ -0,0 +1,24 @@
1
+ import { waitForIdleOrFirstIntent } from '@/lib/waitForIdleOrFirstIntent';
2
+
3
+ let isScheduled = false;
4
+
5
+ export function schedulePreloadModals(): void {
6
+ if (isScheduled || typeof window === 'undefined') {
7
+ return;
8
+ }
9
+
10
+ isScheduled = true;
11
+
12
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
13
+ waitForIdleOrFirstIntent().then(() =>
14
+ Promise.all([
15
+ import('./DictionaryModal'),
16
+ import('./KeyMapModal'),
17
+ import('./MenuModal'),
18
+ import('./RemainingTilesModal'),
19
+ import('./ResultsModal'),
20
+ import('./SettingsModal'),
21
+ import('./WordsModal'),
22
+ ]),
23
+ );
24
+ }
@@ -4,88 +4,49 @@ import Head from 'next/head';
4
4
  import { type FunctionComponent } from 'react';
5
5
  import { Provider } from 'react-redux';
6
6
 
7
- import { AppLayoutProvider } from '@/app-layout';
8
- import { SeoMessage } from '@/components';
7
+ import { SITE_DESCRIPTION, SITE_URL } from '@/parameters';
9
8
  import { store } from '@/state';
10
9
 
11
10
  import '../styles/global.scss';
12
11
 
13
- const DESCRIPTION =
14
- 'Scrabble Solver 2 - Free and open-source analysis tool for Scrabble, Scrabble Duel, Super Scrabble, Letter League, Crossplay, Literaki and Kelimelik. Quickly find top scoring words using given letters and board state. Available in English, French, German, Persian, Polish, Romanian, Spanish, and Turkish.';
15
-
16
- const KEYWORDS = [
17
- 'Scrabble Solver',
18
- 'Scrabble',
19
- 'Scrabble Duel',
20
- 'Solver',
21
- 'Super Scrabble',
22
- 'Kelimelik',
23
- 'Letter League',
24
- 'Crossplay',
25
- 'NYT Crossplay',
26
- 'Literaki',
27
- 'Board',
28
- 'Open-source',
29
- 'Open',
30
- 'Source',
31
- 'Word',
32
- 'Finder',
33
- 'Cheating',
34
- 'Word',
35
- 'English',
36
- 'Français',
37
- 'French',
38
- 'Deutsch',
39
- 'German',
40
- 'Polski',
41
- 'Polish',
42
- 'فارسی',
43
- 'Farsi',
44
- 'Español',
45
- 'Spanish',
46
- 'Română',
47
- 'Romanian',
48
- 'Türkçe',
49
- 'Turkish',
50
- 'SOWPODS',
51
- 'TWL06',
52
- 'SJP',
53
- 'FISE-2017',
54
- 'FISE-2',
55
- 'CNRTL',
56
- 'Kamil Mielnik',
57
- ].join(',');
58
-
59
- const App: FunctionComponent<AppProps> = ({ Component, pageProps }) => (
60
- <>
61
- <Head>
62
- <title>Scrabble Solver 2</title>
63
- <meta charSet="utf-8" />
64
- <meta name="author" content="Kamil Mielnik" />
65
- <meta name="description" content={DESCRIPTION} />
66
- <meta name="keywords" content={KEYWORDS} />
67
- <meta name="robots" content="index, follow, notranslate, noimageindex" />
68
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
69
- <meta property="og:title" content={DESCRIPTION} />
70
- <meta property="og:type" content="website" />
71
- <meta property="og:url" content="https://scrabble-solver.org" />
72
- <meta property="og:image" content="https://scrabble-solver.org/og.png" />
73
- <meta property="og:image:type" content="image/png" />
74
- <meta property="og:image:width" content="1200" />
75
- <meta property="og:image:height" content="630" />
76
- <meta property="og:image:alt" content={DESCRIPTION} />
77
- </Head>
78
-
79
- <Provider store={store}>
80
- <AppLayoutProvider>
81
- <SeoMessage />
82
-
12
+ const TITLE = 'Scrabble Solver 2 - Board Solver & Word Finder';
13
+
14
+ const App: FunctionComponent<AppProps> = ({ Component, pageProps, router }) => {
15
+ const isIndexable = router.pathname === '/';
16
+
17
+ return (
18
+ <>
19
+ <Head>
20
+ <title>{TITLE}</title>
21
+ <meta charSet="utf-8" />
22
+ <meta name="author" content="Kamil Mielnik" />
23
+ <meta name="description" content={SITE_DESCRIPTION} />
24
+ {isIndexable ? <link rel="canonical" href={`${SITE_URL}/`} /> : <meta name="robots" content="noindex" />}
25
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
26
+ <meta property="og:site_name" content="Scrabble Solver" />
27
+ <meta property="og:title" content={TITLE} />
28
+ <meta property="og:description" content={SITE_DESCRIPTION} />
29
+ <meta property="og:type" content="website" />
30
+ <meta property="og:url" content={`${SITE_URL}/`} />
31
+ <meta property="og:locale" content="en_US" />
32
+ <meta property="og:image" content={`${SITE_URL}/og.png`} />
33
+ <meta property="og:image:type" content="image/png" />
34
+ <meta property="og:image:width" content="1200" />
35
+ <meta property="og:image:height" content="630" />
36
+ <meta property="og:image:alt" content="Scrabble tiles spelling out Scrabble Solver 2" />
37
+ <meta name="twitter:card" content="summary_large_image" />
38
+ <meta name="twitter:title" content={TITLE} />
39
+ <meta name="twitter:description" content={SITE_DESCRIPTION} />
40
+ <meta name="twitter:image" content={`${SITE_URL}/og.png`} />
41
+ </Head>
42
+
43
+ <Provider store={store}>
83
44
  <FloatingDelayGroup delay={0}>
84
45
  <Component {...pageProps} />
85
46
  </FloatingDelayGroup>
86
- </AppLayoutProvider>
87
- </Provider>
88
- </>
89
- );
47
+ </Provider>
48
+ </>
49
+ );
50
+ };
90
51
 
91
52
  export default App;
@@ -1,33 +1,99 @@
1
+ import { games } from '@scrabble-solver/configs';
2
+ import { Game, Locale } from '@scrabble-solver/types';
3
+ import fs from 'fs';
1
4
  import Document, { Head, Html, Main, NextScript } from 'next/document';
5
+ import path from 'path';
2
6
  import { type ReactElement } from 'react';
3
7
 
4
- class MyDocument extends Document {
8
+ import { LOCALE_FEATURES } from '@/i18n/constants';
9
+ import { CONFIG_PENDING_CLASS } from '@/parameters';
10
+
11
+ const GAME_DIMENSIONS = Object.fromEntries(
12
+ Object.values(games).map(({ boardHeight, boardWidth, game, rackSize }) => [
13
+ game,
14
+ [boardWidth, boardHeight, rackSize],
15
+ ]),
16
+ );
17
+
18
+ const LOCALE_DIRECTIONS = Object.fromEntries(
19
+ Object.entries(LOCALE_FEATURES).map(([locale, { direction }]) => [locale, direction]),
20
+ );
21
+
22
+ /**
23
+ * The SSR HTML is always an English Scrabble board. This runs before first paint
24
+ * so a returning user's persisted board dimensions and text direction apply without a flash.
25
+ * The board itself cannot be reshaped pre-hydration, so it is hidden (CONFIG_PENDING_CLASS,
26
+ * see global.scss) until hydration applies the persisted config.
27
+ */
28
+ const preHydrationScript = `(function () {
29
+ try {
30
+ var settings = JSON.parse(localStorage.getItem('scrabble-solver.settings'));
31
+
32
+ if (!settings) {
33
+ return;
34
+ }
35
+
36
+ var dimensions = ${JSON.stringify(GAME_DIMENSIONS)}[settings.game];
37
+ var direction = ${JSON.stringify(LOCALE_DIRECTIONS)}[settings.locale];
38
+ var root = document.documentElement;
39
+
40
+ if (dimensions) {
41
+ root.style.setProperty('--board-cols', dimensions[0]);
42
+ root.style.setProperty('--board-rows', dimensions[1]);
43
+ root.style.setProperty('--rack-size', dimensions[2]);
44
+
45
+ if (settings.game !== ${JSON.stringify(Game.Scrabble)}) {
46
+ root.classList.add(${JSON.stringify(CONFIG_PENDING_CLASS)});
47
+ }
48
+ }
49
+
50
+ if (direction) {
51
+ root.dir = direction;
52
+ root.lang = settings.locale;
53
+ }
54
+ } catch (error) {}
55
+ })()`;
56
+
57
+ export default class MyDocument extends Document {
5
58
  render(): ReactElement {
6
59
  return (
7
- <Html lang="en">
8
- <Head>
9
- <link rel="apple-touch-icon-precomposed" sizes="57x57" href="icons/apple-touch-icon-57x57.png" />
10
- <link rel="apple-touch-icon-precomposed" sizes="114x114" href="icons/apple-touch-icon-114x114.png" />
11
- <link rel="apple-touch-icon-precomposed" sizes="72x72" href="icons/apple-touch-icon-72x72.png" />
12
- <link rel="apple-touch-icon-precomposed" sizes="144x144" href="icons/apple-touch-icon-144x144.png" />
13
- <link rel="apple-touch-icon-precomposed" sizes="60x60" href="icons/apple-touch-icon-60x60.png" />
14
- <link rel="apple-touch-icon-precomposed" sizes="120x120" href="icons/apple-touch-icon-120x120.png" />
15
- <link rel="apple-touch-icon-precomposed" sizes="76x76" href="icons/apple-touch-icon-76x76.png" />
16
- <link rel="apple-touch-icon-precomposed" sizes="152x152" href="icons/apple-touch-icon-152x152.png" />
17
- <link rel="icon" type="image/png" href="icons/favicon-196x196.png" sizes="196x196" />
18
- <link rel="icon" type="image/png" href="icons/favicon-96x96.png" sizes="96x96" />
19
- <link rel="icon" type="image/png" href="icons/favicon-32x32.png" sizes="32x32" />
20
- <link rel="icon" type="image/png" href="icons/favicon-16x16.png" sizes="16x16" />
21
- <link rel="icon" type="image/png" href="icons/favicon-128.png" sizes="128x128" />
22
- <link rel="icon" href="icons/favicon.svg" />
60
+ <Html
61
+ /**
62
+ * dir must be present pre-hydration
63
+ */
64
+ dir="ltr"
65
+ /**
66
+ * lang must match the default locale
67
+ */
68
+ lang={Locale.EN_US}
69
+ >
70
+ <InlineCssHead>
71
+ {/* eslint-disable-next-line react/no-danger */}
72
+ <script dangerouslySetInnerHTML={{ __html: preHydrationScript }} />
73
+ <link rel="apple-touch-icon-precomposed" sizes="57x57" href="/icons/apple-touch-icon-57x57.png" />
74
+ <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/icons/apple-touch-icon-114x114.png" />
75
+ <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/icons/apple-touch-icon-72x72.png" />
76
+ <link rel="apple-touch-icon-precomposed" sizes="144x144" href="/icons/apple-touch-icon-144x144.png" />
77
+ <link rel="apple-touch-icon-precomposed" sizes="60x60" href="/icons/apple-touch-icon-60x60.png" />
78
+ <link rel="apple-touch-icon-precomposed" sizes="120x120" href="/icons/apple-touch-icon-120x120.png" />
79
+ <link rel="apple-touch-icon-precomposed" sizes="76x76" href="/icons/apple-touch-icon-76x76.png" />
80
+ <link rel="apple-touch-icon-precomposed" sizes="152x152" href="/icons/apple-touch-icon-152x152.png" />
81
+ <link rel="icon" type="image/png" href="/icons/favicon-196x196.png" sizes="196x196" />
82
+ <link rel="icon" type="image/png" href="/icons/favicon-96x96.png" sizes="96x96" />
83
+ <link rel="icon" type="image/png" href="/icons/favicon-32x32.png" sizes="32x32" />
84
+ <link rel="icon" type="image/png" href="/icons/favicon-16x16.png" sizes="16x16" />
85
+ <link rel="icon" type="image/png" href="/icons/favicon-128.png" sizes="128x128" />
86
+ <link rel="icon" href="/icons/favicon.svg" />
87
+ <link rel="manifest" href="/site.webmanifest" />
23
88
  <meta name="application-name" content="Scrabble Solver" />
89
+ <meta name="theme-color" content="#EFE3AE" />
24
90
  <meta name="msapplication-TileColor" content="#EFE3AE" />
25
- <meta name="msapplication-TileImage" content="icons/mstile-144x144.png" />
26
- <meta name="msapplication-square70x70logo" content="icons/mstile-70x70.png" />
27
- <meta name="msapplication-square150x150logo" content="icons/mstile-150x150.png" />
28
- <meta name="msapplication-wide310x150logo" content="icons/mstile-310x150.png" />
29
- <meta name="msapplication-square310x310logo" content="icons/mstile-310x310.png" />
30
- </Head>
91
+ <meta name="msapplication-TileImage" content="/icons/mstile-144x144.png" />
92
+ <meta name="msapplication-square70x70logo" content="/icons/mstile-70x70.png" />
93
+ <meta name="msapplication-square150x150logo" content="/icons/mstile-150x150.png" />
94
+ <meta name="msapplication-wide310x150logo" content="/icons/mstile-310x150.png" />
95
+ <meta name="msapplication-square310x310logo" content="/icons/mstile-310x310.png" />
96
+ </InlineCssHead>
31
97
 
32
98
  <body>
33
99
  <Main />
@@ -38,4 +104,26 @@ class MyDocument extends Document {
38
104
  }
39
105
  }
40
106
 
41
- export default MyDocument;
107
+ /**
108
+ * Removes render-blocking CSS requests from the critical path.
109
+ */
110
+ class InlineCssHead extends Head {
111
+ getCssLinks(files: Parameters<Head['getCssLinks']>[0]): ReactElement[] | null {
112
+ try {
113
+ const cssFiles = files.allFiles.filter((file) => file.endsWith('.css'));
114
+
115
+ return cssFiles.map((file) => (
116
+ <style
117
+ // eslint-disable-next-line react/no-danger
118
+ dangerouslySetInnerHTML={{
119
+ __html: fs.readFileSync(path.join(process.cwd(), '.next', file), 'utf-8'),
120
+ }}
121
+ data-href={`/_next/${file}`}
122
+ key={file}
123
+ />
124
+ ));
125
+ } catch {
126
+ return super.getCssLinks(files);
127
+ }
128
+ }
129
+ }
@@ -16,7 +16,7 @@ import {
16
16
  import { type NextApiRequest, type NextApiResponse } from 'next';
17
17
 
18
18
  import { getServerLoggingData, isBoardValid, isCharacterValid } from '@/api';
19
- import { isStringArray } from '@/lib';
19
+ import { isStringArray } from '@/lib/isStringArray';
20
20
 
21
21
  interface RequestData {
22
22
  board: Board;
@@ -22,6 +22,7 @@
22
22
 
23
23
  .logo {
24
24
  height: var(--logo--height);
25
+ width: auto;
25
26
  user-select: none;
26
27
  }
27
28
 
@@ -0,0 +1,11 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly logo: string;
4
+ readonly logoContainer: string;
5
+ readonly nav: string;
6
+ readonly navContent: string;
7
+ readonly navLogo: string;
8
+ readonly solver: string;
9
+ };
10
+
11
+ export default styles;