srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/counts.js
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-09-13 21:11:00 +0200
committersrdusr <[email protected]>2025-09-13 21:11:00 +0200
commit0d3864bcebcdba1b1743367d0f84389fd53e37e1 (patch)
tree54a5c028b9fe9b965ffc0240f734b2b5ac81046b /web/src/counts.js
parent29992fe40703cf567177d70f152811bfedb0caad (diff)
downloadtyperpunk-0d3864bcebcdba1b1743367d0f84389fd53e37e1.tar.gz
typerpunk-0d3864bcebcdba1b1743367d0f84389fd53e37e1.zip
Rework the end screen figures, mode picker, corners and race view
End screen - Every figure is now a dim label directly over its value, the two centred on each other, grouped by what they qualify: RAW and PB under WPM, ERR and CONSISTENCY under ACC, KEYSTROKES and CHARACTERS either side of TIME. The row is a grid so TIME sits on the graph's exact centre line rather than drifting with its neighbours' widths. - Errors go back onto the wpm line. Their own y axis implied a magnitude a mistake does not have; what matters is when one happened. - Graph hover reads "wpm ... raw ... time" - the figures first, the second they happened in as the qualifier. Mode picker - Opens from the Single Player button itself, and choosing a mode starts it: picking what to type and starting it are one action. The control has now been a chevron notched into that button, a caption between the two buttons, a pill above them and a chip row below them; as the button's own menu it needs no separate real estate at all. Corners - Settings and Store move to the bottom-left. The top-left is the wordmark's alone. - The global racer count is gone from the home screen - it is not something you can act on there. The Friends control carries "N online" instead, which is. - Presence: users gain a last_seen column, touched at most once a minute per active user on any authenticated request, and the friends list reports who has been seen inside a five-minute window. Multiplayer race view - The standings move to the middle of the screen, the space the end screen's graph occupies, and now include your own row rather than opponents only. Pinned to the top-left corner they put what you are racing against in your peripheral vision and left out the one bar you most need to see. Programming mode - Snippets carry an explanation of what the code does. Shown under the passage while you type in single player; in multiplayer that space belongs to the standings, so it waits for the end screen, where it appears either way.
Diffstat (limited to 'web/src/counts.js')
-rw-r--r--web/src/counts.js28
1 files changed, 15 insertions, 13 deletions
diff --git a/web/src/counts.js b/web/src/counts.js
index 1b98bbe..b06acbf 100644
--- a/web/src/counts.js
+++ b/web/src/counts.js
@@ -1,17 +1,15 @@
import { api } from './api.js';
-import { getOnlineCount } from './multiplayer.js';
import { getUser, onAuthChange } from './auth.js';
-// Live counts for the badges on the Friends and Multiplayer controls: how
-// many people you can race right now, and how many friends you have.
+// How many of your friends are around right now, for the count beside the
+// Friends control.
//
-// Shared and cached rather than fetched per control. The rail is rebuilt on
-// every screen change, and without this each navigation fired a fresh pair of
-// requests - and the main menu's Multiplayer button would have fired its own
-// on top of that, asking the server the same question twice per screen.
+// Shared and cached rather than fetched per control: the rail is rebuilt on
+// every screen change, and without this each navigation fired a fresh
+// request.
const REFRESH_MS = 30000;
-let cache = { online: 0, friends: 0 };
+let cache = { friends: 0, friendsOnline: 0 };
const listeners = new Set();
let timer = null;
let inFlight = false;
@@ -20,13 +18,17 @@ async function refresh() {
if (inFlight) return;
inFlight = true;
try {
- const online = await getOnlineCount().then(r => r.players).catch(() => cache.online);
// Friends only exist for a signed-in user; asking while signed out is
// a guaranteed 401, so skip it rather than log noise on every poll.
- const friends = getUser()
- ? await api.get('/api/friends').then(r => (r.friends || []).length).catch(() => cache.friends)
- : 0;
- cache = { online, friends };
+ if (!getUser()) {
+ cache = { friends: 0, friendsOnline: 0 };
+ } else {
+ const list = await api.get('/api/friends').catch(() => null);
+ if (list) {
+ const friends = list.friends || [];
+ cache = { friends: friends.length, friendsOnline: friends.filter(f => f.online).length };
+ }
+ }
for (const fn of listeners) fn(cache);
} finally {
inFlight = false;