radames commited on
Commit
e61bf53
β€’
1 Parent(s): 1c3ecfe

add local storage keep track of played games

Browse files
frontend/package-lock.json CHANGED
@@ -8,7 +8,8 @@
8
  "name": "wordalle",
9
  "version": "0.0.1",
10
  "dependencies": {
11
- "dom-to-image": "^2.6.0"
 
12
  },
13
  "devDependencies": {
14
  "@sveltejs/adapter-static": "^1.0.0-next.34",
@@ -2019,15 +2020,14 @@
2019
  "dev": true
2020
  },
2021
  "node_modules/nanoid": {
2022
- "version": "3.3.4",
2023
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
2024
- "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
2025
- "dev": true,
2026
  "bin": {
2027
- "nanoid": "bin/nanoid.cjs"
2028
  },
2029
  "engines": {
2030
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
2031
  }
2032
  },
2033
  "node_modules/natural-compare": {
@@ -2294,6 +2294,18 @@
2294
  "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
2295
  "dev": true
2296
  },
 
 
 
 
 
 
 
 
 
 
 
 
2297
  "node_modules/prelude-ls": {
2298
  "version": "1.2.1",
2299
  "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -4376,10 +4388,9 @@
4376
  "dev": true
4377
  },
4378
  "nanoid": {
4379
- "version": "3.3.4",
4380
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
4381
- "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
4382
- "dev": true
4383
  },
4384
  "natural-compare": {
4385
  "version": "1.4.0",
@@ -4494,6 +4505,14 @@
4494
  "nanoid": "^3.3.4",
4495
  "picocolors": "^1.0.0",
4496
  "source-map-js": "^1.0.2"
 
 
 
 
 
 
 
 
4497
  }
4498
  },
4499
  "postcss-import": {
 
8
  "name": "wordalle",
9
  "version": "0.0.1",
10
  "dependencies": {
11
+ "dom-to-image": "^2.6.0",
12
+ "nanoid": "^4.0.0"
13
  },
14
  "devDependencies": {
15
  "@sveltejs/adapter-static": "^1.0.0-next.34",
 
2020
  "dev": true
2021
  },
2022
  "node_modules/nanoid": {
2023
+ "version": "4.0.0",
2024
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
2025
+ "integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==",
 
2026
  "bin": {
2027
+ "nanoid": "bin/nanoid.js"
2028
  },
2029
  "engines": {
2030
+ "node": "^14 || ^16 || >=18"
2031
  }
2032
  },
2033
  "node_modules/natural-compare": {
 
2294
  "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
2295
  "dev": true
2296
  },
2297
+ "node_modules/postcss/node_modules/nanoid": {
2298
+ "version": "3.3.4",
2299
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
2300
+ "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
2301
+ "dev": true,
2302
+ "bin": {
2303
+ "nanoid": "bin/nanoid.cjs"
2304
+ },
2305
+ "engines": {
2306
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
2307
+ }
2308
+ },
2309
  "node_modules/prelude-ls": {
2310
  "version": "1.2.1",
2311
  "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
 
4388
  "dev": true
4389
  },
4390
  "nanoid": {
4391
+ "version": "4.0.0",
4392
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
4393
+ "integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg=="
 
4394
  },
4395
  "natural-compare": {
4396
  "version": "1.4.0",
 
4505
  "nanoid": "^3.3.4",
4506
  "picocolors": "^1.0.0",
4507
  "source-map-js": "^1.0.2"
4508
+ },
4509
+ "dependencies": {
4510
+ "nanoid": {
4511
+ "version": "3.3.4",
4512
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
4513
+ "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
4514
+ "dev": true
4515
+ }
4516
  }
4517
  },
4518
  "postcss-import": {
frontend/package.json CHANGED
@@ -35,6 +35,7 @@
35
  },
36
  "type": "module",
37
  "dependencies": {
38
- "dom-to-image": "^2.6.0"
 
39
  }
40
  }
 
35
  },
36
  "type": "module",
37
  "dependencies": {
38
+ "dom-to-image": "^2.6.0",
39
+ "nanoid": "^4.0.0"
40
  }
41
  }
frontend/src/lib/Result.svelte CHANGED
@@ -44,7 +44,7 @@
44
  }
45
  }
46
  const onKeyup = (e: KeyboardEvent) => {
47
- if (e.key === 'Escape') {
48
  dispatch('restart');
49
  } else if (e.key === ' ') {
50
  saveFile(elToShare);
@@ -58,7 +58,9 @@
58
  const compName = badgesComponents[totalStreaks];
59
  badgeComponent = (await import(`./badges/${compName}.svelte`)).default;
60
  }
61
- window.addEventListener('keyup', onKeyup, true);
 
 
62
  });
63
 
64
  onDestroy(() => {
 
44
  }
45
  }
46
  const onKeyup = (e: KeyboardEvent) => {
47
+ if (e.key === 'Escape' || e.key === 'Enter') {
48
  dispatch('restart');
49
  } else if (e.key === ' ') {
50
  saveFile(elToShare);
 
58
  const compName = badgesComponents[totalStreaks];
59
  badgeComponent = (await import(`./badges/${compName}.svelte`)).default;
60
  }
61
+ setTimeout(() => {
62
+ window.addEventListener('keyup', onKeyup, true);
63
+ }, 1000);
64
  });
65
 
66
  onDestroy(() => {
frontend/src/lib/store.ts ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { browser } from '$app/env';
2
+ import { writable } from 'svelte/store';
3
+ import type { User, SuccessPrompt } from '../types';
4
+ import { nanoid } from 'nanoid';
5
+
6
+ const initialUser: User = nanoid();
7
+ const intialCompletedPrompts: SuccessPrompt[] = [];
8
+
9
+ export const currentUser = writable<User>(
10
+ browser ? JSON.parse(localStorage['user'] || JSON.stringify(initialUser)) : initialUser
11
+ );
12
+ currentUser.subscribe((value) => {
13
+ if (browser) {
14
+ return (localStorage['user'] = JSON.stringify(value));
15
+ }
16
+ });
17
+ export const completedPromptsStore = writable<SuccessPrompt[]>(
18
+ browser
19
+ ? JSON.parse(localStorage['completedPrompts'] || JSON.stringify(intialCompletedPrompts))
20
+ : intialCompletedPrompts
21
+ );
22
+ completedPromptsStore.subscribe((value) => {
23
+ if (browser) {
24
+ return (localStorage['completedPrompts'] = JSON.stringify(value));
25
+ }
26
+ });
frontend/src/routes/index.svelte CHANGED
@@ -7,6 +7,7 @@
7
  import Keyboard from '$lib/Keyboard.svelte';
8
  import Result from '$lib/Result.svelte';
9
  import Message from '$lib/Message.svelte';
 
10
 
11
  import { onMount, onDestroy } from 'svelte';
12
  import { browser, dev } from '$app/env';
@@ -21,11 +22,21 @@
21
  onMount(async () => {
22
  onResize();
23
  promptsData = await fetch(apiUrl + 'data').then((d) => d.json());
 
 
 
 
 
 
 
 
 
24
  restartBoard();
25
  window.addEventListener('keyup', onKeyup, true);
26
  window.addEventListener('resize', onResize);
27
  window.focus();
28
  document.body.addEventListener('click', () => window.focus(), false);
 
29
  });
30
 
31
  function onResize() {
@@ -53,13 +64,12 @@
53
  // Feedback state: message and shake
54
  let message = '';
55
  let shakeRowIndex = -1;
56
- let gameState: GameState = GameState.PLAYING;
57
  // Handle keyboard input.
58
  let allowInput = true;
59
 
60
  function restartBoard() {
61
  //reset all states
62
- gameState = GameState.PLAYING;
63
  shakeRowIndex = -1;
64
  message = '';
65
  currentRowIndex = 0;
@@ -67,6 +77,16 @@
67
  allowInput = true;
68
 
69
  const prompts: string[] = Object.keys(promptsData);
 
 
 
 
 
 
 
 
 
 
70
  const idsToRemove = completedPrompts.map((e) => e.idx);
71
  const promptsFiltered = prompts.filter((_, i) => !idsToRemove.includes(i));
72
  const radomPromptId = ~~(Math.random() * promptsFiltered.length);
@@ -77,6 +97,7 @@
77
  imagePaths = promptsData[randomPrompt].slice(0, 6);
78
  const clue = [...answer].map((a) => (Math.random() > 0.5 ? '*' : a)).join('');
79
  console.log('%cCLUE: ', 'color: red;font-weight:bold', clue);
 
80
  cols = answer.length;
81
  timePerTile = totalTime / cols;
82
 
@@ -154,6 +175,8 @@
154
  if (currentRow.every((tile) => tile.state === LetterState.CORRECT)) {
155
  // yay!
156
  completedPrompts = [...completedPrompts, { prompt: answer, idx: currPromptIndex }];
 
 
157
  setTimeout(() => {
158
  gameState = GameState.SUCESS;
159
  }, totalTime);
 
7
  import Keyboard from '$lib/Keyboard.svelte';
8
  import Result from '$lib/Result.svelte';
9
  import Message from '$lib/Message.svelte';
10
+ import { currentUser, completedPromptsStore } from '$lib/store';
11
 
12
  import { onMount, onDestroy } from 'svelte';
13
  import { browser, dev } from '$app/env';
 
22
  onMount(async () => {
23
  onResize();
24
  promptsData = await fetch(apiUrl + 'data').then((d) => d.json());
25
+
26
+ completedPrompts = $completedPromptsStore;
27
+ if (completedPrompts.length >= Object.keys(promptsData).length) {
28
+ gameState = GameState.COMPLETED;
29
+ }
30
+
31
+ console.log('Current User Data:', $currentUser);
32
+ console.log('Completed Prompts:', $completedPromptsStore);
33
+
34
  restartBoard();
35
  window.addEventListener('keyup', onKeyup, true);
36
  window.addEventListener('resize', onResize);
37
  window.focus();
38
  document.body.addEventListener('click', () => window.focus(), false);
39
+ // update completed prompts with local storage data
40
  });
41
 
42
  function onResize() {
 
64
  // Feedback state: message and shake
65
  let message = '';
66
  let shakeRowIndex = -1;
67
+ let gameState: GameState = GameState.LOADING;
68
  // Handle keyboard input.
69
  let allowInput = true;
70
 
71
  function restartBoard() {
72
  //reset all states
 
73
  shakeRowIndex = -1;
74
  message = '';
75
  currentRowIndex = 0;
 
77
  allowInput = true;
78
 
79
  const prompts: string[] = Object.keys(promptsData);
80
+
81
+ if (completedPrompts.length >= prompts.length || gameState === GameState.COMPLETED) {
82
+ showMessage("You've completed all prompts. Please come back later for more!", -1);
83
+ gameState = GameState.COMPLETED;
84
+ allowInput = false;
85
+ completedPrompts = [];
86
+ } else {
87
+ gameState = GameState.PLAYING;
88
+ }
89
+
90
  const idsToRemove = completedPrompts.map((e) => e.idx);
91
  const promptsFiltered = prompts.filter((_, i) => !idsToRemove.includes(i));
92
  const radomPromptId = ~~(Math.random() * promptsFiltered.length);
 
97
  imagePaths = promptsData[randomPrompt].slice(0, 6);
98
  const clue = [...answer].map((a) => (Math.random() > 0.5 ? '*' : a)).join('');
99
  console.log('%cCLUE: ', 'color: red;font-weight:bold', clue);
100
+ // console.log(answer);
101
  cols = answer.length;
102
  timePerTile = totalTime / cols;
103
 
 
175
  if (currentRow.every((tile) => tile.state === LetterState.CORRECT)) {
176
  // yay!
177
  completedPrompts = [...completedPrompts, { prompt: answer, idx: currPromptIndex }];
178
+ $completedPromptsStore = completedPrompts;
179
+
180
  setTimeout(() => {
181
  gameState = GameState.SUCESS;
182
  }, totalTime);
frontend/src/types.ts CHANGED
@@ -6,9 +6,11 @@ export const enum LetterState {
6
  }
7
 
8
  export const enum GameState {
 
9
  PLAYING,
10
  SUCESS,
11
- FAIL
 
12
  }
13
  export interface Tile {
14
  letter: string;
@@ -27,3 +29,5 @@ export interface SuccessPrompt {
27
  prompt: string;
28
  idx: number;
29
  }
 
 
 
6
  }
7
 
8
  export const enum GameState {
9
+ LOADING,
10
  PLAYING,
11
  SUCESS,
12
+ FAIL,
13
+ COMPLETED
14
  }
15
  export interface Tile {
16
  letter: string;
 
29
  prompt: string;
30
  idx: number;
31
  }
32
+
33
+ export type User = string;