@scrabble-solver/scrabble-solver 2.11.2 → 2.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +6 -6
  3. package/.next/cache/.tsbuildinfo +1 -1
  4. package/.next/cache/eslint/.cache_8dgz12 +1 -1
  5. package/.next/cache/next-server.js.nft.json +1 -1
  6. package/.next/cache/webpack/client-production/0.pack +0 -0
  7. package/.next/cache/webpack/client-production/index.pack +0 -0
  8. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  9. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  10. package/.next/cache/webpack/server-production/0.pack +0 -0
  11. package/.next/cache/webpack/server-production/index.pack +0 -0
  12. package/.next/next-server.js.nft.json +1 -1
  13. package/.next/prerender-manifest.json +1 -1
  14. package/.next/routes-manifest.json +1 -1
  15. package/.next/server/chunks/210.js +109 -0
  16. package/.next/server/chunks/277.js +187 -95
  17. package/.next/server/chunks/44.js +47 -0
  18. package/.next/server/chunks/987.js +91 -0
  19. package/.next/server/middleware-build-manifest.js +1 -1
  20. package/.next/server/pages/404.html +2 -2
  21. package/.next/server/pages/404.js.nft.json +1 -1
  22. package/.next/server/pages/500.html +1 -1
  23. package/.next/server/pages/_app.js +1 -73
  24. package/.next/server/pages/_app.js.nft.json +1 -1
  25. package/.next/server/pages/_document.js.nft.json +1 -1
  26. package/.next/server/pages/api/dictionary/[locale]/[word].js +3 -3
  27. package/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  28. package/.next/server/pages/api/dictionary/[locale].js +3 -3
  29. package/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  30. package/.next/server/pages/api/solve.js +10 -6
  31. package/.next/server/pages/api/solve.js.nft.json +1 -1
  32. package/.next/server/pages/api/verify.js +5 -4
  33. package/.next/server/pages/api/verify.js.nft.json +1 -1
  34. package/.next/server/pages/api/visit.js +3 -3
  35. package/.next/server/pages/api/visit.js.nft.json +1 -1
  36. package/.next/server/pages/index.html +1 -1
  37. package/.next/server/pages/index.js +104 -207
  38. package/.next/server/pages/index.js.nft.json +1 -1
  39. package/.next/server/pages/index.json +1 -1
  40. package/.next/static/{Mdvi3FY0PqkILKLbPlVBU → USLkKOoHbITebIEHkMGX_}/_buildManifest.js +1 -1
  41. package/.next/static/chunks/pages/_app-21c83ddb81fc09d0.js +28 -0
  42. package/.next/static/chunks/pages/index-0858deea02b2a417.js +1 -0
  43. package/.next/static/css/885da289cec275b3.css +1 -0
  44. package/.next/static/css/ea1c8134fe9a143e.css +2 -0
  45. package/.next/trace +53 -54
  46. package/package.json +9 -9
  47. package/src/api/index.ts +1 -0
  48. package/src/api/isCellValid.ts +3 -2
  49. package/src/api/isCharacterValid.ts +13 -0
  50. package/src/components/Button/Button.module.scss +14 -1
  51. package/src/components/Modal/Modal.module.scss +11 -3
  52. package/src/components/NotFound/NotFound.module.scss +13 -4
  53. package/src/components/NotFound/NotFound.tsx +4 -7
  54. package/src/components/Rack/Rack.tsx +3 -1
  55. package/src/components/Tile/Tile.module.scss +23 -18
  56. package/src/components/Tile/Tile.tsx +2 -5
  57. package/src/components/Tile/TilePure.tsx +1 -2
  58. package/src/i18n/constants.ts +65 -0
  59. package/src/i18n/de.json +1 -0
  60. package/src/i18n/en.json +1 -0
  61. package/src/i18n/es.json +1 -0
  62. package/src/i18n/fa.json +1 -0
  63. package/src/i18n/fr.json +1 -0
  64. package/src/i18n/i18n.module.scss +27 -0
  65. package/src/i18n/pl.json +1 -0
  66. package/src/icons/DashCircleFill.svg +1 -0
  67. package/src/icons/EyeFill.svg +5 -0
  68. package/src/icons/index.ts +3 -2
  69. package/src/modals/MenuModal/MenuModal.module.scss +17 -1
  70. package/src/modals/MenuModal/MenuModal.tsx +8 -2
  71. package/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +4 -1
  72. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss +8 -0
  73. package/src/modals/ResultsModal/ResultsModal.tsx +35 -11
  74. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +3 -44
  75. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +4 -2
  76. package/src/pages/api/solve.ts +3 -2
  77. package/src/styles/mixins.scss +2 -0
  78. package/src/styles/variables.scss +12 -0
  79. package/src/types/index.ts +1 -0
  80. package/.next/server/chunks/417.js +0 -221
  81. package/.next/server/chunks/664.js +0 -621
  82. package/.next/static/chunks/pages/_app-495e6f4ccc278bb2.js +0 -28
  83. package/.next/static/chunks/pages/index-5ecc51900ca29685.js +0 -1
  84. package/.next/static/css/17b0a2db8742105f.css +0 -1
  85. package/.next/static/css/e1ffeb2558330c55.css +0 -2
  86. package/src/modals/SettingsModal/components/LocaleSetting/options.ts +0 -68
  87. /package/.next/static/{Mdvi3FY0PqkILKLbPlVBU → USLkKOoHbITebIEHkMGX_}/_ssgManifest.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/scrabble-solver",
3
- "version": "2.11.2",
3
+ "version": "2.11.3",
4
4
  "description": "Scrabble Solver 2 - App",
5
5
  "engines": {
6
6
  "node": ">=16"
@@ -31,13 +31,13 @@
31
31
  "@floating-ui/react": "^0.20.1",
32
32
  "@kamilmielnik/trie": "^2.0.1",
33
33
  "@reduxjs/toolkit": "^1.9.3",
34
- "@scrabble-solver/configs": "^2.11.2",
35
- "@scrabble-solver/constants": "^2.11.2",
36
- "@scrabble-solver/dictionaries": "^2.11.2",
37
- "@scrabble-solver/logger": "^2.11.2",
38
- "@scrabble-solver/solver": "^2.11.2",
39
- "@scrabble-solver/types": "^2.11.2",
40
- "@scrabble-solver/word-definitions": "^2.11.2",
34
+ "@scrabble-solver/configs": "^2.11.3",
35
+ "@scrabble-solver/constants": "^2.11.3",
36
+ "@scrabble-solver/dictionaries": "^2.11.3",
37
+ "@scrabble-solver/logger": "^2.11.3",
38
+ "@scrabble-solver/solver": "^2.11.3",
39
+ "@scrabble-solver/types": "^2.11.3",
40
+ "@scrabble-solver/word-definitions": "^2.11.3",
41
41
  "classnames": "^2.3.2",
42
42
  "include-media": "^2.0.0",
43
43
  "include-media-query-builder": "^1.1.0",
@@ -72,5 +72,5 @@
72
72
  "sass": "^1.59.2",
73
73
  "workbox-webpack-plugin": "^6.5.4"
74
74
  },
75
- "gitHead": "b7ac80ab2a6c0af218756953e354d1e0c7f1e58a"
75
+ "gitHead": "693e06a0f1375268d31d12c1a24924bf5ca3c267"
76
76
  }
package/src/api/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { default as getServerLoggingData } from './getServerLoggingData';
2
2
  export { default as isBoardValid } from './isBoardValid';
3
3
  export { default as isCellValid } from './isCellValid';
4
+ export { default as isCharacterValid } from './isCharacterValid';
4
5
  export { default as isRowValid } from './isRowValid';
@@ -1,6 +1,7 @@
1
- import { BLANK } from '@scrabble-solver/constants';
2
1
  import { CellJson, Config } from '@scrabble-solver/types';
3
2
 
3
+ import isCharacterValid from './isCharacterValid';
4
+
4
5
  const isCellValid = (cell: CellJson, config: Config): boolean => {
5
6
  const { isEmpty, tile, x, y } = cell;
6
7
 
@@ -16,7 +17,7 @@ const isCellValid = (cell: CellJson, config: Config): boolean => {
16
17
  return false;
17
18
  }
18
19
 
19
- if (tile !== null && !config.hasCharacter(tile.character) && tile.character !== BLANK) {
20
+ if (tile !== null && !isCharacterValid(tile.character)) {
20
21
  return false;
21
22
  }
22
23
 
@@ -0,0 +1,13 @@
1
+ const TWO_TILE_CHARACTER_LENGTH = 2;
2
+ const MAX_CHARACTER_LENGTH = TWO_TILE_CHARACTER_LENGTH;
3
+
4
+ const isCharacterValid = (character: string): boolean => {
5
+ /*
6
+ * We could be strict here and check whether config.hasCharacter(character) || character === BLANK
7
+ * but since this case won't really affect/break solving, we don't need to worry about it.
8
+ * It's better to display an empty state than error state in UI, so this is a sanity check only.
9
+ */
10
+ return character.length !== 0 && character.length <= MAX_CHARACTER_LENGTH;
11
+ };
12
+
13
+ export default isCharacterValid;
@@ -60,16 +60,29 @@
60
60
  .content {
61
61
  display: flex;
62
62
  align-items: center;
63
- gap: 20px;
63
+ gap: var(--spacing--l);
64
+
64
65
  }
65
66
 
66
67
  .icon {
68
+ flex: 0 0 auto;
67
69
  width: var(--button--icon--size);
68
70
  height: var(--button--icon--size);
69
71
  transition: var(--transition);
70
72
  }
71
73
 
72
74
  .label {
75
+ @include ellipsis;
76
+
77
+ flex: 1;
73
78
  font-size: var(--font--size--h3);
74
79
  transition: var(--transition);
80
+
81
+ [dir='ltr'] & {
82
+ text-align: left;
83
+ }
84
+
85
+ [dir='rtl'] & {
86
+ text-align: right;
87
+ }
75
88
  }
@@ -89,6 +89,7 @@
89
89
  z-index: 1;
90
90
  flex: 0 0 auto;
91
91
  padding: var(--spacing--l);
92
+ padding-bottom: 0;
92
93
  background-color: var(--color--background);
93
94
  }
94
95
 
@@ -117,18 +118,25 @@
117
118
  position: relative;
118
119
  flex: 1;
119
120
  min-height: 0;
120
- padding: var(--spacing--l);
121
121
  overflow: auto;
122
+ padding: var(--spacing--l);
122
123
  }
123
124
 
124
125
  .footer {
125
126
  flex: 0 0 auto;
126
127
  display: flex;
127
- justify-content: flex-end;
128
+ flex-direction: row-reverse;
129
+ justify-content: space-between;
130
+ gap: var(--spacing--l);
128
131
  padding: var(--spacing--l);
129
- box-shadow: var(--box-shadow);
132
+ padding-top: 0;
130
133
 
131
134
  @include media('>s') {
132
135
  display: none;
133
136
  }
137
+
138
+ > * {
139
+ min-width: 0;
140
+ flex: 1;
141
+ }
134
142
  }
@@ -1,3 +1,5 @@
1
+ @import 'styles/mixins';
2
+
1
3
  .notFound {
2
4
  display: flex;
3
5
  align-items: center;
@@ -11,18 +13,25 @@
11
13
  align-items: center;
12
14
  justify-content: center;
13
15
  flex-direction: column;
14
- padding: var(--spacing--xxl);
16
+ padding: var(--spacing--l);
15
17
  }
16
18
 
17
19
  .icon {
18
- $size: 204px;
20
+ --size: 200px;
19
21
 
20
- height: $size;
21
- width: $size;
22
+ height: var(--size);
23
+ width: var(--size);
22
24
  margin-bottom: var(--spacing--xxl);
23
25
  color: var(--color--red);
26
+
27
+ @include media('<xs') {
28
+ --size: 50%;
29
+
30
+ margin-bottom: var(--spacing--xl);
31
+ }
24
32
  }
25
33
 
26
34
  .tiles {
35
+ max-width: 100%;
27
36
  height: 60px;
28
37
  }
@@ -1,4 +1,3 @@
1
- import Link from 'next/link';
2
1
  import { FunctionComponent } from 'react';
3
2
 
4
3
  import { DashCircleFill } from 'icons';
@@ -11,12 +10,10 @@ const CONTENT = [['HTTP', '404']];
11
10
 
12
11
  const NotFound: FunctionComponent = () => (
13
12
  <div className={styles.notFound}>
14
- <Link href="/">
15
- <a className={styles.link}>
16
- <DashCircleFill className={styles.icon} />
17
- <PlainTiles className={styles.tiles} content={CONTENT} />
18
- </a>
19
- </Link>
13
+ <a className={styles.link} href="/">
14
+ <DashCircleFill className={styles.icon} />
15
+ <PlainTiles className={styles.tiles} content={CONTENT} />
16
+ </a>
20
17
  </div>
21
18
  );
22
19
 
@@ -8,6 +8,7 @@ import {
8
8
  createKeyboardNavigation,
9
9
  extractCharacters,
10
10
  extractInputValue,
11
+ getTileSizes,
11
12
  zipCharactersAndTiles,
12
13
  } from 'lib';
13
14
  import { rackSlice, selectConfig, selectLocale, selectRack, selectResultCandidateTiles, useTypedSelector } from 'state';
@@ -31,6 +32,7 @@ const Rack: FunctionComponent<Props> = ({ className, tileSize }) => {
31
32
  const tilesRefs = useMemo(() => createArray(tilesCount).map(() => createRef<HTMLInputElement>()), [tilesCount]);
32
33
  const activeIndexRef = useRef<number>();
33
34
  const { direction } = LOCALE_FEATURES[locale];
35
+ const { tileFontSize } = getTileSizes(tileSize);
34
36
 
35
37
  const changeActiveIndex = useCallback(
36
38
  (offset: number) => {
@@ -110,7 +112,7 @@ const Rack: FunctionComponent<Props> = ({ className, tileSize }) => {
110
112
  }, [changeActiveIndex, config, direction]);
111
113
 
112
114
  return (
113
- <div className={classNames(styles.rack, className)} onPaste={handlePaste}>
115
+ <div className={classNames(styles.rack, className)} style={{ fontSize: tileFontSize }} onPaste={handlePaste}>
114
116
  {tiles.map(({ character, tile }, index) => (
115
117
  <RackTile
116
118
  activeIndexRef={activeIndexRef}
@@ -34,18 +34,10 @@
34
34
  }
35
35
 
36
36
  &.raised {
37
- --shadow--size: 2px;
38
- --shadow--blur: 2px;
39
- --shadow--spread: -1px;
40
- --shadow--color: rgba(34, 34, 34, 0.8);
41
-
42
- box-shadow: inset calc(-1 * var(--shadow--size)) calc(-1 * var(--shadow--size)) var(--shadow--blur)
43
- var(--shadow--spread) var(--shadow--color);
37
+ box-shadow: var(--box-shadow--raised);
44
38
 
45
39
  @include media('<xs') {
46
- --shadow--size: 1px;
47
- --shadow--spread: 0;
48
- --shadow--blur: 1px;
40
+ box-shadow: var(--box-shadow--raised--subtle);
49
41
  }
50
42
  }
51
43
 
@@ -59,6 +51,13 @@
59
51
  color: var(--color--inactive);
60
52
  }
61
53
 
54
+ &.invalid {
55
+ --background-color: var(--color--foreground);
56
+ --shadow--color: var(--box-shadow--color--inverse);
57
+
58
+ color: var(--color--white);
59
+ }
60
+
62
61
  &.highlighted {
63
62
  --background-color: var(--color--primary);
64
63
 
@@ -114,23 +113,29 @@
114
113
  }
115
114
 
116
115
  .alert {
117
- $size: 30%;
116
+ --size: 30%;
118
117
 
119
118
  position: absolute;
120
- width: $size;
121
- height: $size;
122
- background-color: var(--color--error--opposite);
119
+ width: var(--size);
120
+ height: var(--size);
121
+ background: radial-gradient(
122
+ var(--color--error--opposite),
123
+ var(--color--error--opposite) 85%,
124
+ transparent 85%,
125
+ transparent
126
+ );
123
127
  color: var(--color--error);
128
+ pointer-events: none;
124
129
 
125
130
  [dir='ltr'] & {
126
131
  top: 0;
127
132
  right: 0;
128
- border-top-right-radius: inherit;
133
+ border-bottom-right-radius: inherit;
129
134
  }
130
135
 
131
136
  [dir='rtl'] & {
132
- bottom: 0;
133
- right: 0;
134
- border-bottom-right-radius: inherit;
137
+ top: 0;
138
+ left: 0;
139
+ border-top-left-radius: inherit;
135
140
  }
136
141
  }
@@ -59,11 +59,8 @@ const Tile: FunctionComponent<Props> = ({
59
59
  }) => {
60
60
  const locale = useTypedSelector(selectLocale);
61
61
  const { animateTile, showTilePoints } = useAppLayout();
62
- const { pointsFontSize, tileFontSize, tileSize } = getTileSizes(size);
63
- const style = useMemo(
64
- () => ({ fontSize: tileFontSize, height: tileSize, width: tileSize }),
65
- [tileSize, tileFontSize],
66
- );
62
+ const { pointsFontSize, tileSize } = getTileSizes(size);
63
+ const style = useMemo(() => ({ height: tileSize, width: tileSize }), [tileSize]);
67
64
  const pointsStyle = useMemo(() => ({ fontSize: pointsFontSize }), [pointsFontSize]);
68
65
  const ref = useRef<HTMLInputElement>(null);
69
66
  const mergedRef = useMergeRefs(inputRef ? [ref, inputRef] : [ref]);
@@ -61,10 +61,9 @@ const TilePure: FunctionComponent<Props> = ({
61
61
  <div
62
62
  className={classNames(styles.tile, className, {
63
63
  [styles.blank]: isBlank,
64
- [styles.disabled]: disabled,
65
64
  [styles.empty]: !character,
65
+ [styles.invalid]: !isValid,
66
66
  [styles.highlighted]: highlighted,
67
- [styles.placeholder]: !character,
68
67
  [styles.points1]: points === 1,
69
68
  [styles.points2]: points === 2,
70
69
  [styles.points3]: points === 3,
@@ -1,4 +1,9 @@
1
1
  import { Locale } from '@scrabble-solver/types';
2
+ import { FunctionComponent, SVGAttributes } from 'react';
3
+
4
+ import { FlagDe, FlagEs, FlagFa, FlagFr, FlagGb, FlagPl, FlagUs } from 'icons';
5
+
6
+ import styles from './i18n.module.scss';
2
7
 
3
8
  interface LocaleFeatures {
4
9
  direction: 'ltr' | 'rtl';
@@ -51,3 +56,63 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
51
56
  vowels: true,
52
57
  },
53
58
  };
59
+
60
+ interface Flag {
61
+ className: string;
62
+ Icon: FunctionComponent<SVGAttributes<SVGElement>>;
63
+ label: string;
64
+ name: string;
65
+ value: Locale;
66
+ }
67
+
68
+ export const LOCALE_FLAGS: Record<Locale, Flag> = {
69
+ [Locale.EN_GB]: {
70
+ className: styles.gb,
71
+ Icon: FlagGb,
72
+ label: 'English (GB)',
73
+ name: 'English (GB)',
74
+ value: Locale.EN_GB,
75
+ },
76
+ [Locale.EN_US]: {
77
+ className: styles.us,
78
+ Icon: FlagUs,
79
+ label: 'English (US)',
80
+ name: 'English (US)',
81
+ value: Locale.EN_US,
82
+ },
83
+ [Locale.FA_IR]: {
84
+ className: styles.fa,
85
+ Icon: FlagFa,
86
+ label: 'فارسی',
87
+ name: 'Persian',
88
+ value: Locale.FA_IR,
89
+ },
90
+ [Locale.FR_FR]: {
91
+ className: styles.fr,
92
+ Icon: FlagFr,
93
+ label: 'Français',
94
+ name: 'French',
95
+ value: Locale.FR_FR,
96
+ },
97
+ [Locale.DE_DE]: {
98
+ className: styles.de,
99
+ Icon: FlagDe,
100
+ label: 'Deutsch',
101
+ name: 'German',
102
+ value: Locale.DE_DE,
103
+ },
104
+ [Locale.PL_PL]: {
105
+ className: styles.pl,
106
+ Icon: FlagPl,
107
+ label: 'Polski',
108
+ name: 'Polish',
109
+ value: Locale.PL_PL,
110
+ },
111
+ [Locale.ES_ES]: {
112
+ className: styles.es,
113
+ Icon: FlagEs,
114
+ label: 'Español',
115
+ name: 'Spanish',
116
+ value: Locale.ES_ES,
117
+ },
118
+ };
package/src/i18n/de.json CHANGED
@@ -50,6 +50,7 @@
50
50
  "results.empty-state.uninitialized": "Wörter die aus deinen Buchstaben generiert wurden erscheinen hier.",
51
51
  "results.input.placeholder": "Suchergebnisse... (RegExp)",
52
52
  "results.insert": "Hinzufügen",
53
+ "results.preview": "Vorschau",
53
54
  "results.solve": "Lösen",
54
55
  "settings": "Einstellungen",
55
56
  "settings.autoGroupTiles": "Restliche Steine gruppieren",
package/src/i18n/en.json CHANGED
@@ -50,6 +50,7 @@
50
50
  "results.empty-state.uninitialized": "Words generated from your letters will be shown here.",
51
51
  "results.input.placeholder": "Search results... (RegExp)",
52
52
  "results.insert": "Insert",
53
+ "results.preview": "Preview",
53
54
  "results.solve": "Solve",
54
55
  "settings": "Settings",
55
56
  "settings.autoGroupTiles": "Group remaining tiles",
package/src/i18n/es.json CHANGED
@@ -50,6 +50,7 @@
50
50
  "results.empty-state.uninitialized": "Aquí se mostrarán las palabras generadas a partir de sus letras.",
51
51
  "results.input.placeholder": "Busque una solución... (RegExp)",
52
52
  "results.insert": "Insertar",
53
+ "results.preview": "Vista previa",
53
54
  "results.solve": "Resolver",
54
55
  "settings": "Configuración",
55
56
  "settings.autoGroupTiles": "Agrupar casillas restantes",
package/src/i18n/fa.json CHANGED
@@ -50,6 +50,7 @@
50
50
  "results.empty-state.uninitialized": "کلمات تولید شده از حروف شما اینجا نمایش داده خواهد شد.",
51
51
  "results.input.placeholder": "جستجو در نتایج (RegExp)",
52
52
  "results.insert": "وارد کردن",
53
+ "results.preview": "پیش نمایش",
53
54
  "results.solve": "حل کن",
54
55
  "settings": "تنظیمات",
55
56
  "settings.autoGroupTiles": "کاشی های باقی مانده ی طاقچه را کنار هم قرار بده",
package/src/i18n/fr.json CHANGED
@@ -50,6 +50,7 @@
50
50
  "results.empty-state.uninitialized": "Les mots générés à partir de vos lettres seront affichés ici.",
51
51
  "results.input.placeholder": "Rechercher les résultats... (RegExp)",
52
52
  "results.insert": "Inserer",
53
+ "results.preview": "Prévisualisation",
53
54
  "results.solve": "Résoudre",
54
55
  "settings": "Options",
55
56
  "settings.autoGroupTiles": "Grouper les cases restantes",
@@ -0,0 +1,27 @@
1
+ .de {
2
+ --aspect-ratio: var(--flag--de--aspect-ratio);
3
+ }
4
+
5
+ .es {
6
+ --aspect-ratio: var(--flag--es--aspect-ratio);
7
+ }
8
+
9
+ .fa {
10
+ --aspect-ratio: var(--flag--fa--aspect-ratio);
11
+ }
12
+
13
+ .fr {
14
+ --aspect-ratio: var(--flag--fr--aspect-ratio);
15
+ }
16
+
17
+ .gb {
18
+ --aspect-ratio: var(--flag--gb--aspect-ratio);
19
+ }
20
+
21
+ .pl {
22
+ --aspect-ratio: var(--flag--pl--aspect-ratio);
23
+ }
24
+
25
+ .us {
26
+ --aspect-ratio: var(--flag--us--aspect-ratio);
27
+ }
package/src/i18n/pl.json CHANGED
@@ -50,6 +50,7 @@
50
50
  "results.empty-state.uninitialized": "Tu zostaną wyświetlone słowa wygenerowane z Twoich liter.",
51
51
  "results.input.placeholder": "Szukaj rozwiązania... (RegExp)",
52
52
  "results.insert": "Wstaw",
53
+ "results.preview": "Podgląd",
53
54
  "results.solve": "Rozwiąż",
54
55
  "settings": "Opcje",
55
56
  "settings.autoGroupTiles": "Grupuj pozostałe płytki",
@@ -1,3 +1,4 @@
1
+ <!-- https://icons.getbootstrap.com/icons/dash-circle-fill/ -->
1
2
  <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
2
3
  <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM4.5 7.5a.5.5 0 0 0 0 1h7a.5.5 0 0 0 0-1h-7z" fill="currentColor" />
3
4
  </svg>
@@ -0,0 +1,5 @@
1
+ <!-- https://icons.getbootstrap.com/icons/eye-fill/ -->
2
+ <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M10.5 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z" fill="currentColor" />
4
+ <path d="M0 8s3-5.5 8-5.5S16 8 16 8s-3 5.5-8 5.5S0 8 0 8zm8 3.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z" fill="currentColor" />
5
+ </svg>
@@ -18,15 +18,16 @@ export { default as DashCircleFill } from './DashCircleFill.svg';
18
18
  export { default as Eraser } from './Eraser.svg';
19
19
  export { default as ExclamationSquareFill } from './ExclamationSquareFill.svg';
20
20
  export { default as ExclamationTriangleFill } from './ExclamationTriangleFill.svg';
21
+ export { default as EyeFill } from './EyeFill.svg';
21
22
  export { default as Flag } from './Flag.svg';
22
- export { default as FlagFill } from './FlagFill.svg';
23
+ export { default as FlagDe } from './FlagDe.svg';
23
24
  export { default as FlagEs } from './FlagEs.svg';
24
25
  export { default as FlagFa } from './FlagFa.svg';
26
+ export { default as FlagFill } from './FlagFill.svg';
25
27
  export { default as FlagFr } from './FlagFr.svg';
26
28
  export { default as FlagGb } from './FlagGb.svg';
27
29
  export { default as FlagPl } from './FlagPl.svg';
28
30
  export { default as FlagUs } from './FlagUs.svg';
29
- export { default as FlagDe } from './FlagDe.svg';
30
31
  export { default as Github } from './Github.svg';
31
32
  export { default as InfoCircleFill } from './InfoCircleFill.svg';
32
33
  export { default as Keyboard } from './Keyboard.svg';
@@ -8,10 +8,26 @@
8
8
  &:active,
9
9
  &:focus,
10
10
  &:hover {
11
- box-shadow: 0px 1px 1px 0px var(--box-shadow--color);
11
+ box-shadow: 0 1px 1px 0 var(--box-shadow--color);
12
12
  }
13
13
 
14
14
  & + & {
15
15
  margin-top: var(--spacing--l);
16
16
  }
17
17
  }
18
+
19
+ .settings {
20
+ width: 100%;
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: space-between;
24
+ }
25
+
26
+ .flag {
27
+ --height: var(--button--icon--size);
28
+
29
+ width: calc(var(--height) * var(--aspect--ratio));
30
+ height: var(--height);
31
+ border-radius: var(--border--radius);
32
+ box-shadow: 0 0 0 1px var(--box-shadow--color);
33
+ }
@@ -1,9 +1,10 @@
1
1
  import { FunctionComponent } from 'react';
2
2
 
3
3
  import { Button, Modal } from 'components';
4
+ import { LOCALE_FLAGS } from 'i18n';
4
5
  import { BookHalf, CardChecklist, Cog, Github, Sack } from 'icons';
5
6
  import { GITHUB_PROJECT_URL } from 'parameters';
6
- import { useTranslate } from 'state';
7
+ import { selectLocale, useTranslate, useTypedSelector } from 'state';
7
8
 
8
9
  import styles from './MenuModal.module.scss';
9
10
 
@@ -27,6 +28,8 @@ const Menu: FunctionComponent<Props> = ({
27
28
  onShowWords,
28
29
  }) => {
29
30
  const translate = useTranslate();
31
+ const locale = useTypedSelector(selectLocale);
32
+ const Flag = LOCALE_FLAGS[locale];
30
33
 
31
34
  return (
32
35
  <Modal className={className} isOpen={isOpen} title={translate('menu')} onClose={onClose}>
@@ -59,7 +62,10 @@ const Menu: FunctionComponent<Props> = ({
59
62
  </Button.Link>
60
63
 
61
64
  <Button aria-label={translate('settings')} className={styles.button} Icon={Cog} onClick={onShowSettings}>
62
- {translate('settings')}
65
+ <div className={styles.settings}>
66
+ <span>{translate('settings')}</span>
67
+ <Flag.Icon className={styles.flag} />
68
+ </div>
63
69
  </Button>
64
70
  </Modal>
65
71
  );
@@ -2,6 +2,8 @@ import { FunctionComponent } from 'react';
2
2
 
3
3
  import { Badge, Modal } from 'components';
4
4
  import { LOCALE_FEATURES } from 'i18n';
5
+ import { getTileSizes } from 'lib';
6
+ import { REMAINING_TILES_TILE_SIZE } from 'parameters';
5
7
  import { selectLocale, selectRemainingTilesGroups, useTranslate, useTypedSelector } from 'state';
6
8
 
7
9
  import { Character } from './components';
@@ -17,6 +19,7 @@ const RemainingTilesModal: FunctionComponent<Props> = ({ className, isOpen, onCl
17
19
  const translate = useTranslate();
18
20
  const locale = useTypedSelector(selectLocale);
19
21
  const groups = useTypedSelector(selectRemainingTilesGroups);
22
+ const { tileFontSize } = getTileSizes(REMAINING_TILES_TILE_SIZE);
20
23
  const { direction } = LOCALE_FEATURES[locale];
21
24
 
22
25
  return (
@@ -37,7 +40,7 @@ const RemainingTilesModal: FunctionComponent<Props> = ({ className, isOpen, onCl
37
40
  </span>
38
41
  }
39
42
  >
40
- <div className={styles.content}>
43
+ <div className={styles.content} style={{ fontSize: tileFontSize }}>
41
44
  {tiles.map((tile) => {
42
45
  return (
43
46
  <div className={styles.character} key={tile.character}>
@@ -1,3 +1,5 @@
1
+ @import 'styles/mixins';
2
+
1
3
  .character {
2
4
  display: flex;
3
5
  flex-direction: column;
@@ -29,9 +31,15 @@
29
31
  .remaining {
30
32
  height: 6px;
31
33
  margin-top: var(--spacing--m);
34
+ box-shadow: var(--box-shadow--raised);
35
+
36
+ @include media('<xs') {
37
+ box-shadow: var(--box-shadow--raised--subtle);
38
+ }
32
39
  }
33
40
 
34
41
  .count {
35
42
  padding: var(--spacing--xs) 0;
43
+ font-size: var(--font--size--m);
36
44
  white-space: nowrap;
37
45
  }