@scrabble-solver/scrabble-solver 2.11.4 → 2.11.5
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/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +7 -7
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/eslint/.cache_8dgz12 +1 -1
- package/.next/cache/next-server.js.nft.json +1 -1
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/export-marker.json +1 -1
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +1 -1
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/131.js +1 -1
- package/.next/server/chunks/277.js +728 -877
- package/.next/server/chunks/636.js +286 -0
- package/.next/server/chunks/675.js +550 -0
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/404.js.nft.json +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages/_app.js +73 -9
- package/.next/server/pages/_app.js.nft.json +1 -1
- package/.next/server/pages/_document.js.nft.json +1 -1
- package/.next/server/pages/_error.js +1 -280
- package/.next/server/pages/_error.js.nft.json +1 -1
- package/.next/server/pages/api/solve.js +22 -2
- package/.next/server/pages/index.html +1 -1
- package/.next/server/pages/index.js +382 -313
- package/.next/server/pages/index.js.nft.json +1 -1
- package/.next/server/pages/index.json +1 -1
- package/.next/static/UzQCOB6CHhyOupkEq8oZM/_buildManifest.js +1 -0
- package/.next/static/chunks/pages/{404-448ba28510855455.js → 404-d30fe85d005ce32b.js} +1 -1
- package/.next/static/chunks/pages/_app-e27464a187a58684.js +28 -0
- package/.next/static/chunks/pages/index-3fd280f406cc00fd.js +1 -0
- package/.next/static/css/4bd04cebe207859c.css +1 -0
- package/.next/static/css/5b3b78170f4c5875.css +2 -0
- package/.next/trace +50 -53
- package/next.config.js +1 -0
- package/package.json +12 -13
- package/src/@types/svg.d.ts +1 -1
- package/src/components/Board/Board.tsx +48 -44
- package/src/components/Board/components/Actions/Actions.tsx +4 -2
- package/src/components/Board/components/Cell/Cell.module.scss +59 -1
- package/src/components/Board/hooks/useGrid.ts +5 -3
- package/src/components/Button/Button.module.scss +1 -1
- package/src/components/Loading/Loading.module.scss +1 -1
- package/src/components/Loading/Loading.tsx +1 -1
- package/src/components/Logo/Logo.tsx +10 -12
- package/src/components/Logo/LogoBlueprint.tsx +21 -0
- package/src/components/Logo/index.ts +1 -1
- package/src/components/Modal/Modal.module.scss +1 -6
- package/src/components/Modal/Modal.tsx +15 -8
- package/src/components/NavButtons/NavButtons.tsx +2 -2
- package/src/components/Rack/Rack.module.scss +59 -0
- package/src/components/Results/HeaderButton.tsx +6 -6
- package/src/components/Results/Results.module.scss +3 -0
- package/src/components/Results/Results.tsx +7 -7
- package/src/components/Results/useColumns.ts +2 -5
- package/src/components/Solver/Solver.tsx +6 -23
- package/src/components/Tile/Tile.module.scss +2 -1
- package/src/components/Tile/Tile.tsx +8 -4
- package/src/components/index.ts +0 -3
- package/src/hooks/index.ts +6 -0
- package/src/hooks/useAppLayout.ts +62 -12
- package/src/hooks/useEffectOnce.ts +5 -0
- package/src/hooks/useIsTouchDevice.ts +1 -1
- package/src/hooks/useLatest.ts +13 -0
- package/src/hooks/useLocalStorage.ts +51 -0
- package/src/hooks/useMedia.ts +36 -0
- package/src/hooks/useMediaQueries.ts +13 -0
- package/src/hooks/useMediaQuery.ts +2 -1
- package/src/hooks/useOnWindowResize.ts +13 -0
- package/src/hooks/useViewportSize.ts +19 -0
- package/src/i18n/constants.ts +14 -14
- package/src/lib/arrayEquals.ts +5 -0
- package/src/lib/index.ts +1 -0
- package/src/lib/zipCharactersAndTiles.ts +3 -1
- package/src/modals/DictionaryModal/DictionaryModal.tsx +2 -2
- package/src/modals/KeyMapModal/KeyMapModal.tsx +2 -2
- package/src/modals/KeyMapModal/keys.tsx +0 -2
- package/src/modals/MenuModal/MenuModal.module.scss +28 -4
- package/src/modals/MenuModal/MenuModal.tsx +4 -4
- package/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +2 -2
- package/src/modals/ResultsModal/ResultsModal.module.scss +1 -5
- package/src/modals/ResultsModal/ResultsModal.tsx +10 -2
- package/src/modals/SettingsModal/SettingsModal.tsx +2 -2
- package/src/modals/SettingsModal/components/AutoGroupTilesSetting/lib.ts +3 -1
- package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +1 -1
- package/src/modals/WordsModal/WordsModal.tsx +2 -2
- package/src/pages/index.module.scss +3 -21
- package/src/pages/index.tsx +51 -67
- package/src/parameters/index.ts +29 -2
- package/src/state/localStorage.ts +13 -2
- package/src/state/sagas.ts +16 -8
- package/src/state/slices/boardInitialState.ts +5 -1
- package/src/state/slices/boardSlice.ts +2 -2
- package/src/state/slices/rackInitialState.ts +8 -2
- package/src/state/slices/rackSlice.ts +16 -13
- package/src/state/slices/settingsInitialState.ts +9 -4
- package/src/state/slices/settingsSlice.ts +3 -1
- package/src/styles/animations.scss +0 -20
- package/src/styles/global.scss +0 -7
- package/src/styles/mixins.scss +0 -59
- package/src/styles/variables.scss +11 -0
- package/src/types/index.ts +4 -0
- package/.next/static/MvHZRF4XuJ7g8LLLRkf8U/_buildManifest.js +0 -1
- package/.next/static/chunks/pages/_app-66d80a5594aab8dc.js +0 -28
- package/.next/static/chunks/pages/index-0858deea02b2a417.js +0 -1
- package/.next/static/css/885da289cec275b3.css +0 -1
- package/.next/static/css/ea1c8134fe9a143e.css +0 -2
- package/src/components/LogoSplashScreen/LogoSplashScreen.module.scss +0 -65
- package/src/components/LogoSplashScreen/LogoSplashScreen.tsx +0 -31
- package/src/components/LogoSplashScreen/index.ts +0 -1
- package/src/components/Sizer/Sizer.module.scss +0 -10
- package/src/components/Sizer/Sizer.tsx +0 -10
- package/src/components/Sizer/index.ts +0 -1
- package/src/components/SplashScreen/SplashScreen.module.scss +0 -14
- package/src/components/SplashScreen/SplashScreen.tsx +0 -19
- package/src/components/SplashScreen/index.ts +0 -1
- package/src/hooks/useLocalStorage/index.ts +0 -1
- package/src/hooks/useLocalStorage/useLocalStorage.ts +0 -13
- package/src/hooks/useLocalStorage/useLocalStorageBoard.ts +0 -29
- package/src/hooks/useLocalStorage/useLocalStorageConfigId.ts +0 -29
- package/src/hooks/useLocalStorage/useLocalStorageLocale.ts +0 -32
- package/src/hooks/useLocalStorage/useLocalStorageRack.ts +0 -29
- /package/.next/static/{MvHZRF4XuJ7g8LLLRkf8U → UzQCOB6CHhyOupkEq8oZM}/_ssgManifest.js +0 -0
- /package/{src/components/Logo/Logo.svg → public/logo.svg} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FunctionComponent } from 'react';
|
|
1
|
+
import { FunctionComponent, memo } from 'react';
|
|
2
2
|
|
|
3
3
|
import { Button, Modal } from 'components';
|
|
4
4
|
import { LOCALE_FLAGS } from 'i18n';
|
|
@@ -18,7 +18,7 @@ interface Props {
|
|
|
18
18
|
onShowWords: () => void;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const MenuModal: FunctionComponent<Props> = ({
|
|
22
22
|
className,
|
|
23
23
|
isOpen,
|
|
24
24
|
onClose,
|
|
@@ -63,7 +63,7 @@ const Menu: FunctionComponent<Props> = ({
|
|
|
63
63
|
|
|
64
64
|
<Button aria-label={translate('settings')} className={styles.button} Icon={Cog} onClick={onShowSettings}>
|
|
65
65
|
<div className={styles.settings}>
|
|
66
|
-
<
|
|
66
|
+
<div className={styles.settingsLabel}>{translate('settings')}</div>
|
|
67
67
|
<Flag.Icon className={styles.flag} />
|
|
68
68
|
</div>
|
|
69
69
|
</Button>
|
|
@@ -71,4 +71,4 @@ const Menu: FunctionComponent<Props> = ({
|
|
|
71
71
|
);
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
export default
|
|
74
|
+
export default memo(MenuModal);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FunctionComponent } from 'react';
|
|
1
|
+
import { FunctionComponent, memo } from 'react';
|
|
2
2
|
|
|
3
3
|
import { Badge, Modal } from 'components';
|
|
4
4
|
import { LOCALE_FEATURES } from 'i18n';
|
|
@@ -56,4 +56,4 @@ const RemainingTilesModal: FunctionComponent<Props> = ({ className, isOpen, onCl
|
|
|
56
56
|
);
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
export default RemainingTilesModal;
|
|
59
|
+
export default memo(RemainingTilesModal);
|
|
@@ -13,12 +13,8 @@
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
.dictionary {
|
|
16
|
-
flex: 0
|
|
16
|
+
flex: 0 0 var(--dictionary--height--mobile);
|
|
17
17
|
background-color: var(--color--background--element);
|
|
18
18
|
border: var(--border);
|
|
19
19
|
border-radius: var(--border--radius);
|
|
20
|
-
|
|
21
|
-
@media (max-height: 600px) {
|
|
22
|
-
display: none;
|
|
23
|
-
}
|
|
24
20
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Result } from '@scrabble-solver/types';
|
|
2
|
-
import { FunctionComponent, useMemo } from 'react';
|
|
2
|
+
import { FunctionComponent, memo, useEffect, useMemo } from 'react';
|
|
3
3
|
import { useDispatch } from 'react-redux';
|
|
4
4
|
|
|
5
5
|
import { Button, Dictionary, Modal, Results } from 'components';
|
|
6
|
+
import { useAppLayout } from 'hooks';
|
|
6
7
|
import { Check, EyeFill } from 'icons';
|
|
7
8
|
import { resultsSlice, selectResultCandidate, selectResults, useTranslate, useTypedSelector } from 'state';
|
|
8
9
|
|
|
@@ -17,6 +18,7 @@ interface Props {
|
|
|
17
18
|
const ResultsModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
|
|
18
19
|
const dispatch = useDispatch();
|
|
19
20
|
const translate = useTranslate();
|
|
21
|
+
const { showResultsInModal } = useAppLayout();
|
|
20
22
|
const results = useTypedSelector(selectResults);
|
|
21
23
|
const resultCandidate = useTypedSelector(selectResultCandidate);
|
|
22
24
|
const index = results ? results.findIndex((result) => result.id === resultCandidate?.id) : -1;
|
|
@@ -49,6 +51,12 @@ const ResultsModal: FunctionComponent<Props> = ({ className, isOpen, onClose })
|
|
|
49
51
|
onClose();
|
|
50
52
|
};
|
|
51
53
|
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (isOpen && !showResultsInModal) {
|
|
56
|
+
onClose();
|
|
57
|
+
}
|
|
58
|
+
}, [isOpen, onClose, showResultsInModal]);
|
|
59
|
+
|
|
52
60
|
return (
|
|
53
61
|
<Modal
|
|
54
62
|
className={className}
|
|
@@ -88,4 +96,4 @@ const ResultsModal: FunctionComponent<Props> = ({ className, isOpen, onClose })
|
|
|
88
96
|
);
|
|
89
97
|
};
|
|
90
98
|
|
|
91
|
-
export default ResultsModal;
|
|
99
|
+
export default memo(ResultsModal);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FunctionComponent } from 'react';
|
|
1
|
+
import { FunctionComponent, memo } from 'react';
|
|
2
2
|
|
|
3
3
|
import { Modal } from 'components';
|
|
4
4
|
import { useTranslate } from 'state';
|
|
@@ -31,4 +31,4 @@ const SettingsModal: FunctionComponent<Props> = ({ className, isOpen, onClose })
|
|
|
31
31
|
);
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
export default SettingsModal;
|
|
34
|
+
export default memo(SettingsModal);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { AutoGroupTiles } from 'types';
|
|
2
|
+
|
|
1
3
|
import { NULL_VALUE } from './constants';
|
|
2
4
|
|
|
3
|
-
export const parseValue = (value: string):
|
|
5
|
+
export const parseValue = (value: string): AutoGroupTiles => {
|
|
4
6
|
if (value === 'left' || value === 'right') {
|
|
5
7
|
return value;
|
|
6
8
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
import { FunctionComponent } from 'react';
|
|
2
|
+
import { FunctionComponent, memo } from 'react';
|
|
3
3
|
|
|
4
4
|
import { Badge, Modal } from 'components';
|
|
5
5
|
import { Check, Cross } from 'icons';
|
|
@@ -53,4 +53,4 @@ const WordsModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) =>
|
|
|
53
53
|
);
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
export default WordsModal;
|
|
56
|
+
export default memo(WordsModal);
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
@import 'styles/mixins';
|
|
2
|
-
|
|
3
|
-
.index {
|
|
4
|
-
display: flex;
|
|
5
|
-
flex-direction: column;
|
|
6
|
-
height: 100%;
|
|
7
|
-
opacity: 0;
|
|
8
|
-
overflow: auto;
|
|
9
|
-
transition: var(--transition--long);
|
|
10
|
-
|
|
11
|
-
&.initialized {
|
|
12
|
-
opacity: 1;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
1
|
.nav {
|
|
17
2
|
position: relative;
|
|
18
3
|
z-index: 1;
|
|
@@ -23,7 +8,7 @@
|
|
|
23
8
|
width: 100%;
|
|
24
9
|
display: flex;
|
|
25
10
|
align-items: flex-start;
|
|
26
|
-
padding: var(--
|
|
11
|
+
padding: var(--nav--padding);
|
|
27
12
|
}
|
|
28
13
|
|
|
29
14
|
.navLogo {
|
|
@@ -36,12 +21,9 @@
|
|
|
36
21
|
}
|
|
37
22
|
|
|
38
23
|
.logo {
|
|
39
|
-
|
|
24
|
+
width: calc(var(--logo--aspect-ratio) * var(--logo--height));
|
|
25
|
+
height: var(--logo--height);
|
|
40
26
|
user-select: none;
|
|
41
|
-
|
|
42
|
-
@include media('<l') {
|
|
43
|
-
height: 48px;
|
|
44
|
-
}
|
|
45
27
|
}
|
|
46
28
|
|
|
47
29
|
.solver {
|
package/src/pages/index.tsx
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import classNames from 'classnames';
|
|
2
1
|
import fs from 'fs';
|
|
3
2
|
import path from 'path';
|
|
4
|
-
import { FunctionComponent,
|
|
3
|
+
import { FunctionComponent, useCallback, useState } from 'react';
|
|
5
4
|
import ReactModal from 'react-modal';
|
|
6
5
|
import { useDispatch } from 'react-redux';
|
|
7
|
-
import { useEffectOnce, useMeasure } from 'react-use';
|
|
8
6
|
|
|
9
|
-
import { Logo,
|
|
10
|
-
import {
|
|
7
|
+
import { Logo, NavButtons, Solver, SvgFontFix } from 'components';
|
|
8
|
+
import { useDirection, useEffectOnce, useLanguage, useLocalStorage } from 'hooks';
|
|
11
9
|
import { LOCALE_FEATURES } from 'i18n';
|
|
12
10
|
import {
|
|
13
11
|
DictionaryModal,
|
|
@@ -33,7 +31,6 @@ interface Props {
|
|
|
33
31
|
const Index: FunctionComponent<Props> = ({ version }) => {
|
|
34
32
|
const dispatch = useDispatch();
|
|
35
33
|
const locale = useTypedSelector(selectLocale);
|
|
36
|
-
const { showResultsInModal } = useAppLayout();
|
|
37
34
|
const [showDictionary, setShowDictionary] = useState(false);
|
|
38
35
|
const [showKeyMap, setShowKeyMap] = useState(false);
|
|
39
36
|
const [showMenu, setShowMenu] = useState(false);
|
|
@@ -41,38 +38,36 @@ const Index: FunctionComponent<Props> = ({ version }) => {
|
|
|
41
38
|
const [showResults, setShowResults] = useState(false);
|
|
42
39
|
const [showSettings, setShowSettings] = useState(false);
|
|
43
40
|
const [showWords, setShowWords] = useState(false);
|
|
44
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
45
|
-
const [indexRef, { height: indexHeight, width: indexWidth }] = useMeasure<HTMLDivElement>();
|
|
46
|
-
const [navRef, { height: navHeight }] = useMeasure<HTMLElement>();
|
|
47
|
-
const solverHeight = indexHeight - navHeight;
|
|
48
|
-
const solverWidth = indexWidth;
|
|
49
41
|
const [isClient, setIsClient] = useState(false);
|
|
50
42
|
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
const handleShowResults = useCallback(() => setShowResults(true), []);
|
|
44
|
+
const handleClear = useCallback(() => dispatch(reset()), [dispatch]);
|
|
45
|
+
const handleHideDictionary = useCallback(() => setShowDictionary(false), []);
|
|
46
|
+
const handleHideKeyMap = useCallback(() => setShowKeyMap(false), []);
|
|
47
|
+
const handleHideMenu = useCallback(() => setShowMenu(false), []);
|
|
48
|
+
const handleHideRemainingTiles = useCallback(() => setShowRemainingTiles(false), []);
|
|
49
|
+
const handleHideResults = useCallback(() => setShowResults(false), []);
|
|
50
|
+
const handleHideSettings = useCallback(() => setShowSettings(false), []);
|
|
51
|
+
const handleHideWords = useCallback(() => setShowWords(false), []);
|
|
52
|
+
const handleShowDictionary = useCallback(() => setShowDictionary(true), []);
|
|
53
|
+
const handleShowKeyMap = useCallback(() => setShowKeyMap(true), []);
|
|
54
|
+
const handleShowMenu = useCallback(() => setShowMenu(true), []);
|
|
55
|
+
const handleShowRemainingTiles = useCallback(() => setShowRemainingTiles(true), []);
|
|
56
|
+
const handleShowSettings = useCallback(() => setShowSettings(true), []);
|
|
57
|
+
const handleShowWords = useCallback(() => setShowWords(true), []);
|
|
54
58
|
|
|
55
59
|
useDirection(LOCALE_FEATURES[locale].direction);
|
|
56
60
|
useLanguage(locale);
|
|
57
61
|
useLocalStorage();
|
|
58
62
|
|
|
59
63
|
useEffectOnce(() => {
|
|
60
|
-
setIsClient(true);
|
|
61
|
-
dispatch(initialize());
|
|
62
|
-
setIsInitialized(true);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
if (!showResultsInModal) {
|
|
67
|
-
setShowResults(false);
|
|
68
|
-
}
|
|
69
|
-
}, [showResultsInModal]);
|
|
70
|
-
|
|
71
|
-
useEffect(() => {
|
|
72
64
|
if (process.env.NODE_ENV === 'production') {
|
|
73
65
|
registerServiceWorker();
|
|
74
66
|
}
|
|
75
|
-
|
|
67
|
+
|
|
68
|
+
setIsClient(true);
|
|
69
|
+
dispatch(initialize());
|
|
70
|
+
});
|
|
76
71
|
|
|
77
72
|
if (!isClient) {
|
|
78
73
|
return null;
|
|
@@ -82,58 +77,47 @@ const Index: FunctionComponent<Props> = ({ version }) => {
|
|
|
82
77
|
<>
|
|
83
78
|
<SvgFontFix />
|
|
84
79
|
|
|
85
|
-
<
|
|
86
|
-
<
|
|
87
|
-
<div className={styles.
|
|
88
|
-
<
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
</a>
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
<NavButtons
|
|
95
|
-
onClear={handleClear}
|
|
96
|
-
onShowKeyMap={() => setShowKeyMap(true)}
|
|
97
|
-
onShowMenu={() => setShowMenu(true)}
|
|
98
|
-
onShowRemainingTiles={() => setShowRemainingTiles(true)}
|
|
99
|
-
onShowSettings={() => setShowSettings(true)}
|
|
100
|
-
onShowWords={() => setShowWords(true)}
|
|
101
|
-
/>
|
|
80
|
+
<nav className={styles.nav}>
|
|
81
|
+
<div className={styles.navContent}>
|
|
82
|
+
<div className={styles.navLogo}>
|
|
83
|
+
<a className={styles.logoContainer} href="/" title={version}>
|
|
84
|
+
<Logo className={styles.logo} />
|
|
85
|
+
</a>
|
|
102
86
|
</div>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
87
|
+
|
|
88
|
+
<NavButtons
|
|
89
|
+
onClear={handleClear}
|
|
90
|
+
onShowKeyMap={handleShowKeyMap}
|
|
91
|
+
onShowMenu={handleShowMenu}
|
|
92
|
+
onShowRemainingTiles={handleShowRemainingTiles}
|
|
93
|
+
onShowSettings={handleShowSettings}
|
|
94
|
+
onShowWords={handleShowWords}
|
|
111
95
|
/>
|
|
112
|
-
|
|
113
|
-
</
|
|
96
|
+
</div>
|
|
97
|
+
</nav>
|
|
98
|
+
|
|
99
|
+
<Solver className={styles.solver} onShowResults={handleShowResults} />
|
|
114
100
|
|
|
115
101
|
<MenuModal
|
|
116
102
|
isOpen={showMenu}
|
|
117
|
-
onClose={
|
|
118
|
-
onShowDictionary={
|
|
119
|
-
onShowRemainingTiles={
|
|
120
|
-
onShowSettings={
|
|
121
|
-
onShowWords={
|
|
103
|
+
onClose={handleHideMenu}
|
|
104
|
+
onShowDictionary={handleShowDictionary}
|
|
105
|
+
onShowRemainingTiles={handleShowRemainingTiles}
|
|
106
|
+
onShowSettings={handleShowSettings}
|
|
107
|
+
onShowWords={handleShowWords}
|
|
122
108
|
/>
|
|
123
109
|
|
|
124
|
-
<SettingsModal isOpen={showSettings} onClose={
|
|
125
|
-
|
|
126
|
-
<KeyMapModal isOpen={showKeyMap} onClose={() => setShowKeyMap(false)} />
|
|
110
|
+
<SettingsModal isOpen={showSettings} onClose={handleHideSettings} />
|
|
127
111
|
|
|
128
|
-
<
|
|
112
|
+
<KeyMapModal isOpen={showKeyMap} onClose={handleHideKeyMap} />
|
|
129
113
|
|
|
130
|
-
<
|
|
114
|
+
<WordsModal isOpen={showWords} onClose={handleHideWords} />
|
|
131
115
|
|
|
132
|
-
<
|
|
116
|
+
<RemainingTilesModal isOpen={showRemainingTiles} onClose={handleHideRemainingTiles} />
|
|
133
117
|
|
|
134
|
-
<
|
|
118
|
+
<ResultsModal isOpen={showResults} onClose={handleHideResults} />
|
|
135
119
|
|
|
136
|
-
<
|
|
120
|
+
<DictionaryModal isOpen={showDictionary} onClose={handleHideDictionary} />
|
|
137
121
|
</>
|
|
138
122
|
);
|
|
139
123
|
};
|
package/src/parameters/index.ts
CHANGED
|
@@ -19,8 +19,14 @@ export const COLOR_GREEN = '#bae3ba';
|
|
|
19
19
|
export const COLOR_RED = '#f7c2aa';
|
|
20
20
|
export const COLOR_YELLOW = '#efe3ae';
|
|
21
21
|
|
|
22
|
-
export const
|
|
23
|
-
export const
|
|
22
|
+
export const SPACING_XS = 2;
|
|
23
|
+
export const SPACING_S = 5;
|
|
24
|
+
export const SPACING_M = 10;
|
|
25
|
+
export const SPACING_L = 20;
|
|
26
|
+
export const SPACING_XL = 40;
|
|
27
|
+
|
|
28
|
+
export const COMPONENTS_SPACING = SPACING_XL;
|
|
29
|
+
export const COMPONENTS_SPACING_SMALL = SPACING_L;
|
|
24
30
|
|
|
25
31
|
export const BOARD_CELL_ACTIONS_OFFSET = 3;
|
|
26
32
|
export const BOARD_CELL_BORDER_WIDTH = 1;
|
|
@@ -36,6 +42,23 @@ export const BOARD_TILE_SIZE_MIN = 20;
|
|
|
36
42
|
|
|
37
43
|
export const BORDER_WIDTH = 1;
|
|
38
44
|
|
|
45
|
+
export const BUTTON_ICON_SIZE = 24;
|
|
46
|
+
export const BUTTON_PADDING_VERTICAL = SPACING_M;
|
|
47
|
+
export const BUTTON_HEIGHT = BUTTON_ICON_SIZE + 2 * BUTTON_PADDING_VERTICAL + 2 * BORDER_WIDTH;
|
|
48
|
+
|
|
49
|
+
export const DICTIONARY_HEIGHT = 260;
|
|
50
|
+
export const DICTIONARY_HEIGHT_MOBILE = 110;
|
|
51
|
+
|
|
52
|
+
export const LOGO_ASPECT_RATIO = 682 / 166;
|
|
53
|
+
export const LOGO_HEIGHT = 60;
|
|
54
|
+
export const LOGO_HEIGHT_SMALL = 48;
|
|
55
|
+
export const LOGO_SRC = '/logo.svg';
|
|
56
|
+
|
|
57
|
+
export const MODAL_WIDTH = 370;
|
|
58
|
+
export const MODAL_HEADER_HEIGHT = 45;
|
|
59
|
+
|
|
60
|
+
export const NAV_PADDING = SPACING_L;
|
|
61
|
+
|
|
39
62
|
export const TILE_SIZE = 80;
|
|
40
63
|
|
|
41
64
|
export const PLAIN_TILES_COLOR_DEFAULT = COLOR_GREEN;
|
|
@@ -67,10 +90,14 @@ export const RACK_TILE_SIZE_MAX = 80;
|
|
|
67
90
|
|
|
68
91
|
export const REMAINING_TILES_TILE_SIZE = 50;
|
|
69
92
|
|
|
93
|
+
export const RESULTS_HEADER_HEIGHT = 35;
|
|
94
|
+
|
|
70
95
|
export const RESULTS_ITEM_HEIGHT = 40;
|
|
71
96
|
|
|
72
97
|
export const SOLVER_COLUMN_WIDTH = 580;
|
|
73
98
|
|
|
99
|
+
export const TEXT_INPUT_HEIGHT = 40;
|
|
100
|
+
|
|
74
101
|
export const TILE_APPEAR_DURATION = 200;
|
|
75
102
|
|
|
76
103
|
export const TILE_APPEAR_KEYFRAMES = [
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Board, Locale } from '@scrabble-solver/types';
|
|
2
2
|
import store2 from 'store2';
|
|
3
3
|
|
|
4
|
+
import { AutoGroupTiles, Rack } from 'types';
|
|
5
|
+
|
|
6
|
+
const AUTO_GROUP_TILES = 'auto-group-tiles';
|
|
4
7
|
const BOARD = 'board';
|
|
5
8
|
const CONFIG_ID = 'config-id';
|
|
6
9
|
const LOCALE = 'locale';
|
|
@@ -9,6 +12,14 @@ const RACK = 'rack';
|
|
|
9
12
|
const store = store2.namespace('scrabble-solver');
|
|
10
13
|
|
|
11
14
|
const localStorage = {
|
|
15
|
+
getAutoGroupTiles(): AutoGroupTiles | undefined {
|
|
16
|
+
return store.get(AUTO_GROUP_TILES);
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
setAutoGroupTiles(autoGroupTiles: AutoGroupTiles | undefined): void {
|
|
20
|
+
store.set(AUTO_GROUP_TILES, autoGroupTiles, true);
|
|
21
|
+
},
|
|
22
|
+
|
|
12
23
|
getBoard(): Board | undefined {
|
|
13
24
|
const serialized = store.get(BOARD);
|
|
14
25
|
return serialized ? Board.fromJson(JSON.parse(serialized)) : serialized;
|
|
@@ -35,11 +46,11 @@ const localStorage = {
|
|
|
35
46
|
store.set(LOCALE, locale, true);
|
|
36
47
|
},
|
|
37
48
|
|
|
38
|
-
getRack():
|
|
49
|
+
getRack(): Rack | undefined {
|
|
39
50
|
return store.get(RACK);
|
|
40
51
|
},
|
|
41
52
|
|
|
42
|
-
setRack(rack:
|
|
53
|
+
setRack(rack: Rack | undefined): void {
|
|
43
54
|
store.set(RACK, rack, true);
|
|
44
55
|
},
|
|
45
56
|
};
|
package/src/state/sagas.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/* eslint-disable max-lines */
|
|
2
|
+
|
|
1
3
|
import { PayloadAction } from '@reduxjs/toolkit';
|
|
2
4
|
import { COMMA_ARABIC, COMMA_LATIN } from '@scrabble-solver/constants';
|
|
3
5
|
import { Locale, Result } from '@scrabble-solver/types';
|
|
@@ -15,6 +17,7 @@ import {
|
|
|
15
17
|
selectDictionary,
|
|
16
18
|
selectLocale,
|
|
17
19
|
selectLocaleAutoGroupTiles,
|
|
20
|
+
selectRack,
|
|
18
21
|
} from './selectors';
|
|
19
22
|
import {
|
|
20
23
|
boardSlice,
|
|
@@ -105,9 +108,14 @@ function* onDictionarySubmit(): AnyGenerator {
|
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
function* onInitialize(): AnyGenerator {
|
|
111
|
+
const board = yield select(selectBoard);
|
|
112
|
+
|
|
108
113
|
yield call(visit);
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
|
|
115
|
+
if (!board.isEmpty()) {
|
|
116
|
+
yield* ensureProperTilesCount();
|
|
117
|
+
yield put(verifySlice.actions.submit());
|
|
118
|
+
}
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
function* onReset(): AnyGenerator {
|
|
@@ -191,13 +199,13 @@ function* onVerify(): AnyGenerator {
|
|
|
191
199
|
|
|
192
200
|
function* ensureProperTilesCount(): AnyGenerator {
|
|
193
201
|
const { config } = yield select(selectConfig);
|
|
194
|
-
const
|
|
202
|
+
const rack = yield select(selectRack);
|
|
195
203
|
|
|
196
|
-
if (config.maximumCharactersCount >
|
|
197
|
-
const differenceCount = Math.abs(config.maximumCharactersCount -
|
|
198
|
-
yield put(rackSlice.actions.init([...
|
|
199
|
-
} else if (config.maximumCharactersCount <
|
|
200
|
-
const nonNulls =
|
|
204
|
+
if (config.maximumCharactersCount > rack.length) {
|
|
205
|
+
const differenceCount = Math.abs(config.maximumCharactersCount - rack.length);
|
|
206
|
+
yield put(rackSlice.actions.init([...rack, ...Array(differenceCount).fill(null)]));
|
|
207
|
+
} else if (config.maximumCharactersCount < rack.length) {
|
|
208
|
+
const nonNulls = rack.filter(Boolean).slice(0, config.maximumCharactersCount);
|
|
201
209
|
const differenceCount = Math.abs(config.maximumCharactersCount - nonNulls.length);
|
|
202
210
|
const autoGroupTiles = yield select(selectLocaleAutoGroupTiles);
|
|
203
211
|
yield put(rackSlice.actions.init([...nonNulls, ...Array(differenceCount).fill(null)]));
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { getLocaleConfig } from '@scrabble-solver/configs';
|
|
2
2
|
import { Board } from '@scrabble-solver/types';
|
|
3
3
|
|
|
4
|
+
import localStorage from '../localStorage';
|
|
5
|
+
|
|
4
6
|
import settingsInitialState from './settingsInitialState';
|
|
5
7
|
|
|
6
8
|
export type BoardState = Board;
|
|
7
9
|
|
|
8
10
|
const { configId, locale } = settingsInitialState;
|
|
9
11
|
const { boardHeight, boardWidth } = getLocaleConfig(configId, locale);
|
|
10
|
-
const
|
|
12
|
+
export const boardDefaultState = Board.create(boardWidth, boardHeight);
|
|
13
|
+
|
|
14
|
+
const boardInitialState: BoardState = localStorage.getBoard() || boardDefaultState;
|
|
11
15
|
|
|
12
16
|
// const createOxyphenbutazone = () => {
|
|
13
17
|
// // Tiles: oypbaze
|
|
@@ -2,7 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
|
2
2
|
import { EMPTY_CELL } from '@scrabble-solver/constants';
|
|
3
3
|
import { Board, Cell, Result, Tile } from '@scrabble-solver/types';
|
|
4
4
|
|
|
5
|
-
import boardInitialState from './boardInitialState';
|
|
5
|
+
import boardInitialState, { boardDefaultState } from './boardInitialState';
|
|
6
6
|
|
|
7
7
|
const boardSlice = createSlice({
|
|
8
8
|
initialState: boardInitialState,
|
|
@@ -43,7 +43,7 @@ const boardSlice = createSlice({
|
|
|
43
43
|
},
|
|
44
44
|
|
|
45
45
|
reset: () => {
|
|
46
|
-
return
|
|
46
|
+
return boardDefaultState;
|
|
47
47
|
},
|
|
48
48
|
|
|
49
49
|
toggleCellIsBlank: (state, action: PayloadAction<{ x: number; y: number }>) => {
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import { Rack } from 'types';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import localStorage from '../localStorage';
|
|
4
|
+
|
|
5
|
+
export type RackState = Rack;
|
|
6
|
+
|
|
7
|
+
export const rackDefaultState: RackState = [null, null, null, null, null, null, null];
|
|
8
|
+
|
|
9
|
+
const rackInitialState: RackState = localStorage.getRack() || rackDefaultState;
|
|
4
10
|
|
|
5
11
|
export default rackInitialState;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
2
2
|
import { Tile } from '@scrabble-solver/types';
|
|
3
3
|
|
|
4
|
-
import { createNullMovingComparator, inverseDirection, zipCharactersAndTiles } from 'lib';
|
|
4
|
+
import { arrayEquals, createNullMovingComparator, inverseDirection, zipCharactersAndTiles } from 'lib';
|
|
5
|
+
import { AutoGroupTiles, Rack } from 'types';
|
|
5
6
|
|
|
6
|
-
import rackInitialState from './rackInitialState';
|
|
7
|
+
import rackInitialState, { rackDefaultState } from './rackInitialState';
|
|
7
8
|
|
|
8
9
|
const rackSlice = createSlice({
|
|
9
10
|
initialState: rackInitialState,
|
|
@@ -14,28 +15,30 @@ const rackSlice = createSlice({
|
|
|
14
15
|
return [...state.slice(0, index), character, ...state.slice(index + 1)];
|
|
15
16
|
},
|
|
16
17
|
|
|
17
|
-
changeCharacters: (state, action: PayloadAction<{ characters:
|
|
18
|
+
changeCharacters: (state, action: PayloadAction<{ characters: Rack; index: number }>) => {
|
|
18
19
|
const { characters, index } = action.payload;
|
|
20
|
+
|
|
21
|
+
if (characters.length === 0) {
|
|
22
|
+
return state;
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
const expectedRackLength = state.length;
|
|
20
26
|
const rack = [...state.slice(0, index), ...characters, ...state.slice(index + characters.length)];
|
|
21
27
|
return rack.slice(0, expectedRackLength);
|
|
22
28
|
},
|
|
23
29
|
|
|
24
|
-
groupTiles: (state, action: PayloadAction<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (direction === null) {
|
|
30
|
+
groupTiles: (state, action: PayloadAction<AutoGroupTiles>) => {
|
|
31
|
+
if (action.payload === null) {
|
|
28
32
|
return state;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
const nullMovingComparator = createNullMovingComparator(inverseDirection(
|
|
35
|
+
const nullMovingComparator = createNullMovingComparator(inverseDirection(action.payload));
|
|
32
36
|
const sortedTiles = [...state].sort(nullMovingComparator);
|
|
33
|
-
return sortedTiles;
|
|
37
|
+
return arrayEquals(state, sortedTiles) ? state : sortedTiles;
|
|
34
38
|
},
|
|
35
39
|
|
|
36
|
-
init: (
|
|
37
|
-
|
|
38
|
-
return rack;
|
|
40
|
+
init: (state, action: PayloadAction<Rack>) => {
|
|
41
|
+
return arrayEquals(state, action.payload) ? state : action.payload;
|
|
39
42
|
},
|
|
40
43
|
|
|
41
44
|
removeTiles: (state, action: PayloadAction<Tile[]>) => {
|
|
@@ -45,7 +48,7 @@ const rackSlice = createSlice({
|
|
|
45
48
|
return charactersWithoutMatchingTiles;
|
|
46
49
|
},
|
|
47
50
|
|
|
48
|
-
reset: () =>
|
|
51
|
+
reset: () => rackDefaultState,
|
|
49
52
|
},
|
|
50
53
|
});
|
|
51
54
|
|
|
@@ -2,17 +2,22 @@ import { literaki, scrabble } from '@scrabble-solver/configs';
|
|
|
2
2
|
import { Locale } from '@scrabble-solver/types';
|
|
3
3
|
|
|
4
4
|
import { guessLocale } from 'lib';
|
|
5
|
+
import { AutoGroupTiles } from 'types';
|
|
6
|
+
|
|
7
|
+
import localStorage from '../localStorage';
|
|
5
8
|
|
|
6
9
|
export interface SettingsState {
|
|
7
|
-
autoGroupTiles:
|
|
10
|
+
autoGroupTiles: AutoGroupTiles;
|
|
8
11
|
configId: typeof literaki.id | typeof scrabble.id;
|
|
9
12
|
locale: Locale;
|
|
10
13
|
}
|
|
11
14
|
|
|
15
|
+
const localStorageAutoGroupTiles = localStorage.getAutoGroupTiles();
|
|
16
|
+
|
|
12
17
|
const settingsInitialState: SettingsState = {
|
|
13
|
-
autoGroupTiles: 'left',
|
|
14
|
-
configId: scrabble.id,
|
|
15
|
-
locale: guessLocale(),
|
|
18
|
+
autoGroupTiles: typeof localStorageAutoGroupTiles === 'undefined' ? 'left' : localStorageAutoGroupTiles,
|
|
19
|
+
configId: localStorage.getConfigId() || scrabble.id,
|
|
20
|
+
locale: localStorage.getLocale() || guessLocale(),
|
|
16
21
|
};
|
|
17
22
|
|
|
18
23
|
export default settingsInitialState;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
2
2
|
import { Locale } from '@scrabble-solver/types';
|
|
3
3
|
|
|
4
|
+
import { AutoGroupTiles } from 'types';
|
|
5
|
+
|
|
4
6
|
import settingsInitialState from './settingsInitialState';
|
|
5
7
|
|
|
6
8
|
const settingsSlice = createSlice({
|
|
7
9
|
initialState: settingsInitialState,
|
|
8
10
|
name: 'settings',
|
|
9
11
|
reducers: {
|
|
10
|
-
changeAutoGroupTiles: (state, action: PayloadAction<
|
|
12
|
+
changeAutoGroupTiles: (state, action: PayloadAction<AutoGroupTiles>) => {
|
|
11
13
|
const autoGroupTiles = action.payload;
|
|
12
14
|
return { ...state, autoGroupTiles };
|
|
13
15
|
},
|