@webitel/ui-chats 26.8.4 → 26.8.6
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/package.json +1 -1
- package/src/v2/scripts/__tests__/getMessageStatus.spec.ts +90 -0
- package/src/v2/scripts/getMessageStatus.ts +2 -1
- package/src/v2/scripts/isSelfMessage.ts +29 -0
- package/src/v2/ui/chat-composer/chat-composer.vue +2 -0
- package/src/v2/ui/chat-history/__tests__/chat-history.spec.ts +99 -0
- package/src/v2/ui/chat-history/chat-history.vue +5 -4
- package/src/v2/ui/chat-history/components/chat-date-divider.vue +6 -0
- package/src/v2/ui/chat-history/components/chat-message.vue +45 -11
- package/src/v2/ui/chat-history/components/chat-system-notice.vue +18 -7
- package/src/v2/ui/chat-history/components/scroll-to-bottom-btn.vue +2 -1
- package/types/.tsbuildinfo +1 -1
- package/types/v2/scripts/isSelfMessage.d.ts +10 -0
package/package.json
CHANGED
|
@@ -211,4 +211,94 @@ describe('getMessageStatus', () => {
|
|
|
211
211
|
});
|
|
212
212
|
expect(getMessageStatus(own('3'), t, operator.id)).toBe('read');
|
|
213
213
|
});
|
|
214
|
+
|
|
215
|
+
// A re-joined operator gets a new member id, but the thread snapshot (and so
|
|
216
|
+
// selfMemberId) still holds the old one; their contact is the stable identity.
|
|
217
|
+
describe('after the operator rejoined with a new member id', () => {
|
|
218
|
+
const oldMember = {
|
|
219
|
+
id: 'm-me-old',
|
|
220
|
+
contact: {
|
|
221
|
+
name: 'Dania',
|
|
222
|
+
type: 'webitel',
|
|
223
|
+
sub: '164',
|
|
224
|
+
iss: 'webitel',
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
const newMember = {
|
|
228
|
+
id: 'm-me-new',
|
|
229
|
+
contact: {
|
|
230
|
+
name: 'Dania',
|
|
231
|
+
type: 'webitel',
|
|
232
|
+
sub: '164',
|
|
233
|
+
iss: 'webitel',
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
const t = thread({
|
|
237
|
+
members: [
|
|
238
|
+
oldMember,
|
|
239
|
+
client,
|
|
240
|
+
],
|
|
241
|
+
readStates: [
|
|
242
|
+
{
|
|
243
|
+
memberId: client.id,
|
|
244
|
+
readUpToSeq: '5',
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('still treats their messages as their own', () => {
|
|
250
|
+
expect(
|
|
251
|
+
getMessageStatus(
|
|
252
|
+
message({
|
|
253
|
+
sender: newMember,
|
|
254
|
+
seq: '3',
|
|
255
|
+
}),
|
|
256
|
+
t,
|
|
257
|
+
oldMember.id,
|
|
258
|
+
),
|
|
259
|
+
).toBe('read');
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it('does not claim another operator’s message', () => {
|
|
263
|
+
const other = {
|
|
264
|
+
id: 'm-other',
|
|
265
|
+
contact: {
|
|
266
|
+
name: 'Ola',
|
|
267
|
+
type: 'webitel',
|
|
268
|
+
sub: '289',
|
|
269
|
+
iss: 'webitel',
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
expect(
|
|
273
|
+
getMessageStatus(
|
|
274
|
+
message({
|
|
275
|
+
sender: other,
|
|
276
|
+
}),
|
|
277
|
+
t,
|
|
278
|
+
oldMember.id,
|
|
279
|
+
),
|
|
280
|
+
).toBeNull();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('does not match the same subject from another issuer', () => {
|
|
284
|
+
const lookalike = {
|
|
285
|
+
id: 'm-x',
|
|
286
|
+
contact: {
|
|
287
|
+
name: 'Dania',
|
|
288
|
+
type: 'telegram',
|
|
289
|
+
sub: '164',
|
|
290
|
+
iss: 'telegram',
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
expect(
|
|
294
|
+
getMessageStatus(
|
|
295
|
+
message({
|
|
296
|
+
sender: lookalike,
|
|
297
|
+
}),
|
|
298
|
+
t,
|
|
299
|
+
oldMember.id,
|
|
300
|
+
),
|
|
301
|
+
).toBeNull();
|
|
302
|
+
});
|
|
303
|
+
});
|
|
214
304
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ChatMessageStatus, MessageModel, ThreadModel } from '../types';
|
|
2
2
|
import { isContactCentreSide } from './isContactCentreSide';
|
|
3
|
+
import { isSelfMessage } from './isSelfMessage';
|
|
3
4
|
import { toSeq } from './toTimestamp';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -14,7 +15,7 @@ export const getMessageStatus = (
|
|
|
14
15
|
selfMemberId: string,
|
|
15
16
|
): ChatMessageStatus | null => {
|
|
16
17
|
if (message.deleted || message.system) return null;
|
|
17
|
-
if (!message
|
|
18
|
+
if (!isSelfMessage(message, thread, selfMemberId)) return null;
|
|
18
19
|
|
|
19
20
|
const seq = toSeq(message.seq);
|
|
20
21
|
if (seq === null) return 'sent';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { MessageModel, ThreadModel } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Whether the operator using the UI sent this message.
|
|
5
|
+
*
|
|
6
|
+
* Member ids are per membership: an operator who is removed and added again
|
|
7
|
+
* gets a new one, while `thread.members` (and so `selfMemberId`) may still
|
|
8
|
+
* hold the old. So an id match is not enough; the stable identity is the
|
|
9
|
+
* contact — same subject from the same issuer as the operator's own member.
|
|
10
|
+
*/
|
|
11
|
+
export const isSelfMessage = (
|
|
12
|
+
message: MessageModel,
|
|
13
|
+
thread: ThreadModel,
|
|
14
|
+
selfMemberId: string,
|
|
15
|
+
): boolean => {
|
|
16
|
+
const sender = message.sender;
|
|
17
|
+
if (!sender?.id || !selfMemberId) return false;
|
|
18
|
+
if (sender.id === selfMemberId) return true;
|
|
19
|
+
|
|
20
|
+
const self = thread.members?.find((member) => member.id === selfMemberId);
|
|
21
|
+
const selfContact = self?.contact;
|
|
22
|
+
const senderContact = sender.contact;
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
!!selfContact?.sub &&
|
|
26
|
+
selfContact.sub === senderContact?.sub &&
|
|
27
|
+
selfContact.iss === senderContact?.iss
|
|
28
|
+
);
|
|
29
|
+
};
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
v-if="hasAction(ChatComposerAction.Emoji)"
|
|
41
41
|
:popup-teleport-to="`#${composerId}`"
|
|
42
42
|
:rounded="false"
|
|
43
|
+
variant="text"
|
|
43
44
|
size="sm"
|
|
44
45
|
:title="t('composer.emoji')"
|
|
45
46
|
@insert-emoji="insertText"
|
|
@@ -54,6 +55,7 @@
|
|
|
54
55
|
class="chat-composer__send"
|
|
55
56
|
icon="chat-send"
|
|
56
57
|
color="secondary"
|
|
58
|
+
size="sm"
|
|
57
59
|
:loading="isSending"
|
|
58
60
|
:disabled="isLocked || !canSend"
|
|
59
61
|
:title="t('composer.send')"
|
|
@@ -102,6 +102,105 @@ describe('ChatHistory', () => {
|
|
|
102
102
|
expect(rows[1].find('.message-status').exists()).toBe(true);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
+
describe('avatar tooltips', () => {
|
|
106
|
+
const hover = async (
|
|
107
|
+
activator: ReturnType<ReturnType<typeof setup>['find']>,
|
|
108
|
+
) => {
|
|
109
|
+
await activator.trigger('mouseenter');
|
|
110
|
+
await flushPromises();
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
it('names the author of a message on hover', async () => {
|
|
114
|
+
const wrapper = setup({
|
|
115
|
+
messages: [
|
|
116
|
+
message({
|
|
117
|
+
sender: client,
|
|
118
|
+
}),
|
|
119
|
+
],
|
|
120
|
+
});
|
|
121
|
+
const activator = wrapper.find('.chat-message .wt-tooltip__activator');
|
|
122
|
+
|
|
123
|
+
expect(wrapper.find('.wt-tooltip__floating').exists()).toBe(false);
|
|
124
|
+
await hover(activator);
|
|
125
|
+
|
|
126
|
+
expect(wrapper.find('.wt-tooltip__floating').text()).toBe(
|
|
127
|
+
'Emily Johnson',
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('names the actor of a system notice on hover', async () => {
|
|
132
|
+
const wrapper = setup({
|
|
133
|
+
messages: [
|
|
134
|
+
message({
|
|
135
|
+
sender: operator,
|
|
136
|
+
system: {
|
|
137
|
+
type: 'transferred',
|
|
138
|
+
},
|
|
139
|
+
}),
|
|
140
|
+
],
|
|
141
|
+
});
|
|
142
|
+
await hover(wrapper.find('.chat-system-notice .wt-tooltip__activator'));
|
|
143
|
+
|
|
144
|
+
expect(wrapper.find('.wt-tooltip__floating').text()).toBe(
|
|
145
|
+
'Alina Timoshenko',
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// an empty tooltip bubble is worse than none
|
|
150
|
+
it('shows no tooltip for an author without a name', async () => {
|
|
151
|
+
const nameless = {
|
|
152
|
+
id: 'm-x',
|
|
153
|
+
contact: {
|
|
154
|
+
type: 'telegram',
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
const wrapper = setup({
|
|
158
|
+
messages: [
|
|
159
|
+
message({
|
|
160
|
+
sender: nameless,
|
|
161
|
+
}),
|
|
162
|
+
],
|
|
163
|
+
});
|
|
164
|
+
await hover(wrapper.find('.chat-message .wt-tooltip__activator'));
|
|
165
|
+
|
|
166
|
+
expect(wrapper.find('.wt-tooltip__floating').exists()).toBe(false);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// a rejoined operator gets a new member id, but their contact stays the same
|
|
171
|
+
it('still recognises the operator’s messages after they rejoined under a new member id', () => {
|
|
172
|
+
const me = {
|
|
173
|
+
id: 'm-me',
|
|
174
|
+
contact: {
|
|
175
|
+
name: 'Dania',
|
|
176
|
+
type: 'webitel',
|
|
177
|
+
sub: '164',
|
|
178
|
+
iss: 'webitel',
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
const rejoined = {
|
|
182
|
+
id: 'm-me-2',
|
|
183
|
+
contact: {
|
|
184
|
+
...me.contact,
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
const wrapper = setup({
|
|
188
|
+
thread: thread({
|
|
189
|
+
members: [
|
|
190
|
+
me,
|
|
191
|
+
client,
|
|
192
|
+
],
|
|
193
|
+
}),
|
|
194
|
+
selfMemberId: me.id,
|
|
195
|
+
messages: [
|
|
196
|
+
message({
|
|
197
|
+
sender: rejoined,
|
|
198
|
+
}),
|
|
199
|
+
],
|
|
200
|
+
});
|
|
201
|
+
expect(wrapper.find('.message-status').exists()).toBe(true);
|
|
202
|
+
});
|
|
203
|
+
|
|
105
204
|
it('shows a tombstone for deleted messages', () => {
|
|
106
205
|
const wrapper = setup({
|
|
107
206
|
messages: [
|
|
@@ -82,6 +82,7 @@ import { useChatScroll } from '../../../shared/composables/useChatScroll';
|
|
|
82
82
|
import { useObserveHeightUntilStable } from '../../../shared/composables/useObserveHeightUntilStable';
|
|
83
83
|
import { useChatsV2I18n } from '../../locale/useChatsV2I18n';
|
|
84
84
|
import { collectGalleryImages } from '../../scripts/attachments';
|
|
85
|
+
import { isSelfMessage } from '../../scripts/isSelfMessage';
|
|
85
86
|
import { toHistoryItems } from '../../scripts/toHistoryItems';
|
|
86
87
|
import {
|
|
87
88
|
type ChatHistoryProps,
|
|
@@ -136,8 +137,7 @@ const {
|
|
|
136
137
|
chatContainer: scrollContainer,
|
|
137
138
|
chatContent: scrollContent,
|
|
138
139
|
messages: computed(() => props.messages),
|
|
139
|
-
isSelf: (message) =>
|
|
140
|
-
!!message.sender?.id && message.sender.id === props.selfMemberId,
|
|
140
|
+
isSelf: (message) => isSelfMessage(message, props.thread, props.selfMemberId),
|
|
141
141
|
// a divider must not anchor: a same-day older page keeps its element in place
|
|
142
142
|
itemClass: 'chat-history__entry',
|
|
143
143
|
chatId: computed(() => props.thread.id),
|
|
@@ -224,8 +224,7 @@ watch(
|
|
|
224
224
|
width: 100%;
|
|
225
225
|
overflow-x: hidden;
|
|
226
226
|
overflow-y: auto;
|
|
227
|
-
|
|
228
|
-
scrollbar-gutter: stable both-edges;
|
|
227
|
+
scrollbar-gutter: stable;
|
|
229
228
|
}
|
|
230
229
|
|
|
231
230
|
.chat-history__content {
|
|
@@ -233,6 +232,8 @@ watch(
|
|
|
233
232
|
flex-direction: column;
|
|
234
233
|
gap: var(--wt-ws-chat-window-sizes-root-gap);
|
|
235
234
|
padding: var(--wt-ws-chat-window-sizes-root-padding-y) var(--wt-ws-chat-window-sizes-root-padding-x);
|
|
235
|
+
/* the scrollbar sits a root gap away from the messages, as in DES-730 */
|
|
236
|
+
padding-right: calc(var(--wt-ws-chat-window-sizes-root-padding-x) + var(--wt-ws-chat-window-sizes-root-gap));
|
|
236
237
|
}
|
|
237
238
|
|
|
238
239
|
.chat-history__sentinel {
|
|
@@ -33,4 +33,10 @@ const label = computed(() =>
|
|
|
33
33
|
display: flex;
|
|
34
34
|
justify-content: center;
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
/* DES-730 draws the chip a step lighter than the default secondary; the
|
|
38
|
+
surface palette does not flip with the theme, so dark keeps the default */
|
|
39
|
+
:global(:root:not(.theme--dark)) .chat-date-divider {
|
|
40
|
+
--p-chip-secondary-background: var(--p-surface-50);
|
|
41
|
+
}
|
|
36
42
|
</style>
|
|
@@ -3,12 +3,20 @@
|
|
|
3
3
|
class="chat-message"
|
|
4
4
|
:class="{ 'chat-message--outgoing': isOutgoing }"
|
|
5
5
|
>
|
|
6
|
-
<wt-
|
|
6
|
+
<wt-tooltip
|
|
7
7
|
class="chat-message__avatar"
|
|
8
|
-
|
|
9
|
-
:
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
placement="top"
|
|
9
|
+
:disabled="!authorName"
|
|
10
|
+
>
|
|
11
|
+
<template #activator>
|
|
12
|
+
<wt-avatar
|
|
13
|
+
size="sm"
|
|
14
|
+
:src="avatarUrl"
|
|
15
|
+
:username="authorName"
|
|
16
|
+
/>
|
|
17
|
+
</template>
|
|
18
|
+
{{ authorName }}
|
|
19
|
+
</wt-tooltip>
|
|
12
20
|
<div class="chat-message__bubble">
|
|
13
21
|
<p
|
|
14
22
|
v-if="props.message.deleted"
|
|
@@ -32,19 +40,19 @@
|
|
|
32
40
|
{{ t('history.unsupportedMessage') }}
|
|
33
41
|
</p>
|
|
34
42
|
</template>
|
|
35
|
-
<div class="chat-message__meta typo-
|
|
36
|
-
<span v-if="time">{{ time }}</span>
|
|
43
|
+
<div class="chat-message__meta typo-body-2">
|
|
37
44
|
<message-status
|
|
38
45
|
v-if="status"
|
|
39
46
|
:status="status"
|
|
40
47
|
/>
|
|
48
|
+
<span v-if="time">{{ time }}</span>
|
|
41
49
|
</div>
|
|
42
50
|
</div>
|
|
43
51
|
</div>
|
|
44
52
|
</template>
|
|
45
53
|
|
|
46
54
|
<script setup lang="ts">
|
|
47
|
-
import { WtAvatar } from '@webitel/ui-sdk/components';
|
|
55
|
+
import { WtAvatar, WtTooltip } from '@webitel/ui-sdk/components';
|
|
48
56
|
import { computed } from 'vue';
|
|
49
57
|
|
|
50
58
|
import { useChatsV2I18n } from '../../../locale/useChatsV2I18n';
|
|
@@ -96,6 +104,8 @@ const status = computed(() =>
|
|
|
96
104
|
|
|
97
105
|
<style scoped>
|
|
98
106
|
.chat-message {
|
|
107
|
+
--chat-message-tail-size: 8px;
|
|
108
|
+
|
|
99
109
|
display: flex;
|
|
100
110
|
align-items: flex-start;
|
|
101
111
|
gap: var(--wt-ws-chat-window-sizes-message-item-gap);
|
|
@@ -114,25 +124,49 @@ const status = computed(() =>
|
|
|
114
124
|
display: flex;
|
|
115
125
|
flex-direction: column;
|
|
116
126
|
gap: var(--wt-ws-chat-window-sizes-message-item-chat-message-gap);
|
|
127
|
+
position: relative;
|
|
117
128
|
max-width: 70%;
|
|
118
129
|
min-width: 0;
|
|
119
130
|
padding: var(--wt-ws-chat-window-sizes-message-item-chat-message-padding-y) var(--wt-ws-chat-window-sizes-message-item-chat-message-padding-x);
|
|
120
131
|
border-radius: var(--wt-ws-chat-window-sizes-message-item-chat-message-border-radius);
|
|
121
|
-
background: var(--
|
|
132
|
+
background: var(--chat-message-bubble-background);
|
|
122
133
|
color: var(--wt-ws-chat-window-colors-message-item-chat-message-client-color);
|
|
134
|
+
--chat-message-bubble-background: var(--wt-ws-chat-window-colors-message-item-chat-message-client-background);
|
|
123
135
|
}
|
|
124
136
|
|
|
125
|
-
/* the corner next to the avatar is square, as in DES-730 */
|
|
137
|
+
/* the corner next to the avatar is square and carries an 8px tail, as in DES-730 */
|
|
126
138
|
.chat-message:not(.chat-message--outgoing) .chat-message__bubble {
|
|
139
|
+
margin-left: var(--chat-message-tail-size);
|
|
127
140
|
border-top-left-radius: 0;
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
.chat-message--outgoing .chat-message__bubble {
|
|
144
|
+
margin-right: var(--chat-message-tail-size);
|
|
131
145
|
border-top-right-radius: 0;
|
|
132
|
-
background: var(--wt-ws-chat-window-colors-message-item-chat-message-agent-background);
|
|
146
|
+
--chat-message-bubble-background: var(--wt-ws-chat-window-colors-message-item-chat-message-agent-background);
|
|
133
147
|
color: var(--wt-ws-chat-window-colors-message-item-chat-message-agent-color);
|
|
134
148
|
}
|
|
135
149
|
|
|
150
|
+
/* the tail is the bubble colour left over once a circle is cut out of the
|
|
151
|
+
square beside the bubble's square corner */
|
|
152
|
+
.chat-message__bubble::before {
|
|
153
|
+
position: absolute;
|
|
154
|
+
top: 0;
|
|
155
|
+
width: var(--chat-message-tail-size);
|
|
156
|
+
height: var(--chat-message-tail-size);
|
|
157
|
+
content: '';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.chat-message:not(.chat-message--outgoing) .chat-message__bubble::before {
|
|
161
|
+
right: 100%;
|
|
162
|
+
background: radial-gradient(circle 7.333px at 0.667px 7.333px, transparent 7.2px, var(--chat-message-bubble-background) 7.45px);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.chat-message--outgoing .chat-message__bubble::before {
|
|
166
|
+
left: 100%;
|
|
167
|
+
background: radial-gradient(circle 7.333px at 7.333px 7.333px, transparent 7.2px, var(--chat-message-bubble-background) 7.45px);
|
|
168
|
+
}
|
|
169
|
+
|
|
136
170
|
.chat-message__placeholder {
|
|
137
171
|
margin: 0;
|
|
138
172
|
font-style: italic;
|
|
@@ -5,13 +5,21 @@
|
|
|
5
5
|
>
|
|
6
6
|
<span class="chat-system-notice__line" />
|
|
7
7
|
<span class="chat-system-notice__content typo-caption">
|
|
8
|
-
<wt-
|
|
8
|
+
<wt-tooltip
|
|
9
9
|
v-if="notice.actor"
|
|
10
10
|
class="chat-system-notice__avatar"
|
|
11
|
-
|
|
12
|
-
:
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
placement="top"
|
|
12
|
+
:disabled="!actorRealName"
|
|
13
|
+
>
|
|
14
|
+
<template #activator>
|
|
15
|
+
<wt-avatar
|
|
16
|
+
size="2xs"
|
|
17
|
+
:src="props.resolveAvatarUrl?.(notice.actor)"
|
|
18
|
+
:username="actorName"
|
|
19
|
+
/>
|
|
20
|
+
</template>
|
|
21
|
+
{{ actorRealName }}
|
|
22
|
+
</wt-tooltip>
|
|
15
23
|
<span class="chat-system-notice__text">{{ text }}</span>
|
|
16
24
|
<span
|
|
17
25
|
v-if="time"
|
|
@@ -23,7 +31,7 @@
|
|
|
23
31
|
</template>
|
|
24
32
|
|
|
25
33
|
<script setup lang="ts">
|
|
26
|
-
import { WtAvatar } from '@webitel/ui-sdk/components';
|
|
34
|
+
import { WtAvatar, WtTooltip } from '@webitel/ui-sdk/components';
|
|
27
35
|
import { computed } from 'vue';
|
|
28
36
|
|
|
29
37
|
import { useChatsV2I18n } from '../../../locale/useChatsV2I18n';
|
|
@@ -49,8 +57,11 @@ const { t } = useChatsV2I18n();
|
|
|
49
57
|
|
|
50
58
|
const notice = computed(() => resolveSystemNotice(props.message, props.thread));
|
|
51
59
|
|
|
60
|
+
// the actor's own name; the tooltip stays off for the generic "system" fallback
|
|
61
|
+
const actorRealName = computed(() => participantName(notice.value.actor));
|
|
62
|
+
|
|
52
63
|
const actorName = computed(
|
|
53
|
-
() =>
|
|
64
|
+
() => actorRealName.value || t('systemNotice.system'),
|
|
54
65
|
);
|
|
55
66
|
|
|
56
67
|
const text = computed(() =>
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
</div>
|
|
9
9
|
<wt-rounded-action
|
|
10
10
|
icon="arrow-down"
|
|
11
|
+
size="sm"
|
|
11
12
|
rounded
|
|
12
13
|
@click="emit('scroll')"
|
|
13
14
|
/>
|
|
@@ -34,7 +35,7 @@ const emit = defineEmits<{
|
|
|
34
35
|
<style scoped>
|
|
35
36
|
.scroll-to-bottom-btn {
|
|
36
37
|
position: absolute;
|
|
37
|
-
right: calc(var(--scrollbar-width) + var(--spacing-xs));
|
|
38
|
+
right: calc(var(--scrollbar-width) + var(--wt-ws-chat-window-sizes-root-gap) + var(--spacing-xs));
|
|
38
39
|
bottom: var(--spacing-xs);
|
|
39
40
|
display: flex;
|
|
40
41
|
flex-direction: column;
|