@scrabble-solver/scrabble-solver 2.16.1 → 2.16.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.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +6 -6
- package/.next/cache/.previewinfo +1 -1
- package/.next/cache/.rscinfo +1 -1
- package/.next/cache/.tsbuildinfo +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/client-production/index.pack.old +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack.old +0 -0
- package/.next/prerender-manifest.json +4 -4
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/712.js +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages/index.html +1 -1
- package/.next/server/pages/index.js +1 -1
- package/.next/server/pages/index.json +1 -1
- package/.next/server/pages/not-found.html +1 -1
- package/.next/static/{-2mw8IrOEpCcsQa6oPYhR → 2uHbiXWVmb-guNjYk2sfF}/_buildManifest.js +1 -1
- package/.next/static/chunks/pages/_app-b74c31c912e414e4.js +7 -0
- package/.next/static/chunks/pages/index-35f70f1627836521.js +1 -0
- package/.next/static/css/0af35adb4bab56f0.css +2 -0
- package/.next/static/css/a78e04fe95452380.css +1 -0
- package/.next/trace +21 -21
- package/.next/trace-build +1 -1
- package/package.json +9 -9
- package/src/components/Board/Board.tsx +3 -1
- package/src/components/Board/BoardPure.tsx +3 -0
- package/src/components/Board/components/Cell/Cell.module.scss +6 -0
- package/src/components/Board/components/Cell/Cell.tsx +18 -6
- package/src/components/Board/lib.ts +83 -2
- package/src/components/Board/selectors.ts +20 -1
- package/src/components/DictionaryInput/DictionaryInput.tsx +1 -0
- package/src/components/Modal/Modal.tsx +2 -0
- package/src/components/Progress/Progress.tsx +5 -0
- package/src/components/Rack/components/RackTile/RackTile.tsx +4 -1
- package/src/components/Radio/Radio.tsx +1 -1
- package/src/components/Results/Result.tsx +1 -0
- package/src/components/Results/Results.tsx +8 -2
- package/src/components/Tile/TilePure.tsx +20 -18
- package/src/i18n/languages/english.json +4 -1
- package/src/i18n/languages/french.json +4 -1
- package/src/i18n/languages/german.json +4 -1
- package/src/i18n/languages/persian.json +4 -1
- package/src/i18n/languages/polish.json +4 -1
- package/src/i18n/languages/romanian.json +4 -1
- package/src/i18n/languages/spanish.json +4 -1
- package/src/i18n/languages/turkish.json +4 -1
- package/src/modals/RemainingTilesModal/components/Character/Character.module.scss +4 -0
- package/src/modals/RemainingTilesModal/components/Character/Character.tsx +35 -2
- package/src/modals/SettingsModal/SettingsModal.tsx +8 -0
- package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +4 -4
- package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.module.scss +12 -0
- package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.tsx +51 -0
- package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/index.ts +1 -0
- package/src/modals/SettingsModal/components/index.ts +1 -0
- package/src/state/hoveredTile/index.ts +4 -0
- package/src/state/hoveredTile/initialState.ts +5 -0
- package/src/state/hoveredTile/selectors.ts +3 -0
- package/src/state/hoveredTile/slice.ts +16 -0
- package/src/state/hoveredTile/types.ts +3 -0
- package/src/state/index.ts +1 -0
- package/src/state/localStorage.ts +1 -0
- package/src/state/settings/initialState.ts +1 -0
- package/src/state/settings/selectors.ts +5 -0
- package/src/state/settings/slice.ts +5 -0
- package/src/state/settings/types.ts +1 -0
- package/src/state/store.ts +2 -0
- package/src/state/types.ts +2 -0
- package/src/types/index.ts +3 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/.next/static/chunks/pages/_app-9c9aaea7b6881765.js +0 -7
- package/.next/static/chunks/pages/index-e9ea63e97865edcf.js +0 -1
- package/.next/static/css/78726ae7cf7a5497.css +0 -2
- package/.next/static/css/addf6fd4f75742d0.css +0 -1
- /package/.next/static/{-2mw8IrOEpCcsQa6oPYhR → 2uHbiXWVmb-guNjYk2sfF}/_ssgManifest.js +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"cell.filter-cell.include": "Hedef varış noktası",
|
|
5
5
|
"cell.set-blank": "Boş olarak işaretle",
|
|
6
6
|
"cell.set-not-blank": "Boş değil olarak işaretle",
|
|
7
|
-
"cell.tile.location": "Tahta: harfler
|
|
7
|
+
"cell.tile.location": "Tahta: harfler {{coordinates}}",
|
|
8
8
|
"cell.toggle-direction": "Yazma yönü - geçiş yapmak için tıklayın",
|
|
9
9
|
"common.arrows": "Ok tuşları",
|
|
10
10
|
"common.blanks": "Jokerler",
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
"common.consonants": "Ünlü harfler",
|
|
14
14
|
"common.loading": "Yükleniyor",
|
|
15
15
|
"common.next": "Sonraki",
|
|
16
|
+
"common.off": "Kapalı",
|
|
17
|
+
"common.on": "Açık",
|
|
16
18
|
"common.points": "Puanlar",
|
|
17
19
|
"common.previous": "Öncesi",
|
|
18
20
|
"common.space": "Boşluk çubuğu",
|
|
@@ -64,6 +66,7 @@
|
|
|
64
66
|
"settings.autoGroupTiles.right": "Sağdaki",
|
|
65
67
|
"settings.autoGroupTiles.null": "Gruplamayın",
|
|
66
68
|
"settings.game": "Oyun",
|
|
69
|
+
"settings.highlightUnreachableCells": "Ulaşılamayan kareleri vurgula",
|
|
67
70
|
"settings.inputMode": "Giriş Methodu",
|
|
68
71
|
"settings.inputMode.keyboard": "Klavye",
|
|
69
72
|
"settings.inputMode.touchscreen": "Dokunmatik ekran",
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { BLANK } from '@scrabble-solver/constants';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
|
-
import { type FunctionComponent } from 'react';
|
|
3
|
+
import { type FunctionComponent, useCallback, useEffect } from 'react';
|
|
4
|
+
import { useDispatch } from 'react-redux';
|
|
4
5
|
|
|
5
6
|
import { Progress, Tile } from '@/components';
|
|
6
7
|
import { LOCALE_FEATURES } from '@/i18n';
|
|
7
8
|
import { REMAINING_TILES_TILE_SIZE } from '@/parameters';
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
hoveredTileSlice,
|
|
11
|
+
selectCharacterPoints,
|
|
12
|
+
selectHoveredCharacter,
|
|
13
|
+
selectLocale,
|
|
14
|
+
useTypedSelector,
|
|
15
|
+
} from '@/state';
|
|
9
16
|
import { type RemainingTile } from '@/types';
|
|
10
17
|
|
|
11
18
|
import styles from './Character.module.scss';
|
|
@@ -15,7 +22,9 @@ interface Props {
|
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
export const Character: FunctionComponent<Props> = ({ tile }) => {
|
|
25
|
+
const dispatch = useDispatch();
|
|
18
26
|
const locale = useTypedSelector(selectLocale);
|
|
27
|
+
const hoveredCharacter = useTypedSelector(selectHoveredCharacter);
|
|
19
28
|
const { direction } = LOCALE_FEATURES[locale];
|
|
20
29
|
const { character, count, usedCount } = tile;
|
|
21
30
|
|
|
@@ -27,19 +36,43 @@ export const Character: FunctionComponent<Props> = ({ tile }) => {
|
|
|
27
36
|
const points = useTypedSelector((state) => selectCharacterPoints(state, character));
|
|
28
37
|
const current = direction === 'ltr' ? remainingCount : count;
|
|
29
38
|
const total = direction === 'ltr' ? count : remainingCount;
|
|
39
|
+
const isUsed = usedCount > 0;
|
|
40
|
+
const isHovered = isUsed && hoveredCharacter === character;
|
|
41
|
+
|
|
42
|
+
const handleMouseEnter = useCallback(() => {
|
|
43
|
+
if (!isUsed) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
dispatch(hoveredTileSlice.actions.set(character));
|
|
47
|
+
}, [character, dispatch, isUsed]);
|
|
48
|
+
|
|
49
|
+
const handleMouseLeave = useCallback(() => {
|
|
50
|
+
dispatch(hoveredTileSlice.actions.clear());
|
|
51
|
+
}, [dispatch]);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
return () => {
|
|
55
|
+
dispatch(hoveredTileSlice.actions.clear());
|
|
56
|
+
};
|
|
57
|
+
}, [dispatch]);
|
|
30
58
|
|
|
31
59
|
return (
|
|
32
60
|
<div
|
|
33
61
|
className={classNames(styles.character, {
|
|
34
62
|
[styles.finished]: remainingCount <= 0,
|
|
35
63
|
[styles.overused]: remainingCount < 0,
|
|
64
|
+
[styles.unused]: !isUsed,
|
|
36
65
|
})}
|
|
66
|
+
data-testid={character === BLANK ? 'remaining-tile-blank' : `remaining-tile-${character}`}
|
|
67
|
+
onMouseEnter={handleMouseEnter}
|
|
68
|
+
onMouseLeave={handleMouseLeave}
|
|
37
69
|
>
|
|
38
70
|
<Tile
|
|
39
71
|
aria-label={character}
|
|
40
72
|
character={character}
|
|
41
73
|
className={styles.tile}
|
|
42
74
|
disabled
|
|
75
|
+
highlighted={isHovered}
|
|
43
76
|
isBlank={character === BLANK}
|
|
44
77
|
isValid={remainingCount >= 0}
|
|
45
78
|
points={points}
|
|
@@ -7,6 +7,7 @@ import { useTranslate } from '@/state';
|
|
|
7
7
|
import {
|
|
8
8
|
AutoGroupTilesSetting,
|
|
9
9
|
ConfigSetting,
|
|
10
|
+
HighlightUnreachableCellsSetting,
|
|
10
11
|
InputModeSetting,
|
|
11
12
|
LocaleSetting,
|
|
12
13
|
ShowCoordinatesSetting,
|
|
@@ -50,6 +51,13 @@ const SettingsModalBase: FunctionComponent<Props> = ({ className, isOpen, onClos
|
|
|
50
51
|
<Modal.Section label={translate('settings.removeCellFilters')} title={translate('settings.removeCellFilters')}>
|
|
51
52
|
<RemoveCellFiltersSetting disabled={!isOpen} />
|
|
52
53
|
</Modal.Section>
|
|
54
|
+
|
|
55
|
+
<Modal.Section
|
|
56
|
+
label={translate('settings.highlightUnreachableCells')}
|
|
57
|
+
title={translate('settings.highlightUnreachableCells')}
|
|
58
|
+
>
|
|
59
|
+
<HighlightUnreachableCellsSetting disabled={!isOpen} />
|
|
60
|
+
</Modal.Section>
|
|
53
61
|
</Modal>
|
|
54
62
|
);
|
|
55
63
|
};
|
|
@@ -19,6 +19,10 @@ export const AutoGroupTilesSetting: FunctionComponent<Props> = ({ className, dis
|
|
|
19
19
|
const value = useTypedSelector(selectAutoGroupTiles);
|
|
20
20
|
|
|
21
21
|
const options = [
|
|
22
|
+
{
|
|
23
|
+
label: translate('settings.autoGroupTiles.null'),
|
|
24
|
+
value: NULL_VALUE,
|
|
25
|
+
},
|
|
22
26
|
{
|
|
23
27
|
label: translate('settings.autoGroupTiles.left'),
|
|
24
28
|
value: 'left',
|
|
@@ -27,10 +31,6 @@ export const AutoGroupTilesSetting: FunctionComponent<Props> = ({ className, dis
|
|
|
27
31
|
label: translate('settings.autoGroupTiles.right'),
|
|
28
32
|
value: 'right',
|
|
29
33
|
},
|
|
30
|
-
{
|
|
31
|
-
label: translate('settings.autoGroupTiles.null'),
|
|
32
|
-
value: NULL_VALUE,
|
|
33
|
-
},
|
|
34
34
|
];
|
|
35
35
|
|
|
36
36
|
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type ChangeEvent, type FunctionComponent } from 'react';
|
|
2
|
+
import { useDispatch } from 'react-redux';
|
|
3
|
+
|
|
4
|
+
import { Radio } from '@/components';
|
|
5
|
+
import { selectHighlightUnreachableCells, settingsSlice, useTranslate, useTypedSelector } from '@/state';
|
|
6
|
+
|
|
7
|
+
import styles from './HighlightUnreachableCellsSetting.module.scss';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
className?: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const HighlightUnreachableCellsSetting: FunctionComponent<Props> = ({ className, disabled }) => {
|
|
15
|
+
const dispatch = useDispatch();
|
|
16
|
+
const translate = useTranslate();
|
|
17
|
+
const value = useTypedSelector(selectHighlightUnreachableCells);
|
|
18
|
+
|
|
19
|
+
const options = [
|
|
20
|
+
{
|
|
21
|
+
label: translate('common.off'),
|
|
22
|
+
value: 'off',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
label: translate('common.on'),
|
|
26
|
+
value: 'on',
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
31
|
+
dispatch(settingsSlice.actions.changeHighlightUnreachableCells(event.target.value === 'on'));
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div className={className}>
|
|
36
|
+
{options.map((option) => (
|
|
37
|
+
<Radio
|
|
38
|
+
checked={(value ? 'on' : 'off') === option.value}
|
|
39
|
+
className={styles.option}
|
|
40
|
+
disabled={disabled}
|
|
41
|
+
key={option.value}
|
|
42
|
+
name="highlightUnreachableCells"
|
|
43
|
+
value={option.value}
|
|
44
|
+
onChange={handleChange}
|
|
45
|
+
>
|
|
46
|
+
<div className={styles.label}>{option.label}</div>
|
|
47
|
+
</Radio>
|
|
48
|
+
))}
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { HighlightUnreachableCellsSetting } from './HighlightUnreachableCellsSetting';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { AutoGroupTilesSetting } from './AutoGroupTilesSetting';
|
|
2
2
|
export { ConfigSetting } from './ConfigSetting';
|
|
3
|
+
export { HighlightUnreachableCellsSetting } from './HighlightUnreachableCellsSetting';
|
|
3
4
|
export { InputModeSetting } from './InputModeSetting';
|
|
4
5
|
export { LocaleSetting } from './LocaleSetting';
|
|
5
6
|
export { ShowCoordinatesSetting } from './ShowCoordinatesSetting';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
|
2
|
+
|
|
3
|
+
import { hoveredTileInitialState } from './initialState';
|
|
4
|
+
|
|
5
|
+
export const hoveredTileSlice = createSlice({
|
|
6
|
+
initialState: hoveredTileInitialState,
|
|
7
|
+
name: 'hoveredTile',
|
|
8
|
+
reducers: {
|
|
9
|
+
set: (state, action: PayloadAction<string>) => {
|
|
10
|
+
state.character = action.payload;
|
|
11
|
+
},
|
|
12
|
+
clear: (state) => {
|
|
13
|
+
state.character = null;
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|
package/src/state/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ const SETTINGS = 'settings';
|
|
|
12
12
|
const LEGACY_KEYS: Record<keyof SettingsState, string> = {
|
|
13
13
|
autoGroupTiles: 'auto-group-tiles',
|
|
14
14
|
game: 'config-id',
|
|
15
|
+
highlightUnreachableCells: 'highlight-unreachable-cells',
|
|
15
16
|
inputMode: 'input-mode',
|
|
16
17
|
locale: 'locale',
|
|
17
18
|
removeCellFilters: 'remove-cell-filters',
|
|
@@ -10,6 +10,7 @@ const isTouchScreen = typeof globalThis.matchMedia !== 'undefined' && globalThis
|
|
|
10
10
|
export const settingsInitialState: SettingsState = {
|
|
11
11
|
autoGroupTiles: null,
|
|
12
12
|
game: Game.Scrabble,
|
|
13
|
+
highlightUnreachableCells: false,
|
|
13
14
|
inputMode: isTouchScreen ? 'touchscreen' : 'keyboard',
|
|
14
15
|
locale: guessLocale(),
|
|
15
16
|
removeCellFilters: 'always',
|
|
@@ -19,6 +19,11 @@ export const selectAutoGroupTiles = createSelector([selectSettings], (settings)
|
|
|
19
19
|
|
|
20
20
|
export const selectGame = createSelector([selectSettings], (settings) => settings.game);
|
|
21
21
|
|
|
22
|
+
export const selectHighlightUnreachableCells = createSelector(
|
|
23
|
+
[selectSettings],
|
|
24
|
+
(settings) => settings.highlightUnreachableCells,
|
|
25
|
+
);
|
|
26
|
+
|
|
22
27
|
export const selectInputMode = createSelector([selectSettings], (settings) => settings.inputMode);
|
|
23
28
|
|
|
24
29
|
export const selectLocale = createSelector([selectSettings], (settings) => settings.locale);
|
|
@@ -19,6 +19,11 @@ export const settingsSlice = createSlice({
|
|
|
19
19
|
return { ...state, game };
|
|
20
20
|
},
|
|
21
21
|
|
|
22
|
+
changeHighlightUnreachableCells: (state, action: PayloadAction<boolean>) => {
|
|
23
|
+
const highlightUnreachableCells = action.payload;
|
|
24
|
+
return { ...state, highlightUnreachableCells };
|
|
25
|
+
},
|
|
26
|
+
|
|
22
27
|
changeInputMode: (state, action: PayloadAction<InputMode>) => {
|
|
23
28
|
const inputMode = action.payload;
|
|
24
29
|
return { ...state, inputMode };
|
|
@@ -5,6 +5,7 @@ import type { AutoGroupTiles, InputMode, RemoveCellFilters } from '@/types';
|
|
|
5
5
|
export interface SettingsState {
|
|
6
6
|
autoGroupTiles: AutoGroupTiles;
|
|
7
7
|
game: Game;
|
|
8
|
+
highlightUnreachableCells: boolean;
|
|
8
9
|
inputMode: InputMode;
|
|
9
10
|
locale: Locale;
|
|
10
11
|
showCoordinates: ShowCoordinates;
|
package/src/state/store.ts
CHANGED
|
@@ -4,6 +4,7 @@ import reduxSaga from 'redux-saga';
|
|
|
4
4
|
import { boardSlice } from './board';
|
|
5
5
|
import { cellFiltersSlice } from './cellFilters';
|
|
6
6
|
import { dictionarySlice } from './dictionary';
|
|
7
|
+
import { hoveredTileSlice } from './hoveredTile';
|
|
7
8
|
import { rackSlice } from './rack';
|
|
8
9
|
import { resultsSlice } from './results';
|
|
9
10
|
import { rootSaga } from './sagas';
|
|
@@ -18,6 +19,7 @@ export const store = configureStore({
|
|
|
18
19
|
board: boardSlice.reducer,
|
|
19
20
|
cellFilters: cellFiltersSlice.reducer,
|
|
20
21
|
dictionary: dictionarySlice.reducer,
|
|
22
|
+
hoveredTile: hoveredTileSlice.reducer,
|
|
21
23
|
rack: rackSlice.reducer,
|
|
22
24
|
results: resultsSlice.reducer,
|
|
23
25
|
settings: settingsSlice.reducer,
|
package/src/state/types.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BoardState } from './board';
|
|
2
2
|
import type { CellFiltersState } from './cellFilters';
|
|
3
3
|
import type { DictionaryState } from './dictionary';
|
|
4
|
+
import type { HoveredTileState } from './hoveredTile';
|
|
4
5
|
import type { RackState } from './rack';
|
|
5
6
|
import type { ResultsState } from './results';
|
|
6
7
|
import type { SettingsState } from './settings';
|
|
@@ -11,6 +12,7 @@ export type RootState = {
|
|
|
11
12
|
board: BoardState;
|
|
12
13
|
cellFilters: CellFiltersState;
|
|
13
14
|
dictionary: DictionaryState;
|
|
15
|
+
hoveredTile: HoveredTileState;
|
|
14
16
|
rack: RackState;
|
|
15
17
|
results: ResultsState;
|
|
16
18
|
settings: SettingsState;
|
package/src/types/index.ts
CHANGED
|
@@ -89,6 +89,8 @@ export type TranslationKey =
|
|
|
89
89
|
| 'common.blanks'
|
|
90
90
|
| 'common.consonants'
|
|
91
91
|
| 'common.next'
|
|
92
|
+
| 'common.off'
|
|
93
|
+
| 'common.on'
|
|
92
94
|
| 'common.points'
|
|
93
95
|
| 'common.previous'
|
|
94
96
|
| 'common.space'
|
|
@@ -140,6 +142,7 @@ export type TranslationKey =
|
|
|
140
142
|
| 'settings.autoGroupTiles.right'
|
|
141
143
|
| 'settings.autoGroupTiles.null'
|
|
142
144
|
| 'settings.game'
|
|
145
|
+
| 'settings.highlightUnreachableCells'
|
|
143
146
|
| 'settings.inputMode'
|
|
144
147
|
| 'settings.inputMode.keyboard'
|
|
145
148
|
| 'settings.inputMode.touchscreen'
|