@scrabble-solver/scrabble-solver 2.12.2 → 2.12.3

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 (85) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +6 -6
  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/131.js +478 -106
  16. package/.next/server/chunks/277.js +1132 -976
  17. package/.next/server/chunks/44.js +36 -6
  18. package/.next/server/chunks/865.js +478 -106
  19. package/.next/server/chunks/911.js +894 -773
  20. package/.next/server/middleware-build-manifest.js +1 -1
  21. package/.next/server/pages/404.html +1 -1
  22. package/.next/server/pages/404.js.nft.json +1 -1
  23. package/.next/server/pages/500.html +1 -1
  24. package/.next/server/pages/_app.js +3 -1
  25. package/.next/server/pages/_app.js.nft.json +1 -1
  26. package/.next/server/pages/api/dictionary/[locale]/[word].js +4 -2
  27. package/.next/server/pages/api/solve.js +23 -19
  28. package/.next/server/pages/api/verify.js +8 -5
  29. package/.next/server/pages/index.html +1 -1
  30. package/.next/server/pages/index.js +42 -55
  31. package/.next/server/pages/index.js.nft.json +1 -1
  32. package/.next/server/pages/index.json +1 -1
  33. package/.next/server/pages-manifest.json +1 -1
  34. package/.next/static/chunks/pages/_app-e7f3d1c9c09c8f91.js +32 -0
  35. package/.next/static/chunks/pages/index-82b2939158c7729f.js +1 -0
  36. package/.next/static/css/4e8b47fe382a8a8f.css +2 -0
  37. package/.next/static/css/cfae5256f1689f57.css +1 -0
  38. package/.next/static/{9dmPfnTc_AQTHBPvL7xQe → wNIKOJJzkMSJYb2nOL21o}/_buildManifest.js +1 -1
  39. package/.next/trace +51 -52
  40. package/package.json +9 -9
  41. package/src/components/Board/components/Cell/Cell.module.scss +4 -12
  42. package/src/components/Board/components/Cell/Cell.tsx +4 -0
  43. package/src/components/Board/hooks/useBackgroundImage.tsx +23 -0
  44. package/src/components/PlainTiles/lib/createPlainTile.ts +4 -4
  45. package/src/components/Radio/Radio.module.scss +4 -0
  46. package/src/components/Radio/Radio.tsx +1 -0
  47. package/src/components/SeoMessage/SeoMessage.tsx +3 -3
  48. package/src/hooks/useAppLayout.ts +1 -2
  49. package/src/hooks/useLocalStorage.ts +5 -5
  50. package/src/i18n/constants.ts +31 -61
  51. package/src/lib/extractCharacters.test.ts +3 -3
  52. package/src/lib/extractCharactersByCase.test.ts +3 -3
  53. package/src/lib/getCellSize.ts +2 -2
  54. package/src/modals/MenuModal/MenuModal.module.scss +0 -1
  55. package/src/modals/MenuModal/MenuModal.tsx +3 -3
  56. package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +16 -7
  57. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +1 -4
  58. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +8 -8
  59. package/src/pages/_app.tsx +3 -1
  60. package/src/pages/api/dictionary/[locale]/[word].ts +6 -3
  61. package/src/pages/api/solve.ts +11 -7
  62. package/src/pages/api/verify.ts +11 -7
  63. package/src/pages/index.module.scss +0 -1
  64. package/src/parameters/index.ts +4 -6
  65. package/src/sdk/solve.ts +3 -3
  66. package/src/sdk/verify.ts +3 -3
  67. package/src/service-worker/routeSolveRequests.ts +3 -3
  68. package/src/state/localStorage.ts +6 -6
  69. package/src/state/sagas.ts +18 -7
  70. package/src/state/selectors.ts +3 -3
  71. package/src/state/slices/boardInitialState.ts +3 -3
  72. package/src/state/slices/boardSlice.ts +20 -6
  73. package/src/state/slices/settingsInitialState.ts +3 -4
  74. package/src/state/slices/settingsSlice.ts +5 -5
  75. package/src/styles/variables.scss +0 -9
  76. package/.next/static/chunks/pages/_app-02851b06b95b19cb.js +0 -32
  77. package/.next/static/chunks/pages/index-0ba5607d1aad8a09.js +0 -1
  78. package/.next/static/css/09dfdea53eba31a9.css +0 -2
  79. package/.next/static/css/60e8258da7362a1a.css +0 -1
  80. package/src/i18n/i18n.module.scss +0 -27
  81. package/src/modals/SettingsModal/components/ConfigSetting/options.ts +0 -19
  82. package/src/modals/SettingsModal/components/ConfigSetting/types.ts +0 -9
  83. package/src/modals/SettingsModal/components/InputModeSetting/types.ts +0 -7
  84. package/src/modals/SettingsModal/components/LocaleSetting/types.ts +0 -9
  85. /package/.next/static/{9dmPfnTc_AQTHBPvL7xQe → wNIKOJJzkMSJYb2nOL21o}/_ssgManifest.js +0 -0
@@ -1,9 +1,9 @@
1
- import { getLocaleConfig, isConfigId } from '@scrabble-solver/configs';
1
+ import { getConfig, hasConfig } from '@scrabble-solver/configs';
2
2
  import { BLANK } from '@scrabble-solver/constants';
3
3
  import { dictionaries } from '@scrabble-solver/dictionaries';
4
4
  import logger from '@scrabble-solver/logger';
5
5
  import { solve as solveScrabble } from '@scrabble-solver/solver';
6
- import { Board, Config, isBoardJson, isLocale, Locale, Tile } from '@scrabble-solver/types';
6
+ import { Board, Config, Locale, Tile, isBoardJson, isGame, isLocale } from '@scrabble-solver/types';
7
7
  import { NextApiRequest, NextApiResponse } from 'next';
8
8
 
9
9
  import { getServerLoggingData, isBoardValid, isCharacterValid } from 'api';
@@ -29,7 +29,7 @@ const solve = async (request: NextApiRequest, response: NextApiResponse): Promis
29
29
  boardBlanksCount: board.getBlanksCount(),
30
30
  boardTilesCount: board.getTilesCount(),
31
31
  characters: characters.join(''),
32
- configId: request.body.configId,
32
+ game: request.body.game,
33
33
  locale,
34
34
  },
35
35
  });
@@ -46,21 +46,25 @@ const solve = async (request: NextApiRequest, response: NextApiResponse): Promis
46
46
  };
47
47
 
48
48
  const parseRequest = (request: NextApiRequest): RequestData => {
49
- const { board: boardJson, characters, configId, locale } = request.body;
49
+ const { board: boardJson, characters, game, locale } = request.body;
50
50
 
51
51
  if (!isLocale(locale)) {
52
52
  throw new Error('Invalid "locale" parameter');
53
53
  }
54
54
 
55
- if (!isConfigId(configId)) {
56
- throw new Error('Invalid "configId" parameter');
55
+ if (!isGame(game)) {
56
+ throw new Error('Invalid "game" parameter');
57
57
  }
58
58
 
59
59
  if (!isStringArray(characters) || characters.length === 0) {
60
60
  throw new Error('Invalid "characters" parameter');
61
61
  }
62
62
 
63
- const config = getLocaleConfig(configId, locale);
63
+ if (!hasConfig(game, locale)) {
64
+ throw new Error(`No game "${game}" in "${locale}"`);
65
+ }
66
+
67
+ const config = getConfig(game, locale);
64
68
 
65
69
  for (const character of characters) {
66
70
  if (!isCharacterValid(character)) {
@@ -1,7 +1,7 @@
1
- import { getLocaleConfig, isConfigId } from '@scrabble-solver/configs';
1
+ import { getConfig, hasConfig } from '@scrabble-solver/configs';
2
2
  import { dictionaries } from '@scrabble-solver/dictionaries';
3
3
  import logger from '@scrabble-solver/logger';
4
- import { Board, Config, isBoardJson, isLocale, Locale } from '@scrabble-solver/types';
4
+ import { Board, Config, Locale, isBoardJson, isGame, isLocale } from '@scrabble-solver/types';
5
5
  import { NextApiRequest, NextApiResponse } from 'next';
6
6
 
7
7
  import { getServerLoggingData, isBoardValid } from 'api';
@@ -24,7 +24,7 @@ const verify = async (request: NextApiRequest, response: NextApiResponse): Promi
24
24
  board: board.toString(),
25
25
  boardBlanksCount: board.getBlanksCount(),
26
26
  boardTilesCount: board.getTilesCount(),
27
- configId: request.body.configId,
27
+ game: request.body.game,
28
28
  locale,
29
29
  },
30
30
  });
@@ -42,17 +42,21 @@ const verify = async (request: NextApiRequest, response: NextApiResponse): Promi
42
42
  };
43
43
 
44
44
  const parseRequest = (request: NextApiRequest): RequestData => {
45
- const { board: boardJson, configId, locale } = request.body;
45
+ const { board: boardJson, game, locale } = request.body;
46
46
 
47
47
  if (!isLocale(locale)) {
48
48
  throw new Error('Invalid "locale" parameter');
49
49
  }
50
50
 
51
- if (!isConfigId(configId)) {
52
- throw new Error('Invalid "configId" parameter');
51
+ if (!isGame(game)) {
52
+ throw new Error('Invalid "game" parameter');
53
53
  }
54
54
 
55
- const config = getLocaleConfig(configId, locale);
55
+ if (!hasConfig(game, locale)) {
56
+ throw new Error(`No game "${game}" in "${locale}"`);
57
+ }
58
+
59
+ const config = getConfig(game, locale);
56
60
 
57
61
  if (!isBoardJson(boardJson) || !isBoardValid(boardJson, config)) {
58
62
  throw new Error('Invalid "board" parameter');
@@ -21,7 +21,6 @@
21
21
  }
22
22
 
23
23
  .logo {
24
- width: calc(var(--logo--aspect-ratio) * var(--logo--height));
25
24
  height: var(--logo--height);
26
25
  user-select: none;
27
26
  }
@@ -25,9 +25,11 @@ export const COLOR_BONUS_CHARACTER_3 = '#dde4f6';
25
25
  export const COLOR_BONUS_CHARACTER_5 = '#fbe0d4';
26
26
  export const COLOR_BONUS_CHARACTER_MULTIPLIER_2 = '#b8d5ed';
27
27
  export const COLOR_BONUS_CHARACTER_MULTIPLIER_3 = '#86aed1';
28
+ export const COLOR_BONUS_CHARACTER_MULTIPLIER_4 = '#3477b2';
28
29
  export const COLOR_BONUS_START = '#b284b8';
29
30
  export const COLOR_BONUS_WORD_MULTIPLIER_2 = '#fbc997';
30
31
  export const COLOR_BONUS_WORD_MULTIPLIER_3 = '#f19393';
32
+ export const COLOR_BONUS_WORD_MULTIPLIER_4 = '#ed5e5e';
31
33
  export const COLOR_FILTERED = '#444';
32
34
 
33
35
  export const COLOR_BONUS_CHARACTER: Record<number, string> = {
@@ -40,11 +42,13 @@ export const COLOR_BONUS_CHARACTER: Record<number, string> = {
40
42
  export const COLOR_BONUS_CHARACTER_MULTIPLIER: Record<number, string> = {
41
43
  2: COLOR_BONUS_CHARACTER_MULTIPLIER_2,
42
44
  3: COLOR_BONUS_CHARACTER_MULTIPLIER_3,
45
+ 4: COLOR_BONUS_CHARACTER_MULTIPLIER_4,
43
46
  };
44
47
 
45
48
  export const COLOR_BONUS_WORD: Record<number, string> = {
46
49
  2: COLOR_BONUS_WORD_MULTIPLIER_2,
47
50
  3: COLOR_BONUS_WORD_MULTIPLIER_3,
51
+ 4: COLOR_BONUS_WORD_MULTIPLIER_4,
48
52
  };
49
53
 
50
54
  export const SPACING_XS = 2;
@@ -61,12 +65,6 @@ export const BOARD_CELL_BORDER_WIDTH = 1;
61
65
  export const BOARD_TILE_FONT_SIZE_MIN = 14;
62
66
  export const BOARD_TILE_FONT_SIZE_POINTS_MIN = 10;
63
67
  export const BOARD_TILE_SIZE_MAX = 64;
64
- /**
65
- * 20 - fits all board tiles without horizontal scrollbar on 360px viewport width (font-size: 14px)
66
- * 21 - fits all board tiles without horizontal scrollbar on 375px viewport width (font-size: 14px)
67
- * 26 - tiles start to look good (font-size: 16px)
68
- */
69
- export const BOARD_TILE_SIZE_MIN = 20;
70
68
 
71
69
  export const BORDER_COLOR = '#cdcdcd';
72
70
  export const BORDER_COLOR_LIGHT = '#d9d9d9';
package/src/sdk/solve.ts CHANGED
@@ -5,14 +5,14 @@ import fetchJson from './fetchJson';
5
5
  interface Payload {
6
6
  board: BoardJson;
7
7
  characters: string[];
8
- configId: string;
8
+ game: string;
9
9
  locale: Locale;
10
10
  }
11
11
 
12
- const solve = async ({ board, characters, configId, locale }: Payload): Promise<Result[]> => {
12
+ const solve = async ({ board, characters, game, locale }: Payload): Promise<Result[]> => {
13
13
  const json = await fetchJson<ResultJson[]>('/api/solve', {
14
14
  method: 'POST',
15
- body: JSON.stringify({ board, characters, configId, locale }),
15
+ body: JSON.stringify({ board, characters, game, locale }),
16
16
  });
17
17
 
18
18
  return json.map(Result.fromJson);
package/src/sdk/verify.ts CHANGED
@@ -4,7 +4,7 @@ import fetchJson from './fetchJson';
4
4
 
5
5
  interface Payload {
6
6
  board: BoardJson;
7
- configId: string;
7
+ game: string;
8
8
  locale: Locale;
9
9
  }
10
10
 
@@ -13,10 +13,10 @@ interface Response {
13
13
  validWords: string[];
14
14
  }
15
15
 
16
- const verify = async ({ board, configId, locale }: Payload): Promise<Response> => {
16
+ const verify = async ({ board, game, locale }: Payload): Promise<Response> => {
17
17
  return fetchJson<Response>('/api/verify', {
18
18
  method: 'POST',
19
- body: JSON.stringify({ board, configId, locale }),
19
+ body: JSON.stringify({ board, game, locale }),
20
20
  });
21
21
  };
22
22
 
@@ -2,7 +2,7 @@ import { Trie } from '@kamilmielnik/trie';
2
2
  import { getConfig } from '@scrabble-solver/configs';
3
3
  import { BLANK } from '@scrabble-solver/constants';
4
4
  import { solve } from '@scrabble-solver/solver';
5
- import { Board, Locale, Tile } from '@scrabble-solver/types';
5
+ import { Board, Tile } from '@scrabble-solver/types';
6
6
  import { registerRoute } from 'workbox-routing';
7
7
 
8
8
  import average from './average';
@@ -33,10 +33,10 @@ const routeSolveRequests = () => {
33
33
  registerRoute(
34
34
  ({ url }) => url.origin === location.origin && url.pathname === '/api/solve',
35
35
  async ({ request }) => {
36
- const { board, characters, configId, locale } = await request.clone().json();
36
+ const { board, characters, game, locale } = await request.clone().json();
37
37
 
38
38
  const solveLocal = async (trie: Trie) => {
39
- const config = getConfig(configId)[locale as Locale];
39
+ const config = getConfig(game, locale);
40
40
  const tiles = characters.map((character: string) => new Tile({ character, isBlank: character === BLANK }));
41
41
  const resultsJson = solve(trie, config, Board.fromJson(board), tiles);
42
42
  const json = JSON.stringify(resultsJson);
@@ -1,11 +1,11 @@
1
- import { Board, Locale } from '@scrabble-solver/types';
1
+ import { Board, Game, Locale } from '@scrabble-solver/types';
2
2
  import store2 from 'store2';
3
3
 
4
4
  import { AutoGroupTiles, InputMode, Rack } from 'types';
5
5
 
6
6
  const AUTO_GROUP_TILES = 'auto-group-tiles';
7
7
  const BOARD = 'board';
8
- const CONFIG_ID = 'config-id';
8
+ const GAME_ID = 'config-id';
9
9
  const INPUT_MODE = 'input-mode';
10
10
  const LOCALE = 'locale';
11
11
  const RACK = 'rack';
@@ -31,12 +31,12 @@ const localStorage = {
31
31
  store.set(BOARD, serialized, true);
32
32
  },
33
33
 
34
- getConfigId(): string | undefined {
35
- return store.get(CONFIG_ID);
34
+ getGame(): Game | undefined {
35
+ return store.get(GAME_ID);
36
36
  },
37
37
 
38
- setConfigId(configId: string | undefined): void {
39
- store.set(CONFIG_ID, configId, true);
38
+ setGame(game: Game | undefined): void {
39
+ store.set(GAME_ID, game, true);
40
40
  },
41
41
 
42
42
  getInputMode(): InputMode | undefined {
@@ -1,7 +1,8 @@
1
1
  /* eslint-disable max-lines */
2
2
 
3
3
  import { PayloadAction } from '@reduxjs/toolkit';
4
- import { Locale, Result } from '@scrabble-solver/types';
4
+ import { hasConfig, localesMap } from '@scrabble-solver/configs';
5
+ import { Board, Locale, Result } from '@scrabble-solver/types';
5
6
  import { call, delay, put, select, takeEvery, takeLatest } from 'redux-saga/effects';
6
7
 
7
8
  import { LOCALE_FEATURES } from 'i18n';
@@ -15,6 +16,7 @@ import {
15
16
  selectCharacters,
16
17
  selectConfig,
17
18
  selectDictionary,
19
+ selectGame,
18
20
  selectLocale,
19
21
  selectLocaleAutoGroupTiles,
20
22
  selectRack,
@@ -44,7 +46,7 @@ export function* rootSaga(): AnyGenerator {
44
46
  yield takeEvery([rackSlice.actions.changeCharacter.type, rackSlice.actions.changeCharacters.type], onRackValueChange);
45
47
  yield takeEvery(resultsSlice.actions.applyResult.type, onApplyResult);
46
48
  yield takeEvery(resultsSlice.actions.changeResultCandidate.type, onResultCandidateChange);
47
- yield takeEvery(settingsSlice.actions.changeConfigId.type, onConfigIdChange);
49
+ yield takeEvery(settingsSlice.actions.changeGame.type, onGameChange);
48
50
  yield takeEvery(settingsSlice.actions.changeLocale.type, onLocaleChange);
49
51
  yield takeLatest(dictionarySlice.actions.submit.type, onDictionarySubmit);
50
52
  yield takeLatest(initialize.type, onInitialize);
@@ -77,7 +79,7 @@ function* onApplyResult({ payload: result }: PayloadAction<Result>): AnyGenerato
77
79
  yield put(verifySlice.actions.submit());
78
80
  }
79
81
 
80
- function* onConfigIdChange(): AnyGenerator {
82
+ function* onGameChange(): AnyGenerator {
81
83
  const characters = yield select(selectCharacters);
82
84
 
83
85
  if (characters.length > 0) {
@@ -119,7 +121,9 @@ function* onInitialize(): AnyGenerator {
119
121
  }
120
122
 
121
123
  function* onReset(): AnyGenerator {
122
- yield put(boardSlice.actions.reset());
124
+ const config = yield select(selectConfig);
125
+
126
+ yield put(boardSlice.actions.init(Board.create(config.boardWidth, config.boardHeight)));
123
127
  yield put(cellFilterSlice.actions.reset());
124
128
  yield put(dictionarySlice.actions.reset());
125
129
  yield put(rackSlice.actions.reset());
@@ -128,7 +132,14 @@ function* onReset(): AnyGenerator {
128
132
  yield put(verifySlice.actions.submit());
129
133
  }
130
134
 
131
- function* onLocaleChange(): AnyGenerator {
135
+ function* onLocaleChange({ payload: locale }: PayloadAction<Locale>): AnyGenerator {
136
+ const game = yield select(selectGame);
137
+
138
+ if (!hasConfig(game, locale)) {
139
+ const defaultConfig = localesMap[locale][0];
140
+ yield put(settingsSlice.actions.changeGame(defaultConfig.game));
141
+ }
142
+
132
143
  const characters = yield select(selectCharacters);
133
144
 
134
145
  if (characters.length > 0) {
@@ -166,7 +177,7 @@ function* onSolve(): AnyGenerator {
166
177
  const results = yield call(solve, {
167
178
  board: board.toJson(),
168
179
  characters,
169
- configId: config.id,
180
+ game: config.game,
170
181
  locale,
171
182
  });
172
183
  yield put(resultsSlice.actions.changeResults(results));
@@ -187,7 +198,7 @@ function* onVerify(): AnyGenerator {
187
198
  try {
188
199
  const { invalidWords, validWords } = yield call(verify, {
189
200
  board: board.toJson(),
190
- configId: config.id,
201
+ game: config.game,
191
202
  locale,
192
203
  });
193
204
  yield put(verifySlice.actions.submitSuccess({ board, invalidWords, validWords }));
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable max-lines */
2
2
 
3
3
  import { createSelector } from '@reduxjs/toolkit';
4
- import { getLocaleConfig } from '@scrabble-solver/configs';
4
+ import { getConfig } from '@scrabble-solver/configs';
5
5
  import { BLANK } from '@scrabble-solver/constants';
6
6
  import { Cell, Config, isError, Tile } from '@scrabble-solver/types';
7
7
 
@@ -67,9 +67,9 @@ export const selectBoard = selectBoardRoot;
67
67
 
68
68
  export const selectInputMode = createSelector([selectSettingsRoot], (settings) => settings.inputMode);
69
69
 
70
- export const selectConfigId = createSelector([selectSettingsRoot], (settings) => settings.configId);
70
+ export const selectGame = createSelector([selectSettingsRoot], (settings) => settings.game);
71
71
 
72
- export const selectConfig = createSelector([selectConfigId, selectLocale], getLocaleConfig);
72
+ export const selectConfig = createSelector([selectGame, selectLocale], getConfig);
73
73
 
74
74
  export const selectFilteredCells = selectCellFilterRoot;
75
75
 
@@ -1,4 +1,4 @@
1
- import { getLocaleConfig } from '@scrabble-solver/configs';
1
+ import { getConfig } from '@scrabble-solver/configs';
2
2
  import { Board } from '@scrabble-solver/types';
3
3
 
4
4
  import localStorage from '../localStorage';
@@ -7,8 +7,8 @@ import settingsInitialState from './settingsInitialState';
7
7
 
8
8
  export type BoardState = Board;
9
9
 
10
- const { configId, locale } = settingsInitialState;
11
- const { boardHeight, boardWidth } = getLocaleConfig(configId, locale);
10
+ const { game, locale } = settingsInitialState;
11
+ const { boardHeight, boardWidth } = getConfig(game, locale);
12
12
  export const boardDefaultState = Board.create(boardWidth, boardHeight);
13
13
 
14
14
  const boardInitialState: BoardState = localStorage.getBoard() || boardDefaultState;
@@ -1,8 +1,10 @@
1
1
  import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2
+ import { games } from '@scrabble-solver/configs';
2
3
  import { EMPTY_CELL } from '@scrabble-solver/constants';
3
- import { Board, Cell, Result, Tile } from '@scrabble-solver/types';
4
+ import { Board, Cell, Game, Result, Tile } from '@scrabble-solver/types';
4
5
 
5
- import boardInitialState, { boardDefaultState } from './boardInitialState';
6
+ import boardInitialState from './boardInitialState';
7
+ import settingsSlice from './settingsSlice';
6
8
 
7
9
  const boardSlice = createSlice({
8
10
  initialState: boardInitialState,
@@ -42,10 +44,6 @@ const boardSlice = createSlice({
42
44
  return board;
43
45
  },
44
46
 
45
- reset: () => {
46
- return boardDefaultState;
47
- },
48
-
49
47
  toggleCellIsBlank: (state, action: PayloadAction<{ x: number; y: number }>) => {
50
48
  const newBoard = state.clone();
51
49
  const { x, y } = action.payload;
@@ -58,6 +56,22 @@ const boardSlice = createSlice({
58
56
  return newBoard;
59
57
  },
60
58
  },
59
+ extraReducers: {
60
+ [settingsSlice.actions.changeGame.type]: (state, action: PayloadAction<Game>) => {
61
+ const game = action.payload;
62
+ const config = Object.values(games).find((gameConfig) => gameConfig.game === game);
63
+
64
+ if (!config) {
65
+ throw new Error(`Cannot find config for game "${game}"`);
66
+ }
67
+
68
+ if (state.rows.length !== config.boardHeight || state.rows[0].length !== config.boardWidth) {
69
+ return Board.create(config.boardWidth, config.boardHeight);
70
+ }
71
+
72
+ return state;
73
+ },
74
+ },
61
75
  });
62
76
 
63
77
  export default boardSlice;
@@ -1,5 +1,4 @@
1
- import { literaki, scrabble } from '@scrabble-solver/configs';
2
- import { Locale } from '@scrabble-solver/types';
1
+ import { Game, Locale } from '@scrabble-solver/types';
3
2
 
4
3
  import { guessLocale } from 'lib';
5
4
  import { AutoGroupTiles, InputMode } from 'types';
@@ -8,7 +7,7 @@ import localStorage from '../localStorage';
8
7
 
9
8
  export interface SettingsState {
10
9
  autoGroupTiles: AutoGroupTiles;
11
- configId: typeof literaki.id | typeof scrabble.id;
10
+ game: Game;
12
11
  inputMode: InputMode;
13
12
  locale: Locale;
14
13
  }
@@ -18,7 +17,7 @@ const isTouchScreen = typeof globalThis.matchMedia !== 'undefined' && globalThis
18
17
 
19
18
  const settingsInitialState: SettingsState = {
20
19
  autoGroupTiles: typeof localStorageAutoGroupTiles === 'undefined' ? 'left' : localStorageAutoGroupTiles,
21
- configId: localStorage.getConfigId() || scrabble.id,
20
+ game: localStorage.getGame() || Game.Scrabble,
22
21
  inputMode: localStorage.getInputMode() || (isTouchScreen ? 'touchscreen' : 'keyboard'),
23
22
  locale: localStorage.getLocale() || guessLocale(),
24
23
  };
@@ -1,5 +1,5 @@
1
1
  import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2
- import { Locale } from '@scrabble-solver/types';
2
+ import { Game, Locale } from '@scrabble-solver/types';
3
3
 
4
4
  import { AutoGroupTiles, InputMode } from 'types';
5
5
 
@@ -14,9 +14,9 @@ const settingsSlice = createSlice({
14
14
  return { ...state, autoGroupTiles };
15
15
  },
16
16
 
17
- changeConfigId: (state, action: PayloadAction<string>) => {
18
- const configId = action.payload;
19
- return { ...state, configId };
17
+ changeGame: (state, action: PayloadAction<Game>) => {
18
+ const game = action.payload;
19
+ return { ...state, game };
20
20
  },
21
21
 
22
22
  changeInputMode: (state, action: PayloadAction<InputMode>) => {
@@ -29,7 +29,7 @@ const settingsSlice = createSlice({
29
29
  return { ...state, locale };
30
30
  },
31
31
 
32
- init: (state, action: PayloadAction<Partial<Pick<typeof settingsInitialState, 'configId' | 'locale'>>>) => {
32
+ init: (state, action: PayloadAction<Partial<Pick<typeof settingsInitialState, 'game' | 'locale'>>>) => {
33
33
  return { ...state, ...action.payload };
34
34
  },
35
35
  },
@@ -97,20 +97,11 @@ $easeOutSine: cubic-bezier(0.61, 1, 0.88, 1);
97
97
  --z-index--close-button: 101;
98
98
  --z-index--tooltip: 102;
99
99
 
100
- --flag--de--aspect-ratio: 20 / 12;
101
- --flag--es--aspect-ratio: 750 / 500;
102
- --flag--fa--aspect-ratio: 630 / 360;
103
- --flag--fr--aspect-ratio: 24 / 15;
104
- --flag--gb--aspect-ratio: 60 / 30;
105
- --flag--pl--aspect-ratio: 16 / 10;
106
- --flag--us--aspect-ratio: 7410 / 3900;
107
-
108
100
  --button--icon--size: 24px;
109
101
  --dictionary--height: 260px;
110
102
  --dictionary--height--mobile: 110px;
111
103
  --key--height: 36px;
112
104
  --key--icon--size: 16px;
113
- --logo--aspect-ratio: 682 / 166;
114
105
  --logo--height: 60px;
115
106
  --modal--width: 370px;
116
107
  --nav--height: calc(var(--logo--height) + var(--nav--padding));