@happyvertical/smrt-chat 0.34.5 → 0.34.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/manifest.json +2 -2
- package/dist/smrt-knowledge.json +4 -4
- package/dist/svelte/components/agent/AgentChat.svelte +34 -49
- package/dist/svelte/components/agent/AgentChat.svelte.d.ts.map +1 -1
- package/dist/svelte/components/agent/AgentSelector.svelte +1 -0
- package/dist/svelte/components/agent/AgentSelector.svelte.d.ts.map +1 -1
- package/dist/svelte/components/agent/AgentSessionPanel.svelte +15 -16
- package/dist/svelte/components/agent/AgentSessionPanel.svelte.d.ts.map +1 -1
- package/dist/svelte/components/agent/ToolCallDisplay.svelte +1 -0
- package/dist/svelte/components/agent/ToolCallDisplay.svelte.d.ts.map +1 -1
- package/dist/svelte/components/dialogs/RoomCreateDialog.svelte +29 -94
- package/dist/svelte/components/dialogs/RoomCreateDialog.svelte.d.ts.map +1 -1
- package/dist/svelte/components/dialogs/SearchMessages.svelte +51 -36
- package/dist/svelte/components/dialogs/SearchMessages.svelte.d.ts.map +1 -1
- package/dist/svelte/components/layout/ChatLayout.svelte +1 -0
- package/dist/svelte/components/layout/ChatLayout.svelte.d.ts.map +1 -1
- package/dist/svelte/components/layout/MemberList.svelte +10 -15
- package/dist/svelte/components/layout/MemberList.svelte.d.ts.map +1 -1
- package/dist/svelte/components/layout/RoomHeader.svelte +13 -16
- package/dist/svelte/components/layout/RoomHeader.svelte.d.ts.map +1 -1
- package/dist/svelte/components/layout/RoomList.svelte +26 -17
- package/dist/svelte/components/layout/RoomList.svelte.d.ts.map +1 -1
- package/dist/svelte/components/messages/MessageInput.svelte +34 -48
- package/dist/svelte/components/messages/MessageInput.svelte.d.ts.map +1 -1
- package/dist/svelte/components/messages/MessageItem.svelte +52 -43
- package/dist/svelte/components/messages/MessageItem.svelte.d.ts.map +1 -1
- package/dist/svelte/components/messages/ThreadPanel.svelte +9 -9
- package/dist/svelte/components/messages/ThreadPanel.svelte.d.ts.map +1 -1
- package/dist/svelte/components/shared/FileUpload.svelte +23 -54
- package/dist/svelte/components/shared/FileUpload.svelte.d.ts.map +1 -1
- package/dist/svelte/components/shared/MentionAutocomplete.svelte +1 -0
- package/dist/svelte/components/shared/MentionAutocomplete.svelte.d.ts.map +1 -1
- package/dist/svelte/components/shared/ReactionPicker.svelte +15 -66
- package/dist/svelte/components/shared/ReactionPicker.svelte.d.ts.map +1 -1
- package/dist/svelte/components/tabs/ChatTab.svelte +20 -18
- package/dist/svelte/components/tabs/ChatTab.svelte.d.ts.map +1 -1
- package/dist/svelte/components/tabs/ChatTabList.svelte +13 -10
- package/dist/svelte/components/tabs/ChatTabList.svelte.d.ts.map +1 -1
- package/dist/svelte/components/tabs/MiniChat.svelte +21 -37
- package/dist/svelte/components/tabs/MiniChat.svelte.d.ts.map +1 -1
- package/dist/svelte/index.d.ts +1 -2
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +5 -4
- package/package.json +9 -8
- package/dist/svelte/components/shared/MessageBubble.svelte +0 -81
- package/dist/svelte/components/shared/MessageBubble.svelte.d.ts +0 -16
- package/dist/svelte/components/shared/MessageBubble.svelte.d.ts.map +0 -1
- package/dist/svelte/components/shared/TypingIndicator.svelte +0 -90
- package/dist/svelte/components/shared/TypingIndicator.svelte.d.ts +0 -12
- package/dist/svelte/components/shared/TypingIndicator.svelte.d.ts.map +0 -1
- package/dist/svelte/components/shared/__tests__/MessageBubble.test.js +0 -21
- package/dist/svelte/components/shared/__tests__/TypingIndicator.test.js +0 -27
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* SearchMessages - Message search interface with results list
|
|
4
4
|
* Provides a search input and displays matching messages
|
|
5
5
|
*/
|
|
6
|
+
import { Form, Input } from '@happyvertical/smrt-ui/forms';
|
|
6
7
|
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
8
|
+
import { Button } from '@happyvertical/smrt-ui/ui';
|
|
7
9
|
import { M } from '../../i18n.js';
|
|
8
10
|
import type { ChatMessageData } from '../../types.js';
|
|
9
11
|
|
|
@@ -25,11 +27,16 @@ export interface Props {
|
|
|
25
27
|
let { isOpen, onclose, onsearch, results, onselectresult }: Props = $props();
|
|
26
28
|
|
|
27
29
|
let query = $state('');
|
|
28
|
-
let searchInput = $state<HTMLInputElement | null>(null);
|
|
29
30
|
|
|
30
31
|
const hasResults = $derived(results.length > 0);
|
|
31
32
|
const hasQuery = $derived(query.trim().length > 0);
|
|
32
33
|
|
|
34
|
+
// The Input primitive doesn't expose its inner element, so resolve it by id.
|
|
35
|
+
function focusSearchInput() {
|
|
36
|
+
if (typeof document === 'undefined') return;
|
|
37
|
+
document.getElementById('search-messages-input')?.focus();
|
|
38
|
+
}
|
|
39
|
+
|
|
33
40
|
function handleSubmit() {
|
|
34
41
|
const trimmed = query.trim();
|
|
35
42
|
if (trimmed.length > 0) {
|
|
@@ -94,8 +101,10 @@ $effect(() => {
|
|
|
94
101
|
});
|
|
95
102
|
|
|
96
103
|
$effect(() => {
|
|
97
|
-
if (isOpen
|
|
98
|
-
|
|
104
|
+
if (isOpen) {
|
|
105
|
+
// Defer a frame so the search input is mounted before focusing.
|
|
106
|
+
const raf = requestAnimationFrame(focusSearchInput);
|
|
107
|
+
return () => cancelAnimationFrame(raf);
|
|
99
108
|
}
|
|
100
109
|
});
|
|
101
110
|
</script>
|
|
@@ -108,7 +117,9 @@ $effect(() => {
|
|
|
108
117
|
>
|
|
109
118
|
<div class="search-panel__header">
|
|
110
119
|
<h2 class="search-panel__title">{t(M['chat.search_messages.title'])}</h2>
|
|
111
|
-
<
|
|
120
|
+
<Button
|
|
121
|
+
variant="ghost"
|
|
122
|
+
size="sm"
|
|
112
123
|
class="close-btn"
|
|
113
124
|
type="button"
|
|
114
125
|
onclick={handleClose}
|
|
@@ -118,10 +129,10 @@ $effect(() => {
|
|
|
118
129
|
<path d="M18 6 6 18" />
|
|
119
130
|
<path d="m6 6 12 12" />
|
|
120
131
|
</svg>
|
|
121
|
-
</
|
|
132
|
+
</Button>
|
|
122
133
|
</div>
|
|
123
134
|
|
|
124
|
-
<
|
|
135
|
+
<Form
|
|
125
136
|
class="search-form"
|
|
126
137
|
onsubmit={(e) => { e.preventDefault(); handleSubmit(); }}
|
|
127
138
|
>
|
|
@@ -130,9 +141,9 @@ $effect(() => {
|
|
|
130
141
|
<circle cx="11" cy="11" r="8" />
|
|
131
142
|
<path d="m21 21-4.35-4.35" />
|
|
132
143
|
</svg>
|
|
133
|
-
<
|
|
134
|
-
bind:this={searchInput}
|
|
144
|
+
<Input
|
|
135
145
|
bind:value={query}
|
|
146
|
+
id="search-messages-input"
|
|
136
147
|
type="search"
|
|
137
148
|
class="search-input"
|
|
138
149
|
placeholder={t(M['chat.search_messages.input_placeholder'])}
|
|
@@ -140,20 +151,22 @@ $effect(() => {
|
|
|
140
151
|
aria-label={t(M['chat.search_messages.query'])}
|
|
141
152
|
/>
|
|
142
153
|
{#if hasQuery}
|
|
143
|
-
<
|
|
154
|
+
<Button
|
|
155
|
+
variant="ghost"
|
|
156
|
+
size="sm"
|
|
144
157
|
class="clear-btn"
|
|
145
158
|
type="button"
|
|
146
|
-
onclick={() => { query = '';
|
|
159
|
+
onclick={() => { query = ''; focusSearchInput(); }}
|
|
147
160
|
aria-label={t(M['chat.search_messages.clear'])}
|
|
148
161
|
>
|
|
149
162
|
<svg class="clear-btn__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
150
163
|
<path d="M18 6 6 18" />
|
|
151
164
|
<path d="m6 6 12 12" />
|
|
152
165
|
</svg>
|
|
153
|
-
</
|
|
166
|
+
</Button>
|
|
154
167
|
{/if}
|
|
155
168
|
</div>
|
|
156
|
-
</
|
|
169
|
+
</Form>
|
|
157
170
|
|
|
158
171
|
<div class="search-results" aria-label={t(M['chat.search_messages.results'])}>
|
|
159
172
|
{#if hasResults}
|
|
@@ -163,6 +176,7 @@ $effect(() => {
|
|
|
163
176
|
<ul class="results-list" aria-label={t(M['chat.search_messages.results'])}>
|
|
164
177
|
{#each results as message (message.id)}
|
|
165
178
|
<li class="results-list__item">
|
|
179
|
+
<!-- raw-primitive-allow: large pressable search-result card wrapping rich content (avatar, sender, date, multi-line highlighted message excerpt); no Button primitive owns this structural selection-card pattern -->
|
|
166
180
|
<button
|
|
167
181
|
class="result-item"
|
|
168
182
|
type="button"
|
|
@@ -231,35 +245,28 @@ $effect(() => {
|
|
|
231
245
|
color: var(--smrt-color-on-surface, #1a1c1e);
|
|
232
246
|
}
|
|
233
247
|
|
|
234
|
-
.
|
|
235
|
-
|
|
236
|
-
align-items: center;
|
|
237
|
-
justify-content: center;
|
|
248
|
+
/* :global() pierces into the Button child's rendered <button> (see #1589). */
|
|
249
|
+
.search-panel__header :global(.close-btn) {
|
|
238
250
|
width: 1.75rem;
|
|
239
251
|
height: 1.75rem;
|
|
240
|
-
|
|
252
|
+
padding: 0;
|
|
241
253
|
background: none;
|
|
242
254
|
border-radius: var(--smrt-radius-medium, 0.5rem);
|
|
243
255
|
color: var(--smrt-color-on-surface-variant, #43474e);
|
|
244
|
-
cursor: pointer;
|
|
245
256
|
transition: background var(--smrt-duration-short2, 150ms);
|
|
246
257
|
}
|
|
247
258
|
|
|
248
|
-
.close-btn:hover {
|
|
259
|
+
.search-panel__header :global(.close-btn:hover) {
|
|
249
260
|
background: var(--smrt-color-surface-variant, #e1e2ec);
|
|
250
261
|
}
|
|
251
262
|
|
|
252
|
-
.close-btn:focus-visible {
|
|
253
|
-
outline: 2px solid var(--smrt-color-primary, #005ac1);
|
|
254
|
-
outline-offset: -2px;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
263
|
.close-btn__icon {
|
|
258
264
|
width: 1rem;
|
|
259
265
|
height: 1rem;
|
|
260
266
|
}
|
|
261
267
|
|
|
262
|
-
|
|
268
|
+
/* :global() targets the Form primitive's rendered <form> (see #1589 scoping trap). */
|
|
269
|
+
:global(.search-form) {
|
|
263
270
|
padding: 0.75rem 1rem;
|
|
264
271
|
border-bottom: 1px solid var(--smrt-color-outline-variant, #c4c6d0);
|
|
265
272
|
}
|
|
@@ -287,34 +294,39 @@ $effect(() => {
|
|
|
287
294
|
color: var(--smrt-color-on-surface-variant, #43474e);
|
|
288
295
|
}
|
|
289
296
|
|
|
290
|
-
.search-input
|
|
297
|
+
/* The Input primitive sits inside the bordered .search-input-wrap, which owns
|
|
298
|
+
the border + focus-within ring — so neutralize the primitive's own chrome
|
|
299
|
+
(border/background/padding/box-shadow) and let it render borderless. */
|
|
300
|
+
:global(.search-input) {
|
|
291
301
|
flex: 1;
|
|
292
302
|
border: none;
|
|
293
303
|
outline: none;
|
|
304
|
+
padding: 0;
|
|
294
305
|
background: transparent;
|
|
306
|
+
box-shadow: none;
|
|
295
307
|
font: var(--smrt-typography-body-medium-font, 0.875rem / 1.25 sans-serif);
|
|
296
308
|
color: var(--smrt-color-on-surface, #1a1c1e);
|
|
297
309
|
}
|
|
298
310
|
|
|
299
|
-
.search-input
|
|
300
|
-
|
|
311
|
+
:global(.search-input:focus) {
|
|
312
|
+
border: none;
|
|
313
|
+
outline: none;
|
|
314
|
+
box-shadow: none;
|
|
301
315
|
}
|
|
302
316
|
|
|
303
|
-
.
|
|
317
|
+
/* :global() pierces into the Button child's rendered <button> (see #1589). */
|
|
318
|
+
.search-input-wrap :global(.clear-btn) {
|
|
304
319
|
flex-shrink: 0;
|
|
305
|
-
display: inline-flex;
|
|
306
|
-
align-items: center;
|
|
307
|
-
justify-content: center;
|
|
308
320
|
width: 1.25rem;
|
|
309
321
|
height: 1.25rem;
|
|
310
|
-
|
|
322
|
+
padding: 0;
|
|
311
323
|
background: none;
|
|
312
324
|
border-radius: var(--smrt-radius-full, 9999px);
|
|
313
325
|
color: var(--smrt-color-on-surface-variant, #43474e);
|
|
314
|
-
cursor: pointer;
|
|
315
326
|
}
|
|
316
327
|
|
|
317
|
-
.clear-btn:hover {
|
|
328
|
+
.search-input-wrap :global(.clear-btn:hover) {
|
|
329
|
+
background: none;
|
|
318
330
|
color: var(--smrt-color-on-surface, #1a1c1e);
|
|
319
331
|
}
|
|
320
332
|
|
|
@@ -448,10 +460,13 @@ $effect(() => {
|
|
|
448
460
|
}
|
|
449
461
|
|
|
450
462
|
@media (prefers-reduced-motion: reduce) {
|
|
451
|
-
.close-btn,
|
|
452
463
|
.result-item,
|
|
453
464
|
.search-input-wrap {
|
|
454
465
|
transition: none;
|
|
455
466
|
}
|
|
467
|
+
|
|
468
|
+
.search-panel__header :global(.close-btn) {
|
|
469
|
+
transition: none;
|
|
470
|
+
}
|
|
456
471
|
}
|
|
457
472
|
</style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchMessages.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/dialogs/SearchMessages.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SearchMessages.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/dialogs/SearchMessages.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD,MAAM,WAAW,KAAK;IACpB,uCAAuC;IACvC,MAAM,EAAE,OAAO,CAAC;IAChB,yCAAyC;IACzC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gDAAgD;IAChD,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,qBAAqB;IACrB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,yCAAyC;IACzC,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AAmLD,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -72,6 +72,7 @@ function handlePointerUp() {
|
|
|
72
72
|
/>
|
|
73
73
|
</aside>
|
|
74
74
|
|
|
75
|
+
<!-- raw-primitive-allow: custom drag-to-resize splitter with pointer capture (pointerdown/move/up) and ArrowLeft/ArrowRight keyboard resizing; a press-and-drag control no Button primitive owns -->
|
|
75
76
|
<button
|
|
76
77
|
type="button"
|
|
77
78
|
class="chat-layout__resize-handle"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatLayout.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/layout/ChatLayout.svelte.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAInD,MAAM,WAAW,KAAK;IACpB,2BAA2B;IAC3B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,iCAAiC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gCAAgC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,uCAAuC;IACvC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,wBAAwB;IACxB,QAAQ,EAAE,OAAO,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"ChatLayout.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/layout/ChatLayout.svelte.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAInD,MAAM,WAAW,KAAK;IACpB,2BAA2B;IAC3B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,iCAAiC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gCAAgC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,uCAAuC;IACvC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,wBAAwB;IACxB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAgED,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Lists participants grouped by online status with role badges
|
|
5
5
|
*/
|
|
6
6
|
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
7
|
+
import { Button } from '@happyvertical/smrt-ui/ui';
|
|
7
8
|
import { M } from '../../i18n.messages.js';
|
|
8
9
|
import type { ChatParticipantData } from '../../types.js';
|
|
9
10
|
|
|
@@ -74,7 +75,9 @@ function getRoleBadgeLabel(role: string): string {
|
|
|
74
75
|
<div class="member-list__header">
|
|
75
76
|
<h2 class="member-list__title">Members</h2>
|
|
76
77
|
<span class="member-list__count">{participants.length}</span>
|
|
77
|
-
<
|
|
78
|
+
<Button
|
|
79
|
+
variant="ghost"
|
|
80
|
+
size="sm"
|
|
78
81
|
class="close-btn"
|
|
79
82
|
type="button"
|
|
80
83
|
onclick={onclose}
|
|
@@ -84,7 +87,7 @@ function getRoleBadgeLabel(role: string): string {
|
|
|
84
87
|
<path d="M18 6 6 18" />
|
|
85
88
|
<path d="m6 6 12 12" />
|
|
86
89
|
</svg>
|
|
87
|
-
</
|
|
90
|
+
</Button>
|
|
88
91
|
</div>
|
|
89
92
|
|
|
90
93
|
<div class="member-list__content">
|
|
@@ -235,30 +238,22 @@ function getRoleBadgeLabel(role: string): string {
|
|
|
235
238
|
color: var(--smrt-color-on-surface-variant, #43474e);
|
|
236
239
|
}
|
|
237
240
|
|
|
238
|
-
.
|
|
241
|
+
/* :global() pierces into the Button child's rendered <button> (see #1589). */
|
|
242
|
+
.member-list__header :global(.close-btn) {
|
|
239
243
|
margin-left: auto;
|
|
240
|
-
display: inline-flex;
|
|
241
|
-
align-items: center;
|
|
242
|
-
justify-content: center;
|
|
243
244
|
width: 1.75rem;
|
|
244
245
|
height: 1.75rem;
|
|
245
|
-
|
|
246
|
+
padding: 0;
|
|
246
247
|
background: none;
|
|
247
248
|
border-radius: var(--smrt-radius-medium, 0.5rem);
|
|
248
249
|
color: var(--smrt-color-on-surface-variant, #43474e);
|
|
249
|
-
cursor: pointer;
|
|
250
250
|
transition: background var(--smrt-duration-short2, 150ms);
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
.close-btn:hover {
|
|
253
|
+
.member-list__header :global(.close-btn:hover) {
|
|
254
254
|
background: var(--smrt-color-surface-variant, #e1e2ec);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
.close-btn:focus-visible {
|
|
258
|
-
outline: 2px solid var(--smrt-color-primary, #005ac1);
|
|
259
|
-
outline-offset: -2px;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
257
|
.close-btn__icon {
|
|
263
258
|
width: 1rem;
|
|
264
259
|
height: 1rem;
|
|
@@ -384,7 +379,7 @@ function getRoleBadgeLabel(role: string): string {
|
|
|
384
379
|
}
|
|
385
380
|
|
|
386
381
|
@media (prefers-reduced-motion: reduce) {
|
|
387
|
-
.close-btn {
|
|
382
|
+
.member-list__header :global(.close-btn) {
|
|
388
383
|
transition: none;
|
|
389
384
|
}
|
|
390
385
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemberList.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/layout/MemberList.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MemberList.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/layout/MemberList.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1D,MAAM,WAAW,KAAK;IACpB,wBAAwB;IACxB,YAAY,EAAE,mBAAmB,EAAE,CAAC;IACpC,yCAAyC;IACzC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AA2LD,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Displays room info and provides access to members and search
|
|
5
5
|
*/
|
|
6
6
|
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
7
|
+
import { Button } from '@happyvertical/smrt-ui/ui';
|
|
7
8
|
import { M } from '../../i18n.messages.js';
|
|
8
9
|
import type { ChatRoomData } from '../../types.js';
|
|
9
10
|
|
|
@@ -78,7 +79,9 @@ const roomTypeLabel = $derived.by(() => {
|
|
|
78
79
|
|
|
79
80
|
<div class="room-header__actions">
|
|
80
81
|
{#if onshowmembers}
|
|
81
|
-
<
|
|
82
|
+
<Button
|
|
83
|
+
variant="ghost"
|
|
84
|
+
size="sm"
|
|
82
85
|
class="header-btn"
|
|
83
86
|
type="button"
|
|
84
87
|
onclick={onshowmembers}
|
|
@@ -92,11 +95,13 @@ const roomTypeLabel = $derived.by(() => {
|
|
|
92
95
|
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
|
|
93
96
|
</svg>
|
|
94
97
|
<span class="header-btn__count">{participantCount}</span>
|
|
95
|
-
</
|
|
98
|
+
</Button>
|
|
96
99
|
{/if}
|
|
97
100
|
|
|
98
101
|
{#if onshowsearch}
|
|
99
|
-
<
|
|
102
|
+
<Button
|
|
103
|
+
variant="ghost"
|
|
104
|
+
size="sm"
|
|
100
105
|
class="header-btn"
|
|
101
106
|
type="button"
|
|
102
107
|
onclick={onshowsearch}
|
|
@@ -107,7 +112,7 @@ const roomTypeLabel = $derived.by(() => {
|
|
|
107
112
|
<circle cx="11" cy="11" r="8" />
|
|
108
113
|
<path d="m21 21-4.35-4.35" />
|
|
109
114
|
</svg>
|
|
110
|
-
</
|
|
115
|
+
</Button>
|
|
111
116
|
{/if}
|
|
112
117
|
</div>
|
|
113
118
|
</header>
|
|
@@ -201,28 +206,20 @@ const roomTypeLabel = $derived.by(() => {
|
|
|
201
206
|
gap: 0.25rem;
|
|
202
207
|
}
|
|
203
208
|
|
|
204
|
-
.
|
|
205
|
-
|
|
206
|
-
align-items: center;
|
|
209
|
+
/* :global() pierces into each Button's rendered <button> (see #1589). */
|
|
210
|
+
.room-header__actions :global(.header-btn) {
|
|
207
211
|
gap: 0.25rem;
|
|
208
212
|
padding: 0.375rem 0.5rem;
|
|
209
|
-
border: none;
|
|
210
213
|
background: none;
|
|
211
214
|
border-radius: var(--smrt-radius-medium, 0.5rem);
|
|
212
215
|
color: var(--smrt-color-on-surface-variant, #43474e);
|
|
213
|
-
cursor: pointer;
|
|
214
216
|
transition: background var(--smrt-duration-short2, 150ms);
|
|
215
217
|
}
|
|
216
218
|
|
|
217
|
-
.header-btn:hover {
|
|
219
|
+
.room-header__actions :global(.header-btn:hover) {
|
|
218
220
|
background: var(--smrt-color-surface-variant, #e1e2ec);
|
|
219
221
|
}
|
|
220
222
|
|
|
221
|
-
.header-btn:focus-visible {
|
|
222
|
-
outline: 2px solid var(--smrt-color-primary, #005ac1);
|
|
223
|
-
outline-offset: -2px;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
223
|
.header-btn__icon {
|
|
227
224
|
width: 1.25rem;
|
|
228
225
|
height: 1.25rem;
|
|
@@ -234,7 +231,7 @@ const roomTypeLabel = $derived.by(() => {
|
|
|
234
231
|
}
|
|
235
232
|
|
|
236
233
|
@media (prefers-reduced-motion: reduce) {
|
|
237
|
-
.header-btn {
|
|
234
|
+
.room-header__actions :global(.header-btn) {
|
|
238
235
|
transition: none;
|
|
239
236
|
}
|
|
240
237
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RoomHeader.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/layout/RoomHeader.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RoomHeader.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/layout/RoomHeader.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,MAAM,WAAW,KAAK;IACpB,wBAAwB;IACxB,IAAI,EAAE,YAAY,CAAC;IACnB,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AA+FD,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Groups rooms by type: channels, DMs, and agent conversations
|
|
5
5
|
*/
|
|
6
6
|
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
7
|
+
import { Button } from '@happyvertical/smrt-ui/ui';
|
|
7
8
|
import { M } from '../../i18n.messages.js';
|
|
8
9
|
import type { ChatRoomData } from '../../types.js';
|
|
9
10
|
|
|
@@ -71,19 +72,22 @@ function formatTimestamp(date?: string | Date | null): string {
|
|
|
71
72
|
<nav class="room-list" aria-label={t(M['chat.room_list.rooms_label'])}>
|
|
72
73
|
{#if oncreateroom}
|
|
73
74
|
<div class="room-list__header">
|
|
74
|
-
<
|
|
75
|
+
<Button
|
|
76
|
+
variant="ghost"
|
|
77
|
+
fullWidth
|
|
75
78
|
class="create-room-btn"
|
|
76
79
|
type="button"
|
|
77
80
|
onclick={oncreateroom}
|
|
78
81
|
aria-label={t(M['chat.room_list.create_new_room'])}
|
|
79
82
|
>
|
|
80
83
|
{t(M['chat.room_list.new_room'])}
|
|
81
|
-
</
|
|
84
|
+
</Button>
|
|
82
85
|
</div>
|
|
83
86
|
{/if}
|
|
84
87
|
|
|
85
88
|
{#if channels.length > 0}
|
|
86
89
|
<section class="room-group">
|
|
90
|
+
<!-- raw-primitive-allow: section disclosure trigger with aria-expanded toggling a collapsible room list, wrapping rich content (rotating chevron, group label, room count); structural accordion header no Button primitive owns -->
|
|
87
91
|
<button
|
|
88
92
|
class="room-group__header"
|
|
89
93
|
type="button"
|
|
@@ -101,6 +105,7 @@ function formatTimestamp(date?: string | Date | null): string {
|
|
|
101
105
|
<ul class="room-group__list" role="list">
|
|
102
106
|
{#each channels as room (room.id)}
|
|
103
107
|
<li>
|
|
108
|
+
<!-- raw-primitive-allow: pressable room-selection row with active and aria-current state, wrapping rich content (type icon, name, unread badge); no Button primitive owns this structural nav-selection pattern -->
|
|
104
109
|
<button
|
|
105
110
|
class="room-item"
|
|
106
111
|
class:room-item--active={room.id === currentRoomId}
|
|
@@ -126,6 +131,7 @@ function formatTimestamp(date?: string | Date | null): string {
|
|
|
126
131
|
|
|
127
132
|
{#if directMessages.length > 0}
|
|
128
133
|
<section class="room-group">
|
|
134
|
+
<!-- raw-primitive-allow: section disclosure trigger with aria-expanded toggling a collapsible room list, wrapping rich content (rotating chevron, group label, room count); structural accordion header no Button primitive owns -->
|
|
129
135
|
<button
|
|
130
136
|
class="room-group__header"
|
|
131
137
|
type="button"
|
|
@@ -143,6 +149,7 @@ function formatTimestamp(date?: string | Date | null): string {
|
|
|
143
149
|
<ul class="room-group__list" role="list">
|
|
144
150
|
{#each directMessages as room (room.id)}
|
|
145
151
|
<li>
|
|
152
|
+
<!-- raw-primitive-allow: pressable room-selection row with active and aria-current state, wrapping rich content (avatar, name, last-message preview, timestamp, unread badge); no Button primitive owns this structural nav-selection pattern -->
|
|
146
153
|
<button
|
|
147
154
|
class="room-item"
|
|
148
155
|
class:room-item--active={room.id === currentRoomId}
|
|
@@ -184,6 +191,7 @@ function formatTimestamp(date?: string | Date | null): string {
|
|
|
184
191
|
|
|
185
192
|
{#if agentRooms.length > 0}
|
|
186
193
|
<section class="room-group">
|
|
194
|
+
<!-- raw-primitive-allow: section disclosure trigger with aria-expanded toggling a collapsible room list, wrapping rich content (rotating chevron, group label, room count); structural accordion header no Button primitive owns -->
|
|
187
195
|
<button
|
|
188
196
|
class="room-group__header"
|
|
189
197
|
type="button"
|
|
@@ -201,6 +209,7 @@ function formatTimestamp(date?: string | Date | null): string {
|
|
|
201
209
|
<ul class="room-group__list" role="list">
|
|
202
210
|
{#each agentRooms as room (room.id)}
|
|
203
211
|
<li>
|
|
212
|
+
<!-- raw-primitive-allow: pressable room-selection row with active and aria-current state, wrapping rich content (agent icon, name, unread badge); no Button primitive owns this structural nav-selection pattern -->
|
|
204
213
|
<button
|
|
205
214
|
class="room-item"
|
|
206
215
|
class:room-item--active={room.id === currentRoomId}
|
|
@@ -227,9 +236,9 @@ function formatTimestamp(date?: string | Date | null): string {
|
|
|
227
236
|
<div class="room-list__empty">
|
|
228
237
|
<p>{t(M['chat.room_list.no_rooms'])}</p>
|
|
229
238
|
{#if oncreateroom}
|
|
230
|
-
<
|
|
239
|
+
<Button variant="ghost" size="sm" class="create-link" type="button" onclick={oncreateroom}>
|
|
231
240
|
{t(M['chat.room_list.create_first_room'])}
|
|
232
|
-
</
|
|
241
|
+
</Button>
|
|
233
242
|
{/if}
|
|
234
243
|
</div>
|
|
235
244
|
{/if}
|
|
@@ -247,27 +256,21 @@ function formatTimestamp(date?: string | Date | null): string {
|
|
|
247
256
|
padding: 0.5rem 0.75rem;
|
|
248
257
|
}
|
|
249
258
|
|
|
250
|
-
.
|
|
251
|
-
|
|
259
|
+
/* :global() pierces into the Button child's rendered <button> (see #1589). */
|
|
260
|
+
.room-list__header :global(.create-room-btn) {
|
|
252
261
|
padding: 0.5rem 0.75rem;
|
|
253
262
|
border: 1px dashed var(--smrt-color-outline, #74777f);
|
|
254
263
|
border-radius: var(--smrt-radius-medium, 0.5rem);
|
|
255
264
|
background: transparent;
|
|
256
265
|
color: var(--smrt-color-primary, #005ac1);
|
|
257
266
|
font: var(--smrt-typography-label-large-font, 500 0.875rem / 1.25 sans-serif);
|
|
258
|
-
cursor: pointer;
|
|
259
267
|
transition: background var(--smrt-duration-short2, 150ms);
|
|
260
268
|
}
|
|
261
269
|
|
|
262
|
-
.create-room-btn:hover {
|
|
270
|
+
.room-list__header :global(.create-room-btn:hover) {
|
|
263
271
|
background: var(--smrt-color-primary-container, #d6e3ff);
|
|
264
272
|
}
|
|
265
273
|
|
|
266
|
-
.create-room-btn:focus-visible {
|
|
267
|
-
outline: 2px solid var(--smrt-color-primary, #005ac1);
|
|
268
|
-
outline-offset: -2px;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
274
|
.room-group {
|
|
272
275
|
margin-top: 0.25rem;
|
|
273
276
|
}
|
|
@@ -452,20 +455,26 @@ function formatTimestamp(date?: string | Date | null): string {
|
|
|
452
455
|
font: var(--smrt-typography-body-medium-font, 0.875rem / 1.25 sans-serif);
|
|
453
456
|
}
|
|
454
457
|
|
|
455
|
-
.
|
|
456
|
-
|
|
458
|
+
/* :global() pierces into the Button child's rendered <button> (see #1589). */
|
|
459
|
+
.room-list__empty :global(.create-link) {
|
|
457
460
|
background: none;
|
|
458
461
|
color: var(--smrt-color-primary, #005ac1);
|
|
459
462
|
font: var(--smrt-typography-label-large-font, 500 0.875rem / 1.25 sans-serif);
|
|
460
|
-
cursor: pointer;
|
|
461
463
|
text-decoration: underline;
|
|
462
464
|
}
|
|
463
465
|
|
|
466
|
+
.room-list__empty :global(.create-link:hover) {
|
|
467
|
+
background: none;
|
|
468
|
+
}
|
|
469
|
+
|
|
464
470
|
@media (prefers-reduced-motion: reduce) {
|
|
465
471
|
.room-item,
|
|
466
|
-
.create-room-btn,
|
|
467
472
|
.room-group__chevron {
|
|
468
473
|
transition: none;
|
|
469
474
|
}
|
|
475
|
+
|
|
476
|
+
.room-list__header :global(.create-room-btn) {
|
|
477
|
+
transition: none;
|
|
478
|
+
}
|
|
470
479
|
}
|
|
471
480
|
</style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RoomList.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/layout/RoomList.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RoomList.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/layout/RoomList.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,MAAM,WAAW,KAAK;IACpB,2BAA2B;IAC3B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,iCAAiC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAoMD,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|