detached a2d83fb

fix(chat-room): drop redundant room header bar, topic moves to tab tooltip

commit
a2d83fb4c7e07ecc39f57c8f9e50955c4491d835
author
Kit · · 2026-09-27 13:49 UTC
parent
6750577
signature
SSH UnverifiedSHA256:H91DFuEG4jpk5edzLA4aUKkpv4zv9Q339ipRmkph6Tk The key is unknown
2 files · +25 -45
M src/lib/components/chat-room.svelte +15 -44
@@ -35,12 +35,10 @@
3535 // Props
3636 let {
3737 roomId: requestedRoomId = null,
38- roomName = 'General',
3938 initialTextStyle = DEFAULT_TEXT_STYLE,
4039 showUserList = false
4140 } = $props<{
4241 roomId?: Id<'chatRooms'> | null;
43- roomName?: string;
4442 initialTextStyle?: TextStyle;
4543 /** Mobile only: whether the people list is expanded */
4644 showUserList?: boolean;
@@ -64,10 +62,6 @@
6462 (requestedRoomId ?? defaultRoomQuery?.data?.id) as Id<'chatRooms'> | undefined
6563 );
6664
67- // Room topic (from public group rooms list)
68- const groupRoomsQuery = isClient ? useQuery(convexApi.aim.getGroupRooms, {}) : null;
69- const roomTopic = $derived(groupRoomsQuery?.data?.find((r) => r.id === roomId)?.topic ?? null);
70-
7165 // Subscribe to messages - skipped until the room ID is available
7266 const messagesQuery = isClient
7367 ? useQuery(convexApi.queries.getMessagesPublic, () => (roomId ? { roomId } : 'skip'))
@@ -1051,21 +1045,18 @@
10511045 </script>
10521046
10531047 <div class="chat-room">
1054- <div class="room-header">
1055- <img src="/aim/chat-room-16.png" alt="" width="16" height="16" />
1056- <span class="room-name">{roomName}</span>
1057- {#if roomTopic}
1058- <span class="room-topic">— {roomTopic}</span>
1059- {/if}
1060- {#if mentionUnreadCount > 0}
1061- <span class="room-mentions"
1062- >({mentionUnreadCount} mention{mentionUnreadCount > 1 ? 's' : ''})</span
1063- >
1064- {/if}
1065- {#if connectionError}
1066- <span class="connection-error">⚠️ {connectionError}</span>
1067- {/if}
1068- </div>
1048+ {#if mentionUnreadCount > 0 || connectionError}
1049+ <div class="room-status">
1050+ {#if mentionUnreadCount > 0}
1051+ <span class="room-mentions"
1052+ >({mentionUnreadCount} mention{mentionUnreadCount > 1 ? 's' : ''})</span
1053+ >
1054+ {/if}
1055+ {#if connectionError}
1056+ <span class="connection-error">⚠️ {connectionError}</span>
1057+ {/if}
1058+ </div>
1059+ {/if}
10691060
10701061 <div class="room-panel" bind:this={roomPanel}>
10711062 <div class="chat-container">
@@ -1449,32 +1440,12 @@
14491440 }
14501441
14511442 /* ===== Layout inside the XP window ===== */
1452- .room-header {
1443+ .room-status {
14531444 display: flex;
1454- align-items: center;
1445+ justify-content: flex-end;
14551446 gap: 6px;
1456- padding: 3px 6px;
1457- margin-bottom: 4px;
1458- background: #ece9d8;
1459- border-bottom: 1px solid #aca899;
1460- color: #333;
1461- font-family: Tahoma, 'Pixelated MS Sans Serif', sans-serif;
14621447 font-size: 11px;
1463- flex: 0 0 auto;
1464- min-width: 0;
1465- }
1466-
1467- .room-name {
1468- font-weight: bold;
1469- }
1470-
1471- .room-topic {
1472- color: #666;
1473- overflow: hidden;
1474- text-overflow: ellipsis;
1475- white-space: nowrap;
1476- min-width: 0;
1477- flex: 1;
1448+ margin-bottom: 3px;
14781449 }
14791450
14801451 .room-mentions {
@@ -35,12 +35,10 @@
35 // Props35 // Props
36 let {36 let {
37 roomId: requestedRoomId = null,37 roomId: requestedRoomId = null,
38- roomName = 'General',
39 initialTextStyle = DEFAULT_TEXT_STYLE,38 initialTextStyle = DEFAULT_TEXT_STYLE,
40 showUserList = false39 showUserList = false
41 } = $props<{40 } = $props<{
42 roomId?: Id<'chatRooms'> | null;41 roomId?: Id<'chatRooms'> | null;
43- roomName?: string;
44 initialTextStyle?: TextStyle;42 initialTextStyle?: TextStyle;
45 /** Mobile only: whether the people list is expanded */43 /** Mobile only: whether the people list is expanded */
46 showUserList?: boolean;44 showUserList?: boolean;
@@ -64,10 +62,6 @@
64 (requestedRoomId ?? defaultRoomQuery?.data?.id) as Id<'chatRooms'> | undefined62 (requestedRoomId ?? defaultRoomQuery?.data?.id) as Id<'chatRooms'> | undefined
65 );63 );
66 64
67- // Room topic (from public group rooms list)
68- const groupRoomsQuery = isClient ? useQuery(convexApi.aim.getGroupRooms, {}) : null;
69- const roomTopic = $derived(groupRoomsQuery?.data?.find((r) => r.id === roomId)?.topic ?? null);
70-
71 // Subscribe to messages - skipped until the room ID is available65 // Subscribe to messages - skipped until the room ID is available
72 const messagesQuery = isClient66 const messagesQuery = isClient
73 ? useQuery(convexApi.queries.getMessagesPublic, () => (roomId ? { roomId } : 'skip'))67 ? useQuery(convexApi.queries.getMessagesPublic, () => (roomId ? { roomId } : 'skip'))
@@ -1051,21 +1045,18 @@
1051 </script>1045 </script>
1052 1046
1053 <div class="chat-room">1047 <div class="chat-room">
1054- <div class="room-header">1048+ {#if mentionUnreadCount > 0 || connectionError}
1055- <img src="/aim/chat-room-16.png" alt="" width="16" height="16" />1049+ <div class="room-status">
1056- <span class="room-name">{roomName}</span>1050+ {#if mentionUnreadCount > 0}
1057- {#if roomTopic}1051+ <span class="room-mentions"
1058- <span class="room-topic">— {roomTopic}</span>1052+ >({mentionUnreadCount} mention{mentionUnreadCount > 1 ? 's' : ''})</span
1059- {/if}1053+ >
1060- {#if mentionUnreadCount > 0}1054+ {/if}
1061- <span class="room-mentions"1055+ {#if connectionError}
1062- >({mentionUnreadCount} mention{mentionUnreadCount > 1 ? 's' : ''})</span1056+ <span class="connection-error">⚠️ {connectionError}</span>
1063- >1057+ {/if}
1064- {/if}1058+ </div>
1065- {#if connectionError}1059+ {/if}
1066- <span class="connection-error">⚠️ {connectionError}</span>
1067- {/if}
1068- </div>
1069 1060
1070 <div class="room-panel" bind:this={roomPanel}>1061 <div class="room-panel" bind:this={roomPanel}>
1071 <div class="chat-container">1062 <div class="chat-container">
@@ -1449,32 +1440,12 @@
1449 }1440 }
1450 1441
1451 /* ===== Layout inside the XP window ===== */1442 /* ===== Layout inside the XP window ===== */
1452- .room-header {1443+ .room-status {
1453 display: flex;1444 display: flex;
1454- align-items: center;1445+ justify-content: flex-end;
1455 gap: 6px;1446 gap: 6px;
1456- padding: 3px 6px;
1457- margin-bottom: 4px;
1458- background: #ece9d8;
1459- border-bottom: 1px solid #aca899;
1460- color: #333;
1461- font-family: Tahoma, 'Pixelated MS Sans Serif', sans-serif;
1462 font-size: 11px;1447 font-size: 11px;
1463- flex: 0 0 auto;1448+ margin-bottom: 3px;
1464- min-width: 0;
1465- }
1466-
1467- .room-name {
1468- font-weight: bold;
1469- }
1470-
1471- .room-topic {
1472- color: #666;
1473- overflow: hidden;
1474- text-overflow: ellipsis;
1475- white-space: nowrap;
1476- min-width: 0;
1477- flex: 1;
1478 }1449 }
1479 1450
1480 .room-mentions {1451 .room-mentions {
M src/lib/components/desktop/chat-rooms-window.svelte +10 -1
@@ -4,12 +4,20 @@
44 import { desktop, CHAT_WINDOW_ID } from '$lib/states/desktop.svelte';
55 import { chatState } from '$lib/states/chat.svelte';
66 import type { TextStyle } from '$lib/types/text-formatting';
7+ import { useQuery } from 'convex-svelte';
8+ import { api } from '../../../convex/_generated/api';
9+ import { convexAvailable } from '$lib/aim/client';
710
811 let { initialTextStyle }: { initialTextStyle?: TextStyle } = $props();
912
1013 const currentUser = $derived(chatState.getCurrentUser());
1114 let showUserList = $state(false);
1215
16+ // Room topics show as tab tooltips
17+ const roomsQuery = convexAvailable ? useQuery(api.aim.getGroupRooms, {}) : null;
18+ const topicOf = (roomId: string | null) =>
19+ roomsQuery?.data?.find((r) => (roomId ? r.id === roomId : r.isDefault))?.topic;
20+
1321 const tabKey = (roomId: string | null) => roomId ?? 'default';
1422 </script>
1523
@@ -39,6 +47,7 @@
3947 role="tab"
4048 aria-selected={active}
4149 aria-controls="room-panel-{tabKey(tab.roomId)}"
50+ title={topicOf(tab.roomId) ?? tab.roomName}
4251 onclick={() => desktop.selectRoomTab(tab.roomId)}
4352 onauxclick={(e) => {
4453 if (e.button === 1 && desktop.roomTabs.length > 1) desktop.closeRoomTab(tab.roomId);
@@ -72,7 +81,7 @@
7281 class="tab-panel"
7382 hidden={tab.roomId !== desktop.activeRoomId}
7483 >
75- <ChatRoom roomId={tab.roomId} roomName={tab.roomName} {initialTextStyle} {showUserList} />
84+ <ChatRoom roomId={tab.roomId} {initialTextStyle} {showUserList} />
7685 </div>
7786 {/each}
7887 </div>
@@ -4,12 +4,20 @@
4 import { desktop, CHAT_WINDOW_ID } from '$lib/states/desktop.svelte';4 import { desktop, CHAT_WINDOW_ID } from '$lib/states/desktop.svelte';
5 import { chatState } from '$lib/states/chat.svelte';5 import { chatState } from '$lib/states/chat.svelte';
6 import type { TextStyle } from '$lib/types/text-formatting';6 import type { TextStyle } from '$lib/types/text-formatting';
7+ import { useQuery } from 'convex-svelte';
8+ import { api } from '../../../convex/_generated/api';
9+ import { convexAvailable } from '$lib/aim/client';
7 10
8 let { initialTextStyle }: { initialTextStyle?: TextStyle } = $props();11 let { initialTextStyle }: { initialTextStyle?: TextStyle } = $props();
9 12
10 const currentUser = $derived(chatState.getCurrentUser());13 const currentUser = $derived(chatState.getCurrentUser());
11 let showUserList = $state(false);14 let showUserList = $state(false);
12 15
16+ // Room topics show as tab tooltips
17+ const roomsQuery = convexAvailable ? useQuery(api.aim.getGroupRooms, {}) : null;
18+ const topicOf = (roomId: string | null) =>
19+ roomsQuery?.data?.find((r) => (roomId ? r.id === roomId : r.isDefault))?.topic;
20+
13 const tabKey = (roomId: string | null) => roomId ?? 'default';21 const tabKey = (roomId: string | null) => roomId ?? 'default';
14 </script>22 </script>
15 23
@@ -39,6 +47,7 @@
39 role="tab"47 role="tab"
40 aria-selected={active}48 aria-selected={active}
41 aria-controls="room-panel-{tabKey(tab.roomId)}"49 aria-controls="room-panel-{tabKey(tab.roomId)}"
50+ title={topicOf(tab.roomId) ?? tab.roomName}
42 onclick={() => desktop.selectRoomTab(tab.roomId)}51 onclick={() => desktop.selectRoomTab(tab.roomId)}
43 onauxclick={(e) => {52 onauxclick={(e) => {
44 if (e.button === 1 && desktop.roomTabs.length > 1) desktop.closeRoomTab(tab.roomId);53 if (e.button === 1 && desktop.roomTabs.length > 1) desktop.closeRoomTab(tab.roomId);
@@ -72,7 +81,7 @@
72 class="tab-panel"81 class="tab-panel"
73 hidden={tab.roomId !== desktop.activeRoomId}82 hidden={tab.roomId !== desktop.activeRoomId}
74 >83 >
75- <ChatRoom roomId={tab.roomId} roomName={tab.roomName} {initialTextStyle} {showUserList} />84+ <ChatRoom roomId={tab.roomId} {initialTextStyle} {showUserList} />
76 </div>85 </div>
77 {/each}86 {/each}
78 </div>87 </div>

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