Spaces:
Runtime error
Runtime error
add local storage keep track of played games
Browse files- frontend/package-lock.json +30 -11
- frontend/package.json +2 -1
- frontend/src/lib/Result.svelte +4 -2
- frontend/src/lib/store.ts +26 -0
- frontend/src/routes/index.svelte +25 -2
- frontend/src/types.ts +5 -1
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": "
|
2023 |
-
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-
|
2024 |
-
"integrity": "sha512-
|
2025 |
-
"dev": true,
|
2026 |
"bin": {
|
2027 |
-
"nanoid": "bin/nanoid.
|
2028 |
},
|
2029 |
"engines": {
|
2030 |
-
"node": "^
|
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": "
|
4380 |
-
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-
|
4381 |
-
"integrity": "sha512-
|
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 |
-
|
|
|
|
|
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.
|
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;
|