scrabble-solver 2.10.11 → 2.11.0
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.
- package/lerna.json +1 -1
- package/package.json +8 -8
- package/packages/configs/package.json +3 -3
- package/packages/constants/package.json +1 -1
- package/packages/dictionaries/package-lock.json +2 -2
- package/packages/dictionaries/package.json +4 -4
- package/packages/logger/package-lock.json +8 -8
- package/packages/logger/package.json +1 -1
- package/packages/scrabble-solver/.next/BUILD_ID +1 -1
- package/packages/scrabble-solver/.next/build-manifest.json +12 -12
- package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
- package/packages/scrabble-solver/.next/cache/eslint/.cache_8dgz12 +1 -1
- package/packages/scrabble-solver/.next/cache/next-server.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
- package/packages/scrabble-solver/.next/next-server.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/prerender-manifest.json +1 -1
- package/packages/scrabble-solver/.next/required-server-files.json +1 -1
- package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
- package/packages/scrabble-solver/.next/server/chunks/{176.js → 277.js} +734 -590
- package/packages/scrabble-solver/.next/server/chunks/{290.js → 417.js} +3 -3
- package/packages/scrabble-solver/.next/server/chunks/50.js +371 -343
- package/packages/scrabble-solver/.next/server/chunks/664.js +15 -15
- package/packages/scrabble-solver/.next/server/chunks/859.js +17 -10
- package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
- package/packages/scrabble-solver/.next/server/next-font-manifest.js +1 -0
- package/packages/scrabble-solver/.next/server/pages/404.html +2 -2
- package/packages/scrabble-solver/.next/server/pages/404.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/500.html +1 -1
- package/packages/scrabble-solver/.next/server/pages/_app.js +4 -4
- package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/_document.js +2 -2
- package/packages/scrabble-solver/.next/server/pages/_document.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/_error.js +4 -4
- package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js +4 -4
- package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js +3 -3
- package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/solve.js +9 -10
- package/packages/scrabble-solver/.next/server/pages/api/solve.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/verify.js +3 -3
- package/packages/scrabble-solver/.next/server/pages/api/verify.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/visit.js +3 -3
- package/packages/scrabble-solver/.next/server/pages/api/visit.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.html +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.js +253 -159
- package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
- package/packages/scrabble-solver/.next/static/45ye7793DY705HOcuK9lJ/_buildManifest.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/main-0ecb9ccfcb6c9b24.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/404-e0f30450e9920dc3.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/_app-d7acee5e526752d9.js +28 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/{_error-8353112a01355ec2.js → _error-54de1933a164a1ff.js} +1 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/index-35d2c1c79a201ae2.js +1 -0
- package/packages/scrabble-solver/.next/static/css/a48caa6f57de6e98.css +1 -0
- package/packages/scrabble-solver/.next/static/css/c49bbe944ddd1b39.css +2 -0
- package/packages/scrabble-solver/.next/trace +55 -55
- package/packages/scrabble-solver/package-lock.json +224 -233
- package/packages/scrabble-solver/package.json +11 -11
- package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.module.scss +1 -0
- package/packages/scrabble-solver/src/components/Board/hooks/useGrid.ts +1 -1
- package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss +13 -8
- package/packages/scrabble-solver/src/components/Dictionary/Dictionary.tsx +5 -5
- package/packages/scrabble-solver/src/components/Loading/Loading.tsx +1 -1
- package/packages/scrabble-solver/src/components/Modal/Modal.module.scss +0 -1
- package/packages/scrabble-solver/src/components/NavButtons/NavButtons.tsx +4 -5
- package/packages/scrabble-solver/src/components/Results/Results.module.scss +5 -2
- package/packages/scrabble-solver/src/components/Results/Results.tsx +11 -11
- package/packages/scrabble-solver/src/components/Solver/Solver.module.scss +1 -0
- package/packages/scrabble-solver/src/components/Solver/Solver.tsx +13 -26
- package/packages/scrabble-solver/src/components/Solver/components/FloatingSolveButton/FloatingSolveButton.module.scss +7 -0
- package/packages/scrabble-solver/src/components/Solver/components/{SolveButton/SolveButton.tsx → FloatingSolveButton/FloatingSolveButton.tsx} +6 -6
- package/packages/scrabble-solver/src/components/Solver/components/FloatingSolveButton/index.ts +1 -0
- package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss +19 -4
- package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +13 -1
- package/packages/scrabble-solver/src/components/Solver/components/index.ts +1 -1
- package/packages/scrabble-solver/src/components/Spinner/Spinner.module.scss +11 -0
- package/packages/scrabble-solver/src/components/Spinner/Spinner.tsx +19 -0
- package/packages/scrabble-solver/src/components/Spinner/index.ts +1 -0
- package/packages/scrabble-solver/src/components/Tile/Tile.tsx +5 -5
- package/packages/scrabble-solver/src/components/index.ts +1 -0
- package/packages/scrabble-solver/src/hooks/index.ts +1 -0
- package/packages/scrabble-solver/src/hooks/useAppLayout.ts +29 -0
- package/packages/scrabble-solver/src/i18n/de.json +1 -0
- package/packages/scrabble-solver/src/i18n/en.json +1 -0
- package/packages/scrabble-solver/src/i18n/es.json +1 -0
- package/packages/scrabble-solver/src/i18n/fa.json +1 -0
- package/packages/scrabble-solver/src/i18n/fr.json +1 -0
- package/packages/scrabble-solver/src/i18n/index.ts +1 -1
- package/packages/scrabble-solver/src/i18n/pl.json +1 -0
- package/packages/scrabble-solver/src/modals/DictionaryModal/DictionaryModal.module.scss +18 -0
- package/packages/scrabble-solver/src/modals/DictionaryModal/DictionaryModal.tsx +27 -0
- package/packages/scrabble-solver/src/modals/DictionaryModal/index.ts +1 -0
- package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.tsx +7 -1
- package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.module.scss +18 -0
- package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.tsx +8 -7
- package/packages/scrabble-solver/src/modals/index.ts +1 -0
- package/packages/scrabble-solver/src/pages/api/solve.ts +9 -10
- package/packages/scrabble-solver/src/pages/index.tsx +20 -15
- package/packages/scrabble-solver/src/state/localStorage.ts +0 -9
- package/packages/scrabble-solver/src/styles/animations.scss +10 -0
- package/packages/scrabble-solver/src/styles/global.scss +1 -1
- package/packages/scrabble-solver/src/styles/variables.scss +1 -1
- package/packages/scrabble-solver/src/types/index.ts +1 -0
- package/packages/solver/package-lock.json +2 -2
- package/packages/solver/package.json +5 -5
- package/packages/types/package.json +2 -2
- package/packages/word-definitions/build/lib/normalizeDefinition.js +1 -1
- package/packages/word-definitions/package-lock.json +8 -8
- package/packages/word-definitions/package.json +2 -2
- package/packages/word-definitions/src/lib/normalizeDefinition.ts +1 -1
- package/packages/word-definitions/src/parse/__tests__/expected/en-US.oe.json +7 -0
- package/packages/word-definitions/src/parse/__tests__/input/en-US.oe.html +1337 -0
- package/packages/word-definitions/src/parse/parse.test.ts +1 -0
- package/packages/word-lists/package-lock.json +8 -8
- package/packages/word-lists/package.json +2 -2
- package/packages/configs/package-lock.json +0 -58
- package/packages/constants/package-lock.json +0 -13
- package/packages/scrabble-solver/.next/server/font-loader-manifest.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/main-74c4d6b2b5c362f3.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/404-6c1a6e3251710371.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/_app-d98e480ff8c583de.js +0 -28
- package/packages/scrabble-solver/.next/static/chunks/pages/index-bd1c7d3872c37456.js +0 -1
- package/packages/scrabble-solver/.next/static/css/a9b55372a26cf77d.css +0 -1
- package/packages/scrabble-solver/.next/static/css/b8954b85e2fa5b63.css +0 -2
- package/packages/scrabble-solver/.next/static/msKI0ZURgJImoGBJvCBiF/_buildManifest.js +0 -1
- package/packages/scrabble-solver/src/components/Solver/components/SolveButton/SolveButton.module.scss +0 -4
- package/packages/scrabble-solver/src/components/Solver/components/SolveButton/index.ts +0 -1
- package/packages/types/package-lock.json +0 -30
- /package/packages/scrabble-solver/.next/server/{font-loader-manifest.json → next-font-manifest.json} +0 -0
- /package/packages/scrabble-solver/.next/static/{msKI0ZURgJImoGBJvCBiF → 45ye7793DY705HOcuK9lJ}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { COMPONENTS_SPACING, COMPONENTS_SPACING_SMALL } from 'parameters';
|
|
2
|
+
|
|
3
|
+
import useIsTouchDevice from './useIsTouchDevice';
|
|
4
|
+
import useMediaQuery from './useMediaQuery';
|
|
5
|
+
|
|
6
|
+
const useAppLayout = () => {
|
|
7
|
+
const isTouchDevice = useIsTouchDevice();
|
|
8
|
+
const isLessThanXs = useMediaQuery('<xs');
|
|
9
|
+
const isLessThanS = useMediaQuery('<s');
|
|
10
|
+
const isLessThanM = useMediaQuery('<m');
|
|
11
|
+
const isLessThanL = useMediaQuery('<l');
|
|
12
|
+
const isLessThanXl = useMediaQuery('<xl');
|
|
13
|
+
const showColumn = !isLessThanL;
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
animateTile: !isLessThanXs,
|
|
17
|
+
componentsSpacing: isLessThanXl ? COMPONENTS_SPACING_SMALL : COMPONENTS_SPACING,
|
|
18
|
+
isBoardFullWidth: isLessThanM,
|
|
19
|
+
showColumn,
|
|
20
|
+
showCompactControls: !showColumn,
|
|
21
|
+
showFloatingSolveButton: isTouchDevice,
|
|
22
|
+
showKeyMap: !isTouchDevice,
|
|
23
|
+
showResultsInModal: isLessThanL,
|
|
24
|
+
showShortNav: isLessThanS,
|
|
25
|
+
showTilePoints: !isLessThanXs,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default useAppLayout;
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"common.vowels": "Vokale",
|
|
18
18
|
"common.word": "Wort",
|
|
19
19
|
"common.words": "Wörter",
|
|
20
|
+
"dictionary": "Wörterbuch",
|
|
20
21
|
"dictionary.empty-state.no-definitions": "Wort existiert im Wörterbuch aber hat keine Definition.",
|
|
21
22
|
"dictionary.empty-state.no-results": "Wort kann nicht im Wörterbuch gefunden werden.",
|
|
22
23
|
"dictionary.empty-state.not-allowed": "Dieses Wort ist nicht erlaubt.",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"common.vowels": "Vowels",
|
|
18
18
|
"common.word": "Word",
|
|
19
19
|
"common.words": "Words",
|
|
20
|
+
"dictionary": "Dictionary",
|
|
20
21
|
"dictionary.empty-state.no-definitions": "Word exists in the dictionary but it does not have a definition.",
|
|
21
22
|
"dictionary.empty-state.no-results": "Unable to find word definition in the dictionary.",
|
|
22
23
|
"dictionary.empty-state.not-allowed": "This word is not allowed.",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"common.vowels": "Vocales",
|
|
18
18
|
"common.word": "Palabra",
|
|
19
19
|
"common.words": "Palabras",
|
|
20
|
+
"dictionary": "Diccionario",
|
|
20
21
|
"dictionary.empty-state.no-definitions": "La palabra existe en el diccionario pero no tiene una definición.",
|
|
21
22
|
"dictionary.empty-state.no-results": "No se puede encontrar la definición de palabra en el diccionario.",
|
|
22
23
|
"dictionary.empty-state.not-allowed": "Esta palabra no es aceptable.",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"common.vowels": "حروف مصوت",
|
|
18
18
|
"common.word": "کلمه",
|
|
19
19
|
"common.words": "کلمات",
|
|
20
|
+
"dictionary": "فرهنگ لغت",
|
|
20
21
|
"dictionary.empty-state.no-definitions": "کلمه در فرهنگ لغت وجود دارد، ولی معنایی برای آن ثبت نشده است.",
|
|
21
22
|
"dictionary.empty-state.no-results": "کلمه در فرهنگ لغت یافت نشد.",
|
|
22
23
|
"dictionary.empty-state.not-allowed": "این کلمه مجاز نیست.",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"common.vowels": "Voyelles",
|
|
18
18
|
"common.word": "Mot",
|
|
19
19
|
"common.words": "Mots",
|
|
20
|
+
"dictionary": "Dictionnaire",
|
|
20
21
|
"dictionary.empty-state.no-definitions": "Le mot existe dans le dictionary mais n'a pas de définition.",
|
|
21
22
|
"dictionary.empty-state.no-results": "Impossible de trouver une définition pour ce mot dans le dictionaire.",
|
|
22
23
|
"dictionary.empty-state.not-allowed": "Ce mot n'est pas pas acceptable.",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"common.vowels": "Samogłoski",
|
|
18
18
|
"common.word": "Słowo",
|
|
19
19
|
"common.words": "Słowa",
|
|
20
|
+
"dictionary": "Słownik",
|
|
20
21
|
"dictionary.empty-state.no-definitions": "Słowo istnieje w słowniku ale nie posiada definicji.",
|
|
21
22
|
"dictionary.empty-state.no-results": "Nie udało się znaleźć definicji słowa w słowniku.",
|
|
22
23
|
"dictionary.empty-state.not-allowed": "To słowo nie jest dopuszczalne w grach.",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.content {
|
|
2
|
+
height: 100%;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
background-color: var(--color--background--element);
|
|
6
|
+
border: var(--border);
|
|
7
|
+
box-shadow: var(--box-shadow);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.dictionary {
|
|
11
|
+
flex: 1;
|
|
12
|
+
border-bottom: var(--border);
|
|
13
|
+
max-height: initial;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.dictionaryInput {
|
|
17
|
+
flex: 0 0 auto;
|
|
18
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FunctionComponent } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Dictionary, DictionaryInput, Modal } from 'components';
|
|
4
|
+
import { useTranslate } from 'state';
|
|
5
|
+
|
|
6
|
+
import styles from './DictionaryModal.module.scss';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
className?: string;
|
|
10
|
+
isOpen: boolean;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const DictionaryModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
|
|
15
|
+
const translate = useTranslate();
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Modal className={className} isOpen={isOpen} title={translate('dictionary')} onClose={onClose}>
|
|
19
|
+
<div className={styles.content}>
|
|
20
|
+
<Dictionary className={styles.dictionary} />
|
|
21
|
+
<DictionaryInput className={styles.dictionaryInput} />
|
|
22
|
+
</div>
|
|
23
|
+
</Modal>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default DictionaryModal;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './DictionaryModal';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FunctionComponent } from 'react';
|
|
2
2
|
|
|
3
3
|
import { Button, Modal } from 'components';
|
|
4
|
-
import { CardChecklist, Cog, Github, Sack } from 'icons';
|
|
4
|
+
import { BookHalf, CardChecklist, Cog, Github, Sack } from 'icons';
|
|
5
5
|
import { GITHUB_PROJECT_URL } from 'parameters';
|
|
6
6
|
import { useTranslate } from 'state';
|
|
7
7
|
|
|
@@ -11,6 +11,7 @@ interface Props {
|
|
|
11
11
|
className?: string;
|
|
12
12
|
isOpen: boolean;
|
|
13
13
|
onClose: () => void;
|
|
14
|
+
onShowDictionary: () => void;
|
|
14
15
|
onShowRemainingTiles: () => void;
|
|
15
16
|
onShowSettings: () => void;
|
|
16
17
|
onShowWords: () => void;
|
|
@@ -20,6 +21,7 @@ const Menu: FunctionComponent<Props> = ({
|
|
|
20
21
|
className,
|
|
21
22
|
isOpen,
|
|
22
23
|
onClose,
|
|
24
|
+
onShowDictionary,
|
|
23
25
|
onShowRemainingTiles,
|
|
24
26
|
onShowSettings,
|
|
25
27
|
onShowWords,
|
|
@@ -41,6 +43,10 @@ const Menu: FunctionComponent<Props> = ({
|
|
|
41
43
|
{translate('words')}
|
|
42
44
|
</Button>
|
|
43
45
|
|
|
46
|
+
<Button aria-label={translate('dictionary')} className={styles.button} Icon={BookHalf} onClick={onShowDictionary}>
|
|
47
|
+
{translate('dictionary')}
|
|
48
|
+
</Button>
|
|
49
|
+
|
|
44
50
|
<Button.Link
|
|
45
51
|
aria-label={translate('github')}
|
|
46
52
|
className={styles.button}
|
|
@@ -1,6 +1,24 @@
|
|
|
1
|
+
@import 'styles/mixins';
|
|
2
|
+
|
|
1
3
|
.content {
|
|
2
4
|
position: relative;
|
|
3
5
|
display: flex;
|
|
4
6
|
flex-direction: column;
|
|
5
7
|
height: 100%;
|
|
8
|
+
gap: var(--spacing--l);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.results {
|
|
12
|
+
flex: 1;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.dictionary {
|
|
16
|
+
flex: 0 0 calc(var(--dictionary--height) - var(--text-input--height));
|
|
17
|
+
background-color: var(--color--background--element);
|
|
18
|
+
border: var(--border);
|
|
19
|
+
box-shadow: var(--box-shadow);
|
|
20
|
+
|
|
21
|
+
@media (max-height: 600px) {
|
|
22
|
+
display: none;
|
|
23
|
+
}
|
|
6
24
|
}
|
|
@@ -2,8 +2,7 @@ import { Result } from '@scrabble-solver/types';
|
|
|
2
2
|
import { FunctionComponent, useMemo } from 'react';
|
|
3
3
|
import { useDispatch } from 'react-redux';
|
|
4
4
|
|
|
5
|
-
import { Modal, Results } from 'components';
|
|
6
|
-
import { useMediaQuery } from 'hooks';
|
|
5
|
+
import { Dictionary, Modal, Results } from 'components';
|
|
7
6
|
import {
|
|
8
7
|
resultsSlice,
|
|
9
8
|
selectResultCandidate,
|
|
@@ -23,7 +22,6 @@ interface Props {
|
|
|
23
22
|
const ResultsModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
|
|
24
23
|
const dispatch = useDispatch();
|
|
25
24
|
const translate = useTranslate();
|
|
26
|
-
const isLessThanS = useMediaQuery('<s');
|
|
27
25
|
const results = useTypedSelector(selectSortedFilteredResults);
|
|
28
26
|
const resultCandidate = useTypedSelector(selectResultCandidate);
|
|
29
27
|
const index = (results || []).findIndex((result) => result.id === resultCandidate?.id);
|
|
@@ -32,20 +30,23 @@ const ResultsModal: FunctionComponent<Props> = ({ className, isOpen, onClose })
|
|
|
32
30
|
const callbacks = useMemo(
|
|
33
31
|
() => ({
|
|
34
32
|
onClick: (result: Result) => {
|
|
35
|
-
|
|
33
|
+
const isSelected = result === resultCandidate;
|
|
36
34
|
|
|
37
|
-
if (
|
|
35
|
+
if (isSelected) {
|
|
38
36
|
onClose();
|
|
37
|
+
} else {
|
|
38
|
+
dispatch(resultsSlice.actions.changeResultCandidate(result));
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
}),
|
|
42
|
-
[dispatch,
|
|
42
|
+
[dispatch, onClose, resultCandidate],
|
|
43
43
|
);
|
|
44
44
|
|
|
45
45
|
return (
|
|
46
46
|
<Modal className={className} isOpen={isOpen} title={translate('results')} onClose={onClose}>
|
|
47
47
|
<div className={styles.content}>
|
|
48
|
-
<Results callbacks={callbacks} highlightedIndex={highlightedIndex} />
|
|
48
|
+
<Results callbacks={callbacks} className={styles.results} highlightedIndex={highlightedIndex} />
|
|
49
|
+
<Dictionary className={styles.dictionary} />
|
|
49
50
|
</div>
|
|
50
51
|
</Modal>
|
|
51
52
|
);
|
|
@@ -57,30 +57,29 @@ const parseRequest = (request: NextApiRequest): RequestData => {
|
|
|
57
57
|
throw new Error('Invalid "configId" parameter');
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
const config = getLocaleConfig(configId, locale);
|
|
61
|
-
|
|
62
|
-
if (!isBoardJson(boardJson) || !isBoardValid(boardJson, config)) {
|
|
63
|
-
throw new Error('Invalid "board" parameter');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
60
|
if (!isStringArray(characters) || characters.length === 0) {
|
|
67
61
|
throw new Error('Invalid "characters" parameter');
|
|
68
62
|
}
|
|
69
63
|
|
|
64
|
+
const config = getLocaleConfig(configId, locale);
|
|
65
|
+
|
|
70
66
|
for (const character of characters) {
|
|
71
67
|
if (!config.hasCharacter(character) && character !== BLANK) {
|
|
72
68
|
throw new Error('Invalid "characters" parameter');
|
|
73
69
|
}
|
|
74
70
|
}
|
|
75
|
-
|
|
76
|
-
const board = Board.fromJson(boardJson);
|
|
77
|
-
const blankTilesCount = characters.filter((character) => character === BLANK).length;
|
|
78
|
-
const blanksCount = board.getBlanksCount() + blankTilesCount;
|
|
71
|
+
const blanksCount = characters.filter((character) => character === BLANK).length;
|
|
79
72
|
|
|
80
73
|
if (blanksCount > config.blanksCount) {
|
|
81
74
|
throw new Error('Too many blank tiles passed');
|
|
82
75
|
}
|
|
83
76
|
|
|
77
|
+
if (!isBoardJson(boardJson) || !isBoardValid(boardJson, config)) {
|
|
78
|
+
throw new Error('Invalid "board" parameter');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const board = Board.fromJson(boardJson);
|
|
82
|
+
|
|
84
83
|
return {
|
|
85
84
|
board,
|
|
86
85
|
characters,
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import {
|
|
4
|
+
import { FunctionComponent, useEffect, useState } from 'react';
|
|
5
5
|
import ReactModal from 'react-modal';
|
|
6
6
|
import { useDispatch } from 'react-redux';
|
|
7
7
|
import { useEffectOnce, useMeasure } from 'react-use';
|
|
8
8
|
|
|
9
9
|
import { Logo, LogoSplashScreen, NavButtons, Solver, SvgFontFix } from 'components';
|
|
10
|
-
import { useDirection, useLanguage, useLocalStorage
|
|
10
|
+
import { useAppLayout, useDirection, useLanguage, useLocalStorage } from 'hooks';
|
|
11
11
|
import { LOCALE_FEATURES } from 'i18n';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
DictionaryModal,
|
|
14
|
+
KeyMapModal,
|
|
15
|
+
MenuModal,
|
|
16
|
+
RemainingTilesModal,
|
|
17
|
+
ResultsModal,
|
|
18
|
+
SettingsModal,
|
|
19
|
+
WordsModal,
|
|
20
|
+
} from 'modals';
|
|
13
21
|
import { INITIALIZATION_DURATION } from 'parameters';
|
|
14
22
|
import { registerServiceWorker } from 'serviceWorkerManager';
|
|
15
|
-
import { initialize,
|
|
23
|
+
import { initialize, reset, selectLocale, useTypedSelector } from 'state';
|
|
16
24
|
|
|
17
25
|
import styles from './index.module.scss';
|
|
18
26
|
|
|
@@ -26,7 +34,8 @@ interface Props {
|
|
|
26
34
|
const Index: FunctionComponent<Props> = ({ version }) => {
|
|
27
35
|
const dispatch = useDispatch();
|
|
28
36
|
const locale = useTypedSelector(selectLocale);
|
|
29
|
-
const
|
|
37
|
+
const { showResultsInModal } = useAppLayout();
|
|
38
|
+
const [showDictionary, setShowDictionary] = useState(false);
|
|
30
39
|
const [showKeyMap, setShowKeyMap] = useState(false);
|
|
31
40
|
const [showMenu, setShowMenu] = useState(false);
|
|
32
41
|
const [showRemainingTiles, setShowRemainingTiles] = useState(false);
|
|
@@ -44,13 +53,6 @@ const Index: FunctionComponent<Props> = ({ version }) => {
|
|
|
44
53
|
dispatch(reset());
|
|
45
54
|
};
|
|
46
55
|
|
|
47
|
-
const handleSplashAnimationEnd = (event: AnimationEvent<HTMLDivElement>) => {
|
|
48
|
-
if (event.target === event.currentTarget && !localStorage.getHasVisited()) {
|
|
49
|
-
setShowSettings(true);
|
|
50
|
-
localStorage.setHasVisited(true);
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
56
|
useDirection(LOCALE_FEATURES[locale].direction);
|
|
55
57
|
useLanguage(locale);
|
|
56
58
|
useLocalStorage();
|
|
@@ -65,10 +67,10 @@ const Index: FunctionComponent<Props> = ({ version }) => {
|
|
|
65
67
|
});
|
|
66
68
|
|
|
67
69
|
useEffect(() => {
|
|
68
|
-
if (!
|
|
70
|
+
if (!showResultsInModal) {
|
|
69
71
|
setShowResults(false);
|
|
70
72
|
}
|
|
71
|
-
}, [
|
|
73
|
+
}, [showResultsInModal]);
|
|
72
74
|
|
|
73
75
|
useEffect(() => {
|
|
74
76
|
if (process.env.NODE_ENV === 'production') {
|
|
@@ -115,6 +117,7 @@ const Index: FunctionComponent<Props> = ({ version }) => {
|
|
|
115
117
|
<MenuModal
|
|
116
118
|
isOpen={showMenu}
|
|
117
119
|
onClose={() => setShowMenu(false)}
|
|
120
|
+
onShowDictionary={() => setShowDictionary(true)}
|
|
118
121
|
onShowRemainingTiles={() => setShowRemainingTiles(true)}
|
|
119
122
|
onShowSettings={() => setShowSettings(true)}
|
|
120
123
|
onShowWords={() => setShowWords(true)}
|
|
@@ -130,7 +133,9 @@ const Index: FunctionComponent<Props> = ({ version }) => {
|
|
|
130
133
|
|
|
131
134
|
<ResultsModal isOpen={showResults} onClose={() => setShowResults(false)} />
|
|
132
135
|
|
|
133
|
-
<
|
|
136
|
+
<DictionaryModal isOpen={showDictionary} onClose={() => setShowDictionary(false)} />
|
|
137
|
+
|
|
138
|
+
<LogoSplashScreen forceShow={!isInitialized} />
|
|
134
139
|
</>
|
|
135
140
|
);
|
|
136
141
|
};
|
|
@@ -3,7 +3,6 @@ import store2 from 'store2';
|
|
|
3
3
|
|
|
4
4
|
const BOARD = 'board';
|
|
5
5
|
const CONFIG_ID = 'config-id';
|
|
6
|
-
const HAS_VISITED = 'has-visited';
|
|
7
6
|
const LOCALE = 'locale';
|
|
8
7
|
const RACK = 'rack';
|
|
9
8
|
|
|
@@ -28,14 +27,6 @@ const localStorage = {
|
|
|
28
27
|
store.set(CONFIG_ID, configId, true);
|
|
29
28
|
},
|
|
30
29
|
|
|
31
|
-
getHasVisited(): boolean {
|
|
32
|
-
return Boolean(store.get(HAS_VISITED));
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
setHasVisited(hasVisited: boolean): void {
|
|
36
|
-
store.set(HAS_VISITED, hasVisited, true);
|
|
37
|
-
},
|
|
38
|
-
|
|
39
30
|
getLocale(): Locale | undefined {
|
|
40
31
|
return store.get(LOCALE);
|
|
41
32
|
},
|
|
@@ -86,10 +86,10 @@ $easeOutSine: cubic-bezier(0.61, 1, 0.88, 1);
|
|
|
86
86
|
--z-index--close-button: 101;
|
|
87
87
|
--z-index--tooltip: 102;
|
|
88
88
|
|
|
89
|
+
--button--icon--size: 24px;
|
|
89
90
|
--dictionary--height: 260px;
|
|
90
91
|
--modal--width: 370px;
|
|
91
92
|
--solver-column--width: 580px;
|
|
92
93
|
--square-button--size: 32px;
|
|
93
|
-
--button--icon--size: 24px;
|
|
94
94
|
--text-input--height: 40px;
|
|
95
95
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scrabble-solver/solver",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@scrabble-solver/solver",
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.11.0",
|
|
10
10
|
"license": "CC-BY-NC-ND-4.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@kamilmielnik/trie": "^2.0.1"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scrabble-solver/solver",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Scrabble Solver 2 - Solver",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@kamilmielnik/trie": "^2.0.1",
|
|
28
|
-
"@scrabble-solver/types": "^2.
|
|
28
|
+
"@scrabble-solver/types": "^2.11.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@scrabble-solver/configs": "^2.
|
|
32
|
-
"@scrabble-solver/constants": "^2.
|
|
33
|
-
"@scrabble-solver/dictionaries": "^2.
|
|
31
|
+
"@scrabble-solver/configs": "^2.11.0",
|
|
32
|
+
"@scrabble-solver/constants": "^2.11.0",
|
|
33
|
+
"@scrabble-solver/dictionaries": "^2.11.0"
|
|
34
34
|
},
|
|
35
35
|
"gitHead": "1e2d1ad49a288d4a44196d8e3336740da132c637"
|
|
36
36
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scrabble-solver/types",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Scrabble Solver 2 - Types",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"clean:force": "npm run clean && rimraf package-lock.json"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@scrabble-solver/constants": "^2.
|
|
27
|
+
"@scrabble-solver/constants": "^2.11.0"
|
|
28
28
|
},
|
|
29
29
|
"gitHead": "1e2d1ad49a288d4a44196d8e3336740da132c637"
|
|
30
30
|
}
|
|
@@ -7,7 +7,7 @@ const striptags_1 = __importDefault(require("striptags"));
|
|
|
7
7
|
const EMPHASIS_TAGS = ['a', 'b', 'em', 'internalXref'];
|
|
8
8
|
const normalizeHtmlTags = (definition) => (0, striptags_1.default)((0, striptags_1.default)(definition, EMPHASIS_TAGS), undefined, '"');
|
|
9
9
|
const normalizeLineBreaks = (definition) => definition.replace(/\r\n/g, '\n');
|
|
10
|
-
const normalizeWhitespace = (definition) => definition.replace(/[ ]+/g, ' ');
|
|
10
|
+
const normalizeWhitespace = (definition) => definition.replace(/[^\S\n ]+/g, ' ').replace(/[ ]+/g, ' ');
|
|
11
11
|
const normalizeQuotes = (definition) => definition.replace(/\."/g, '".');
|
|
12
12
|
/**
|
|
13
13
|
* `(1.2) definition` -> `definition`
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scrabble-solver/word-definitions",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@scrabble-solver/word-definitions",
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.11.0",
|
|
10
10
|
"license": "CC-BY-NC-ND-4.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"cheerio": "^1.0.0-rc.12",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
29
|
"node_modules/@types/node": {
|
|
30
|
-
"version": "18.
|
|
31
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.
|
|
32
|
-
"integrity": "sha512-
|
|
30
|
+
"version": "18.15.0",
|
|
31
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.0.tgz",
|
|
32
|
+
"integrity": "sha512-z6nr0TTEOBGkzLGmbypWOGnpSpSIBorEhC4L+4HeQ2iezKCi4f77kyslRwvHeNitymGQ+oFyIWGP96l/DPSV9w==",
|
|
33
33
|
"dev": true
|
|
34
34
|
},
|
|
35
35
|
"node_modules/boolbase": {
|
|
@@ -249,9 +249,9 @@
|
|
|
249
249
|
}
|
|
250
250
|
},
|
|
251
251
|
"@types/node": {
|
|
252
|
-
"version": "18.
|
|
253
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.
|
|
254
|
-
"integrity": "sha512-
|
|
252
|
+
"version": "18.15.0",
|
|
253
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.0.tgz",
|
|
254
|
+
"integrity": "sha512-z6nr0TTEOBGkzLGmbypWOGnpSpSIBorEhC4L+4HeQ2iezKCi4f77kyslRwvHeNitymGQ+oFyIWGP96l/DPSV9w==",
|
|
255
255
|
"dev": true
|
|
256
256
|
},
|
|
257
257
|
"boolbase": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scrabble-solver/word-definitions",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Scrabble Solver 2 - Word definitions",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"clean": "rimraf build/ node_modules/ package-lock.json"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@scrabble-solver/types": "^2.
|
|
26
|
+
"@scrabble-solver/types": "^2.11.0",
|
|
27
27
|
"cheerio": "^1.0.0-rc.12",
|
|
28
28
|
"follow-redirects": "^1.15.2",
|
|
29
29
|
"striptags": "^3.2.0"
|
|
@@ -8,7 +8,7 @@ const normalizeHtmlTags: Normalize = (definition) => striptags(striptags(definit
|
|
|
8
8
|
|
|
9
9
|
const normalizeLineBreaks: Normalize = (definition) => definition.replace(/\r\n/g, '\n');
|
|
10
10
|
|
|
11
|
-
const normalizeWhitespace: Normalize = (definition) => definition.replace(/[ ]+/g, ' ');
|
|
11
|
+
const normalizeWhitespace: Normalize = (definition) => definition.replace(/[^\S\n ]+/g, ' ').replace(/[ ]+/g, ' ');
|
|
12
12
|
|
|
13
13
|
const normalizeQuotes: Normalize = (definition) => definition.replace(/\."/g, '".');
|
|
14
14
|
|