@scrabble-solver/scrabble-solver 2.11.2 → 2.11.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 (87) 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/210.js +109 -0
  16. package/.next/server/chunks/277.js +187 -95
  17. package/.next/server/chunks/44.js +47 -0
  18. package/.next/server/chunks/987.js +91 -0
  19. package/.next/server/middleware-build-manifest.js +1 -1
  20. package/.next/server/pages/404.html +2 -2
  21. package/.next/server/pages/404.js.nft.json +1 -1
  22. package/.next/server/pages/500.html +1 -1
  23. package/.next/server/pages/_app.js +1 -73
  24. package/.next/server/pages/_app.js.nft.json +1 -1
  25. package/.next/server/pages/_document.js.nft.json +1 -1
  26. package/.next/server/pages/api/dictionary/[locale]/[word].js +3 -3
  27. package/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  28. package/.next/server/pages/api/dictionary/[locale].js +3 -3
  29. package/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  30. package/.next/server/pages/api/solve.js +10 -6
  31. package/.next/server/pages/api/solve.js.nft.json +1 -1
  32. package/.next/server/pages/api/verify.js +5 -4
  33. package/.next/server/pages/api/verify.js.nft.json +1 -1
  34. package/.next/server/pages/api/visit.js +3 -3
  35. package/.next/server/pages/api/visit.js.nft.json +1 -1
  36. package/.next/server/pages/index.html +1 -1
  37. package/.next/server/pages/index.js +104 -207
  38. package/.next/server/pages/index.js.nft.json +1 -1
  39. package/.next/server/pages/index.json +1 -1
  40. package/.next/static/{Mdvi3FY0PqkILKLbPlVBU → USLkKOoHbITebIEHkMGX_}/_buildManifest.js +1 -1
  41. package/.next/static/chunks/pages/_app-21c83ddb81fc09d0.js +28 -0
  42. package/.next/static/chunks/pages/index-0858deea02b2a417.js +1 -0
  43. package/.next/static/css/885da289cec275b3.css +1 -0
  44. package/.next/static/css/ea1c8134fe9a143e.css +2 -0
  45. package/.next/trace +53 -54
  46. package/package.json +9 -9
  47. package/src/api/index.ts +1 -0
  48. package/src/api/isCellValid.ts +3 -2
  49. package/src/api/isCharacterValid.ts +13 -0
  50. package/src/components/Button/Button.module.scss +14 -1
  51. package/src/components/Modal/Modal.module.scss +11 -3
  52. package/src/components/NotFound/NotFound.module.scss +13 -4
  53. package/src/components/NotFound/NotFound.tsx +4 -7
  54. package/src/components/Rack/Rack.tsx +3 -1
  55. package/src/components/Tile/Tile.module.scss +23 -18
  56. package/src/components/Tile/Tile.tsx +2 -5
  57. package/src/components/Tile/TilePure.tsx +1 -2
  58. package/src/i18n/constants.ts +65 -0
  59. package/src/i18n/de.json +1 -0
  60. package/src/i18n/en.json +1 -0
  61. package/src/i18n/es.json +1 -0
  62. package/src/i18n/fa.json +1 -0
  63. package/src/i18n/fr.json +1 -0
  64. package/src/i18n/i18n.module.scss +27 -0
  65. package/src/i18n/pl.json +1 -0
  66. package/src/icons/DashCircleFill.svg +1 -0
  67. package/src/icons/EyeFill.svg +5 -0
  68. package/src/icons/index.ts +3 -2
  69. package/src/modals/MenuModal/MenuModal.module.scss +17 -1
  70. package/src/modals/MenuModal/MenuModal.tsx +8 -2
  71. package/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +4 -1
  72. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss +8 -0
  73. package/src/modals/ResultsModal/ResultsModal.tsx +35 -11
  74. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +3 -44
  75. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +4 -2
  76. package/src/pages/api/solve.ts +3 -2
  77. package/src/styles/mixins.scss +2 -0
  78. package/src/styles/variables.scss +12 -0
  79. package/src/types/index.ts +1 -0
  80. package/.next/server/chunks/417.js +0 -221
  81. package/.next/server/chunks/664.js +0 -621
  82. package/.next/static/chunks/pages/_app-495e6f4ccc278bb2.js +0 -28
  83. package/.next/static/chunks/pages/index-5ecc51900ca29685.js +0 -1
  84. package/.next/static/css/17b0a2db8742105f.css +0 -1
  85. package/.next/static/css/e1ffeb2558330c55.css +0 -2
  86. package/src/modals/SettingsModal/components/LocaleSetting/options.ts +0 -68
  87. /package/.next/static/{Mdvi3FY0PqkILKLbPlVBU → USLkKOoHbITebIEHkMGX_}/_ssgManifest.js +0 -0
@@ -3,7 +3,7 @@ import { FunctionComponent, useMemo } from 'react';
3
3
  import { useDispatch } from 'react-redux';
4
4
 
5
5
  import { Button, Dictionary, Modal, Results } from 'components';
6
- import { Check } from 'icons';
6
+ import { Check, EyeFill } from 'icons';
7
7
  import { resultsSlice, selectResultCandidate, selectResults, useTranslate, useTypedSelector } from 'state';
8
8
 
9
9
  import styles from './ResultsModal.module.scss';
@@ -37,20 +37,44 @@ const ResultsModal: FunctionComponent<Props> = ({ className, isOpen, onClose })
37
37
  [dispatch, onClose, resultCandidate],
38
38
  );
39
39
 
40
+ const handleInsert = () => {
41
+ if (resultCandidate) {
42
+ dispatch(resultsSlice.actions.applyResult(resultCandidate));
43
+ }
44
+
45
+ onClose();
46
+ };
47
+
48
+ const handlePreview = () => {
49
+ onClose();
50
+ };
51
+
40
52
  return (
41
53
  <Modal
42
54
  className={className}
43
55
  footer={
44
- <Button
45
- aria-label={translate('results.insert')}
46
- disabled={!resultCandidate}
47
- Icon={Check}
48
- tooltip={translate('results.insert')}
49
- variant="primary"
50
- onClick={onClose}
51
- >
52
- {translate('results.insert')}
53
- </Button>
56
+ <>
57
+ <Button
58
+ aria-label={translate('results.insert')}
59
+ disabled={!resultCandidate}
60
+ Icon={Check}
61
+ tooltip={translate('results.insert')}
62
+ variant="primary"
63
+ onClick={handleInsert}
64
+ >
65
+ {translate('results.insert')}
66
+ </Button>
67
+
68
+ <Button
69
+ aria-label={translate('results.preview')}
70
+ disabled={!resultCandidate}
71
+ Icon={EyeFill}
72
+ tooltip={translate('results.preview')}
73
+ onClick={handlePreview}
74
+ >
75
+ {translate('results.preview')}
76
+ </Button>
77
+ </>
54
78
  }
55
79
  isOpen={isOpen}
56
80
  title={translate('results')}
@@ -18,52 +18,11 @@
18
18
  }
19
19
 
20
20
  .flag {
21
- $height: 32px;
21
+ --height: 32px;
22
22
 
23
- height: $height;
23
+ width: calc(var(--height) * var(--aspect--ratio));
24
+ height: var(--height);
24
25
  border-radius: var(--border--radius);
25
26
  box-shadow: var(--box-shadow);
26
27
  transition: var(--transition);
27
-
28
- &.de {
29
- $aspect-ratio: 1.6;
30
-
31
- width: $height * $aspect-ratio;
32
- }
33
-
34
- &.es {
35
- $aspect-ratio: 1.5;
36
-
37
- width: $height * $aspect-ratio;
38
- }
39
-
40
- &.fa {
41
- $aspect-ratio: 1.75;
42
-
43
- width: $height * $aspect-ratio;
44
- }
45
-
46
- &.fr {
47
- $aspect-ratio: 1.6;
48
-
49
- width: $height * $aspect-ratio;
50
- }
51
-
52
- &.gb {
53
- $aspect-ratio: 2;
54
-
55
- width: $height * $aspect-ratio;
56
- }
57
-
58
- &.pl {
59
- $aspect-ratio: 1.6;
60
-
61
- width: $height * $aspect-ratio;
62
- }
63
-
64
- &.us {
65
- $aspect-ratio: 1.9;
66
-
67
- width: $height * $aspect-ratio;
68
- }
69
28
  }
@@ -4,16 +4,18 @@ import { ChangeEvent, FunctionComponent } from 'react';
4
4
  import { useDispatch } from 'react-redux';
5
5
 
6
6
  import { Radio } from 'components';
7
+ import { LOCALE_FLAGS } from 'i18n';
7
8
  import { selectLocale, settingsSlice, useTypedSelector } from 'state';
8
9
 
9
10
  import styles from './LocaleSetting.module.scss';
10
- import options from './options';
11
11
 
12
12
  interface Props {
13
13
  className?: string;
14
14
  disabled: boolean;
15
15
  }
16
16
 
17
+ const OPTIONS = Object.values(LOCALE_FLAGS).sort((a, b) => a.name.localeCompare(b.name));
18
+
17
19
  const LocaleSetting: FunctionComponent<Props> = ({ className, disabled }) => {
18
20
  const dispatch = useDispatch();
19
21
  const locale = useTypedSelector(selectLocale);
@@ -25,7 +27,7 @@ const LocaleSetting: FunctionComponent<Props> = ({ className, disabled }) => {
25
27
 
26
28
  return (
27
29
  <div className={className}>
28
- {options.map(({ Icon, ...option }) => (
30
+ {OPTIONS.map(({ Icon, ...option }) => (
29
31
  <Radio
30
32
  checked={locale === option.value}
31
33
  className={classNames(styles.option, className, {
@@ -6,7 +6,7 @@ import { solve as solveScrabble } from '@scrabble-solver/solver';
6
6
  import { Board, Config, isBoardJson, isLocale, Locale, Tile } from '@scrabble-solver/types';
7
7
  import { NextApiRequest, NextApiResponse } from 'next';
8
8
 
9
- import { getServerLoggingData, isBoardValid } from 'api';
9
+ import { getServerLoggingData, isBoardValid, isCharacterValid } from 'api';
10
10
  import { isStringArray } from 'lib';
11
11
 
12
12
  interface RequestData {
@@ -63,10 +63,11 @@ const parseRequest = (request: NextApiRequest): RequestData => {
63
63
  const config = getLocaleConfig(configId, locale);
64
64
 
65
65
  for (const character of characters) {
66
- if (!config.hasCharacter(character) && character !== BLANK) {
66
+ if (!isCharacterValid(character)) {
67
67
  throw new Error('Invalid "characters" parameter');
68
68
  }
69
69
  }
70
+
70
71
  const blanksCount = characters.filter((character) => character === BLANK).length;
71
72
 
72
73
  if (blanksCount > config.blanksCount) {
@@ -119,7 +119,9 @@ $media-expressions: (
119
119
  input {
120
120
  position: absolute;
121
121
  top: -100%;
122
+ right: -100%;
122
123
  left: -100%;
124
+ bottom: -100%;
123
125
  width: 300%;
124
126
  height: 300%;
125
127
  clip-path: inset((100% / 3));
@@ -12,9 +12,13 @@ $easeOutSine: cubic-bezier(0.61, 1, 0.88, 1);
12
12
  --box-shadow: 0 0 var(--box-shadow--blur) var(--box-shadow--spread) var(--box-shadow--color);
13
13
  --box-shadow--blur: 8px;
14
14
  --box-shadow--color: rgba(0, 0, 0, 0.15);
15
+ --box-shadow--color--inverse: rgba(255, 255, 255, 0.85);
16
+ --box-shadow--color--raised: rgba(34, 34, 34, 0.8);
15
17
  --box-shadow--spread: 1px;
16
18
  --box-shadow--null: 0 0 var(--box-shadow--blur) var(--box-shadow--spread) transparent;
17
19
  --box-shadow--error: 0 0 var(--box-shadow--blur) var(--box-shadow--spread) var(--color--error);
20
+ --box-shadow--raised: inset -2px -2px 2px -1px var(--box-shadow--color--raised);
21
+ --box-shadow--raised--subtle: inset -1px -1px 1px 0 var(--box-shadow--color--raised);
18
22
 
19
23
  --color--white: #ffffff;
20
24
  --color--blue: #c7d8f9;
@@ -94,6 +98,14 @@ $easeOutSine: cubic-bezier(0.61, 1, 0.88, 1);
94
98
  --z-index--close-button: 101;
95
99
  --z-index--tooltip: 102;
96
100
 
101
+ --flag--de--aspect-ratio: 20 / 12;
102
+ --flag--es--aspect-ratio: 750 / 500;
103
+ --flag--fa--aspect-ratio: 630 / 360;
104
+ --flag--fr--aspect-ratio: 24 / 15;
105
+ --flag--gb--aspect-ratio: 60 / 30;
106
+ --flag--pl--aspect-ratio: 16 / 10;
107
+ --flag--us--aspect-ratio: 7410 / 3900;
108
+
97
109
  --button--icon--size: 24px;
98
110
  --dictionary--height: 260px;
99
111
  --modal--width: 370px;
@@ -92,6 +92,7 @@ export type TranslationKey =
92
92
  | 'results.empty-state.uninitialized'
93
93
  | 'results.input.placeholder'
94
94
  | 'results.insert'
95
+ | 'results.preview'
95
96
  | 'results.solve'
96
97
  | 'settings'
97
98
  | 'settings.autoGroupTiles'
@@ -1,221 +0,0 @@
1
- "use strict";
2
- exports.id = 417;
3
- exports.ids = [417];
4
- exports.modules = {
5
-
6
- /***/ 38436:
7
- /***/ ((__unused_webpack_module, exports) => {
8
-
9
-
10
- Object.defineProperty(exports, "__esModule", ({ value: true }));
11
- exports.VOWELS = exports.CONSONANTS = exports.NO_BONUS = exports.EMPTY_CELL = exports.BONUS_WORD = exports.BONUS_CHARACTER = exports.BLANK = exports.COMMA_LATIN = exports.COMMA_ARABIC = void 0;
12
- exports.COMMA_ARABIC = '،';
13
- exports.COMMA_LATIN = ',';
14
- exports.BLANK = ' ';
15
- exports.BONUS_CHARACTER = 'BONUS_CHARACTER';
16
- exports.BONUS_WORD = 'BONUS_WORD';
17
- exports.EMPTY_CELL = ' ';
18
- exports.NO_BONUS = { characterMultiplier: 1, wordMultiplier: 1 };
19
- exports.CONSONANTS = [
20
- 'b',
21
- 'c',
22
- 'ć',
23
- 'd',
24
- 'f',
25
- 'g',
26
- 'h',
27
- 'j',
28
- 'k',
29
- 'l',
30
- 'ł',
31
- 'm',
32
- 'n',
33
- 'ń',
34
- 'ñ',
35
- 'p',
36
- 'q',
37
- 'r',
38
- 's',
39
- 'ś',
40
- 't',
41
- 'v',
42
- 'w',
43
- 'x',
44
- 'z',
45
- 'ź',
46
- 'ż',
47
- ];
48
- exports.VOWELS = ['a', 'ą', 'ä', 'e', 'ę', 'i', 'o', 'ó', 'ö', 'u', 'ü', 'y'];
49
-
50
-
51
- /***/ }),
52
-
53
- /***/ 98793:
54
- /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
55
-
56
-
57
- var __importDefault = (this && this.__importDefault) || function (mod) {
58
- return (mod && mod.__esModule) ? mod : { "default": mod };
59
- };
60
- Object.defineProperty(exports, "__esModule", ({ value: true }));
61
- exports.OUTPUT_DIRECTORY = void 0;
62
- const os_1 = __importDefault(__webpack_require__(22037));
63
- const path_1 = __importDefault(__webpack_require__(71017));
64
- exports.OUTPUT_DIRECTORY = path_1.default.resolve(os_1.default.homedir(), '.scrabble-solver', 'logs');
65
-
66
-
67
- /***/ }),
68
-
69
- /***/ 52954:
70
- /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
71
-
72
-
73
- var __importDefault = (this && this.__importDefault) || function (mod) {
74
- return (mod && mod.__esModule) ? mod : { "default": mod };
75
- };
76
- Object.defineProperty(exports, "__esModule", ({ value: true }));
77
- exports["default"] = void 0;
78
- var logger_1 = __webpack_require__(6730);
79
- Object.defineProperty(exports, "default", ({ enumerable: true, get: function () { return __importDefault(logger_1).default; } }));
80
-
81
-
82
- /***/ }),
83
-
84
- /***/ 6730:
85
- /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
86
-
87
-
88
- var __importDefault = (this && this.__importDefault) || function (mod) {
89
- return (mod && mod.__esModule) ? mod : { "default": mod };
90
- };
91
- Object.defineProperty(exports, "__esModule", ({ value: true }));
92
- const path_1 = __importDefault(__webpack_require__(71017));
93
- const winston_1 = __webpack_require__(46050);
94
- const constants_1 = __webpack_require__(98793);
95
- const logger = (0, winston_1.createLogger)({
96
- level: 'info',
97
- format: winston_1.format.combine(winston_1.format.timestamp({
98
- format: 'YYYY-MM-DD HH:mm:ss',
99
- }), winston_1.format.errors({ stack: true }), winston_1.format.splat(), winston_1.format.json(), winston_1.format.prettyPrint()),
100
- transports: [
101
- new winston_1.transports.File({
102
- filename: path_1.default.resolve(constants_1.OUTPUT_DIRECTORY, 'error.log'),
103
- level: 'error',
104
- }),
105
- new winston_1.transports.File({
106
- filename: path_1.default.resolve(constants_1.OUTPUT_DIRECTORY, 'all.log'),
107
- }),
108
- new winston_1.transports.Console({
109
- format: winston_1.format.combine(winston_1.format.colorize(), winston_1.format.simple()),
110
- level: 'error',
111
- }),
112
- ],
113
- });
114
- exports["default"] = logger;
115
-
116
-
117
- /***/ }),
118
-
119
- /***/ 78570:
120
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
121
-
122
-
123
- // EXPORTS
124
- __webpack_require__.d(__webpack_exports__, {
125
- "X8": () => (/* reexport */ api_getServerLoggingData),
126
- "p2": () => (/* reexport */ api_isBoardValid)
127
- });
128
-
129
- // UNUSED EXPORTS: isCellValid, isRowValid
130
-
131
- ;// CONCATENATED MODULE: ./src/api/getServerLoggingData.ts
132
- const getServerLoggingData = (request)=>({
133
- origin: request.headers.origin,
134
- referer: request.headers.referer,
135
- userAgent: request.headers["user-agent"],
136
- xForwardedFor: request.headers["x-forwarded-for"],
137
- xRealIp: request.headers["x-real-ip"]
138
- });
139
- /* harmony default export */ const api_getServerLoggingData = (getServerLoggingData);
140
-
141
- // EXTERNAL MODULE: ../constants/build/index.js
142
- var build = __webpack_require__(38436);
143
- ;// CONCATENATED MODULE: ./src/api/isCellValid.ts
144
-
145
- const isCellValid = (cell, config)=>{
146
- const { isEmpty , tile , x , y } = cell;
147
- if (x < 0 || x >= config.boardWidth) {
148
- return false;
149
- }
150
- if (y < 0 || y >= config.boardHeight) {
151
- return false;
152
- }
153
- if (isEmpty && tile !== null) {
154
- return false;
155
- }
156
- if (tile !== null && !config.hasCharacter(tile.character) && tile.character !== build.BLANK) {
157
- return false;
158
- }
159
- return true;
160
- };
161
- /* harmony default export */ const api_isCellValid = (isCellValid);
162
-
163
- ;// CONCATENATED MODULE: ./src/api/isRowValid.ts
164
-
165
- const isRowValid = (row, config)=>{
166
- if (row.length !== config.boardWidth) {
167
- return false;
168
- }
169
- for (const cell of row){
170
- if (!api_isCellValid(cell, config)) {
171
- return false;
172
- }
173
- }
174
- return true;
175
- };
176
- /* harmony default export */ const api_isRowValid = (isRowValid);
177
-
178
- ;// CONCATENATED MODULE: ./src/api/isBoardValid.ts
179
-
180
- const isBoardValid = (board, config)=>{
181
- if (board.length !== config.boardHeight) {
182
- return false;
183
- }
184
- for (const row of board){
185
- if (!api_isRowValid(row, config)) {
186
- return false;
187
- }
188
- }
189
- return areTwoCharacterTilesValid(board, config);
190
- };
191
- const areTwoCharacterTilesValid = (board, config)=>{
192
- const cells = board.flat().filter((cell)=>cell && cell.tile && config.isTwoCharacterTilePrefix(cell.tile.character));
193
- for (const cell of cells){
194
- for (const characters of config.twoCharacterTiles){
195
- const canCheckDown = cell.y + 1 < board.length;
196
- const canCheckRight = cell.x + 1 < board[0].length;
197
- const cellDown = board[cell.y + 1][cell.x];
198
- const cellRight = board[cell.y][cell.x + 1];
199
- const collidesDown = canCheckDown && cellDown.tile && cellDown.tile.character === characters[1];
200
- const collidesRight = canCheckRight && cellRight.tile && cellRight.tile.character === characters[1];
201
- const collides = collidesDown || collidesRight;
202
- if (cell.tile && characters.startsWith(cell.tile.character) && collides) {
203
- return false;
204
- }
205
- }
206
- }
207
- return true;
208
- };
209
- /* harmony default export */ const api_isBoardValid = (isBoardValid);
210
-
211
- ;// CONCATENATED MODULE: ./src/api/index.ts
212
-
213
-
214
-
215
-
216
-
217
-
218
- /***/ })
219
-
220
- };
221
- ;