@scrabble-solver/scrabble-solver 2.10.0 → 2.10.2

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 (144) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +19 -31
  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-development/0.pack +0 -0
  7. package/.next/cache/webpack/client-development/1.pack +0 -0
  8. package/.next/cache/webpack/client-development/2.pack +0 -0
  9. package/.next/cache/webpack/client-development/3.pack +0 -0
  10. package/.next/cache/webpack/client-development/4.pack +0 -0
  11. package/.next/cache/webpack/client-development/index.pack +0 -0
  12. package/.next/cache/webpack/client-development/index.pack.old +0 -0
  13. package/.next/cache/webpack/client-production/0.pack +0 -0
  14. package/.next/cache/webpack/client-production/index.pack +0 -0
  15. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  16. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  17. package/.next/cache/webpack/server-development/0.pack +0 -0
  18. package/.next/cache/webpack/server-development/10.pack_ +0 -0
  19. package/.next/cache/webpack/server-development/5.pack_ +0 -0
  20. package/.next/cache/webpack/server-development/8.pack_ +0 -0
  21. package/.next/cache/webpack/server-development/index.pack +0 -0
  22. package/.next/cache/webpack/server-production/0.pack +0 -0
  23. package/.next/cache/webpack/server-production/index.pack +0 -0
  24. package/.next/images-manifest.json +1 -1
  25. package/.next/next-server.js.nft.json +1 -1
  26. package/.next/prerender-manifest.json +1 -1
  27. package/.next/required-server-files.json +1 -1
  28. package/.next/routes-manifest.json +1 -1
  29. package/.next/server/chunks/131.js +1399 -117
  30. package/.next/server/chunks/{515.js → 176.js} +850 -732
  31. package/.next/server/chunks/210.js +122 -0
  32. package/.next/server/chunks/{939.js → 290.js} +4 -3
  33. package/.next/server/chunks/44.js +33 -33
  34. package/.next/server/chunks/50.js +5 -9
  35. package/.next/server/chunks/{413.js → 579.js} +184 -117
  36. package/.next/server/chunks/664.js +537 -350
  37. package/.next/server/chunks/859.js +56 -23
  38. package/.next/server/chunks/865.js +1 -1
  39. package/.next/server/middleware-build-manifest.js +1 -1
  40. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  41. package/.next/server/pages/404.html +2 -2
  42. package/.next/server/pages/404.js.nft.json +1 -1
  43. package/.next/server/pages/500.html +2 -2
  44. package/.next/server/pages/_app.js +23 -5
  45. package/.next/server/pages/_app.js.nft.json +1 -1
  46. package/.next/server/pages/_document.js +2 -2
  47. package/.next/server/pages/_error.js +206 -25
  48. package/.next/server/pages/_error.js.nft.json +1 -1
  49. package/.next/server/pages/api/dictionary/[locale]/[word].js +11 -11
  50. package/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  51. package/.next/server/pages/api/dictionary/[locale].js +10 -10
  52. package/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  53. package/.next/server/pages/api/solve.js +34 -36
  54. package/.next/server/pages/api/solve.js.nft.json +1 -1
  55. package/.next/server/pages/api/verify.js +10 -10
  56. package/.next/server/pages/api/verify.js.nft.json +1 -1
  57. package/.next/server/pages/api/visit.js +3 -3
  58. package/.next/server/pages/api/visit.js.nft.json +1 -1
  59. package/.next/server/pages/index.html +2 -2
  60. package/.next/server/pages/index.js +44 -128
  61. package/.next/server/pages/index.js.nft.json +1 -1
  62. package/.next/server/pages/index.json +1 -1
  63. package/.next/server/pages-manifest.json +4 -4
  64. package/.next/static/FjrbXpI5fkt4lmko-vL_7/_buildManifest.js +1 -0
  65. package/.next/static/{vscqn7BEtAxJteWSwNnas → FjrbXpI5fkt4lmko-vL_7}/_ssgManifest.js +0 -0
  66. package/.next/static/chunks/361-d16f336a9752a55a.js +1 -0
  67. package/.next/static/chunks/724-eb48df4d1ba3df8b.js +5 -0
  68. package/.next/static/chunks/amp.js +720 -0
  69. package/.next/static/chunks/framework-2c79e2a64abdb08b.js +33 -0
  70. package/.next/static/chunks/main-f11614d8aa7ee555.js +1 -0
  71. package/.next/static/chunks/main.js +1076 -0
  72. package/.next/static/chunks/pages/404-24f9617eeb8d6dc1.js +1 -0
  73. package/.next/static/chunks/pages/_app-959e495f0f221247.js +24 -0
  74. package/.next/static/chunks/pages/_app.js +2121 -0
  75. package/.next/static/chunks/pages/_error-8353112a01355ec2.js +1 -0
  76. package/.next/static/chunks/pages/_error.js +28 -0
  77. package/.next/static/chunks/pages/index-1e30dafa41bddb80.js +1 -0
  78. package/.next/static/chunks/pages/index.js +5314 -0
  79. package/.next/static/chunks/react-refresh.js +62 -0
  80. package/.next/static/chunks/webpack-59c5c889f52620d6.js +1 -0
  81. package/.next/static/chunks/webpack.js +1237 -0
  82. package/.next/static/css/aafd07997120f1e4.css +1 -0
  83. package/.next/static/css/c8d26240c04079b9.css +1 -0
  84. package/.next/static/css/eb9d57f7103525ab.css +1 -0
  85. package/.next/static/development/_buildManifest.js +1 -0
  86. package/.next/static/development/_ssgManifest.js +1 -0
  87. package/.next/static/webpack/fb4b50d5e70ee127.webpack.hot-update.json +1 -0
  88. package/.next/static/webpack/pages/index.fb4b50d5e70ee127.hot-update.js +171 -0
  89. package/.next/static/webpack/webpack.fb4b50d5e70ee127.hot-update.js +18 -0
  90. package/.next/trace +52 -52
  91. package/package.json +21 -21
  92. package/public/og.png +0 -0
  93. package/src/components/Board/Board.module.scss +1 -2
  94. package/src/components/Board/BoardPure.tsx +2 -0
  95. package/src/components/Board/components/Cell/Cell.module.scss +65 -55
  96. package/src/components/Board/components/Cell/Cell.tsx +9 -0
  97. package/src/components/Board/components/Cell/CellPure.tsx +11 -2
  98. package/src/components/Board/hooks/useGrid.ts +6 -6
  99. package/src/components/NavButtons/NavButtons.tsx +11 -1
  100. package/src/components/Rack/Rack.tsx +16 -4
  101. package/src/components/Rack/RackTile.tsx +10 -1
  102. package/src/components/RemainingTiles/Character.module.scss +0 -1
  103. package/src/components/RemainingTiles/Character.tsx +1 -0
  104. package/src/components/Results/Results.tsx +2 -2
  105. package/src/components/Settings/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +2 -2
  106. package/src/components/Settings/components/LocaleSetting/options.ts +9 -1
  107. package/src/components/Solver/Solver.module.scss +85 -0
  108. package/src/components/Solver/Solver.tsx +75 -0
  109. package/src/components/Solver/index.ts +1 -0
  110. package/src/components/Tile/Tile.module.scss +51 -7
  111. package/src/components/Tile/Tile.tsx +3 -0
  112. package/src/components/Tile/TilePure.tsx +8 -1
  113. package/src/components/index.ts +1 -0
  114. package/src/hooks/index.ts +1 -0
  115. package/src/hooks/useIsTouchDevice.ts +7 -0
  116. package/src/i18n/fr.json +1 -1
  117. package/src/icons/ExclamationSquareFill.svg +4 -0
  118. package/src/icons/index.ts +1 -0
  119. package/src/lib/getRemainingTilesGroups.ts +24 -26
  120. package/src/pages/index.module.scss +1 -75
  121. package/src/pages/index.tsx +11 -73
  122. package/src/parameters/index.ts +2 -0
  123. package/src/sdk/findWordDefinitions.ts +1 -1
  124. package/src/service-worker/average.ts +9 -0
  125. package/src/service-worker/routeSolveRequests.ts +46 -7
  126. package/src/state/sagas.ts +19 -5
  127. package/src/state/selectors.ts +30 -2
  128. package/src/state/slices/boardInitialState.ts +27 -0
  129. package/src/styles/mixins.scss +6 -1
  130. package/src/styles/variables.scss +6 -3
  131. package/.next/InjectManifest.js.nft.json +0 -1
  132. package/.next/static/chunks/368-d423e70be6c0c473.js +0 -1
  133. package/.next/static/chunks/546-447e243fc9de2c59.js +0 -1
  134. package/.next/static/chunks/framework-4556c45dd113b893.js +0 -1
  135. package/.next/static/chunks/main-a75cf611e061d8f8.js +0 -1
  136. package/.next/static/chunks/pages/404-932294135c3206dd.js +0 -1
  137. package/.next/static/chunks/pages/_app-3f5508a5f544d9eb.js +0 -1
  138. package/.next/static/chunks/pages/_error-a4ba2246ff8fb532.js +0 -1
  139. package/.next/static/chunks/pages/index-8af7a9d7a2cd98a7.js +0 -1
  140. package/.next/static/chunks/webpack-5752944655d749a0.js +0 -1
  141. package/.next/static/css/6b1833fd19d3a74a.css +0 -1
  142. package/.next/static/css/a6154e4ca046ca13.css +0 -1
  143. package/.next/static/css/bad53af6f8616677.css +0 -1
  144. package/.next/static/vscqn7BEtAxJteWSwNnas/_buildManifest.js +0 -1
@@ -0,0 +1,85 @@
1
+ @import 'styles/mixins';
2
+
3
+ .solver {
4
+ display: flex;
5
+ flex-direction: column;
6
+ height: 100%;
7
+ }
8
+
9
+ .contentWrapper {
10
+ $board-size: 15;
11
+ $tile-size-max: 60px;
12
+ $tile-border-size: 1px;
13
+
14
+ flex: 1;
15
+ padding: 0 var(--spacing--xl);
16
+ max-height: $board-size * ($tile-size-max + $tile-border-size) + $tile-border-size;
17
+ }
18
+
19
+ .content {
20
+ display: flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ height: 100%;
24
+ gap: var(--spacing--xl);
25
+
26
+ @include tablet {
27
+ gap: var(--spacing--l);
28
+ }
29
+ }
30
+
31
+ .boardContainer {
32
+ display: flex;
33
+ position: relative;
34
+ }
35
+
36
+ .sidebar {
37
+ display: flex;
38
+ flex-direction: column;
39
+ flex: 0 0 var(--sidebar--width);
40
+ gap: var(--spacing--xl);
41
+
42
+ @include tablet {
43
+ gap: var(--spacing--l);
44
+ }
45
+ }
46
+
47
+ .dictionary {
48
+ display: flex;
49
+ flex-direction: column;
50
+ }
51
+
52
+ .dictionaryOutput {
53
+ flex: 1;
54
+ border-bottom: var(--border);
55
+ }
56
+
57
+ .dictionaryInput {
58
+ flex: 0 0 auto;
59
+ }
60
+
61
+ .resultsContainer {
62
+ flex: 1;
63
+ position: relative;
64
+ }
65
+
66
+ .rackContainer {
67
+ position: relative;
68
+ z-index: 1;
69
+ flex: 0 0 auto;
70
+ display: flex;
71
+ justify-content: center;
72
+ margin: var(--spacing--xl) var(--spacing--l);
73
+
74
+ @include tablet {
75
+ margin: var(--spacing--l);
76
+ }
77
+ }
78
+
79
+ .rack {
80
+ border: var(--border);
81
+ }
82
+
83
+ .submitInput {
84
+ display: none;
85
+ }
@@ -0,0 +1,75 @@
1
+ import classNames from 'classnames';
2
+ import { FormEvent, FunctionComponent } from 'react';
3
+ import { useDispatch } from 'react-redux';
4
+ import { useMeasure } from 'react-use';
5
+
6
+ import { useIsTablet } from 'hooks';
7
+ import { getCellSize } from 'lib';
8
+ import { COMPONENTS_SPACING, COMPONENTS_SPACING_MOBILE, DICTIONARY_HEIGHT } from 'parameters';
9
+ import { selectConfig, solveSlice, useTypedSelector } from 'state';
10
+
11
+ import Board from '../Board';
12
+ import Dictionary from '../Dictionary';
13
+ import DictionaryInput from '../DictionaryInput';
14
+ import Rack from '../Rack';
15
+ import Results from '../Results';
16
+ import Well from '../Well';
17
+
18
+ import styles from './Solver.module.scss';
19
+
20
+ interface Props {
21
+ className?: string;
22
+ }
23
+
24
+ const Solver: FunctionComponent<Props> = ({ className }) => {
25
+ const dispatch = useDispatch();
26
+ const isTablet = useIsTablet();
27
+ const [boardRef, { height: boardHeight }] = useMeasure<HTMLDivElement>();
28
+ const [contentRef, { height: contentHeight, width: contentWidth }] = useMeasure<HTMLDivElement>();
29
+ const [resultsContainerRef, { height: resultsContainerHeight, width: resultsContainerWidth }] =
30
+ useMeasure<HTMLDivElement>();
31
+ const config = useTypedSelector(selectConfig);
32
+ const cellSize = getCellSize(config, contentWidth - resultsContainerWidth, contentHeight);
33
+ const componentsSpacing = isTablet ? COMPONENTS_SPACING_MOBILE : COMPONENTS_SPACING;
34
+ const resultsHeight = boardHeight - DICTIONARY_HEIGHT - componentsSpacing;
35
+
36
+ const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
37
+ event.preventDefault();
38
+ dispatch(solveSlice.actions.submit());
39
+ };
40
+
41
+ return (
42
+ <div className={classNames(styles.solver, className)}>
43
+ <div className={styles.contentWrapper}>
44
+ <div className={styles.content} ref={contentRef}>
45
+ <form className={styles.boardContainer} onSubmit={handleSubmit}>
46
+ {contentWidth > 0 && <Board cellSize={cellSize} innerRef={boardRef} />}
47
+ <input className={styles.submitInput} tabIndex={-1} type="submit" />
48
+ </form>
49
+
50
+ <div className={styles.sidebar} style={{ height: boardHeight + 1 }}>
51
+ <Well className={styles.resultsContainer} ref={resultsContainerRef}>
52
+ {resultsContainerWidth > 0 && resultsContainerHeight > 0 && (
53
+ <Results height={resultsHeight} width={resultsContainerWidth} />
54
+ )}
55
+ </Well>
56
+
57
+ <Well>
58
+ <div className={styles.dictionary} style={{ height: DICTIONARY_HEIGHT }}>
59
+ <Dictionary className={styles.dictionaryOutput} />
60
+ <DictionaryInput className={styles.dictionaryInput} />
61
+ </div>
62
+ </Well>
63
+ </div>
64
+ </div>
65
+ </div>
66
+
67
+ <form className={styles.rackContainer} onSubmit={handleSubmit}>
68
+ <Rack className={styles.rack} />
69
+ <input className={styles.submitInput} tabIndex={-1} type="submit" />
70
+ </form>
71
+ </div>
72
+ );
73
+ };
74
+
75
+ export default Solver;
@@ -0,0 +1 @@
1
+ export { default } from './Solver';
@@ -1,6 +1,10 @@
1
+ @import 'styles/mixins';
2
+
1
3
  .tile {
4
+ --background-color: transparent;
5
+
2
6
  position: relative;
3
- background-color: transparent;
7
+ background-color: var(--background-color);
4
8
  transition: var(--transition);
5
9
 
6
10
  &.raised {
@@ -8,24 +12,34 @@
8
12
  }
9
13
 
10
14
  &.points1 {
11
- background-color: var(--color--yellow);
15
+ --background-color: var(--color--yellow);
16
+
17
+ background-color: var(--background-color);
12
18
  }
13
19
 
14
20
  &.points2 {
15
- background-color: var(--color--green);
21
+ --background-color: var(--color--green);
22
+
23
+ background-color: var(--background-color);
16
24
  }
17
25
 
18
26
  &.points3,
19
27
  &.points4 {
20
- background-color: var(--color--blue);
28
+ --background-color: var(--color--blue);
29
+
30
+ background-color: var(--background-color);
21
31
  }
22
32
 
23
33
  &.points5 {
24
- background-color: var(--color--red);
34
+ --background-color: var(--color--red);
35
+
36
+ background-color: var(--background-color);
25
37
  }
26
38
 
27
39
  &.blank {
28
- background-color: white;
40
+ --background-color: white;
41
+
42
+ background-color: var(--background-color);
29
43
 
30
44
  .character {
31
45
  color: black;
@@ -33,7 +47,9 @@
33
47
  }
34
48
 
35
49
  &.highlighted {
36
- background-color: var(--color--primary);
50
+ --background-color: var(--color--primary);
51
+
52
+ background-color: var(--background-color);
37
53
  color: white;
38
54
 
39
55
  .character {
@@ -44,6 +60,13 @@
44
60
  color: inherit;
45
61
  }
46
62
  }
63
+
64
+ &.invalid {
65
+ --background-color: var(--color--red--light);
66
+
67
+ background-color: var(--background-color);
68
+ color: var(--color--error);
69
+ }
47
70
  }
48
71
 
49
72
  .character {
@@ -52,6 +75,7 @@
52
75
  padding: 0;
53
76
  box-sizing: border-box;
54
77
  background-color: transparent;
78
+ color: inherit;
55
79
  border: none;
56
80
  font-weight: bold;
57
81
  text-transform: uppercase;
@@ -72,6 +96,8 @@
72
96
  }
73
97
 
74
98
  .points {
99
+ @include text-stroke(var(--background-color), 1px);
100
+
75
101
  position: absolute;
76
102
  font-weight: bold;
77
103
  user-select: none;
@@ -88,3 +114,21 @@
88
114
  left: 9%;
89
115
  }
90
116
  }
117
+
118
+ .alert {
119
+ $size: 30%;
120
+
121
+ position: absolute;
122
+ width: $size;
123
+ height: $size;
124
+
125
+ [dir='ltr'] & {
126
+ top: 0;
127
+ right: 0;
128
+ }
129
+
130
+ [dir='rtl'] & {
131
+ bottom: 0;
132
+ right: 0;
133
+ }
134
+ }
@@ -23,6 +23,7 @@ interface Props {
23
23
  highlighted?: boolean;
24
24
  inputRef?: RefObject<HTMLInputElement>;
25
25
  isBlank?: boolean;
26
+ isValid?: boolean;
26
27
  placeholder?: string;
27
28
  points?: number;
28
29
  raised?: boolean;
@@ -41,6 +42,7 @@ const Tile: FunctionComponent<Props> = ({
41
42
  highlighted,
42
43
  inputRef: ref,
43
44
  isBlank,
45
+ isValid,
44
46
  placeholder,
45
47
  points,
46
48
  raised,
@@ -82,6 +84,7 @@ const Tile: FunctionComponent<Props> = ({
82
84
  inputRef={inputRef}
83
85
  inputStyle={inputStyle}
84
86
  isBlank={isBlank}
87
+ isValid={isValid}
85
88
  placeholder={placeholder}
86
89
  points={points}
87
90
  pointsFormatted={pointsFormatted}
@@ -9,6 +9,8 @@ import {
9
9
  RefObject,
10
10
  } from 'react';
11
11
 
12
+ import { ExclamationSquareFill } from 'icons';
13
+
12
14
  import styles from './Tile.module.scss';
13
15
 
14
16
  interface Props {
@@ -21,6 +23,7 @@ interface Props {
21
23
  inputRef: RefObject<HTMLInputElement>;
22
24
  inputStyle?: CSSProperties;
23
25
  isBlank?: boolean;
26
+ isValid?: boolean;
24
27
  placeholder?: string;
25
28
  points?: number;
26
29
  pointsFormatted?: string;
@@ -43,6 +46,7 @@ const TilePure: FunctionComponent<Props> = ({
43
46
  inputRef,
44
47
  inputStyle,
45
48
  isBlank,
49
+ isValid,
46
50
  placeholder,
47
51
  points,
48
52
  pointsFormatted,
@@ -56,8 +60,9 @@ const TilePure: FunctionComponent<Props> = ({
56
60
  }) => (
57
61
  <div
58
62
  className={classNames(styles.tile, className, {
59
- [styles.highlighted]: highlighted,
60
63
  [styles.blank]: isBlank,
64
+ [styles.highlighted]: highlighted,
65
+ [styles.invalid]: !isValid,
61
66
  [styles.raised]: raised,
62
67
  [styles.points1]: points === 1,
63
68
  [styles.points2]: points === 2,
@@ -90,6 +95,8 @@ const TilePure: FunctionComponent<Props> = ({
90
95
  {pointsFormatted}
91
96
  </span>
92
97
  )}
98
+
99
+ {!isValid && <ExclamationSquareFill className={styles.alert} />}
93
100
  </div>
94
101
  );
95
102
 
@@ -20,6 +20,7 @@ export { default as ResultsInput } from './ResultsInput';
20
20
  export { default as Screen } from './Screen';
21
21
  export { default as Settings } from './Settings';
22
22
  export { default as Sidebar } from './Sidebar';
23
+ export { default as Solver } from './Solver';
23
24
  export { default as Splash } from './Splash';
24
25
  export { default as SquareButton } from './SquareButton';
25
26
  export { default as SvgFontCss } from './SvgFontCss';
@@ -1,5 +1,6 @@
1
1
  export { default as useDirection } from './useDirection';
2
2
  export { default as useIsTablet } from './useIsTablet';
3
+ export { default as useIsTouchDevice } from './useIsTouchDevice';
3
4
  export { default as useLanguage } from './useLanguage';
4
5
  export { default as useLocalStorage } from './useLocalStorage';
5
6
  export { default as usePortal } from './usePortal';
@@ -0,0 +1,7 @@
1
+ import { useMedia } from 'react-use';
2
+
3
+ const useIsTouchDevice = () => {
4
+ return useMedia('(hover: none)', false);
5
+ };
6
+
7
+ export default useIsTouchDevice;
package/src/i18n/fr.json CHANGED
@@ -40,7 +40,7 @@
40
40
  "results.empty-state.no-filtered-results": "Aucun résultat ne correspond à cette requête",
41
41
  "results.empty-state.no-results": "Pas de résultats - impossible de générer des mots.",
42
42
  "results.empty-state.outdated": "Les résultats sont dépassé. Cliquer ci-dessous pour mettre à jour.",
43
- "results.empty-state.uninitialized": "Words generated from your letters will be shown here.",
43
+ "results.empty-state.uninitialized": "Les mots générés à partir de vos lettres seront affichés ici.",
44
44
  "results.input.placeholder": "Rechercher les résultats... (RegExp)",
45
45
  "results.solve": "Résoudre",
46
46
  "settings": "Options",
@@ -0,0 +1,4 @@
1
+ <!-- https://icons.getbootstrap.com/icons/exclamation-square-fill/ -->
2
+ <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6 4c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995A.905.905 0 0 1 8 4zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z" fill="currentColor" />
4
+ </svg>
@@ -11,6 +11,7 @@ export { default as Cross } from './Cross.svg';
11
11
  export { default as CrossFill } from './CrossFill.svg';
12
12
  export { default as DashCircleFill } from './DashCircleFill.svg';
13
13
  export { default as Eraser } from './Eraser.svg';
14
+ export { default as ExclamationSquareFill } from './ExclamationSquareFill.svg';
14
15
  export { default as Flag } from './Flag.svg';
15
16
  export { default as FlagEs } from './FlagEs.svg';
16
17
  export { default as FlagFa } from './FlagFa.svg';
@@ -8,32 +8,29 @@ import getTotalRemainingTilesCount from './getTotalRemainingTilesCount';
8
8
  const getRemainingTilesGroups = (remainingTiles: RemainingTile[]): RemainingTilesGroup[] => {
9
9
  const consonants = remainingTiles.filter(isConsonant);
10
10
  const vowels = remainingTiles.filter(isVowel);
11
+ const other = remainingTiles.filter(isOther);
11
12
  const groups: RemainingTilesGroup[] = [];
12
13
 
13
- if (consonants.length + vowels.length > 0) {
14
- groups.push({
15
- remainingCount: getRemainingTilesCount(vowels),
16
- tiles: vowels,
17
- translationKey: 'common.vowels',
18
- totalCount: getTotalRemainingTilesCount(vowels),
19
- });
20
-
21
- groups.push({
22
- remainingCount: getRemainingTilesCount(consonants),
23
- tiles: consonants,
24
- translationKey: 'common.consonants',
25
- totalCount: getTotalRemainingTilesCount(consonants),
26
- });
27
- } else {
28
- const tiles = remainingTiles.filter(isLetter);
29
-
30
- groups.push({
31
- remainingCount: getRemainingTilesCount(tiles),
32
- tiles,
33
- translationKey: 'common.tiles',
34
- totalCount: getTotalRemainingTilesCount(tiles),
35
- });
36
- }
14
+ groups.push({
15
+ remainingCount: getRemainingTilesCount(vowels),
16
+ tiles: vowels,
17
+ translationKey: 'common.vowels',
18
+ totalCount: getTotalRemainingTilesCount(vowels),
19
+ });
20
+
21
+ groups.push({
22
+ remainingCount: getRemainingTilesCount(consonants),
23
+ tiles: consonants,
24
+ translationKey: 'common.consonants',
25
+ totalCount: getTotalRemainingTilesCount(consonants),
26
+ });
27
+
28
+ groups.push({
29
+ remainingCount: getRemainingTilesCount(other),
30
+ tiles: other,
31
+ translationKey: 'common.tiles',
32
+ totalCount: getTotalRemainingTilesCount(other),
33
+ });
37
34
 
38
35
  const twoCharacterTiles = remainingTiles.filter(isTwoCharacter);
39
36
  const blanks = remainingTiles.filter(isBlank);
@@ -59,10 +56,11 @@ const isConsonant = (tile: RemainingTile): boolean => CONSONANTS.includes(tile.c
59
56
 
60
57
  const isVowel = (tile: RemainingTile): boolean => VOWELS.includes(tile.character);
61
58
 
62
- const isLetter = (tile: RemainingTile): boolean => !isBlank(tile) && !isTwoCharacter(tile);
63
-
64
59
  const isTwoCharacter = (tile: RemainingTile): boolean => tile.character.length === 2;
65
60
 
66
61
  const isBlank = (tile: RemainingTile): boolean => tile.character === BLANK;
67
62
 
63
+ const isOther = (tile: RemainingTile) =>
64
+ !isConsonant(tile) && !isVowel(tile) && !isBlank(tile) && !isTwoCharacter(tile);
65
+
68
66
  export default getRemainingTilesGroups;
@@ -43,80 +43,6 @@
43
43
  }
44
44
  }
45
45
 
46
- .contentWrapper {
47
- $board-size: 15;
48
- $tile-size-max: 60px;
49
- $tile-border-size: 1px;
50
-
51
- flex: 1;
52
- padding: 0 var(--spacing--xl);
53
- max-height: $board-size * ($tile-size-max + $tile-border-size) + $tile-border-size;
54
- }
55
-
56
- .content {
57
- display: flex;
58
- align-items: center;
59
- justify-content: center;
60
- height: 100%;
61
- gap: var(--spacing--xl);
62
-
63
- @include tablet {
64
- gap: var(--spacing--l);
65
- }
66
- }
67
-
68
- .boardContainer {
69
- display: flex;
70
- position: relative;
71
- }
72
-
73
- .sidebar {
74
- display: flex;
75
- flex-direction: column;
76
- flex: 0 0 var(--sidebar--width);
77
- gap: var(--spacing--xl);
78
-
79
- @include tablet {
80
- gap: var(--spacing--l);
81
- }
82
- }
83
-
84
- .dictionary {
85
- display: flex;
86
- flex-direction: column;
87
- }
88
-
89
- .dictionaryOutput {
90
- flex: 1;
91
- border-bottom: var(--border);
92
- }
93
-
94
- .dictionaryInput {
95
- flex: 0 0 auto;
96
- }
97
-
98
- .resultsContainer {
46
+ .solver {
99
47
  flex: 1;
100
- position: relative;
101
- }
102
-
103
- .rackContainer {
104
- position: relative;
105
- z-index: 1;
106
- flex: 0 0 auto;
107
- display: flex;
108
- justify-content: center;
109
- margin: var(--spacing--xl) var(--spacing--l);
110
-
111
- @include tablet {
112
- margin: var(--spacing--l);
113
- }
114
- }
115
-
116
- .rack {
117
- border: var(--border);
118
- }
119
-
120
- .submitInput {
121
- display: none;
122
48
  }
@@ -1,33 +1,17 @@
1
1
  import classNames from 'classnames';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
- import { AnimationEvent, FormEvent, FunctionComponent, useEffect, useState } from 'react';
4
+ import { AnimationEvent, FunctionComponent, useEffect, useState } from 'react';
5
5
  import Modal from 'react-modal';
6
6
  import { useDispatch } from 'react-redux';
7
- import { useEffectOnce, useMeasure } from 'react-use';
8
-
9
- import {
10
- Board,
11
- Dictionary,
12
- DictionaryInput,
13
- KeyMap,
14
- Logo,
15
- NavButtons,
16
- Rack,
17
- RemainingTiles,
18
- Results,
19
- Settings,
20
- Splash,
21
- SvgFontFix,
22
- Well,
23
- Words,
24
- } from 'components';
25
- import { useDirection, useIsTablet, useLanguage, useLocalStorage } from 'hooks';
7
+ import { useEffectOnce } from 'react-use';
8
+
9
+ import { KeyMap, Logo, NavButtons, RemainingTiles, Settings, Solver, Splash, SvgFontFix, Words } from 'components';
10
+ import { useDirection, useLanguage, useLocalStorage } from 'hooks';
26
11
  import { LOCALE_FEATURES } from 'i18n';
27
- import { getCellSize } from 'lib';
28
- import { COMPONENTS_SPACING, COMPONENTS_SPACING_MOBILE, DICTIONARY_HEIGHT } from 'parameters';
12
+ import { INITIALIZATION_DURATION } from 'parameters';
29
13
  import { registerServiceWorker } from 'serviceWorkerManager';
30
- import { initialize, localStorage, reset, selectConfig, selectLocale, solveSlice, useTypedSelector } from 'state';
14
+ import { initialize, localStorage, reset, selectLocale, useTypedSelector } from 'state';
31
15
 
32
16
  import styles from './index.module.scss';
33
17
 
@@ -40,30 +24,16 @@ interface Props {
40
24
  const Index: FunctionComponent<Props> = ({ version }) => {
41
25
  const dispatch = useDispatch();
42
26
  const locale = useTypedSelector(selectLocale);
43
- const isTablet = useIsTablet();
44
27
  const [showKeyMap, setShowKeyMap] = useState(false);
45
28
  const [showRemainingTiles, setShowRemainingTiles] = useState(false);
46
29
  const [showSettings, setShowSettings] = useState(false);
47
30
  const [showWords, setShowWords] = useState(false);
48
- const [boardRef, { height: boardHeight }] = useMeasure<HTMLDivElement>();
49
- const [contentRef, { height: contentHeight, width: contentWidth }] = useMeasure<HTMLDivElement>();
50
- const [resultsContainerRef, { height: resultsContainerHeight, width: resultsContainerWidth }] =
51
- useMeasure<HTMLDivElement>();
52
- const config = useTypedSelector(selectConfig);
53
- const cellSize = getCellSize(config, contentWidth - resultsContainerWidth, contentHeight);
54
- const isInitializedInitial = contentWidth > 0 && boardHeight > 0 && resultsContainerWidth > 0;
55
- const [isInitialized, setIsInitialized] = useState(isInitializedInitial);
56
- const resultsHeight = boardHeight - DICTIONARY_HEIGHT - (isTablet ? COMPONENTS_SPACING_MOBILE : COMPONENTS_SPACING);
31
+ const [isInitialized, setIsInitialized] = useState(false);
57
32
 
58
33
  const handleClear = () => {
59
34
  dispatch(reset());
60
35
  };
61
36
 
62
- const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
63
- event.preventDefault();
64
- dispatch(solveSlice.actions.submit());
65
- };
66
-
67
37
  const handleSplashAnimationEnd = (event: AnimationEvent<HTMLDivElement>) => {
68
38
  if (event.target === event.currentTarget && !localStorage.getHasVisited()) {
69
39
  setShowSettings(true);
@@ -71,8 +41,7 @@ const Index: FunctionComponent<Props> = ({ version }) => {
71
41
  }
72
42
  };
73
43
 
74
- const { direction } = LOCALE_FEATURES[locale];
75
- useDirection(direction);
44
+ useDirection(LOCALE_FEATURES[locale].direction);
76
45
  useLanguage(locale);
77
46
  useLocalStorage();
78
47
 
@@ -81,7 +50,7 @@ const Index: FunctionComponent<Props> = ({ version }) => {
81
50
 
82
51
  setTimeout(() => {
83
52
  setIsInitialized(true);
84
- }, 100);
53
+ }, INITIALIZATION_DURATION);
85
54
  });
86
55
 
87
56
  useEffect(() => {
@@ -111,44 +80,13 @@ const Index: FunctionComponent<Props> = ({ version }) => {
111
80
  />
112
81
  </div>
113
82
 
114
- <div className={styles.contentWrapper}>
115
- <div className={styles.content} ref={contentRef}>
116
- <form className={styles.boardContainer} onSubmit={handleSubmit}>
117
- {contentWidth > 0 && <Board cellSize={cellSize} innerRef={boardRef} />}
118
- <input className={styles.submitInput} tabIndex={-1} type="submit" />
119
- </form>
120
-
121
- <div className={styles.sidebar} style={{ height: boardHeight + 1 }}>
122
- <Well className={styles.resultsContainer} ref={resultsContainerRef}>
123
- {resultsContainerWidth > 0 && resultsContainerHeight > 0 && (
124
- <Results height={resultsHeight} width={resultsContainerWidth} />
125
- )}
126
- </Well>
127
-
128
- <Well>
129
- <div className={styles.dictionary} style={{ height: DICTIONARY_HEIGHT }}>
130
- <Dictionary className={styles.dictionaryOutput} />
131
- <DictionaryInput className={styles.dictionaryInput} />
132
- </div>
133
- </Well>
134
- </div>
135
- </div>
136
- </div>
137
-
138
- <form className={styles.rackContainer} onSubmit={handleSubmit}>
139
- <Rack className={styles.rack} />
140
- <input className={styles.submitInput} tabIndex={-1} type="submit" />
141
- </form>
83
+ <Solver className={styles.solver} />
142
84
  </div>
143
85
 
144
86
  <Settings isOpen={showSettings} onClose={() => setShowSettings(false)} />
145
-
146
87
  <KeyMap isOpen={showKeyMap} onClose={() => setShowKeyMap(false)} />
147
-
148
88
  <Words isOpen={showWords} onClose={() => setShowWords(false)} />
149
-
150
89
  <RemainingTiles isOpen={showRemainingTiles} onClose={() => setShowRemainingTiles(false)} />
151
-
152
90
  <Splash forceShow={!isInitialized} onAnimationEnd={handleSplashAnimationEnd} />
153
91
  </>
154
92
  );