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