@scrabble-solver/scrabble-solver 2.10.3 → 2.10.4

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 (188) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +13 -13
  3. package/.next/cache/.tsbuildinfo +1 -1
  4. package/.next/cache/eslint/.cache_8dgz12 +1 -1
  5. package/.next/cache/next-server.js.nft.json +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/edge-server-production/0.pack +0 -0
  9. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  10. package/.next/cache/webpack/server-production/0.pack +0 -0
  11. package/.next/cache/webpack/server-production/index.pack +0 -0
  12. package/.next/next-server.js.nft.json +1 -1
  13. package/.next/prerender-manifest.json +1 -1
  14. package/.next/routes-manifest.json +1 -1
  15. package/.next/server/chunks/176.js +1269 -1559
  16. package/.next/server/chunks/579.js +50 -26
  17. package/.next/server/middleware-build-manifest.js +1 -1
  18. package/.next/server/pages/404.html +2 -2
  19. package/.next/server/pages/404.js.nft.json +1 -1
  20. package/.next/server/pages/500.html +2 -2
  21. package/.next/server/pages/_app.js.nft.json +1 -1
  22. package/.next/server/pages/api/solve.js +22 -6
  23. package/.next/server/pages/index.html +2 -2
  24. package/.next/server/pages/index.js +1539 -52
  25. package/.next/server/pages/index.js.nft.json +1 -1
  26. package/.next/server/pages/index.json +1 -1
  27. package/.next/server/pages-manifest.json +3 -3
  28. package/.next/static/P7XhuDLmwJJqC8kgPjX42/_buildManifest.js +1 -0
  29. package/.next/static/{FJkPF91uL-OCAJKTTpVSP → P7XhuDLmwJJqC8kgPjX42}/_ssgManifest.js +0 -0
  30. package/.next/static/chunks/490-d29992f1c264d70e.js +5 -0
  31. package/.next/static/chunks/528-9942ddad0031ff79.js +1 -0
  32. package/.next/static/chunks/pages/{404-24f9617eeb8d6dc1.js → 404-6c99a0c91257c60b.js} +1 -1
  33. package/.next/static/chunks/pages/_app-fa0661b072fc6af9.js +24 -0
  34. package/.next/static/chunks/pages/index-d761f0af070273d2.js +1 -0
  35. package/.next/static/css/78e42ad01f580f64.css +1 -0
  36. package/.next/static/css/97eb6ee0c4300c83.css +1 -0
  37. package/.next/static/css/dcca0c1a39cf5ef5.css +1 -0
  38. package/.next/trace +55 -52
  39. package/package.json +11 -9
  40. package/src/components/Badge/Badge.module.scss +4 -5
  41. package/src/components/Board/BoardPure.tsx +5 -5
  42. package/src/components/Button/Button.module.scss +10 -38
  43. package/src/components/Button/Button.tsx +6 -5
  44. package/src/components/Dictionary/Dictionary.module.scss +1 -2
  45. package/src/components/Dictionary/Dictionary.tsx +2 -6
  46. package/src/components/DictionaryInput/DictionaryInput.module.scss +1 -3
  47. package/src/components/EmptyState/EmptyState.module.scss +6 -7
  48. package/src/components/EmptyState/EmptyState.tsx +6 -6
  49. package/src/components/Key/Key.module.scss +0 -1
  50. package/src/components/{Splash/Splash.module.scss → LogoSplashScreen/LogoSplashScreen.module.scss} +1 -1
  51. package/src/components/{Splash/Splash.tsx → LogoSplashScreen/LogoSplashScreen.tsx} +7 -7
  52. package/src/components/LogoSplashScreen/index.ts +1 -0
  53. package/src/components/{Sidebar/Sidebar.module.scss → Modal/Modal.module.scss} +25 -20
  54. package/src/components/{Sidebar/Sidebar.tsx → Modal/Modal.tsx} +9 -9
  55. package/src/components/{Sidebar → Modal}/components/Section/Section.module.scss +0 -0
  56. package/src/components/{Sidebar → Modal}/components/Section/Section.tsx +0 -0
  57. package/src/components/{Sidebar → Modal}/components/Section/index.ts +0 -0
  58. package/src/components/{Sidebar → Modal}/components/index.ts +0 -0
  59. package/src/components/Modal/index.ts +1 -0
  60. package/src/components/NavButtons/NavButtons.tsx +22 -3
  61. package/src/components/Progress/Progress.module.scss +9 -0
  62. package/src/components/Progress/Progress.tsx +38 -0
  63. package/src/components/Progress/index.ts +1 -0
  64. package/src/components/Rack/Rack.module.scss +2 -0
  65. package/src/components/Rack/Rack.tsx +3 -1
  66. package/src/components/Rack/RackTile.tsx +3 -2
  67. package/src/components/ResultCandidatePicker/ResultCandidatePicker.module.scss +76 -0
  68. package/src/components/ResultCandidatePicker/ResultCandidatePicker.tsx +38 -0
  69. package/src/components/ResultCandidatePicker/index.ts +1 -0
  70. package/src/components/Results/Result.tsx +64 -43
  71. package/src/components/Results/Results.module.scss +9 -16
  72. package/src/components/Results/Results.tsx +45 -28
  73. package/src/components/Results/SolveButton.tsx +9 -7
  74. package/src/components/Results/{getColumns.ts → getLocaleColumns.ts} +2 -2
  75. package/src/components/Results/types.ts +16 -0
  76. package/src/components/Results/useColumns.ts +44 -0
  77. package/src/components/ResultsInput/ResultsInput.module.scss +1 -3
  78. package/src/components/Sizer/Sizer.module.scss +10 -0
  79. package/src/components/Sizer/Sizer.tsx +10 -0
  80. package/src/components/Sizer/index.ts +1 -0
  81. package/src/components/Solver/Solver.module.scss +83 -27
  82. package/src/components/Solver/Solver.tsx +157 -24
  83. package/src/components/Solver/components/ApplyButton/ApplyButton.module.scss +5 -0
  84. package/src/components/Solver/components/ApplyButton/ApplyButton.tsx +37 -0
  85. package/src/components/Solver/components/ApplyButton/index.ts +1 -0
  86. package/src/components/Solver/components/EmptyState/EmptyState.module.scss +59 -0
  87. package/src/components/Solver/components/EmptyState/EmptyState.tsx +41 -0
  88. package/src/components/Solver/components/EmptyState/index.ts +1 -0
  89. package/src/components/Solver/components/SolveButton/SolveButton.module.scss +4 -0
  90. package/src/components/Solver/components/SolveButton/SolveButton.tsx +42 -0
  91. package/src/components/Solver/components/SolveButton/index.ts +1 -0
  92. package/src/components/Solver/components/index.ts +3 -0
  93. package/src/components/{Screen/Screen.module.scss → SplashScreen/SplashScreen.module.scss} +2 -12
  94. package/src/components/{Screen/Screen.tsx → SplashScreen/SplashScreen.tsx} +4 -4
  95. package/src/components/SplashScreen/index.ts +1 -0
  96. package/src/components/SquareButton/SquareButton.module.scss +3 -3
  97. package/src/components/Tile/Tile.module.scss +7 -15
  98. package/src/components/Tooltip/Tooltip.module.scss +0 -1
  99. package/src/components/index.ts +6 -7
  100. package/src/hooks/index.ts +1 -1
  101. package/src/hooks/useMediaQuery.ts +11 -0
  102. package/src/hooks/usePortal.tsx +1 -1
  103. package/src/i18n/de.json +2 -0
  104. package/src/i18n/en.json +2 -0
  105. package/src/i18n/es.json +2 -0
  106. package/src/i18n/fa.json +2 -0
  107. package/src/i18n/fr.json +2 -0
  108. package/src/i18n/pl.json +2 -0
  109. package/src/icons/CardChecklist.svg +5 -0
  110. package/src/icons/Check.svg +2 -2
  111. package/src/icons/ChevronDown.svg +4 -0
  112. package/src/icons/CrossCircleFill.svg +4 -0
  113. package/src/icons/{CrossFill.svg → CrossSquareFill.svg} +0 -0
  114. package/src/icons/ExclamationTriangleFill.svg +4 -0
  115. package/src/icons/InfoCircleFill.svg +4 -0
  116. package/src/icons/List.svg +4 -0
  117. package/src/icons/Search.svg +4 -0
  118. package/src/icons/index.ts +8 -2
  119. package/src/{components/KeyMap/KeyMap.tsx → modals/KeyMapModal/KeyMapModal.tsx} +11 -13
  120. package/src/{components/KeyMap → modals/KeyMapModal}/components/Mapping/Mapping.module.scss +0 -0
  121. package/src/{components/KeyMap → modals/KeyMapModal}/components/Mapping/Mapping.tsx +0 -0
  122. package/src/{components/KeyMap → modals/KeyMapModal}/components/Mapping/index.ts +0 -0
  123. package/src/{components/KeyMap → modals/KeyMapModal}/components/index.ts +0 -0
  124. package/src/modals/KeyMapModal/index.ts +1 -0
  125. package/src/{components/KeyMap → modals/KeyMapModal}/keys.tsx +1 -2
  126. package/src/modals/MenuModal/MenuModal.module.scss +46 -0
  127. package/src/modals/MenuModal/MenuModal.tsx +54 -0
  128. package/src/modals/MenuModal/index.ts +1 -0
  129. package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss +28 -0
  130. package/src/{components/RemainingTiles/RemainingTiles.tsx → modals/RemainingTilesModal/RemainingTilesModal.tsx} +14 -12
  131. package/src/{components/RemainingTiles → modals/RemainingTilesModal/components/Character}/Character.module.scss +6 -2
  132. package/src/{components/RemainingTiles → modals/RemainingTilesModal/components/Character}/Character.tsx +11 -3
  133. package/src/modals/RemainingTilesModal/components/Character/index.ts +1 -0
  134. package/src/modals/RemainingTilesModal/components/index.ts +1 -0
  135. package/src/modals/RemainingTilesModal/index.ts +1 -0
  136. package/src/modals/ResultsModal/ResultsModal.module.scss +7 -0
  137. package/src/modals/ResultsModal/ResultsModal.tsx +58 -0
  138. package/src/modals/ResultsModal/index.ts +1 -0
  139. package/src/modals/SettingsModal/SettingsModal.tsx +34 -0
  140. package/src/{components/Settings → modals/SettingsModal}/components/AutoGroupTilesSetting/AutoGroupTilesSetting.module.scss +0 -0
  141. package/src/{components/Settings → modals/SettingsModal}/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +1 -2
  142. package/src/{components/Settings → modals/SettingsModal}/components/AutoGroupTilesSetting/constants.ts +0 -0
  143. package/src/{components/Settings → modals/SettingsModal}/components/AutoGroupTilesSetting/index.ts +0 -0
  144. package/src/{components/Settings → modals/SettingsModal}/components/AutoGroupTilesSetting/lib.ts +0 -0
  145. package/src/{components/Settings → modals/SettingsModal}/components/ConfigSetting/ConfigSetting.module.scss +0 -0
  146. package/src/{components/Settings → modals/SettingsModal}/components/ConfigSetting/ConfigSetting.tsx +1 -2
  147. package/src/{components/Settings → modals/SettingsModal}/components/ConfigSetting/index.ts +0 -0
  148. package/src/{components/Settings → modals/SettingsModal}/components/ConfigSetting/options.ts +0 -0
  149. package/src/{components/Settings → modals/SettingsModal}/components/ConfigSetting/types.ts +0 -0
  150. package/src/{components/Settings → modals/SettingsModal}/components/LocaleSetting/LocaleSetting.module.scss +0 -0
  151. package/src/{components/Settings → modals/SettingsModal}/components/LocaleSetting/LocaleSetting.tsx +1 -2
  152. package/src/{components/Settings → modals/SettingsModal}/components/LocaleSetting/index.ts +0 -0
  153. package/src/{components/Settings → modals/SettingsModal}/components/LocaleSetting/options.ts +0 -0
  154. package/src/{components/Settings → modals/SettingsModal}/components/LocaleSetting/types.ts +0 -0
  155. package/src/{components/Settings → modals/SettingsModal}/components/index.ts +0 -0
  156. package/src/modals/SettingsModal/index.ts +1 -0
  157. package/src/{components/Words/Words.module.scss → modals/WordsModal/WordsModal.module.scss} +7 -1
  158. package/src/{components/Words/Words.tsx → modals/WordsModal/WordsModal.tsx} +10 -12
  159. package/src/modals/WordsModal/index.ts +1 -0
  160. package/src/modals/index.ts +6 -0
  161. package/src/pages/index.module.scss +6 -4
  162. package/src/pages/index.tsx +63 -26
  163. package/src/parameters/index.ts +28 -6
  164. package/src/state/createAppStore.ts +7 -4
  165. package/src/styles/mixins.scss +15 -13
  166. package/src/styles/variables.scss +15 -17
  167. package/src/types/index.ts +2 -0
  168. package/tsconfig.json +1 -0
  169. package/.next/cache/webpack/client-development/7.pack_ +0 -0
  170. package/.next/static/FJkPF91uL-OCAJKTTpVSP/_buildManifest.js +0 -1
  171. package/.next/static/chunks/361-d16f336a9752a55a.js +0 -1
  172. package/.next/static/chunks/724-eb48df4d1ba3df8b.js +0 -5
  173. package/.next/static/chunks/pages/_app-959e495f0f221247.js +0 -24
  174. package/.next/static/chunks/pages/index-1e30dafa41bddb80.js +0 -1
  175. package/.next/static/css/aafd07997120f1e4.css +0 -1
  176. package/.next/static/css/cb5b206454513f3c.css +0 -1
  177. package/.next/static/css/eb9d57f7103525ab.css +0 -1
  178. package/src/components/KeyMap/index.ts +0 -1
  179. package/src/components/RemainingTiles/RemainingTiles.module.scss +0 -16
  180. package/src/components/RemainingTiles/index.ts +0 -1
  181. package/src/components/Screen/index.ts +0 -1
  182. package/src/components/Settings/Settings.tsx +0 -35
  183. package/src/components/Settings/index.ts +0 -1
  184. package/src/components/Sidebar/index.ts +0 -1
  185. package/src/components/Splash/index.ts +0 -1
  186. package/src/components/Words/index.ts +0 -1
  187. package/src/hooks/useIsTablet.ts +0 -10
  188. package/src/icons/Play.svg +0 -4
@@ -1,13 +1,11 @@
1
1
  import { FunctionComponent } from 'react';
2
2
 
3
+ import { Badge, Modal } from 'components';
3
4
  import { LOCALE_FEATURES } from 'i18n';
4
5
  import { selectLocale, selectRemainingTilesGroups, useTranslate, useTypedSelector } from 'state';
5
6
 
6
- import Badge from '../Badge';
7
- import Sidebar from '../Sidebar';
8
-
9
- import Character from './Character';
10
- import styles from './RemainingTiles.module.scss';
7
+ import { Character } from './components';
8
+ import styles from './RemainingTilesModal.module.scss';
11
9
 
12
10
  interface Props {
13
11
  className?: string;
@@ -15,20 +13,20 @@ interface Props {
15
13
  onClose: () => void;
16
14
  }
17
15
 
18
- const RemainingTiles: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
16
+ const RemainingTilesModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
19
17
  const translate = useTranslate();
20
18
  const locale = useTypedSelector(selectLocale);
21
19
  const groups = useTypedSelector(selectRemainingTilesGroups);
22
20
  const { direction } = LOCALE_FEATURES[locale];
23
21
 
24
22
  return (
25
- <Sidebar className={className} isOpen={isOpen} title={translate('remaining-tiles')} onClose={onClose}>
23
+ <Modal className={className} isOpen={isOpen} title={translate('remaining-tiles')} onClose={onClose}>
26
24
  {groups.map(({ remainingCount, tiles, translationKey, totalCount }) => {
27
25
  const current = direction === 'ltr' ? remainingCount : totalCount;
28
26
  const total = direction === 'ltr' ? totalCount : remainingCount;
29
27
 
30
28
  return (
31
- <Sidebar.Section
29
+ <Modal.Section
32
30
  key={translationKey}
33
31
  title={
34
32
  <span className={styles.title}>
@@ -41,14 +39,18 @@ const RemainingTiles: FunctionComponent<Props> = ({ className, isOpen, onClose }
41
39
  >
42
40
  <div className={styles.content}>
43
41
  {tiles.map((tile) => {
44
- return <Character key={tile.character} tile={tile} />;
42
+ return (
43
+ <div className={styles.character} key={tile.character}>
44
+ <Character tile={tile} />
45
+ </div>
46
+ );
45
47
  })}
46
48
  </div>
47
- </Sidebar.Section>
49
+ </Modal.Section>
48
50
  );
49
51
  })}
50
- </Sidebar>
52
+ </Modal>
51
53
  );
52
54
  };
53
55
 
54
- export default RemainingTiles;
56
+ export default RemainingTilesModal;
@@ -25,8 +25,12 @@
25
25
  }
26
26
  }
27
27
 
28
+ .remaining {
29
+ height: 6px;
30
+ margin-top: var(--spacing--m);
31
+ }
32
+
28
33
  .count {
29
34
  padding: var(--spacing--xs) 0;
30
- text-align: center;
31
- font-size: var(--font--size--s);
35
+ white-space: nowrap;
32
36
  }
@@ -2,13 +2,12 @@ import { BLANK } from '@scrabble-solver/constants';
2
2
  import classNames from 'classnames';
3
3
  import { FunctionComponent } from 'react';
4
4
 
5
+ import { Progress, Tile } from 'components';
5
6
  import { LOCALE_FEATURES } from 'i18n';
6
7
  import { REMAINING_TILES_TILE_SIZE } from 'parameters';
7
8
  import { selectCharacterPoints, selectLocale, useTypedSelector } from 'state';
8
9
  import { RemainingTile } from 'types';
9
10
 
10
- import Tile from '../Tile';
11
-
12
11
  import styles from './Character.module.scss';
13
12
 
14
13
  interface Props {
@@ -30,7 +29,6 @@ const Character: FunctionComponent<Props> = ({ tile }) => {
30
29
  [styles.finished]: remainingCount <= 0,
31
30
  [styles.overused]: remainingCount < 0,
32
31
  })}
33
- key={character}
34
32
  >
35
33
  <Tile
36
34
  character={character}
@@ -42,6 +40,16 @@ const Character: FunctionComponent<Props> = ({ tile }) => {
42
40
  raised
43
41
  size={REMAINING_TILES_TILE_SIZE}
44
42
  />
43
+
44
+ <Progress
45
+ className={styles.remaining}
46
+ max={count}
47
+ style={{
48
+ width: REMAINING_TILES_TILE_SIZE,
49
+ }}
50
+ value={remainingCount}
51
+ />
52
+
45
53
  <div className={styles.count}>
46
54
  {current.toLocaleString(locale)} / {total.toLocaleString(locale)}
47
55
  </div>
@@ -0,0 +1 @@
1
+ export { default } from './Character';
@@ -0,0 +1 @@
1
+ export { default as Character } from './Character';
@@ -0,0 +1 @@
1
+ export { default } from './RemainingTilesModal';
@@ -0,0 +1,7 @@
1
+ .content {
2
+ position: relative;
3
+ display: flex;
4
+ flex-direction: column;
5
+ height: 100%;
6
+ background-color: white;
7
+ }
@@ -0,0 +1,58 @@
1
+ import { Result } from '@scrabble-solver/types';
2
+ import { FunctionComponent, useMemo } from 'react';
3
+ import { useDispatch } from 'react-redux';
4
+ import { useMeasure } from 'react-use';
5
+
6
+ import { Modal, Results, Sizer, Well } from 'components';
7
+ import { useMediaQuery } from 'hooks';
8
+ import {
9
+ resultsSlice,
10
+ selectResultCandidate,
11
+ selectSortedFilteredResults,
12
+ useTranslate,
13
+ useTypedSelector,
14
+ } from 'state';
15
+
16
+ import styles from './ResultsModal.module.scss';
17
+
18
+ interface Props {
19
+ className?: string;
20
+ isOpen: boolean;
21
+ onClose: () => void;
22
+ }
23
+
24
+ const ResultsModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
25
+ const dispatch = useDispatch();
26
+ const translate = useTranslate();
27
+ const [sizerRef, { height, width }] = useMeasure<HTMLDivElement>();
28
+ const isLessThanM = useMediaQuery('<m');
29
+ const results = useTypedSelector(selectSortedFilteredResults);
30
+ const resultCandidate = useTypedSelector(selectResultCandidate);
31
+ const index = (results || []).findIndex((result) => result.id === resultCandidate?.id);
32
+ const highlightedIndex = index === -1 ? undefined : index;
33
+
34
+ const callbacks = useMemo(
35
+ () => ({
36
+ onClick: (result: Result) => {
37
+ dispatch(resultsSlice.actions.changeResultCandidate(result));
38
+
39
+ if (isLessThanM) {
40
+ onClose();
41
+ }
42
+ },
43
+ }),
44
+ [dispatch, isLessThanM, onClose],
45
+ );
46
+
47
+ return (
48
+ <Modal className={className} isOpen={isOpen} title={translate('results')} onClose={onClose}>
49
+ <Well className={styles.content}>
50
+ <Sizer ref={sizerRef} />
51
+
52
+ <Results callbacks={callbacks} height={height} highlightedIndex={highlightedIndex} width={width} />
53
+ </Well>
54
+ </Modal>
55
+ );
56
+ };
57
+
58
+ export default ResultsModal;
@@ -0,0 +1 @@
1
+ export { default } from './ResultsModal';
@@ -0,0 +1,34 @@
1
+ import { FunctionComponent } from 'react';
2
+
3
+ import { Modal } from 'components';
4
+ import { useTranslate } from 'state';
5
+
6
+ import { AutoGroupTilesSetting, ConfigSetting, LocaleSetting } from './components';
7
+
8
+ interface Props {
9
+ className?: string;
10
+ isOpen: boolean;
11
+ onClose: () => void;
12
+ }
13
+
14
+ const SettingsModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
15
+ const translate = useTranslate();
16
+
17
+ return (
18
+ <Modal className={className} isOpen={isOpen} title={translate('settings')} onClose={onClose}>
19
+ <Modal.Section title={translate('settings.game')}>
20
+ <ConfigSetting disabled={!isOpen} />
21
+ </Modal.Section>
22
+
23
+ <Modal.Section title={translate('settings.language')}>
24
+ <LocaleSetting disabled={!isOpen} />
25
+ </Modal.Section>
26
+
27
+ <Modal.Section title={translate('settings.autoGroupTiles')}>
28
+ <AutoGroupTilesSetting disabled={!isOpen} />
29
+ </Modal.Section>
30
+ </Modal>
31
+ );
32
+ };
33
+
34
+ export default SettingsModal;
@@ -1,10 +1,9 @@
1
1
  import { ChangeEvent, FunctionComponent } from 'react';
2
2
  import { useDispatch } from 'react-redux';
3
3
 
4
+ import { Radio } from 'components';
4
5
  import { selectAutoGroupTiles, settingsSlice, useTranslate, useTypedSelector } from 'state';
5
6
 
6
- import Radio from '../../../Radio';
7
-
8
7
  import styles from './AutoGroupTilesSetting.module.scss';
9
8
  import { NULL_VALUE } from './constants';
10
9
  import { parseValue } from './lib';
@@ -1,10 +1,9 @@
1
1
  import { ChangeEvent, FunctionComponent } from 'react';
2
2
  import { useDispatch } from 'react-redux';
3
3
 
4
+ import { Radio } from 'components';
4
5
  import { selectConfigId, settingsSlice, useTypedSelector } from 'state';
5
6
 
6
- import Radio from '../../../Radio';
7
-
8
7
  import styles from './ConfigSetting.module.scss';
9
8
  import options from './options';
10
9
 
@@ -3,10 +3,9 @@ import classNames from 'classnames';
3
3
  import { ChangeEvent, FunctionComponent } from 'react';
4
4
  import { useDispatch } from 'react-redux';
5
5
 
6
+ import { Radio } from 'components';
6
7
  import { selectLocale, settingsSlice, useTypedSelector } from 'state';
7
8
 
8
- import Radio from '../../../Radio';
9
-
10
9
  import styles from './LocaleSetting.module.scss';
11
10
  import options from './options';
12
11
 
@@ -0,0 +1 @@
1
+ export { default } from './SettingsModal';
@@ -6,7 +6,13 @@
6
6
  }
7
7
 
8
8
  .badge {
9
- margin-left: var(--spacing--m);
9
+ [dir='ltr'] & {
10
+ margin-left: var(--spacing--m);
11
+ }
12
+
13
+ [dir='rtl'] & {
14
+ margin-right: var(--spacing--m);
15
+ }
10
16
  }
11
17
 
12
18
  .word {
@@ -1,13 +1,11 @@
1
1
  import classNames from 'classnames';
2
2
  import { FunctionComponent } from 'react';
3
3
 
4
+ import { Badge, Modal } from 'components';
4
5
  import { Check, Cross } from 'icons';
5
6
  import { selectLocale, selectVerify, useTranslate, useTypedSelector } from 'state';
6
7
 
7
- import Badge from '../Badge';
8
- import Sidebar from '../Sidebar';
9
-
10
- import styles from './Words.module.scss';
8
+ import styles from './WordsModal.module.scss';
11
9
 
12
10
  interface Props {
13
11
  className?: string;
@@ -15,14 +13,14 @@ interface Props {
15
13
  onClose: () => void;
16
14
  }
17
15
 
18
- const Words: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
16
+ const WordsModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
19
17
  const translate = useTranslate();
20
18
  const locale = useTypedSelector(selectLocale);
21
19
  const { invalidWords, validWords } = useTypedSelector(selectVerify);
22
20
 
23
21
  return (
24
- <Sidebar className={className} isOpen={isOpen} title={translate('words')} onClose={onClose}>
25
- <Sidebar.Section
22
+ <Modal className={className} isOpen={isOpen} title={translate('words')} onClose={onClose}>
23
+ <Modal.Section
26
24
  title={
27
25
  <span className={styles.title}>
28
26
  <span>{translate('words.invalid')}</span>
@@ -35,9 +33,9 @@ const Words: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
35
33
  <Cross className={classNames(styles.icon, styles.invalid)} /> {word}
36
34
  </div>
37
35
  ))}
38
- </Sidebar.Section>
36
+ </Modal.Section>
39
37
 
40
- <Sidebar.Section
38
+ <Modal.Section
41
39
  title={
42
40
  <span className={styles.title}>
43
41
  <span>{translate('words.valid')}</span>
@@ -50,9 +48,9 @@ const Words: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
50
48
  <Check className={classNames(styles.icon, styles.valid)} /> {word}
51
49
  </div>
52
50
  ))}
53
- </Sidebar.Section>
54
- </Sidebar>
51
+ </Modal.Section>
52
+ </Modal>
55
53
  );
56
54
  };
57
55
 
58
- export default Words;
56
+ export default WordsModal;
@@ -0,0 +1 @@
1
+ export { default } from './WordsModal';
@@ -0,0 +1,6 @@
1
+ export { default as KeyMapModal } from './KeyMapModal';
2
+ export { default as MenuModal } from './MenuModal';
3
+ export { default as RemainingTilesModal } from './RemainingTilesModal';
4
+ export { default as ResultsModal } from './ResultsModal';
5
+ export { default as SettingsModal } from './SettingsModal';
6
+ export { default as WordsModal } from './WordsModal';
@@ -4,10 +4,8 @@
4
4
  display: flex;
5
5
  flex-direction: column;
6
6
  height: 100%;
7
- min-width: 900px;
8
- min-height: 700px;
9
7
  opacity: 0;
10
- overflow: hidden;
8
+ overflow: auto;
11
9
  transition: var(--transition);
12
10
  transition-duration: var(--transition--duration--long);
13
11
 
@@ -20,6 +18,10 @@
20
18
  position: relative;
21
19
  z-index: 1;
22
20
  flex: 0 0 auto;
21
+ }
22
+
23
+ .navContent {
24
+ width: 100%;
23
25
  display: flex;
24
26
  align-items: flex-start;
25
27
  padding: var(--spacing--l);
@@ -38,7 +40,7 @@
38
40
  height: 60px;
39
41
  user-select: none;
40
42
 
41
- @include tablet {
43
+ @include media('<l') {
42
44
  height: 48px;
43
45
  }
44
46
  }
@@ -2,33 +2,42 @@ import classNames from 'classnames';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
  import { AnimationEvent, FunctionComponent, useEffect, useState } from 'react';
5
- import Modal from 'react-modal';
5
+ import ReactModal from 'react-modal';
6
6
  import { useDispatch } from 'react-redux';
7
- import { useEffectOnce } from 'react-use';
7
+ import { useEffectOnce, useMeasure } from 'react-use';
8
8
 
9
- import { KeyMap, Logo, NavButtons, RemainingTiles, Settings, Solver, Splash, SvgFontFix, Words } from 'components';
10
- import { useDirection, useLanguage, useLocalStorage } from 'hooks';
9
+ import { Logo, LogoSplashScreen, NavButtons, Solver, SvgFontFix } from 'components';
10
+ import { useDirection, useLanguage, useLocalStorage, useMediaQuery } from 'hooks';
11
11
  import { LOCALE_FEATURES } from 'i18n';
12
+ import { KeyMapModal, MenuModal, RemainingTilesModal, ResultsModal, SettingsModal, WordsModal } from 'modals';
12
13
  import { INITIALIZATION_DURATION } from 'parameters';
13
14
  import { registerServiceWorker } from 'serviceWorkerManager';
14
15
  import { initialize, localStorage, reset, selectLocale, useTypedSelector } from 'state';
15
16
 
16
17
  import styles from './index.module.scss';
17
18
 
18
- Modal.setAppElement('#__next');
19
+ ReactModal.setAppElement('#__next');
19
20
 
20
21
  interface Props {
21
22
  version: string;
22
23
  }
23
24
 
25
+ // eslint-disable-next-line max-statements
24
26
  const Index: FunctionComponent<Props> = ({ version }) => {
25
27
  const dispatch = useDispatch();
26
28
  const locale = useTypedSelector(selectLocale);
29
+ const isLessThanL = useMediaQuery('<l');
27
30
  const [showKeyMap, setShowKeyMap] = useState(false);
31
+ const [showMenu, setShowMenu] = useState(false);
28
32
  const [showRemainingTiles, setShowRemainingTiles] = useState(false);
33
+ const [showResults, setShowResults] = useState(false);
29
34
  const [showSettings, setShowSettings] = useState(false);
30
35
  const [showWords, setShowWords] = useState(false);
31
36
  const [isInitialized, setIsInitialized] = useState(false);
37
+ const [indexRef, { height: indexHeight, width: indexWidth }] = useMeasure<HTMLDivElement>();
38
+ const [navRef, { height: navHeight }] = useMeasure<HTMLDivElement>();
39
+ const solverHeight = indexHeight - navHeight;
40
+ const solverWidth = indexWidth;
32
41
 
33
42
  const handleClear = () => {
34
43
  dispatch(reset());
@@ -48,11 +57,17 @@ const Index: FunctionComponent<Props> = ({ version }) => {
48
57
  useEffectOnce(() => {
49
58
  dispatch(initialize());
50
59
 
51
- setTimeout(() => {
60
+ globalThis.setTimeout(() => {
52
61
  setIsInitialized(true);
53
62
  }, INITIALIZATION_DURATION);
54
63
  });
55
64
 
65
+ useEffect(() => {
66
+ if (!isLessThanL) {
67
+ setShowResults(false);
68
+ }
69
+ }, [isLessThanL]);
70
+
56
71
  useEffect(() => {
57
72
  if (process.env.NODE_ENV === 'production') {
58
73
  registerServiceWorker();
@@ -63,31 +78,53 @@ const Index: FunctionComponent<Props> = ({ version }) => {
63
78
  <>
64
79
  <SvgFontFix />
65
80
 
66
- <div className={classNames(styles.index, { [styles.initialized]: isInitialized })}>
67
- <div className={styles.nav}>
68
- <div className={styles.navLogo}>
69
- <a className={styles.logoContainer} href="/" title={version}>
70
- <Logo className={styles.logo} />
71
- </a>
81
+ <div className={classNames(styles.index, { [styles.initialized]: isInitialized })} ref={indexRef}>
82
+ <div className={styles.nav} ref={navRef}>
83
+ <div className={styles.navContent}>
84
+ <div className={styles.navLogo}>
85
+ <a className={styles.logoContainer} href="/" title={version}>
86
+ <Logo className={styles.logo} />
87
+ </a>
88
+ </div>
89
+
90
+ <NavButtons
91
+ onClear={handleClear}
92
+ onShowKeyMap={() => setShowKeyMap(true)}
93
+ onShowMenu={() => setShowMenu(true)}
94
+ onShowRemainingTiles={() => setShowRemainingTiles(true)}
95
+ onShowSettings={() => setShowSettings(true)}
96
+ onShowWords={() => setShowWords(true)}
97
+ />
72
98
  </div>
73
-
74
- <NavButtons
75
- onClear={handleClear}
76
- onShowKeyMap={() => setShowKeyMap(true)}
77
- onShowRemainingTiles={() => setShowRemainingTiles(true)}
78
- onShowSettings={() => setShowSettings(true)}
79
- onShowWords={() => setShowWords(true)}
80
- />
81
99
  </div>
82
100
 
83
- <Solver className={styles.solver} />
101
+ <Solver
102
+ className={styles.solver}
103
+ height={solverHeight}
104
+ width={solverWidth}
105
+ onShowResults={() => setShowResults(true)}
106
+ />
84
107
  </div>
85
108
 
86
- <Settings isOpen={showSettings} onClose={() => setShowSettings(false)} />
87
- <KeyMap isOpen={showKeyMap} onClose={() => setShowKeyMap(false)} />
88
- <Words isOpen={showWords} onClose={() => setShowWords(false)} />
89
- <RemainingTiles isOpen={showRemainingTiles} onClose={() => setShowRemainingTiles(false)} />
90
- <Splash forceShow={!isInitialized} onAnimationEnd={handleSplashAnimationEnd} />
109
+ <MenuModal
110
+ isOpen={showMenu}
111
+ onClose={() => setShowMenu(false)}
112
+ onShowRemainingTiles={() => setShowRemainingTiles(true)}
113
+ onShowSettings={() => setShowSettings(true)}
114
+ onShowWords={() => setShowWords(true)}
115
+ />
116
+
117
+ <SettingsModal isOpen={showSettings} onClose={() => setShowSettings(false)} />
118
+
119
+ <KeyMapModal isOpen={showKeyMap} onClose={() => setShowKeyMap(false)} />
120
+
121
+ <WordsModal isOpen={showWords} onClose={() => setShowWords(false)} />
122
+
123
+ <RemainingTilesModal isOpen={showRemainingTiles} onClose={() => setShowRemainingTiles(false)} />
124
+
125
+ <ResultsModal isOpen={showResults} onClose={() => setShowResults(false)} />
126
+
127
+ <LogoSplashScreen forceShow={!isInitialized} onAnimationEnd={handleSplashAnimationEnd} />
91
128
  </>
92
129
  );
93
130
  };
@@ -1,3 +1,11 @@
1
+ export const BREAKPOINTS = {
2
+ xs: 480,
3
+ s: 768,
4
+ m: 992,
5
+ l: 1200,
6
+ xl: 1400,
7
+ };
8
+
1
9
  export const GITHUB_PROJECT_URL = 'https://github.com/kamilmielnik/scrabble-solver';
2
10
 
3
11
  export const INITIALIZATION_DURATION = 100;
@@ -11,15 +19,24 @@ export const COLOR_RED = '#f7c2aa';
11
19
  export const COLOR_YELLOW = '#efe3ae';
12
20
 
13
21
  export const COMPONENTS_SPACING = 40;
14
- export const COMPONENTS_SPACING_MOBILE = 20;
22
+ export const COMPONENTS_SPACING_SMALL = 20;
15
23
 
16
24
  export const BOARD_CELL_BORDER_WIDTH = 1;
17
25
  export const BOARD_TILE_FONT_SIZE_MIN = 14;
18
26
  export const BOARD_TILE_FONT_SIZE_POINTS_MIN = 10;
19
27
  export const BOARD_TILE_SIZE_MAX = 64;
20
- export const BOARD_TILE_SIZE_MIN = 32;
28
+ /**
29
+ * 20 - fits all board tiles without horizontal scrollbar on 360px viewport width (font-size: 14px)
30
+ * 21 - fits all board tiles without horizontal scrollbar on 375px viewport width (font-size: 14px)
31
+ * 26 - tiles start to look good (font-size: 16px)
32
+ */
33
+ export const BOARD_TILE_SIZE_MIN = 20;
34
+
35
+ export const BORDER_WIDTH = 1;
21
36
 
22
- export const DICTIONARY_HEIGHT = 220;
37
+ export const COLUMN_MIN_HEIGHT = 588.5;
38
+
39
+ export const DICTIONARY_HEIGHT = 260;
23
40
 
24
41
  export const TILE_SIZE = 80;
25
42
 
@@ -45,8 +62,13 @@ export const PLAIN_TILES_TILE_SIZE = 80;
45
62
  export const PLAIN_TILES_VERSION_TILE_COLOR = COLOR_GREEN;
46
63
  export const PLAIN_TILES_VERSION_TILE_SIZE = TILE_SIZE;
47
64
 
65
+ export const PROGRESS_COLOR_VALUE = 'var(--color--violet--light)';
66
+ export const PROGRESS_COLOR_BACKGROUND = 'var(--color--inactive)';
67
+
68
+ export const RACK_TILE_SIZE_MAX = 80;
69
+
48
70
  export const REMAINING_TILES_TILE_SIZE = 50;
49
71
 
50
- export const RESULTS_HEADER_HEIGHT = 35;
51
- export const RESULTS_ITEM_HEIGHT = 34;
52
- export const RESULTS_INPUT_HEIGHT = 43;
72
+ export const RESULTS_HEADER_HEIGHT = 34;
73
+ export const RESULTS_ITEM_HEIGHT = 40;
74
+ export const RESULTS_INPUT_HEIGHT = 40;
@@ -1,4 +1,4 @@
1
- import { createStore, applyMiddleware } from 'redux';
1
+ import { applyMiddleware, compose, createStore } from 'redux';
2
2
  import reduxSaga from 'redux-saga';
3
3
 
4
4
  import rootReducer from './rootReducer';
@@ -8,12 +8,15 @@ import { RootState } from './types';
8
8
  const sagaMiddleware = reduxSaga();
9
9
  const initialState: Partial<RootState> | undefined = undefined;
10
10
 
11
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
12
+ // @ts-ignore
13
+ // eslint-disable-next-line no-underscore-dangle
14
+ const composeEnhancers = globalThis.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
15
+
11
16
  const createAppStore = (): ReturnType<typeof createStore> => {
12
- const store = createStore(rootReducer, initialState, createEnhancer());
17
+ const store = createStore(rootReducer, initialState, composeEnhancers(applyMiddleware(sagaMiddleware)));
13
18
  sagaMiddleware.run(rootSaga);
14
19
  return store;
15
20
  };
16
21
 
17
- const createEnhancer = () => applyMiddleware(sagaMiddleware);
18
-
19
22
  export default createAppStore;