vue-wiguet-chatweb 0.1.34 โ†’ 0.1.35

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. package/README.md +68 -68
  2. package/dist/App.vue.d.ts +2 -0
  3. package/dist/components/Chat.vue.d.ts +5 -2
  4. package/dist/components/ChatMessage.vue.d.ts +12 -0
  5. package/dist/components/DangerIcon.vue.d.ts +1 -1
  6. package/dist/components/IconAttach.vue.d.ts +1 -1
  7. package/dist/components/IconChat.vue.d.ts +1 -1
  8. package/dist/components/IconClose.vue.d.ts +1 -1
  9. package/dist/components/IconSend.vue.d.ts +1 -1
  10. package/dist/components/IconTelegram.vue.d.ts +1 -1
  11. package/dist/components/IconWhatsApp.vue.d.ts +1 -1
  12. package/dist/components/Loader.vue.d.ts +1 -1
  13. package/dist/components/MessageList.vue.d.ts +3 -2
  14. package/dist/components/ODialog/IPropsDialog.d.ts +0 -1
  15. package/dist/components/ODialog/ODialog.vue.d.ts +13 -15
  16. package/dist/components/Widget.vue.d.ts +1 -2
  17. package/dist/dto/app.dto.d.ts +0 -1
  18. package/dist/index.d.ts +0 -1
  19. package/dist/main.d.ts +0 -1
  20. package/dist/store/config.d.ts +0 -1
  21. package/dist/store/index.d.ts +0 -1
  22. package/dist/style.css +1 -1
  23. package/dist/vue-wiguet-chatweb.js +791 -754
  24. package/dist/vue-wiguet-chatweb.umd.cjs +26 -26
  25. package/package.json +66 -66
  26. package/src/assets/emojis/AngryIcon.svg +4 -4
  27. package/src/assets/emojis/HappiestIcon.svg +4 -4
  28. package/src/assets/emojis/HappyIcon.svg +4 -4
  29. package/src/assets/emojis/NeutralIcon.svg +4 -4
  30. package/src/assets/emojis/SadIcon.svg +4 -4
  31. package/src/components/Chat.vue +716 -696
  32. package/src/components/ChatMessage.vue +102 -102
  33. package/src/components/DangerIcon.vue +12 -12
  34. package/src/components/IconAttach.vue +24 -24
  35. package/src/components/IconChat.vue +23 -23
  36. package/src/components/IconClose.vue +5 -5
  37. package/src/components/IconSend.vue +8 -8
  38. package/src/components/IconTelegram.vue +28 -28
  39. package/src/components/IconWhatsApp.vue +39 -39
  40. package/src/components/IconWidget.vue +45 -45
  41. package/src/components/Loader.vue +31 -31
  42. package/src/components/LoadingComponent.vue +111 -111
  43. package/src/components/MessageList.vue +357 -357
  44. package/src/components/ODialog/IPropsDialog.ts +4 -4
  45. package/src/components/ODialog/IPropsSidebar.ts +13 -13
  46. package/src/components/ODialog/ODialog.vue +107 -107
  47. package/src/components/Widget.vue +196 -196
  48. package/src/components/__tests__/Chat.spec.ts +5 -5
  49. package/src/components/__tests__/ChatMessage.spec.ts +5 -5
  50. package/src/components/__tests__/MessageList.spec.ts +47 -47
@@ -1,357 +1,357 @@
1
- <template>
2
- <div ref="target" class="target"></div>
3
- <div class="messages-container-list">
4
- <div
5
- v-for="message in props.messages"
6
- :key="message.id"
7
- class="message"
8
- :class="message.esCliente ? 'message-right' : 'message-left'"
9
- >
10
- <div class="message-container">
11
- <div
12
- v-if="message.error && message.esCliente"
13
- class="btn-container-widget"
14
- >
15
- <button
16
- text
17
- rounded
18
- class="btn-danger"
19
- icon="fa-solid fa-circle-exclamation"
20
- aria-label="Cancel"
21
- @click="emit('retry', message)"
22
- >
23
- <DangerIcon />
24
- </button>
25
- </div>
26
- <div class="chat-message">
27
- <div class="bubble" :class="message.esCliente ? 'right' : 'left'">
28
- <div :class="message.esCliente ? 'content-right' : 'content-left'">
29
- <div v-if="message.message === '๐Ÿ˜Š๐Ÿ˜„๐Ÿ™‚๐Ÿ˜๐Ÿ™'" class="flex flex-col gap-2" >
30
- <div class="mb-2">
31
- <strong style="display: block;">Ayรบdanos a mejorar nuestro servicio.</strong>
32
- <span>ยฟQue le pareciรณ la atenciรณn?</span>
33
- </div>
34
-
35
- <div style="font-size: 14px;" class="flex justify-between gap-2">
36
- <a
37
- v-for="emojiParam in emojis"
38
- :key="emojiParam.value"
39
- :href="!message.response ? 'javascript:' : undefined"
40
- class="btn-icon"
41
- :class="{ 'content-disabled' : !showIcon(message, emojiParam) }"
42
- @click="!message.response && emit('onQualifying', { message, emoji: emojiParam })"
43
- >
44
- <div class="flex flex-col items-center">
45
- <img :src="emojiParam.icon" alt="icono" class="icon" />
46
- <span>{{ emojiParam.label }}</span>
47
- </div>
48
- </a>
49
- </div>
50
- </div>
51
-
52
- <div v-else>
53
- <div v-if="message.messageType?.code === MESSAGE_TYPE_CODES.IMAGEN" style="text-align: center;">
54
- <a href="javascript:" class="btn-icon" @click="emit('see', message)">
55
- <img :src="message.thumbnailFile ?? message.urlFile" alt="image" width="150" />
56
- </a>
57
- </div>
58
-
59
- <div v-if="emoji[message.message ?? '']">
60
- <img :src="emoji[message.message]" alt="icono" class="icon" />
61
- </div>
62
-
63
- <div v-else class="message-text" style="white-space: pre-line" v-html="textToRichFormat(message.message)"></div>
64
- </div>
65
-
66
- <div class="detail-message flex justify-between mt-2">
67
- <span class="mr-5" v-if="message.sender?.nombreCompleto">
68
- {{
69
- message.esCliente
70
- ? message.sender?.nombreCompleto
71
- : "ECOSISTEMA JL"
72
- }}
73
- </span>
74
- <span class="mr-5" v-else> </span>
75
- <span>
76
- {{
77
- DateTime.fromISO(message.createdAt).toFormat(
78
- "dd-MM-yyyy HH:mm"
79
- )
80
- }}
81
- </span>
82
- </div>
83
- </div>
84
- </div>
85
- </div>
86
- </div>
87
- </div>
88
- </div>
89
- </template>
90
-
91
- <script setup lang="ts">
92
- import { PropType, onBeforeMount, ref, watch, h } from 'vue';
93
- import { useIntersectionObserver } from "@vueuse/core";
94
- import { type Message } from "../dto/app.dto";
95
- import { DateTime } from "luxon";
96
- import DangerIcon from "./DangerIcon.vue";
97
- import SadIcon from '../assets/emojis/SadIcon.svg'
98
- import AngryIcon from '../assets/emojis/AngryIcon.svg'
99
- import HappiestIcon from '../assets/emojis/HappiestIcon.svg'
100
- import NeutralIcon from '../assets/emojis/NeutralIcon.svg'
101
- import HappyIcon from '../assets/emojis/HappyIcon.svg'
102
- import { MESSAGE_TYPE_CODES } from '../resources/constants/message-type.constant';
103
-
104
- const emit = defineEmits(["loadMore", "retry", "onQualifying", "see"]);
105
- const props = defineProps({
106
- messages: {
107
- type: Array as PropType<Message[]>,
108
- default: () => [],
109
- },
110
- canLoadMoreMessages: {
111
- type: Boolean,
112
- default: false,
113
- },
114
- });
115
-
116
- const target = ref();
117
-
118
- const { pause, resume } = useIntersectionObserver(
119
- target,
120
- ([{ isIntersecting }]) => {
121
- if (isIntersecting) {
122
- emit("loadMore");
123
- }
124
- }
125
- );
126
-
127
- function showIcon(message: Message, emojiParam: any) {
128
- if(!message.response || typeof message.response !=='object') return true;
129
-
130
- return emojiParam.iconUnicode === message.response.message
131
- }
132
-
133
- onBeforeMount(() => {
134
- if (!props.canLoadMoreMessages) {
135
- pause();
136
- }
137
- });
138
- watch(
139
- () => props.canLoadMoreMessages,
140
- (current) => {
141
- if (current) {
142
- resume();
143
- return;
144
- }
145
- pause();
146
- }
147
- );
148
-
149
- type RichTextType = {
150
- regex: RegExp;
151
- tag: string;
152
- };
153
-
154
- const richText: { [key in string]: RichTextType } = {
155
- BOLD: { regex: /\*(.+?)\*(?!\*)/g, tag: '<strong--custom-tag>{val}</strong--custom-tag>' },
156
- ITALIC: { regex: /_(.+?)_/, tag: '<i--custom-tag>{val}</i--custom-tag>' },
157
- CROSSED_OUT: { regex: /~(.+?)~(?!~)/g, tag: '<del--custom-tag>{val}</del--custom-tag>' },
158
- URL: {
159
- regex: /(http?s?:\/\/[^\s]+)/g,
160
- tag: '<a--custom-tag href="{val}" target="_blank">{val}</a--custom-tag>',
161
- },
162
- };
163
-
164
- function textToRichFormat(text: string) {
165
- const richTextValues = Object.values(richText);
166
-
167
- if (!richTextValues || (Array.isArray(richTextValues) && richTextValues.length === 0))
168
- return text;
169
-
170
- const newMessage = () => {
171
-
172
- return richTextValues.reduce((textPrev, rtv) => {
173
- return textPrev.replace(rtv.regex, (middleValueAssert, middleValue) => {
174
- const regexVerifyExistTag = /--custom-tag/;
175
-
176
- if (regexVerifyExistTag.test(middleValueAssert)) return middleValueAssert;
177
-
178
- return rtv.tag.replace(/{val}/g, middleValue);
179
- });
180
- }, text);
181
- };
182
-
183
- return newMessage().replace(/--custom-tag/g, '');
184
- }
185
-
186
- const emojis = [
187
- { label: 'Excelente', value: 1, icon: HappiestIcon, iconUnicode: '๐Ÿ˜Š'},
188
- { label: 'Buena', value: 2, icon: HappyIcon, iconUnicode: '๐Ÿ˜„'},
189
- { label: 'Aceptable', value: 3, icon: NeutralIcon, iconUnicode: '๐Ÿ™‚'},
190
- { label: 'Mala', value: 4, icon: SadIcon, iconUnicode: '๐Ÿ˜'},
191
- { label: 'Muy Mala', value: 5, icon: AngryIcon, iconUnicode: '๐Ÿ™'},
192
- ]
193
- ''
194
- const emoji: { [key in string]: any } = {
195
- '๐Ÿ˜Š': HappiestIcon,
196
- '๐Ÿ˜„': HappyIcon,
197
- '๐Ÿ™‚': NeutralIcon,
198
- '๐Ÿ˜': SadIcon,
199
- '๐Ÿ™': AngryIcon,
200
- '': null
201
- }
202
-
203
- </script>
204
-
205
- <style scoped>
206
- .bubble {
207
- --r: 25px;
208
- /* the radius */
209
- --t: 30px;
210
- /* the size of the tail */
211
-
212
- padding: calc(2 * var(--r) / 3);
213
- -webkit-mask: radial-gradient(var(--t) at var(--_d) 0, #0000 98%, #000 102%)
214
- var(--_d) 100% / calc(100% - var(--r)) var(--t) no-repeat,
215
- conic-gradient(at var(--r) var(--r), #000 75%, #0000 0) calc(var(--r) / -2)
216
- calc(var(--r) / -2) padding-box,
217
- radial-gradient(50% 50%, #000 98%, #0000 101%) 0 0 / var(--r) var(--r) space
218
- padding-box;
219
- mask: radial-gradient(var(--t) at var(--_d) 0, #0000 98%, #000 102%) var(--_d)
220
- 100% / calc(100% - var(--r)) var(--t) no-repeat,
221
- conic-gradient(at var(--r) var(--r), #000 75%, #0000 0) calc(var(--r) / -2)
222
- calc(var(--r) / -2) padding-box,
223
- radial-gradient(50% 50%, #000 98%, #0000 101%) 0 0 / var(--r) var(--r) space
224
- padding-box;
225
- /* background: linear-gradient(135deg, #FE6D00, #1384C5) border-box; */
226
- color: #fff;
227
- height: 100%;
228
- }
229
-
230
- .left {
231
- --_d: 0%;
232
- border-left: var(--t) solid #0000;
233
- margin-right: 0;
234
- background-color: #fcd7ae;
235
- color: #4d4d4d;
236
- }
237
-
238
- .bubble > .content-left {
239
- margin-right: 10px;
240
- margin-bottom: 1px;
241
- }
242
-
243
- .right {
244
- --_d: 100%;
245
- border-right: var(--t) solid #0000;
246
- margin-right: 0;
247
- background-color: #fdeedb;
248
- color: #4d4d4d;
249
- }
250
-
251
- .bubble > .content-right {
252
- margin-bottom: 1px;
253
- margin-right: 10px;
254
- }
255
-
256
- .message-text {
257
- margin-bottom: 10px;
258
- overflow-wrap: break-word;
259
- }
260
- .detail-message {
261
- font-size: 10px;
262
- color: #808080;
263
- display: flex;
264
- justify-content: space-between;
265
- }
266
-
267
- .chat-message {
268
- display: flex;
269
- flex-direction: column;
270
- justify-content: center;
271
- }
272
-
273
- .message {
274
- width: 100%;
275
- display: flex;
276
- }
277
-
278
- .message-left {
279
- justify-content: start;
280
- }
281
- .message-right {
282
- justify-content: end;
283
- }
284
- .target {
285
- padding: 0.5rem 0;
286
- width: 100%;
287
- }
288
-
289
- .btn-danger {
290
- background-color: transparent;
291
- border: 0;
292
- border-radius: 50%;
293
- cursor: pointer;
294
- padding: 0;
295
- width: 30px;
296
- height: 30px;
297
- display: flex;
298
- align-items: center;
299
- justify-content: center;
300
- & svg {
301
- width: 24px;
302
- height: 24px;
303
- }
304
- &:hover {
305
- background-color: rgba(255, 0, 0, 0.226);
306
- }
307
- }
308
-
309
- .btn-container-widget {
310
- display: flex;
311
- align-items: center;
312
- position: absolute;
313
- left: -40px;
314
- top: 50%;
315
- transform: translateY(-50%);
316
- }
317
-
318
- .message-container {
319
- min-width: 80%;
320
- max-width: 80%;
321
- position: relative;
322
- margin-bottom: 0.5rem;
323
- }
324
-
325
- .messages-container-list {
326
- width: 100%;
327
- }
328
-
329
- .icon {
330
- width: 2rem;
331
- }
332
-
333
- .btn-icon {
334
- text-decoration: none;
335
- border: none;
336
- color: rgb(156 163 175 / 1);
337
- }
338
-
339
- .btn-icon:hover:not(.content-disabled) {
340
- color: rgb(31 41 55 / 1);
341
- }
342
-
343
- .btn-icon span {
344
- text-wrap: nowrap;
345
- }
346
-
347
- .btn-icon .icon {
348
- font-size: 2rem;
349
- }
350
-
351
- .content-disabled {
352
- -webkit-filter: grayscale(1); /* Google Chrome, Safari 6+ & Opera 15+ */
353
- filter: grayscale(1); /* Microsoft Edge and Firefox 35+ */
354
- opacity: 0.5;
355
- }
356
-
357
- </style>
1
+ <template>
2
+ <div ref="target" class="target"></div>
3
+ <div class="messages-container-list">
4
+ <div
5
+ v-for="message in props.messages"
6
+ :key="message.id"
7
+ class="message"
8
+ :class="message.esCliente ? 'message-right' : 'message-left'"
9
+ >
10
+ <div class="message-container">
11
+ <div
12
+ v-if="message.error && message.esCliente"
13
+ class="btn-container-widget"
14
+ >
15
+ <button
16
+ text
17
+ rounded
18
+ class="btn-danger"
19
+ icon="fa-solid fa-circle-exclamation"
20
+ aria-label="Cancel"
21
+ @click="emit('retry', message)"
22
+ >
23
+ <DangerIcon />
24
+ </button>
25
+ </div>
26
+ <div class="chat-message">
27
+ <div class="bubble" :class="message.esCliente ? 'right' : 'left'">
28
+ <div :class="message.esCliente ? 'content-right' : 'content-left'">
29
+ <div v-if="message.message === '๐Ÿ˜Š๐Ÿ˜„๐Ÿ™‚๐Ÿ˜๐Ÿ™'" class="flex flex-col gap-2" >
30
+ <div class="mb-2">
31
+ <strong style="display: block;">Ayรบdanos a mejorar nuestro servicio.</strong>
32
+ <span>ยฟQue le pareciรณ la atenciรณn?</span>
33
+ </div>
34
+
35
+ <div style="font-size: 14px;" class="flex justify-between gap-2">
36
+ <a
37
+ v-for="emojiParam in emojis"
38
+ :key="emojiParam.value"
39
+ :href="!message.response ? 'javascript:' : undefined"
40
+ class="btn-icon"
41
+ :class="{ 'content-disabled' : !showIcon(message, emojiParam) }"
42
+ @click="!message.response && emit('onQualifying', { message, emoji: emojiParam })"
43
+ >
44
+ <div class="flex flex-col items-center">
45
+ <img :src="emojiParam.icon" alt="icono" class="icon" />
46
+ <span>{{ emojiParam.label }}</span>
47
+ </div>
48
+ </a>
49
+ </div>
50
+ </div>
51
+
52
+ <div v-else>
53
+ <div v-if="message.messageType?.code === MESSAGE_TYPE_CODES.IMAGEN" style="text-align: center;">
54
+ <a href="javascript:" class="btn-icon" @click="emit('see', message)">
55
+ <img :src="message.thumbnailFile ?? message.urlFile" alt="image" width="150" />
56
+ </a>
57
+ </div>
58
+
59
+ <div v-if="emoji[message.message ?? '']">
60
+ <img :src="emoji[message.message]" alt="icono" class="icon" />
61
+ </div>
62
+
63
+ <div v-else class="message-text" style="white-space: pre-line" v-html="textToRichFormat(message.message)"></div>
64
+ </div>
65
+
66
+ <div class="detail-message flex justify-between mt-2">
67
+ <span class="mr-5" v-if="message.sender?.nombreCompleto">
68
+ {{
69
+ message.esCliente
70
+ ? message.sender?.nombreCompleto
71
+ : "ECOSISTEMA JL"
72
+ }}
73
+ </span>
74
+ <span class="mr-5" v-else> </span>
75
+ <span>
76
+ {{
77
+ DateTime.fromISO(message.createdAt).toFormat(
78
+ "dd-MM-yyyy HH:mm"
79
+ )
80
+ }}
81
+ </span>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ </div>
89
+ </template>
90
+
91
+ <script setup lang="ts">
92
+ import { PropType, onBeforeMount, ref, watch, h } from 'vue';
93
+ import { useIntersectionObserver } from "@vueuse/core";
94
+ import { type Message } from "../dto/app.dto";
95
+ import { DateTime } from "luxon";
96
+ import DangerIcon from "./DangerIcon.vue";
97
+ import SadIcon from '../assets/emojis/SadIcon.svg'
98
+ import AngryIcon from '../assets/emojis/AngryIcon.svg'
99
+ import HappiestIcon from '../assets/emojis/HappiestIcon.svg'
100
+ import NeutralIcon from '../assets/emojis/NeutralIcon.svg'
101
+ import HappyIcon from '../assets/emojis/HappyIcon.svg'
102
+ import { MESSAGE_TYPE_CODES } from '../resources/constants/message-type.constant';
103
+
104
+ const emit = defineEmits(["loadMore", "retry", "onQualifying", "see"]);
105
+ const props = defineProps({
106
+ messages: {
107
+ type: Array as PropType<Message[]>,
108
+ default: () => [],
109
+ },
110
+ canLoadMoreMessages: {
111
+ type: Boolean,
112
+ default: false,
113
+ },
114
+ });
115
+
116
+ const target = ref();
117
+
118
+ const { pause, resume } = useIntersectionObserver(
119
+ target,
120
+ ([{ isIntersecting }]) => {
121
+ if (isIntersecting) {
122
+ emit("loadMore");
123
+ }
124
+ }
125
+ );
126
+
127
+ function showIcon(message: Message, emojiParam: any) {
128
+ if(!message.response || typeof message.response !=='object') return true;
129
+
130
+ return emojiParam.iconUnicode === message.response.message
131
+ }
132
+
133
+ onBeforeMount(() => {
134
+ if (!props.canLoadMoreMessages) {
135
+ pause();
136
+ }
137
+ });
138
+ watch(
139
+ () => props.canLoadMoreMessages,
140
+ (current) => {
141
+ if (current) {
142
+ resume();
143
+ return;
144
+ }
145
+ pause();
146
+ }
147
+ );
148
+
149
+ type RichTextType = {
150
+ regex: RegExp;
151
+ tag: string;
152
+ };
153
+
154
+ const richText: { [key in string]: RichTextType } = {
155
+ BOLD: { regex: /\*(.+?)\*(?!\*)/g, tag: '<strong--custom-tag>{val}</strong--custom-tag>' },
156
+ ITALIC: { regex: /_(.+?)_/, tag: '<i--custom-tag>{val}</i--custom-tag>' },
157
+ CROSSED_OUT: { regex: /~(.+?)~(?!~)/g, tag: '<del--custom-tag>{val}</del--custom-tag>' },
158
+ URL: {
159
+ regex: /(http?s?:\/\/[^\s]+)/g,
160
+ tag: '<a--custom-tag href="{val}" target="_blank">{val}</a--custom-tag>',
161
+ },
162
+ };
163
+
164
+ function textToRichFormat(text: string) {
165
+ const richTextValues = Object.values(richText);
166
+
167
+ if (!richTextValues || (Array.isArray(richTextValues) && richTextValues.length === 0))
168
+ return text;
169
+
170
+ const newMessage = () => {
171
+
172
+ return richTextValues.reduce((textPrev, rtv) => {
173
+ return textPrev.replace(rtv.regex, (middleValueAssert, middleValue) => {
174
+ const regexVerifyExistTag = /--custom-tag/;
175
+
176
+ if (regexVerifyExistTag.test(middleValueAssert)) return middleValueAssert;
177
+
178
+ return rtv.tag.replace(/{val}/g, middleValue);
179
+ });
180
+ }, text);
181
+ };
182
+
183
+ return newMessage().replace(/--custom-tag/g, '');
184
+ }
185
+
186
+ const emojis = [
187
+ { label: 'Excelente', value: 1, icon: HappiestIcon, iconUnicode: '๐Ÿ˜Š'},
188
+ { label: 'Buena', value: 2, icon: HappyIcon, iconUnicode: '๐Ÿ˜„'},
189
+ { label: 'Aceptable', value: 3, icon: NeutralIcon, iconUnicode: '๐Ÿ™‚'},
190
+ { label: 'Mala', value: 4, icon: SadIcon, iconUnicode: '๐Ÿ˜'},
191
+ { label: 'Muy Mala', value: 5, icon: AngryIcon, iconUnicode: '๐Ÿ™'},
192
+ ]
193
+ ''
194
+ const emoji: { [key in string]: any } = {
195
+ '๐Ÿ˜Š': HappiestIcon,
196
+ '๐Ÿ˜„': HappyIcon,
197
+ '๐Ÿ™‚': NeutralIcon,
198
+ '๐Ÿ˜': SadIcon,
199
+ '๐Ÿ™': AngryIcon,
200
+ '': null
201
+ }
202
+
203
+ </script>
204
+
205
+ <style scoped>
206
+ .bubble {
207
+ --r: 25px;
208
+ /* the radius */
209
+ --t: 30px;
210
+ /* the size of the tail */
211
+
212
+ padding: calc(2 * var(--r) / 3);
213
+ -webkit-mask: radial-gradient(var(--t) at var(--_d) 0, #0000 98%, #000 102%)
214
+ var(--_d) 100% / calc(100% - var(--r)) var(--t) no-repeat,
215
+ conic-gradient(at var(--r) var(--r), #000 75%, #0000 0) calc(var(--r) / -2)
216
+ calc(var(--r) / -2) padding-box,
217
+ radial-gradient(50% 50%, #000 98%, #0000 101%) 0 0 / var(--r) var(--r) space
218
+ padding-box;
219
+ mask: radial-gradient(var(--t) at var(--_d) 0, #0000 98%, #000 102%) var(--_d)
220
+ 100% / calc(100% - var(--r)) var(--t) no-repeat,
221
+ conic-gradient(at var(--r) var(--r), #000 75%, #0000 0) calc(var(--r) / -2)
222
+ calc(var(--r) / -2) padding-box,
223
+ radial-gradient(50% 50%, #000 98%, #0000 101%) 0 0 / var(--r) var(--r) space
224
+ padding-box;
225
+ /* background: linear-gradient(135deg, #FE6D00, #1384C5) border-box; */
226
+ color: #fff;
227
+ height: 100%;
228
+ }
229
+
230
+ .left {
231
+ --_d: 0%;
232
+ border-left: var(--t) solid #0000;
233
+ margin-right: 0;
234
+ background-color: #fcd7ae;
235
+ color: #4d4d4d;
236
+ }
237
+
238
+ .bubble > .content-left {
239
+ margin-right: 10px;
240
+ margin-bottom: 1px;
241
+ }
242
+
243
+ .right {
244
+ --_d: 100%;
245
+ border-right: var(--t) solid #0000;
246
+ margin-right: 0;
247
+ background-color: #fdeedb;
248
+ color: #4d4d4d;
249
+ }
250
+
251
+ .bubble > .content-right {
252
+ margin-bottom: 1px;
253
+ margin-right: 10px;
254
+ }
255
+
256
+ .message-text {
257
+ margin-bottom: 10px;
258
+ overflow-wrap: break-word;
259
+ }
260
+ .detail-message {
261
+ font-size: 10px;
262
+ color: #808080;
263
+ display: flex;
264
+ justify-content: space-between;
265
+ }
266
+
267
+ .chat-message {
268
+ display: flex;
269
+ flex-direction: column;
270
+ justify-content: center;
271
+ }
272
+
273
+ .message {
274
+ width: 100%;
275
+ display: flex;
276
+ }
277
+
278
+ .message-left {
279
+ justify-content: start;
280
+ }
281
+ .message-right {
282
+ justify-content: end;
283
+ }
284
+ .target {
285
+ padding: 0.5rem 0;
286
+ width: 100%;
287
+ }
288
+
289
+ .btn-danger {
290
+ background-color: transparent;
291
+ border: 0;
292
+ border-radius: 50%;
293
+ cursor: pointer;
294
+ padding: 0;
295
+ width: 30px;
296
+ height: 30px;
297
+ display: flex;
298
+ align-items: center;
299
+ justify-content: center;
300
+ & svg {
301
+ width: 24px;
302
+ height: 24px;
303
+ }
304
+ &:hover {
305
+ background-color: rgba(255, 0, 0, 0.226);
306
+ }
307
+ }
308
+
309
+ .btn-container-widget {
310
+ display: flex;
311
+ align-items: center;
312
+ position: absolute;
313
+ left: -40px;
314
+ top: 50%;
315
+ transform: translateY(-50%);
316
+ }
317
+
318
+ .message-container {
319
+ min-width: 80%;
320
+ max-width: 80%;
321
+ position: relative;
322
+ margin-bottom: 0.5rem;
323
+ }
324
+
325
+ .messages-container-list {
326
+ width: 100%;
327
+ }
328
+
329
+ .icon {
330
+ width: 2rem;
331
+ }
332
+
333
+ .btn-icon {
334
+ text-decoration: none;
335
+ border: none;
336
+ color: rgb(156 163 175 / 1);
337
+ }
338
+
339
+ .btn-icon:hover:not(.content-disabled) {
340
+ color: rgb(31 41 55 / 1);
341
+ }
342
+
343
+ .btn-icon span {
344
+ text-wrap: nowrap;
345
+ }
346
+
347
+ .btn-icon .icon {
348
+ font-size: 2rem;
349
+ }
350
+
351
+ .content-disabled {
352
+ -webkit-filter: grayscale(1); /* Google Chrome, Safari 6+ & Opera 15+ */
353
+ filter: grayscale(1); /* Microsoft Edge and Firefox 35+ */
354
+ opacity: 0.5;
355
+ }
356
+
357
+ </style>