chat-rooms-window.svelte RawHistoryFolder

1<script lang="ts">
2	import ChatRoom from '../chat-room.svelte';
3	import XpWindow from './xp-window.svelte';
4	import { desktop, CHAT_WINDOW_ID } from '$lib/states/desktop.svelte';
5	import { chatState } from '$lib/states/chat.svelte';
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';
10
11	let { initialTextStyle }: { initialTextStyle?: TextStyle } = $props();
12
13	const currentUser = $derived(chatState.getCurrentUser());
14	let showUserList = $state(false);
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
21	const tabKey = (roomId: string | null) => roomId ?? 'default';
22</script>
23
24<XpWindow
25	id={CHAT_WINDOW_ID}
26	width={800}
27	height={600}
28	minWidth={420}
29	minHeight={420}
30	showMaximize
31	bodyClass="chat-rooms-body"
32>
33	{#snippet menu()}
34		<button type="button" onclick={() => desktop.openBuddyList()}>Contacts</button>
35		<button type="button" onclick={() => desktop.openNewRoom()}>Nouveau salon</button>
36		<button type="button" onclick={() => (showUserList = !showUserList)}>Participants</button>
37		{#if !currentUser}
38			<button type="button" onclick={() => desktop.openLogin('signin')}>Se connecter</button>
39		{/if}
40	{/snippet}
41
42	<menu role="tablist" class="room-tabs">
43		{#each desktop.roomTabs as tab (tabKey(tab.roomId))}
44			{@const active = tab.roomId === desktop.activeRoomId}
45			<button
46				type="button"
47				role="tab"
48				aria-selected={active}
49				aria-controls="room-panel-{tabKey(tab.roomId)}"
50				title={topicOf(tab.roomId) ?? tab.roomName}
51				onclick={() => desktop.selectRoomTab(tab.roomId)}
52				onkeydown={(e) => {
53					if (e.key === 'Delete' && desktop.roomTabs.length > 1) desktop.closeRoomTab(tab.roomId);
54				}}
55				onauxclick={(e) => {
56					if (e.button === 1 && desktop.roomTabs.length > 1) desktop.closeRoomTab(tab.roomId);
57				}}
58			>
59				<img src="/aim/chat-room-16.png" alt="" width="14" height="14" />
60				<span>{tab.roomName}</span>
61			</button>
62			{#if desktop.roomTabs.length > 1}
63				<!-- Sibling of the tab (a button cannot contain another button) -->
64				<button
65					type="button"
66					class="tab-close"
67					class:active
68					aria-label="Fermer {tab.roomName}"
69					title="Fermer {tab.roomName}"
70					onclick={() => desktop.closeRoomTab(tab.roomId)}>×</button
71				>
72			{/if}
73		{/each}
74	</menu>
75
76	<div class="tab-panels">
77		{#each desktop.roomTabs as tab (tabKey(tab.roomId))}
78			<!-- Every open room stays mounted so switching tabs keeps scroll and draft -->
79			<div
80				id="room-panel-{tabKey(tab.roomId)}"
81				role="tabpanel"
82				class="tab-panel"
83				hidden={tab.roomId !== desktop.activeRoomId}
84			>
85				<ChatRoom roomId={tab.roomId} {initialTextStyle} {showUserList} />
86			</div>
87		{/each}
88	</div>
89</XpWindow>
90
91<style>
92	.room-tabs {
93		flex: 0 0 auto;
94		margin-top: 2px;
95	}
96
97	.room-tabs button {
98		display: flex;
99		align-items: center;
100		gap: 4px;
101		padding: 2px 8px 3px;
102		font:
103			11px Tahoma,
104			'Pixelated MS Sans Serif',
105			sans-serif;
106		max-width: 180px;
107	}
108
109	.room-tabs button span:first-of-type {
110		overflow: hidden;
111		text-overflow: ellipsis;
112		white-space: nowrap;
113	}
114
115	.room-tabs button.tab-close {
116		margin-left: -1px;
117		padding: 0 4px;
118		line-height: 12px;
119		color: #555;
120		cursor: default;
121	}
122
123	.room-tabs button.tab-close.active {
124		background-color: #ece9d8;
125		position: relative;
126		z-index: 8;
127		margin-top: -2px;
128		margin-bottom: 1px;
129	}
130
131	.tab-close:hover {
132		background: #c75050;
133		color: #fff;
134	}
135
136	.tab-panels {
137		flex: 1 1 auto;
138		min-height: 0;
139		display: flex;
140		flex-direction: column;
141		background: #fcfcfe;
142		border: 1px solid #919b9c;
143		padding: 4px;
144		position: relative;
145		z-index: 2;
146	}
147
148	/* xp.css frames every [role=tabpanel]; the outer .tab-panels is the frame here */
149	.tab-panel {
150		padding: 0;
151		margin: 0;
152		border: 0;
153		background: transparent;
154		flex: 1 1 auto;
155		min-height: 0;
156		display: flex;
157		flex-direction: column;
158	}
159
160	.tab-panel[hidden] {
161		display: none;
162	}
163</style>

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 9

↑↓ moveenter openesc close