feat(chat): add transient presence flash and 5s reconnect grace period
CI / test (push) Successful in 1m33s
CI / docker (push) Successful in 2m10s

This commit is contained in:
zwitschi committed 2026-08-13 20:45:52 +02:00
1 parent 4eb88a4594
commit cef002862e
19 files changed
+299 -37

No files matched your search

+26 -2
View File
@@ -22,6 +22,8 @@ let usersVisible = true;
let typingUser = "";
let lastTypingSent = 0;
let typingTimeout: number | undefined;
let flashTimeout: number | undefined;
let flashFadeTimeout: number | undefined;
const onlineUsers = new Set<string>();
// Player error recovery state (STREAMING.md contract)
@@ -96,20 +98,25 @@ function connectWebSocket(room: string) {
return;
}
hideTyping(msg.username);
addMessage(msg.type || "public", msg.text, msg.username, msg.timestamp);
// Track presence from system join/leave messages
// Presence join/leave announcements become transient flashes, not chat rows.
if (msg.type === "system" && msg.username === "system") {
const joined = msg.text?.match(/^(\S+) joined /);
const left = msg.text?.match(/^(\S+) left /);
if (joined) {
onlineUsers.add(joined[1]);
renderPresence();
showFlash(`${joined[1]} joined`);
return;
} else if (left) {
onlineUsers.delete(left[1]);
renderPresence();
showFlash(`${left[1]} left`);
return;
}
}
addMessage(msg.type || "public", msg.text, msg.username, msg.timestamp);
};
ws.onclose = () => {
@@ -142,6 +149,23 @@ function addMessage(type: string, text: string, sender = "", timestamp = new Dat
messages.scrollTop = messages.scrollHeight;
}
function showFlash(text: string) {
const el = document.getElementById("chat-flash");
if (!el) return;
el.textContent = text;
el.hidden = false;
el.classList.remove("fade-out");
window.clearTimeout(flashTimeout);
window.clearTimeout(flashFadeTimeout);
flashTimeout = window.setTimeout(() => {
el.classList.add("fade-out");
flashFadeTimeout = window.setTimeout(() => {
el.hidden = true;
el.classList.remove("fade-out");
}, 500);
}, 3000);
}
function renderPresence() {
const list = document.getElementById("presence-list");
if (!list) return;