detached 7a8fd7b

fix(chat-room): restore offline users below the people list with last-seen tooltip

commit
7a8fd7b12e27a11d7869146bda5a7f8e4cef642e
author
Kit · · 2026-09-27 14:11 UTC
parent
10bef9d
signature
SSH UnverifiedSHA256:H91DFuEG4jpk5edzLA4aUKkpv4zv9Q339ipRmkph6Tk The key is unknown
1 file · +40 -0
M src/lib/components/chat-room.svelte +40 -0
@@ -289,6 +289,7 @@
289289
290290 // User counts
291291 const usersOnline = $derived(onlineUsers.filter((u) => u.status !== 'offline'));
292+ const usersOffline = $derived(onlineUsers.filter((u) => u.status === 'offline'));
292293 const selectedUser = $derived(onlineUsers.find((u) => u.id === selectedUserId) ?? null);
293294
294295 const mentionableUsers = $derived(
@@ -1353,6 +1354,31 @@
13531354 <span class="nickname">{user.nickname}</span>
13541355 </div>
13551356 {/each}
1357+ {#if usersOffline.length > 0}
1358+ <div class="offline-separator" role="presentation">Hors ligne</div>
1359+ {#each usersOffline as user (user.id)}
1360+ <div
1361+ class="user offline"
1362+ class:selected={selectedUserId === user.id}
1363+ role="option"
1364+ aria-selected={selectedUserId === user.id}
1365+ tabindex="0"
1366+ title={statusLabel(user)}
1367+ onclick={(e) => {
1368+ e.stopPropagation();
1369+ selectedUserId = user.id;
1370+ closeUserMenu();
1371+ }}
1372+ ondblclick={() => openImWith(user)}
1373+ oncontextmenu={(e) => openUserMenu(e, user)}
1374+ onkeydown={(e) => {
1375+ if (e.key === 'Enter') openImWith(user);
1376+ }}
1377+ >
1378+ <span class="nickname">{user.nickname}</span>
1379+ </div>
1380+ {/each}
1381+ {/if}
13561382 </div>
13571383 <div class="people-actions">
13581384 <button
@@ -1522,6 +1548,20 @@
15221548 overflow: hidden;
15231549 }
15241550
1551+ .offline-separator {
1552+ margin: 4px 2px 2px;
1553+ padding-top: 3px;
1554+ border-top: 1px solid #d4d0c8;
1555+ color: #808080;
1556+ font-size: 0.7rem;
1557+ user-select: none;
1558+ }
1559+
1560+ .user.offline .nickname {
1561+ color: #808080;
1562+ font-style: italic;
1563+ }
1564+
15251565 .user .nickname {
15261566 overflow: hidden;
15271567 text-overflow: ellipsis;
@@ -289,6 +289,7 @@
289 289
290 // User counts290 // User counts
291 const usersOnline = $derived(onlineUsers.filter((u) => u.status !== 'offline'));291 const usersOnline = $derived(onlineUsers.filter((u) => u.status !== 'offline'));
292+ const usersOffline = $derived(onlineUsers.filter((u) => u.status === 'offline'));
292 const selectedUser = $derived(onlineUsers.find((u) => u.id === selectedUserId) ?? null);293 const selectedUser = $derived(onlineUsers.find((u) => u.id === selectedUserId) ?? null);
293 294
294 const mentionableUsers = $derived(295 const mentionableUsers = $derived(
@@ -1353,6 +1354,31 @@
1353 <span class="nickname">{user.nickname}</span>1354 <span class="nickname">{user.nickname}</span>
1354 </div>1355 </div>
1355 {/each}1356 {/each}
1357+ {#if usersOffline.length > 0}
1358+ <div class="offline-separator" role="presentation">Hors ligne</div>
1359+ {#each usersOffline as user (user.id)}
1360+ <div
1361+ class="user offline"
1362+ class:selected={selectedUserId === user.id}
1363+ role="option"
1364+ aria-selected={selectedUserId === user.id}
1365+ tabindex="0"
1366+ title={statusLabel(user)}
1367+ onclick={(e) => {
1368+ e.stopPropagation();
1369+ selectedUserId = user.id;
1370+ closeUserMenu();
1371+ }}
1372+ ondblclick={() => openImWith(user)}
1373+ oncontextmenu={(e) => openUserMenu(e, user)}
1374+ onkeydown={(e) => {
1375+ if (e.key === 'Enter') openImWith(user);
1376+ }}
1377+ >
1378+ <span class="nickname">{user.nickname}</span>
1379+ </div>
1380+ {/each}
1381+ {/if}
1356 </div>1382 </div>
1357 <div class="people-actions">1383 <div class="people-actions">
1358 <button1384 <button
@@ -1522,6 +1548,20 @@
1522 overflow: hidden;1548 overflow: hidden;
1523 }1549 }
1524 1550
1551+ .offline-separator {
1552+ margin: 4px 2px 2px;
1553+ padding-top: 3px;
1554+ border-top: 1px solid #d4d0c8;
1555+ color: #808080;
1556+ font-size: 0.7rem;
1557+ user-select: none;
1558+ }
1559+
1560+ .user.offline .nickname {
1561+ color: #808080;
1562+ font-style: italic;
1563+ }
1564+
1525 .user .nickname {1565 .user .nickname {
1526 overflow: hidden;1566 overflow: hidden;
1527 text-overflow: ellipsis;1567 text-overflow: ellipsis;

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 3

Tags 8

↑↓ moveenter openesc close