From 0d3864bcebcdba1b1743367d0f84389fd53e37e1 Mon Sep 17 00:00:00 2001
From: srdusr <99972264+srdusr@users.noreply.github.com>
Date: Sat, 13 Sep 2025 21:11:00 +0200
Subject: 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.
---
web/src/topRail.js | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
(limited to 'web/src/topRail.js')
diff --git a/web/src/topRail.js b/web/src/topRail.js
index b6b50d7..e8418f6 100644
--- a/web/src/topRail.js
+++ b/web/src/topRail.js
@@ -40,7 +40,8 @@ export function renderTopRail(root, { onShowAccount, onShowFriends, extras = []
const friends = document.createElement('div');
friends.className = 'friends-control';
if (onShowFriends) {
- friends.innerHTML = ``;
+ friends.innerHTML = `
+ `;
}
wrap.appendChild(friends);
@@ -90,11 +91,18 @@ export function renderTopRail(root, { onShowAccount, onShowFriends, extras = []
// Friends ------------------------------------------------------------
const friendsBtn = friends.querySelector('[data-action="rail-friends"]');
if (friendsBtn) friendsBtn.addEventListener('click', onShowFriends);
- const friendsBadge = friends.querySelector('[data-badge="friends"]');
- function paintCounts({ friends: friendCount }) {
- if (!friendsBadge) return;
- friendsBadge.hidden = !friendCount;
- friendsBadge.textContent = String(friendCount);
+ // How many friends are online, not how many you have - a total is a fact
+ // about your account, whereas "2 online" is a reason to open the screen.
+ const friendsOnlineEl = friends.querySelector('[data-badge="friends-online"]');
+ function paintCounts({ friends: friendCount, friendsOnline }) {
+ if (friendsBtn) {
+ friendsBtn.dataset.tooltip = !friendCount
+ ? 'Friends'
+ : (friendsOnline ? `Friends - ${friendsOnline} of ${friendCount} online` : `Friends - ${friendCount}, none online`);
+ }
+ if (!friendsOnlineEl) return;
+ friendsOnlineEl.hidden = !friendsOnline;
+ friendsOnlineEl.textContent = `${friendsOnline} online`;
}
paintCounts(getCounts());
const unsubscribeCounts = onCountsChange(paintCounts);
--
cgit v1.2.3