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>