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 Unverified
SHA256:H91DFuEG4jpk5edzLA4aUKkpv4zv9Q339ipRmkph6TkThe key is unknown
1 file · +40 -0
M src/lib/components/chat-room.svelte +40 -0
| @@ -289,6 +289,7 @@ | |||
| 289 | 289 | ||
| 290 | 290 | // User counts | |
| 291 | 291 | const usersOnline = $derived(onlineUsers.filter((u) => u.status !== 'offline')); | |
| 292 | + | const usersOffline = $derived(onlineUsers.filter((u) => u.status === 'offline')); | |
| 292 | 293 | const selectedUser = $derived(onlineUsers.find((u) => u.id === selectedUserId) ?? null); | |
| 293 | 294 | ||
| 294 | 295 | const mentionableUsers = $derived( | |
| @@ -1353,6 +1354,31 @@ | |||
| 1353 | 1354 | <span class="nickname">{user.nickname}</span> | |
| 1354 | 1355 | </div> | |
| 1355 | 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 | 1382 | </div> | |
| 1357 | 1383 | <div class="people-actions"> | |
| 1358 | 1384 | <button | |
| @@ -1522,6 +1548,20 @@ | |||
| 1522 | 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 | 1565 | .user .nickname { | |
| 1526 | 1566 | overflow: hidden; | |
| 1527 | 1567 | text-overflow: ellipsis; | |
| @@ -289,6 +289,7 @@ | |||||
| 289 | 289 | ||||
| 290 | // User counts | 290 | // 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 | <button | 1384 | <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; | ||