@scrabble-solver/scrabble-solver 2.17.0 → 2.18.1
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 +22 -20
- 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/diagnostics/framework.json +1 -1
- package/.next/dynamic-css-manifest.json +8 -1
- package/.next/next-minimal-server.js.nft.json +1 -1
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +4 -4
- package/.next/react-loadable-manifest.json +176 -1
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/309.js +1 -0
- package/.next/server/chunks/{785.js → 316.js} +1 -1
- package/.next/server/chunks/344.js +1 -0
- package/.next/server/chunks/371.js +1 -0
- package/.next/server/chunks/465.js +1 -0
- package/.next/server/chunks/546.js +1 -0
- package/.next/server/chunks/623.js +1 -0
- package/.next/server/chunks/624.js +1 -0
- package/.next/server/chunks/641.js +1 -0
- package/.next/server/chunks/671.js +1 -1
- package/.next/server/chunks/692.js +1 -0
- package/.next/server/chunks/705.js +1 -0
- package/.next/server/chunks/712.js +1 -1
- package/.next/server/chunks/846.js +1 -0
- package/.next/server/chunks/853.js +15 -0
- package/.next/server/chunks/886.js +1 -0
- package/.next/server/chunks/916.js +1 -0
- package/.next/server/chunks/953.js +1 -0
- package/.next/server/chunks/961.js +1 -0
- package/.next/server/chunks/968.js +1 -0
- package/.next/server/dynamic-css-manifest.js +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/404.html +29 -1
- package/.next/server/pages/500.html +29 -1
- package/.next/server/pages/_app.js +1 -1
- package/.next/server/pages/_app.js.nft.json +1 -1
- package/.next/server/pages/_document.js +28 -1
- package/.next/server/pages/_document.js.nft.json +1 -1
- package/.next/server/pages/_error.js +28 -1
- package/.next/server/pages/_error.js.nft.json +1 -1
- package/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
- package/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
- package/.next/server/pages/api/solve.js +1 -1
- package/.next/server/pages/api/solve.js.nft.json +1 -1
- package/.next/server/pages/api/verify.js.nft.json +1 -1
- package/.next/server/pages/api/visit.js.nft.json +1 -1
- package/.next/server/pages/index.html +29 -1
- package/.next/server/pages/index.js +30 -1
- package/.next/server/pages/index.js.nft.json +1 -1
- package/.next/server/pages/index.json +1 -1
- package/.next/server/pages/not-found.html +29 -1
- package/.next/server/pages/not-found.js.nft.json +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/server/webpack-api-runtime.js +1 -1
- package/.next/server/webpack-runtime.js +1 -1
- package/.next/static/5KOWzYqfY1Z2rjrzptr8D/_buildManifest.js +1 -0
- package/.next/static/chunks/101-829ab8a8d310e7a0.js +3 -0
- package/.next/static/chunks/106.e414e88694add27f.js +1 -0
- package/.next/static/chunks/127.125d896a19061d71.js +1 -0
- package/.next/static/chunks/18.8b91e137d239e15c.js +1 -0
- package/.next/static/chunks/277.6785dfaf22fdb0b7.js +1 -0
- package/.next/static/chunks/307.67f52f13e3d60d4e.js +1 -0
- package/.next/static/chunks/341.79535ba85bf1986f.js +1 -0
- package/.next/static/chunks/363.01eed3233f92b6a4.js +1 -0
- package/.next/static/chunks/422.1559ae6756912ca5.js +1 -0
- package/.next/static/chunks/541.dcd9e8b804f88da5.js +1 -0
- package/.next/static/chunks/631.98d42abad0a60af6.js +1 -0
- package/.next/static/chunks/663.d2c9ca36b26695b8.js +1 -0
- package/.next/static/chunks/711.ba7b8f900dfd40d0.js +1 -0
- package/.next/static/chunks/744.b06c9a3de4a1d877.js +1 -0
- package/.next/static/chunks/820.97b82f751ca49579.js +1 -0
- package/.next/static/chunks/865.a9b563a45848a83c.js +1 -0
- package/.next/static/chunks/912.ff8037ba9d4db5c8.js +1 -0
- package/.next/static/chunks/939.19b33a3d3c351d73.js +1 -0
- package/.next/static/chunks/990.61296e5870b91f11.js +1 -0
- package/.next/static/chunks/framework-626cbd48ac5aca57.js +1 -0
- package/.next/static/chunks/main-b92e08f3fc96dd8d.js +5 -0
- package/.next/static/chunks/pages/_app-2e607dcd4135f340.js +1 -0
- package/.next/static/chunks/pages/{_error-afeda7c5231b6c3c.js → _error-f0290a98eb3ed0ec.js} +1 -1
- package/.next/static/chunks/pages/index-e0087247c995328d.js +1 -0
- package/.next/static/chunks/pages/not-found-a59f9deeeff63d17.js +1 -0
- package/.next/static/chunks/webpack-cfb34d175e081981.js +1 -0
- package/.next/static/css/2d03f0da2c678dfc.css +1 -0
- package/.next/static/css/4dbcacc1122ac6b9.css +2 -0
- package/.next/static/css/7b6724d2df70f48f.css +1 -0
- package/.next/static/css/b736be3bd02b5d99.css +1 -0
- package/.next/static/css/b74cd7de82dabcdd.css +1 -0
- package/.next/static/css/c403ce739a9c0d83.css +1 -0
- package/.next/static/css/ca311e6c030663d4.css +1 -0
- package/.next/static/css/dee878eb64099d92.css +1 -0
- package/.next/static/css/fbfdce70731d0d2b.css +1 -0
- package/.next/trace +21 -21
- package/.next/trace-build +1 -1
- package/empty-module.js +2 -0
- package/next.config.js +13 -2
- package/package.json +43 -17
- package/public/llms.txt +11 -0
- package/public/robots.txt +5 -0
- package/public/site.webmanifest +14 -0
- package/scripts/generate-scss-types.ts +112 -0
- package/src/@types/scss.d.ts +6 -9
- package/src/@types/svg.d.ts +1 -1
- package/src/components/Alert/Alert.module.scss.d.ts +13 -0
- package/src/components/Alert/Alert.tsx +4 -1
- package/src/components/Badge/Badge.module.scss.d.ts +6 -0
- package/src/components/Board/Board.module.scss +10 -0
- package/src/components/Board/Board.module.scss.d.ts +17 -0
- package/src/components/Board/Board.tsx +14 -26
- package/src/components/Board/BoardPure.tsx +54 -49
- package/src/components/Board/components/Actions/Actions.module.scss +18 -18
- package/src/components/Board/components/Actions/Actions.module.scss.d.ts +7 -0
- package/src/components/Board/components/Actions/Actions.tsx +6 -3
- package/src/components/Board/components/Actions/lib.ts +3 -1
- package/src/components/Board/components/Cell/Cell.module.scss.d.ts +13 -0
- package/src/components/Board/components/Cell/Cell.tsx +28 -33
- package/src/components/Board/components/InputPrompt/InputPrompt.module.scss.d.ts +10 -0
- package/src/components/Board/components/InputPrompt/InputPrompt.tsx +1 -1
- package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.module.scss.d.ts +8 -0
- package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.tsx +2 -2
- package/src/components/Board/getBoardBackground.ts +175 -0
- package/src/components/Board/hooks/index.ts +0 -1
- package/src/components/Board/hooks/useBoardStyle.ts +10 -20
- package/src/components/Board/hooks/useFloatingActions.ts +3 -6
- package/src/components/Board/hooks/useGrid.ts +6 -3
- package/src/components/Board/selectors.ts +1 -1
- package/src/components/Button/Button.module.scss.d.ts +12 -0
- package/src/components/Dictionary/Dictionary.module.scss +1 -0
- package/src/components/Dictionary/Dictionary.module.scss.d.ts +14 -0
- package/src/components/Dictionary/Dictionary.tsx +1 -3
- package/src/components/DictionaryInput/DictionaryInput.module.scss.d.ts +7 -0
- package/src/components/DictionaryInput/DictionaryInput.tsx +1 -1
- package/src/components/EmptyState/EmptyState.module.scss.d.ts +7 -0
- package/src/components/EmptyState/EmptyState.tsx +1 -1
- package/src/components/IconButton/IconButton.module.scss.d.ts +8 -0
- package/src/components/Key/Key.module.scss.d.ts +6 -0
- package/src/components/Keys/Arrows/Arrows.module.scss.d.ts +11 -0
- package/src/components/Keys/Arrows/Arrows.tsx +4 -1
- package/src/components/Keys/index.tsx +1 -1
- package/src/components/Loading/Loading.module.scss.d.ts +9 -0
- package/src/components/Loading/Loading.tsx +1 -1
- package/src/components/Logo/Logo.tsx +4 -9
- package/src/components/Logo/LogoBlueprint.tsx +1 -0
- package/src/components/Modal/Modal.module.scss.d.ts +15 -0
- package/src/components/Modal/Modal.tsx +16 -3
- package/src/components/Modal/components/Section/Section.module.scss.d.ts +7 -0
- package/src/components/NavButtons/NavButtons.module.scss +20 -0
- package/src/components/NavButtons/NavButtons.module.scss.d.ts +13 -0
- package/src/components/NavButtons/NavButtons.tsx +29 -45
- package/src/components/NotFound/NotFound.module.scss.d.ts +9 -0
- package/src/components/NotFound/NotFound.tsx +1 -1
- package/src/components/PlainTiles/PlainTiles.module.scss.d.ts +11 -0
- package/src/components/PlainTiles/PlainTiles.tsx +0 -1
- package/src/components/PlainTiles/Tile.tsx +3 -4
- package/src/components/PlainTiles/lib.ts +4 -19
- package/src/components/PlainTiles/types.ts +0 -1
- package/src/components/Progress/Progress.module.scss +7 -0
- package/src/components/Progress/Progress.module.scss.d.ts +6 -0
- package/src/components/Progress/Progress.tsx +2 -11
- package/src/components/Rack/Rack.module.scss +3 -0
- package/src/components/Rack/Rack.module.scss.d.ts +10 -0
- package/src/components/Rack/Rack.tsx +8 -11
- package/src/components/Rack/components/InputPrompt/InputPrompt.module.scss +2 -0
- package/src/components/Rack/components/InputPrompt/InputPrompt.module.scss.d.ts +7 -0
- package/src/components/Rack/components/InputPrompt/InputPrompt.tsx +1 -13
- package/src/components/Rack/components/InputPrompt/lib.ts +1 -1
- package/src/components/Rack/components/RackTile/RackTile.module.scss.d.ts +6 -0
- package/src/components/Rack/components/RackTile/RackTile.tsx +5 -4
- package/src/components/Rack/selectors.ts +1 -1
- package/src/components/Radio/Radio.module.scss.d.ts +12 -0
- package/src/components/Results/Cell.tsx +3 -12
- package/src/components/Results/Header.tsx +9 -18
- package/src/components/Results/HeaderButton.tsx +4 -5
- package/src/components/Results/Result.tsx +4 -12
- package/src/components/Results/Results.module.scss +4 -6
- package/src/components/Results/Results.module.scss.d.ts +27 -0
- package/src/components/Results/Results.tsx +4 -3
- package/src/components/Results/SolveButton.tsx +1 -1
- package/src/components/ResultsInput/ResultsInput.module.scss.d.ts +7 -0
- package/src/components/ResultsInput/ResultsInput.tsx +1 -1
- package/src/components/Solver/Solver.module.scss +6 -5
- package/src/components/Solver/Solver.module.scss.d.ts +20 -0
- package/src/components/Solver/Solver.tsx +19 -21
- package/src/components/Solver/components/InsertButton/InsertButton.module.scss.d.ts +7 -0
- package/src/components/Solver/components/InsertButton/InsertButton.tsx +1 -1
- package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss.d.ts +18 -0
- package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +3 -1
- package/src/components/Spinner/Spinner.module.scss.d.ts +10 -0
- package/src/components/Tile/Tile.module.scss +3 -0
- package/src/components/Tile/Tile.module.scss.d.ts +19 -0
- package/src/components/Tile/Tile.tsx +5 -14
- package/src/components/Tile/TilePure.tsx +2 -12
- package/src/components/Tooltip/Tooltip.module.scss.d.ts +7 -0
- package/src/components/Tooltip/Tooltip.tsx +14 -3
- package/src/components/Tooltip/useTooltip.ts +1 -0
- package/src/hooks/useColumns.ts +4 -7
- package/src/hooks/useDeferredRender.ts +20 -0
- package/src/hooks/useDirection.ts +4 -3
- package/src/hooks/useLanguage.ts +2 -2
- package/src/hooks/useLocalStorage.ts +32 -8
- package/src/hooks/useMedia.ts +26 -26
- package/src/i18n/constants.ts +2 -15
- package/src/i18n/i18n.ts +18 -17
- package/src/i18n/languages/english.json +0 -1
- package/src/i18n/languages/french.json +0 -1
- package/src/i18n/languages/german.json +0 -1
- package/src/i18n/languages/persian.json +0 -1
- package/src/i18n/languages/polish.json +0 -1
- package/src/i18n/languages/romanian.json +0 -1
- package/src/i18n/languages/spanish.json +0 -1
- package/src/i18n/languages/turkish.json +0 -1
- package/src/i18n/localeIcons.ts +24 -0
- package/src/lib/localeTransliterate.test.ts +5 -0
- package/src/lib/localeTransliterate.ts +26 -6
- package/src/lib/waitForIdleOrFirstIntent.ts +44 -0
- package/src/modals/DictionaryModal/DictionaryModal.module.scss.d.ts +8 -0
- package/src/modals/DictionaryModal/DictionaryModal.tsx +3 -1
- package/src/modals/KeyMapModal/KeyMapModal.tsx +3 -1
- package/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss.d.ts +11 -0
- package/src/modals/MenuModal/MenuModal.module.scss +5 -0
- package/src/modals/MenuModal/MenuModal.module.scss.d.ts +10 -0
- package/src/modals/MenuModal/MenuModal.tsx +16 -5
- package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss +4 -1
- package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss.d.ts +9 -0
- package/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +4 -6
- package/src/modals/RemainingTilesModal/components/Character/Character.module.scss +1 -0
- package/src/modals/RemainingTilesModal/components/Character/Character.module.scss.d.ts +12 -0
- package/src/modals/RemainingTilesModal/components/Character/Character.tsx +5 -12
- package/src/modals/ResultsModal/ResultsModal.module.scss.d.ts +8 -0
- package/src/modals/ResultsModal/ResultsModal.tsx +8 -4
- package/src/modals/SettingsModal/SettingsModal.tsx +2 -2
- package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.module.scss.d.ts +7 -0
- package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +1 -1
- package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.module.scss.d.ts +7 -0
- package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +1 -1
- package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.module.scss.d.ts +7 -0
- package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.tsx +1 -1
- package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.module.scss.d.ts +7 -0
- package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.tsx +1 -1
- package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss.d.ts +8 -0
- package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +24 -21
- package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.module.scss.d.ts +7 -0
- package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.tsx +1 -1
- package/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.module.scss.d.ts +7 -0
- package/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.tsx +1 -5
- package/src/modals/WordsModal/WordsModal.module.scss.d.ts +11 -0
- package/src/modals/WordsModal/WordsModal.tsx +4 -2
- package/src/modals/preload.ts +24 -0
- package/src/pages/_app.tsx +37 -76
- package/src/pages/_document.tsx +112 -24
- package/src/pages/api/solve.ts +1 -1
- package/src/pages/index.module.scss +1 -0
- package/src/pages/index.module.scss.d.ts +11 -0
- package/src/pages/index.tsx +127 -40
- package/src/pages/not-found.tsx +14 -3
- package/src/parameters/index.ts +31 -93
- package/src/serviceWorkerManager.ts +5 -2
- package/src/state/actions.ts +1 -1
- package/src/state/app/index.ts +4 -0
- package/src/state/app/initialState.ts +6 -0
- package/src/state/app/selectors.ts +5 -0
- package/src/state/app/slice.ts +20 -0
- package/src/state/app/types.ts +4 -0
- package/src/state/board/initialState.ts +1 -2
- package/src/state/i18n/index.ts +4 -0
- package/src/state/i18n/initialState.ts +5 -0
- package/src/state/i18n/selectors.ts +3 -0
- package/src/state/i18n/slice.ts +16 -0
- package/src/state/i18n/types.ts +7 -0
- package/src/state/index.ts +2 -0
- package/src/state/lib.ts +1 -1
- package/src/state/localStorage.ts +86 -29
- package/src/state/rack/initialState.ts +1 -2
- package/src/state/rack/slice.ts +4 -1
- package/src/state/results/lib.ts +5 -5
- package/src/state/results/selectors.ts +1 -1
- package/src/state/sagas.ts +125 -9
- package/src/state/selectors.ts +1 -1
- package/src/state/settings/initialState.ts +7 -10
- package/src/state/settings/selectors.ts +7 -2
- package/src/state/settings/slice.ts +5 -2
- package/src/state/store.ts +4 -0
- package/src/state/types.ts +4 -0
- package/src/styles/_tokens.scss +1 -0
- package/src/styles/global.scss +9 -0
- package/src/styles/variables.module.scss +0 -21
- package/src/styles/variables.module.scss.d.ts +27 -0
- package/src/styles/variables.scss +46 -2
- package/src/types/index.ts +1 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/.next/server/chunks/129.js +0 -1
- package/.next/server/chunks/318.js +0 -3
- package/.next/server/chunks/791.js +0 -15
- package/.next/static/OLE8_ZInlGH7ENU0NIOpf/_buildManifest.js +0 -1
- package/.next/static/chunks/830.661816bf0de8c2f1.js +0 -1
- package/.next/static/chunks/framework-3cf15b8041c59dd3.js +0 -1
- package/.next/static/chunks/main-5b999f3f24ebfa84.js +0 -5
- package/.next/static/chunks/pages/_app-7024e7a27ffbb2fa.js +0 -7
- package/.next/static/chunks/pages/index-8b398b0a5d870773.js +0 -1
- package/.next/static/chunks/pages/not-found-9e076427bad69d90.js +0 -1
- package/.next/static/chunks/webpack-3943d624bbb47a64.js +0 -1
- package/.next/static/css/a78e04fe95452380.css +0 -1
- package/.next/static/css/aedeaada218d7280.css +0 -2
- package/src/app-layout/AppLayoutContext.tsx +0 -25
- package/src/app-layout/index.ts +0 -1
- package/src/app-layout/useAppLayoutValue.ts +0 -112
- package/src/components/Board/hooks/useBackgroundImage.tsx +0 -279
- package/src/components/SeoMessage/SeoMessage.tsx +0 -18
- package/src/components/SeoMessage/index.ts +0 -1
- package/src/components/index.ts +0 -26
- package/src/hooks/index.ts +0 -12
- package/src/hooks/useOnWindowResize.ts +0 -11
- package/src/hooks/useViewportSize.ts +0 -17
- package/src/i18n/index.ts +0 -2
- package/src/icons/Flag.svg +0 -4
- package/src/icons/Star.svg +0 -4
- package/src/icons/index.ts +0 -49
- package/src/lib/getTileSizes.ts +0 -13
- package/src/lib/index.ts +0 -24
- package/src/modals/index.ts +0 -7
- /package/.next/static/{OLE8_ZInlGH7ENU0NIOpf → 5KOWzYqfY1Z2rjrzptr8D}/_ssgManifest.js +0 -0
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import { Board, type BoardJson } from '@scrabble-solver/types';
|
|
1
|
+
import { Board, type BoardJson, isObject, type Locale } from '@scrabble-solver/types';
|
|
2
2
|
import store2 from 'store2';
|
|
3
3
|
|
|
4
|
-
import type { Rack } from '@/types';
|
|
4
|
+
import type { Rack, Translations } from '@/types';
|
|
5
5
|
|
|
6
6
|
import type { SettingsState } from './settings/types';
|
|
7
7
|
|
|
8
8
|
const BOARD = 'board';
|
|
9
9
|
const RACK = 'rack';
|
|
10
10
|
const SETTINGS = 'settings';
|
|
11
|
+
const TRANSLATIONS = 'translations';
|
|
12
|
+
|
|
13
|
+
interface PersistedTranslations {
|
|
14
|
+
locale: Locale;
|
|
15
|
+
translations: Translations;
|
|
16
|
+
version: string;
|
|
17
|
+
}
|
|
11
18
|
|
|
12
19
|
const LEGACY_KEYS: Record<keyof SettingsState, string> = {
|
|
13
20
|
autoGroupTiles: 'auto-group-tiles',
|
|
@@ -21,33 +28,15 @@ const LEGACY_KEYS: Record<keyof SettingsState, string> = {
|
|
|
21
28
|
|
|
22
29
|
const store = store2.namespace('scrabble-solver');
|
|
23
30
|
|
|
24
|
-
/**
|
|
25
|
-
* Introduced in 2.15.26 on 2026/04/27.
|
|
26
|
-
* Life expectancy: 1y.
|
|
27
|
-
*/
|
|
28
|
-
const migrateLegacySettings = (): Partial<SettingsState> => {
|
|
29
|
-
const settings: Partial<SettingsState> = {};
|
|
30
|
-
let hasLegacy = false;
|
|
31
|
-
|
|
32
|
-
for (const [setting, legacyKey] of Object.entries(LEGACY_KEYS) as [keyof SettingsState, string][]) {
|
|
33
|
-
if (store.has(legacyKey)) {
|
|
34
|
-
settings[setting] = store.get(legacyKey);
|
|
35
|
-
store.remove(legacyKey);
|
|
36
|
-
hasLegacy = true;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (hasLegacy) {
|
|
41
|
-
store.set(SETTINGS, settings, true);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return settings;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
31
|
export const localStorage = {
|
|
48
32
|
getBoard(): Board | undefined {
|
|
49
|
-
|
|
50
|
-
|
|
33
|
+
try {
|
|
34
|
+
const serialized = store.get(BOARD) as string | undefined;
|
|
35
|
+
return serialized ? Board.fromJson(JSON.parse(serialized) as BoardJson) : undefined;
|
|
36
|
+
} catch {
|
|
37
|
+
store.remove(BOARD);
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
51
40
|
},
|
|
52
41
|
|
|
53
42
|
setBoard(board: Board | undefined): void {
|
|
@@ -56,7 +45,14 @@ export const localStorage = {
|
|
|
56
45
|
},
|
|
57
46
|
|
|
58
47
|
getRack(): Rack | undefined {
|
|
59
|
-
|
|
48
|
+
const rack = store.get(RACK) as Rack | undefined;
|
|
49
|
+
|
|
50
|
+
if (rack !== undefined && !Array.isArray(rack)) {
|
|
51
|
+
store.remove(RACK);
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return rack;
|
|
60
56
|
},
|
|
61
57
|
|
|
62
58
|
setRack(rack: Rack | undefined): void {
|
|
@@ -65,10 +61,71 @@ export const localStorage = {
|
|
|
65
61
|
|
|
66
62
|
getSettings(): Partial<SettingsState> {
|
|
67
63
|
const stored = store.get(SETTINGS) as Partial<SettingsState> | undefined;
|
|
68
|
-
|
|
64
|
+
|
|
65
|
+
if (stored !== undefined && !isObject(stored)) {
|
|
66
|
+
store.remove(SETTINGS);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return migrateHiddenShowCoordinates(isObject(stored) ? stored : migrateLegacySettings());
|
|
69
70
|
},
|
|
70
71
|
|
|
71
72
|
setSettings(settings: SettingsState): void {
|
|
72
73
|
store.set(SETTINGS, settings, true);
|
|
73
74
|
},
|
|
75
|
+
|
|
76
|
+
getTranslations(locale: Locale, version: string): Translations | undefined {
|
|
77
|
+
const stored = store.get(TRANSLATIONS) as PersistedTranslations | undefined;
|
|
78
|
+
|
|
79
|
+
if (typeof stored === 'undefined') {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!isObject(stored) || stored.locale !== locale || stored.version !== version || !isObject(stored.translations)) {
|
|
84
|
+
store.remove(TRANSLATIONS);
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return stored.translations;
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
setTranslations(locale: Locale, version: string, translations: Translations): void {
|
|
92
|
+
store.set(TRANSLATIONS, { locale, translations, version } satisfies PersistedTranslations, true);
|
|
93
|
+
},
|
|
74
94
|
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Introduced in 2.15.26 on 2026/04/27.
|
|
98
|
+
* Life expectancy: 1y.
|
|
99
|
+
*/
|
|
100
|
+
function migrateLegacySettings(): Partial<SettingsState> {
|
|
101
|
+
const settings: Partial<SettingsState> = {};
|
|
102
|
+
let hasLegacy = false;
|
|
103
|
+
|
|
104
|
+
for (const [setting, legacyKey] of Object.entries(LEGACY_KEYS) as [keyof SettingsState, string][]) {
|
|
105
|
+
if (store.has(legacyKey)) {
|
|
106
|
+
settings[setting] = store.get(legacyKey);
|
|
107
|
+
store.remove(legacyKey);
|
|
108
|
+
hasLegacy = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (hasLegacy) {
|
|
113
|
+
store.set(SETTINGS, settings, true);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return settings;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The 'hidden' showCoordinates option was removed on 2026/08/13.
|
|
121
|
+
* Life expectancy: 1y.
|
|
122
|
+
*/
|
|
123
|
+
function migrateHiddenShowCoordinates(settings: Partial<SettingsState>): Partial<SettingsState> {
|
|
124
|
+
if (String(settings.showCoordinates) !== 'hidden') {
|
|
125
|
+
return settings;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const migrated: Partial<SettingsState> = { ...settings, showCoordinates: 'original' };
|
|
129
|
+
store.set(SETTINGS, migrated, true);
|
|
130
|
+
return migrated;
|
|
131
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { getConfig } from '@scrabble-solver/configs';
|
|
2
2
|
|
|
3
|
-
import { localStorage } from '../localStorage';
|
|
4
3
|
import { settingsInitialState } from '../settings';
|
|
5
4
|
|
|
6
5
|
import type { RackState } from './types';
|
|
@@ -9,4 +8,4 @@ const defaultConfig = getConfig(settingsInitialState.game, settingsInitialState.
|
|
|
9
8
|
|
|
10
9
|
export const rackDefaultState: RackState = Array(defaultConfig.rackSize).fill(null);
|
|
11
10
|
|
|
12
|
-
export const rackInitialState: RackState =
|
|
11
|
+
export const rackInitialState: RackState = rackDefaultState;
|
package/src/state/rack/slice.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
|
2
2
|
import { type Tile } from '@scrabble-solver/types';
|
|
3
3
|
|
|
4
|
-
import { arrayEquals
|
|
4
|
+
import { arrayEquals } from '@/lib/arrayEquals';
|
|
5
|
+
import { createNullMovingComparator } from '@/lib/createNullMovingComparator';
|
|
6
|
+
import { inverseDirection } from '@/lib/inverseDirection';
|
|
7
|
+
import { zipCharactersAndTiles } from '@/lib/zipCharactersAndTiles';
|
|
5
8
|
import { type AutoGroupTiles, type Rack } from '@/types';
|
|
6
9
|
|
|
7
10
|
import { rackDefaultState, rackInitialState } from './initialState';
|
package/src/state/results/lib.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { type Result, type ShowCoordinates } from '@scrabble-solver/types';
|
|
2
2
|
|
|
3
|
-
import { createKeyComparator
|
|
3
|
+
import { createKeyComparator } from '@/lib/createKeyComparator';
|
|
4
|
+
import { createRegExp } from '@/lib/createRegExp';
|
|
5
|
+
import { createStringComparator } from '@/lib/createStringComparator';
|
|
6
|
+
import { getCoordinate } from '@/lib/getCoordinate';
|
|
7
|
+
import { reverseComparator } from '@/lib/reverseComparator';
|
|
4
8
|
import {
|
|
5
9
|
type CellFilter,
|
|
6
10
|
type Comparator,
|
|
@@ -11,10 +15,6 @@ import {
|
|
|
11
15
|
} from '@/types';
|
|
12
16
|
|
|
13
17
|
export const getCoordinates = (result: Result, showCoordinates: ShowCoordinates): string => {
|
|
14
|
-
if (showCoordinates === 'hidden') {
|
|
15
|
-
return '';
|
|
16
|
-
}
|
|
17
|
-
|
|
18
18
|
const firstCell = result.cells[0];
|
|
19
19
|
const x = getCoordinate(firstCell.x, showCoordinates === 'original' ? 'letter' : 'number');
|
|
20
20
|
const y = getCoordinate(firstCell.y, showCoordinates === 'original' ? 'number' : 'letter');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createSelector } from '@reduxjs/toolkit';
|
|
2
2
|
|
|
3
|
-
import { createRegExp } from '@/lib';
|
|
3
|
+
import { createRegExp } from '@/lib/createRegExp';
|
|
4
4
|
|
|
5
5
|
import { selectCellFilters } from '../cellFilters';
|
|
6
6
|
import { selectLocale, selectShowCoordinates } from '../settings';
|
package/src/state/sagas.ts
CHANGED
|
@@ -5,18 +5,23 @@
|
|
|
5
5
|
|
|
6
6
|
import { type PayloadAction } from '@reduxjs/toolkit';
|
|
7
7
|
import { hasConfig, languages } from '@scrabble-solver/configs';
|
|
8
|
-
import { Board,
|
|
8
|
+
import { Board, Locale, type Result } from '@scrabble-solver/types';
|
|
9
9
|
import { call, delay, put, select, spawn, takeEvery, takeLatest } from 'redux-saga/effects';
|
|
10
10
|
|
|
11
|
-
import { LOCALE_FEATURES } from '@/i18n';
|
|
12
|
-
import {
|
|
11
|
+
import { LOCALE_FEATURES } from '@/i18n/constants';
|
|
12
|
+
import { loadTranslations } from '@/i18n/i18n';
|
|
13
|
+
import { memoize } from '@/lib/memoize';
|
|
14
|
+
import { waitForFirstIntent, waitForIdleOrFirstIntent } from '@/lib/waitForIdleOrFirstIntent';
|
|
13
15
|
import { findWordDefinitions, solve, verify, visit } from '@/sdk';
|
|
14
16
|
import { prefetchDictionary } from '@/solver-worker';
|
|
15
17
|
|
|
16
18
|
import { initialize, reset } from './actions';
|
|
19
|
+
import { appSlice, selectVersion } from './app';
|
|
17
20
|
import { boardSlice, selectBoard } from './board';
|
|
18
21
|
import { cellFiltersSlice, selectCellFilter } from './cellFilters';
|
|
19
22
|
import { dictionarySlice, selectDictionary } from './dictionary';
|
|
23
|
+
import { i18nSlice, selectLoadedTranslations } from './i18n';
|
|
24
|
+
import { localStorage } from './localStorage';
|
|
20
25
|
import { rackSlice, selectCharacters, selectRack } from './rack';
|
|
21
26
|
import { resultsSlice } from './results';
|
|
22
27
|
import {
|
|
@@ -25,8 +30,11 @@ import {
|
|
|
25
30
|
selectLocale,
|
|
26
31
|
selectLocaleAutoGroupTiles,
|
|
27
32
|
selectRemoveCellFilters,
|
|
33
|
+
settingsInitialState,
|
|
28
34
|
settingsSlice,
|
|
35
|
+
type SettingsState,
|
|
29
36
|
} from './settings';
|
|
37
|
+
import { guessLocale } from './settings/lib';
|
|
30
38
|
import { solveSlice } from './solve';
|
|
31
39
|
import { verifySlice } from './verify';
|
|
32
40
|
|
|
@@ -119,13 +127,22 @@ function* onDictionarySubmit(): AnyGenerator {
|
|
|
119
127
|
}
|
|
120
128
|
}
|
|
121
129
|
|
|
122
|
-
function* onInitialize(): AnyGenerator {
|
|
130
|
+
function* onInitialize({ payload }: PayloadAction<{ version: string }>): AnyGenerator {
|
|
131
|
+
try {
|
|
132
|
+
yield* hydratePersistedState(payload.version);
|
|
133
|
+
// oxlint-disable-next-line no-empty
|
|
134
|
+
} catch {
|
|
135
|
+
} finally {
|
|
136
|
+
yield put(appSlice.actions.hydrated());
|
|
137
|
+
}
|
|
138
|
+
|
|
123
139
|
const board = yield select(selectBoard);
|
|
124
140
|
const locale = yield select(selectLocale);
|
|
125
141
|
|
|
126
|
-
yield spawn(
|
|
127
|
-
|
|
128
|
-
yield spawn(
|
|
142
|
+
yield spawn(prefetchDictionaryOnFirstIntent);
|
|
143
|
+
yield spawn(loadLocaleTranslations, locale);
|
|
144
|
+
yield spawn(preloadTranslationsWhenIdle);
|
|
145
|
+
yield spawn(visitWhenIdle);
|
|
129
146
|
|
|
130
147
|
if (!board.isEmpty()) {
|
|
131
148
|
yield* resetRack();
|
|
@@ -133,6 +150,100 @@ function* onInitialize(): AnyGenerator {
|
|
|
133
150
|
}
|
|
134
151
|
}
|
|
135
152
|
|
|
153
|
+
function* hydratePersistedState(version: string): AnyGenerator {
|
|
154
|
+
const isTouchScreen = globalThis.matchMedia?.('(hover: none)').matches ?? false;
|
|
155
|
+
const settings: Pick<SettingsState, 'game' | 'inputMode' | 'locale'> & Partial<SettingsState> = {
|
|
156
|
+
game: settingsInitialState.game,
|
|
157
|
+
inputMode: isTouchScreen ? ('touchscreen' as const) : ('keyboard' as const),
|
|
158
|
+
locale: guessLocale(),
|
|
159
|
+
...localStorage.getSettings(),
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
if (!hasConfig(settings.game, settings.locale)) {
|
|
163
|
+
const localeDefault = Object.values(languages).find((config) => config.locale === settings.locale);
|
|
164
|
+
settings.game = localeDefault?.game ?? settingsInitialState.game;
|
|
165
|
+
settings.locale = localeDefault?.locale ?? guessLocale();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
yield put(settingsSlice.actions.init(settings));
|
|
169
|
+
yield* hydratePersistedTranslations(settings.locale, version);
|
|
170
|
+
|
|
171
|
+
const config = yield select(selectConfig);
|
|
172
|
+
const currentBoard: Board = yield select(selectBoard);
|
|
173
|
+
const board = localStorage.getBoard();
|
|
174
|
+
|
|
175
|
+
if (board) {
|
|
176
|
+
yield put(boardSlice.actions.init(board));
|
|
177
|
+
} else if (currentBoard.rows.length !== config.boardHeight || currentBoard.rows[0].length !== config.boardWidth) {
|
|
178
|
+
yield put(boardSlice.actions.init(Board.create(config.boardWidth, config.boardHeight)));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const currentRack = yield select(selectRack);
|
|
182
|
+
const rack = localStorage.getRack();
|
|
183
|
+
|
|
184
|
+
if (rack) {
|
|
185
|
+
yield put(rackSlice.actions.init(rack));
|
|
186
|
+
} else if (currentRack.length !== config.rackSize) {
|
|
187
|
+
yield put(rackSlice.actions.init(Array(config.rackSize).fill(null)));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Applied synchronously so the first post-hydration paint is already translated
|
|
192
|
+
function* hydratePersistedTranslations(locale: Locale, version: string): AnyGenerator {
|
|
193
|
+
const translations = localStorage.getTranslations(locale, version);
|
|
194
|
+
|
|
195
|
+
if (translations) {
|
|
196
|
+
yield put(i18nSlice.actions.loaded({ locale, translations }));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function* visitWhenIdle(): AnyGenerator {
|
|
201
|
+
yield call(waitForIdleOrFirstIntent);
|
|
202
|
+
yield call(visit);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function* prefetchDictionaryOnFirstIntent(): AnyGenerator {
|
|
206
|
+
yield call(waitForFirstIntent);
|
|
207
|
+
const locale = yield select(selectLocale);
|
|
208
|
+
yield call(prefetchDictionary, locale);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function* loadLocaleTranslations(locale: Locale): AnyGenerator {
|
|
212
|
+
const loaded = yield select(selectLoadedTranslations);
|
|
213
|
+
|
|
214
|
+
if (loaded[locale]) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const translations = yield call(loadTranslations, locale);
|
|
219
|
+
yield put(i18nSlice.actions.loaded({ locale, translations }));
|
|
220
|
+
|
|
221
|
+
const activeLocale = yield select(selectLocale);
|
|
222
|
+
|
|
223
|
+
if (locale === activeLocale) {
|
|
224
|
+
const version = yield select(selectVersion);
|
|
225
|
+
localStorage.setTranslations(locale, version, translations);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// The cache makes the next boot's first paint translated without waiting for a chunk download
|
|
230
|
+
function* persistTranslationsCache(locale: Locale): AnyGenerator {
|
|
231
|
+
const loaded = yield select(selectLoadedTranslations);
|
|
232
|
+
const version = yield select(selectVersion);
|
|
233
|
+
|
|
234
|
+
if (loaded[locale]) {
|
|
235
|
+
localStorage.setTranslations(locale, version, loaded[locale]);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function* preloadTranslationsWhenIdle(): AnyGenerator {
|
|
240
|
+
yield call(waitForIdleOrFirstIntent);
|
|
241
|
+
|
|
242
|
+
for (const locale of Object.values(Locale)) {
|
|
243
|
+
yield spawn(loadLocaleTranslations, locale);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
136
247
|
function* onReset(): AnyGenerator {
|
|
137
248
|
const config = yield select(selectConfig);
|
|
138
249
|
|
|
@@ -146,7 +257,9 @@ function* onReset(): AnyGenerator {
|
|
|
146
257
|
}
|
|
147
258
|
|
|
148
259
|
function* onLocaleChange({ payload: locale }: PayloadAction<Locale>): AnyGenerator {
|
|
260
|
+
yield spawn(loadLocaleTranslations, locale);
|
|
149
261
|
yield spawn(prefetchDictionary, locale);
|
|
262
|
+
yield* persistTranslationsCache(locale);
|
|
150
263
|
|
|
151
264
|
const game = yield select(selectGame);
|
|
152
265
|
|
|
@@ -176,11 +289,14 @@ function* onResultCandidateChange({ payload: result }: PayloadAction<Result | nu
|
|
|
176
289
|
return;
|
|
177
290
|
}
|
|
178
291
|
|
|
179
|
-
yield delay(SUBMIT_DELAY);
|
|
180
|
-
|
|
181
292
|
const locale: Locale = yield select(selectLocale);
|
|
182
293
|
const uniqueWords = Array.from(new Set(result.words));
|
|
183
294
|
const input = uniqueWords.join(LOCALE_FEATURES[locale].separator);
|
|
295
|
+
|
|
296
|
+
if (!memoizedFindWordDefinitions.hasCache(locale, input)) {
|
|
297
|
+
yield delay(SUBMIT_DELAY);
|
|
298
|
+
}
|
|
299
|
+
|
|
184
300
|
yield put(dictionarySlice.actions.changeInput(input));
|
|
185
301
|
yield put(dictionarySlice.actions.submit());
|
|
186
302
|
}
|
package/src/state/selectors.ts
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import { Game } from '@scrabble-solver/types';
|
|
1
|
+
import { Game, Locale } from '@scrabble-solver/types';
|
|
2
2
|
|
|
3
|
-
import { localStorage } from '../localStorage';
|
|
4
|
-
|
|
5
|
-
import { guessLocale } from './lib';
|
|
6
3
|
import type { SettingsState } from './types';
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Deterministic defaults shared by the server render and the client's hydration render.
|
|
7
|
+
*/
|
|
10
8
|
export const settingsInitialState: SettingsState = {
|
|
11
9
|
autoGroupTiles: null,
|
|
12
10
|
game: Game.Scrabble,
|
|
13
11
|
highlightUnreachableCells: false,
|
|
14
|
-
inputMode:
|
|
15
|
-
locale:
|
|
12
|
+
inputMode: 'keyboard',
|
|
13
|
+
locale: Locale.EN_US,
|
|
16
14
|
removeCellFilters: 'always',
|
|
17
|
-
showCoordinates: '
|
|
18
|
-
...localStorage.getSettings(),
|
|
15
|
+
showCoordinates: 'original',
|
|
19
16
|
};
|
|
@@ -3,8 +3,10 @@ import { getConfig } from '@scrabble-solver/configs';
|
|
|
3
3
|
import { BLANK } from '@scrabble-solver/constants';
|
|
4
4
|
import { type Cell, type Tile } from '@scrabble-solver/types';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { LOCALE_FEATURES } from '@/i18n/constants';
|
|
7
|
+
import { englishTranslations } from '@/i18n/i18n';
|
|
7
8
|
|
|
9
|
+
import { selectLoadedTranslations } from '../i18n';
|
|
8
10
|
import type { RootState } from '../types';
|
|
9
11
|
|
|
10
12
|
const selectCell = (_: unknown, cell: Cell): Cell => cell;
|
|
@@ -68,6 +70,9 @@ export const selectCellIsValid = createSelector([selectConfig, selectCell], (con
|
|
|
68
70
|
return config.tiles.some((tile) => tile.character === cell.tile.character);
|
|
69
71
|
});
|
|
70
72
|
|
|
71
|
-
export const selectTranslations = createSelector(
|
|
73
|
+
export const selectTranslations = createSelector(
|
|
74
|
+
[selectLocale, selectLoadedTranslations],
|
|
75
|
+
(locale, translations) => translations[locale] ?? englishTranslations,
|
|
76
|
+
);
|
|
72
77
|
|
|
73
78
|
export const selectRemoveCellFilters = createSelector([selectSettings], (settings) => settings.removeCellFilters);
|
|
@@ -44,8 +44,11 @@ export const settingsSlice = createSlice({
|
|
|
44
44
|
return { ...state, removeCellFilters };
|
|
45
45
|
},
|
|
46
46
|
|
|
47
|
-
init: (state, action: PayloadAction<Partial<
|
|
48
|
-
|
|
47
|
+
init: (state, action: PayloadAction<Partial<typeof settingsInitialState>>) => {
|
|
48
|
+
const settings = { ...state, ...action.payload };
|
|
49
|
+
const keys = Object.keys(settings) as (keyof typeof settingsInitialState)[];
|
|
50
|
+
const hasDiff = keys.some((key) => settings[key] !== state[key]);
|
|
51
|
+
return hasDiff ? settings : state;
|
|
49
52
|
},
|
|
50
53
|
},
|
|
51
54
|
});
|
package/src/state/store.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { configureStore } from '@reduxjs/toolkit';
|
|
2
2
|
import reduxSaga from 'redux-saga';
|
|
3
3
|
|
|
4
|
+
import { appSlice } from './app';
|
|
4
5
|
import { boardSlice } from './board';
|
|
5
6
|
import { cellFiltersSlice } from './cellFilters';
|
|
6
7
|
import { dictionarySlice } from './dictionary';
|
|
7
8
|
import { hoveredTileSlice } from './hoveredTile';
|
|
9
|
+
import { i18nSlice } from './i18n';
|
|
8
10
|
import { rackSlice } from './rack';
|
|
9
11
|
import { resultsSlice } from './results';
|
|
10
12
|
import { rootSaga } from './sagas';
|
|
@@ -16,10 +18,12 @@ const sagaMiddleware = reduxSaga();
|
|
|
16
18
|
|
|
17
19
|
export const store = configureStore({
|
|
18
20
|
reducer: {
|
|
21
|
+
app: appSlice.reducer,
|
|
19
22
|
board: boardSlice.reducer,
|
|
20
23
|
cellFilters: cellFiltersSlice.reducer,
|
|
21
24
|
dictionary: dictionarySlice.reducer,
|
|
22
25
|
hoveredTile: hoveredTileSlice.reducer,
|
|
26
|
+
i18n: i18nSlice.reducer,
|
|
23
27
|
rack: rackSlice.reducer,
|
|
24
28
|
results: resultsSlice.reducer,
|
|
25
29
|
settings: settingsSlice.reducer,
|
package/src/state/types.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { AppState } from './app';
|
|
1
2
|
import type { BoardState } from './board';
|
|
2
3
|
import type { CellFiltersState } from './cellFilters';
|
|
3
4
|
import type { DictionaryState } from './dictionary';
|
|
4
5
|
import type { HoveredTileState } from './hoveredTile';
|
|
6
|
+
import type { I18nState } from './i18n';
|
|
5
7
|
import type { RackState } from './rack';
|
|
6
8
|
import type { ResultsState } from './results';
|
|
7
9
|
import type { SettingsState } from './settings';
|
|
@@ -9,10 +11,12 @@ import type { SolveState } from './solve';
|
|
|
9
11
|
import type { VerifyState } from './verify';
|
|
10
12
|
|
|
11
13
|
export type RootState = {
|
|
14
|
+
app: AppState;
|
|
12
15
|
board: BoardState;
|
|
13
16
|
cellFilters: CellFiltersState;
|
|
14
17
|
dictionary: DictionaryState;
|
|
15
18
|
hoveredTile: HoveredTileState;
|
|
19
|
+
i18n: I18nState;
|
|
16
20
|
rack: RackState;
|
|
17
21
|
results: ResultsState;
|
|
18
22
|
settings: SettingsState;
|
package/src/styles/_tokens.scss
CHANGED
package/src/styles/global.scss
CHANGED
|
@@ -50,3 +50,12 @@ h4 {
|
|
|
50
50
|
nextjs-portal {
|
|
51
51
|
display: none;
|
|
52
52
|
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Added pre-paint by _document's inline script when the persisted game differs from the
|
|
56
|
+
* prerendered default board; removed after hydration applies the persisted config.
|
|
57
|
+
* The class name must match CONFIG_PENDING_CLASS in parameters/index.ts.
|
|
58
|
+
*/
|
|
59
|
+
html.config-pending main {
|
|
60
|
+
visibility: hidden;
|
|
61
|
+
}
|
|
@@ -7,23 +7,16 @@
|
|
|
7
7
|
breakpointL: strip-unit($breakpoint-l);
|
|
8
8
|
breakpointXl: strip-unit($breakpoint-xl);
|
|
9
9
|
|
|
10
|
-
borderColor: $border-color;
|
|
11
10
|
borderColorLight: $border-color-light;
|
|
12
|
-
borderRadius: strip-unit($border-radius);
|
|
13
11
|
borderWidth: strip-unit($border-width);
|
|
14
12
|
|
|
15
|
-
colorBlue: $color-blue;
|
|
16
13
|
colorBlueLight: $color-blue-light;
|
|
17
|
-
colorGreen: $color-green;
|
|
18
14
|
colorGreenLight: $color-green-light;
|
|
19
|
-
colorRed: $color-red;
|
|
20
15
|
colorRedLight: $color-red-light;
|
|
21
16
|
colorVioletLight: $color-violet-light;
|
|
22
|
-
colorYellow: $color-yellow;
|
|
23
17
|
colorYellowLight: $color-yellow-light;
|
|
24
18
|
|
|
25
19
|
colorBackground: $color-background;
|
|
26
|
-
colorForegroundSecondary: $color-foreground-secondary;
|
|
27
20
|
|
|
28
21
|
colorBonusCharacterMultiplier2: $color-bonus-character-multiplier-2;
|
|
29
22
|
colorBonusCharacterMultiplier3: $color-bonus-character-multiplier-3;
|
|
@@ -32,22 +25,8 @@
|
|
|
32
25
|
colorBonusWordMultiplier3: $color-bonus-word-multiplier-3;
|
|
33
26
|
colorBonusWordMultiplier4: $color-bonus-word-multiplier-4;
|
|
34
27
|
|
|
35
|
-
spacingXs: strip-unit($spacing-xs);
|
|
36
|
-
spacingS: strip-unit($spacing-s);
|
|
37
|
-
spacingM: strip-unit($spacing-m);
|
|
38
|
-
spacingL: strip-unit($spacing-l);
|
|
39
|
-
spacingXl: strip-unit($spacing-xl);
|
|
40
|
-
|
|
41
28
|
transitionDuration: strip-unit($transition-duration);
|
|
42
29
|
transitionDurationLong: strip-unit($transition-duration-long);
|
|
43
30
|
|
|
44
|
-
buttonIconSize: strip-unit($button-icon-size);
|
|
45
|
-
dictionaryHeight: strip-unit($dictionary-height);
|
|
46
|
-
dictionaryHeightMobile: strip-unit($dictionary-height-mobile);
|
|
47
|
-
logoHeight: strip-unit($logo-height);
|
|
48
|
-
logoHeightSmall: strip-unit($logo-height-small);
|
|
49
|
-
modalWidth: strip-unit($modal-width);
|
|
50
31
|
resultsItemHeight: strip-unit($results-item-height);
|
|
51
|
-
solverColumnWidth: strip-unit($solver-column-width);
|
|
52
|
-
textInputHeight: strip-unit($text-input-height);
|
|
53
32
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Generated by scripts/generate-scss-types.ts - do not edit.
|
|
2
|
+
declare const styles: {
|
|
3
|
+
readonly borderColorLight: string;
|
|
4
|
+
readonly borderWidth: string;
|
|
5
|
+
readonly breakpointL: string;
|
|
6
|
+
readonly breakpointM: string;
|
|
7
|
+
readonly breakpointS: string;
|
|
8
|
+
readonly breakpointXl: string;
|
|
9
|
+
readonly breakpointXs: string;
|
|
10
|
+
readonly colorBackground: string;
|
|
11
|
+
readonly colorBlueLight: string;
|
|
12
|
+
readonly colorBonusCharacterMultiplier2: string;
|
|
13
|
+
readonly colorBonusCharacterMultiplier3: string;
|
|
14
|
+
readonly colorBonusCharacterMultiplier4: string;
|
|
15
|
+
readonly colorBonusWordMultiplier2: string;
|
|
16
|
+
readonly colorBonusWordMultiplier3: string;
|
|
17
|
+
readonly colorBonusWordMultiplier4: string;
|
|
18
|
+
readonly colorGreenLight: string;
|
|
19
|
+
readonly colorRedLight: string;
|
|
20
|
+
readonly colorVioletLight: string;
|
|
21
|
+
readonly colorYellowLight: string;
|
|
22
|
+
readonly resultsItemHeight: string;
|
|
23
|
+
readonly transitionDuration: string;
|
|
24
|
+
readonly transitionDurationLong: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default styles;
|