@nyaruka/temba-components 0.109.1 → 0.110.0

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.
Files changed (86) hide show
  1. package/CHANGELOG.md +19 -2
  2. package/dist/static/svg/index.svg +1 -1
  3. package/dist/temba-components.js +362 -355
  4. package/dist/temba-components.js.map +1 -1
  5. package/out-tsc/src/compose/Compose.js +62 -106
  6. package/out-tsc/src/compose/Compose.js.map +1 -1
  7. package/out-tsc/src/contacts/ContactChat.js +64 -59
  8. package/out-tsc/src/contacts/ContactChat.js.map +1 -1
  9. package/out-tsc/src/vectoricon/index.js +1 -2
  10. package/out-tsc/src/vectoricon/index.js.map +1 -1
  11. package/out-tsc/test/temba-compose.test.js +24 -440
  12. package/out-tsc/test/temba-compose.test.js.map +1 -1
  13. package/out-tsc/test/temba-contact-chat.test.js +30 -167
  14. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  15. package/package.json +1 -1
  16. package/screenshots/truth/compose/attachments-tab.png +0 -0
  17. package/screenshots/truth/compose/attachments-with-failures.png +0 -0
  18. package/screenshots/truth/compose/attachments-with-files-and-failures.png +0 -0
  19. package/screenshots/truth/compose/attachments-with-files-focused.png +0 -0
  20. package/screenshots/truth/compose/attachments-with-files.png +0 -0
  21. package/screenshots/truth/compose/intial-text.png +0 -0
  22. package/screenshots/truth/compose/no-counter.png +0 -0
  23. package/screenshots/truth/compose/wraps-text-and-spaces.png +0 -0
  24. package/screenshots/truth/compose/wraps-text-and-url.png +0 -0
  25. package/screenshots/truth/compose/wraps-text-no-spaces.png +0 -0
  26. package/screenshots/truth/contacts/chat-failure.png +0 -0
  27. package/src/compose/Compose.ts +69 -103
  28. package/src/contacts/ContactChat.ts +69 -70
  29. package/src/untyped.d.ts +1 -1
  30. package/src/vectoricon/index.ts +1 -2
  31. package/static/svg/index.svg +1 -1
  32. package/test/temba-compose.test.ts +29 -590
  33. package/test/temba-contact-chat.test.ts +30 -263
  34. package/web-test-runner.config.mjs +1 -0
  35. package/screenshots/truth/compose/attachments-and-send-button.png +0 -0
  36. package/screenshots/truth/compose/attachments-no-send-button.png +0 -0
  37. package/screenshots/truth/compose/attachments-with-all-files-and-click-send.png +0 -0
  38. package/screenshots/truth/compose/attachments-with-all-files.png +0 -0
  39. package/screenshots/truth/compose/attachments-with-failure-files.png +0 -0
  40. package/screenshots/truth/compose/attachments-with-success-files-and-click-send.png +0 -0
  41. package/screenshots/truth/compose/attachments-with-success-files.png +0 -0
  42. package/screenshots/truth/compose/chatbox-attachments-counter-and-send-button.png +0 -0
  43. package/screenshots/truth/compose/chatbox-attachments-counter-no-send-button.png +0 -0
  44. package/screenshots/truth/compose/chatbox-attachments-no-counter-and-send-button.png +0 -0
  45. package/screenshots/truth/compose/chatbox-attachments-no-counter-no-send-button.png +0 -0
  46. package/screenshots/truth/compose/chatbox-counter-and-send-button.png +0 -0
  47. package/screenshots/truth/compose/chatbox-counter-no-send-button.png +0 -0
  48. package/screenshots/truth/compose/chatbox-no-counter-and-send-button.png +0 -0
  49. package/screenshots/truth/compose/chatbox-no-counter-no-send-button.png +0 -0
  50. package/screenshots/truth/compose/chatbox-no-text-attachments-with-all-files-and-click-send.png +0 -0
  51. package/screenshots/truth/compose/chatbox-no-text-attachments-with-all-files.png +0 -0
  52. package/screenshots/truth/compose/chatbox-no-text-attachments-with-failure-files.png +0 -0
  53. package/screenshots/truth/compose/chatbox-no-text-attachments-with-success-files-and-click-send.png +0 -0
  54. package/screenshots/truth/compose/chatbox-no-text-attachments-with-success-files.png +0 -0
  55. package/screenshots/truth/compose/chatbox-with-text-and-click-send.png +0 -0
  56. package/screenshots/truth/compose/chatbox-with-text-and-hit-enter.png +0 -0
  57. package/screenshots/truth/compose/chatbox-with-text-and-spaces.png +0 -0
  58. package/screenshots/truth/compose/chatbox-with-text-and-url.png +0 -0
  59. package/screenshots/truth/compose/chatbox-with-text-attachments-no-files-and-click-send.png +0 -0
  60. package/screenshots/truth/compose/chatbox-with-text-attachments-no-files-and-hit-enter.png +0 -0
  61. package/screenshots/truth/compose/chatbox-with-text-attachments-no-files.png +0 -0
  62. package/screenshots/truth/compose/chatbox-with-text-attachments-with-all-files-and-click-send.png +0 -0
  63. package/screenshots/truth/compose/chatbox-with-text-attachments-with-all-files-and-hit-enter.png +0 -0
  64. package/screenshots/truth/compose/chatbox-with-text-attachments-with-all-files.png +0 -0
  65. package/screenshots/truth/compose/chatbox-with-text-attachments-with-failure-files.png +0 -0
  66. package/screenshots/truth/compose/chatbox-with-text-attachments-with-success-files-and-click-send.png +0 -0
  67. package/screenshots/truth/compose/chatbox-with-text-attachments-with-success-files-and-hit-enter.png +0 -0
  68. package/screenshots/truth/compose/chatbox-with-text-attachments-with-success-files.png +0 -0
  69. package/screenshots/truth/compose/chatbox-with-text-no-spaces.png +0 -0
  70. package/screenshots/truth/compose/chatbox-with-text.png +0 -0
  71. package/screenshots/truth/contacts/compose-attachments-no-text-failure.png +0 -0
  72. package/screenshots/truth/contacts/compose-text-and-attachments-failure-attachments.png +0 -0
  73. package/screenshots/truth/contacts/compose-text-and-attachments-failure-generic.png +0 -0
  74. package/screenshots/truth/contacts/compose-text-and-attachments-failure-text-and-attachments.png +0 -0
  75. package/screenshots/truth/contacts/compose-text-and-attachments-failure-text.png +0 -0
  76. package/screenshots/truth/contacts/compose-text-no-attachments-failure.png +0 -0
  77. package/screenshots/truth/contacts/compose-text-no-attachments-success.png +0 -0
  78. package/static/svg/work/traced/folder-shield.svg +0 -1
  79. package/static/svg/work/used/folder-shield.svg +0 -3
  80. /package/screenshots/truth/contacts/{compose-attachments-no-text-success.png → chat-for-active-contact.png} +0 -0
  81. /package/screenshots/truth/contacts/{contact-archived-hide-chatbox.png → chat-for-archived-contact.png} +0 -0
  82. /package/screenshots/truth/contacts/{contact-blocked-hide-chatbox.png → chat-for-blocked-contact.png} +0 -0
  83. /package/screenshots/truth/contacts/{contact-stopped-hide-chatbox.png → chat-for-stopped-contact.png} +0 -0
  84. /package/screenshots/truth/contacts/{compose-text-and-attachments-success.png → chat-sends-attachments-only.png} +0 -0
  85. /package/screenshots/truth/contacts/{contact-active-default.png → chat-sends-text-and-attachments.png} +0 -0
  86. /package/screenshots/truth/contacts/{contact-active-show-chatbox.png → chat-sends-text-only.png} +0 -0
@@ -1,7 +1,7 @@
1
1
  import { useFakeTimers } from 'sinon';
2
2
  import { Compose } from '../src/compose/Compose';
3
3
  import { ContactChat } from '../src/contacts/ContactChat';
4
- import { Attachment } from '../src/interfaces';
4
+ import { Attachment, CustomEventType } from '../src/interfaces';
5
5
  import {
6
6
  assertScreenshot,
7
7
  clearMockPosts,
@@ -13,12 +13,12 @@ import {
13
13
  mockPOST
14
14
  } from '../test/utils.test';
15
15
  import {
16
- getInvalidText,
17
16
  getValidAttachments,
18
17
  getValidText,
19
18
  updateComponent
20
19
  } from './temba-compose.test';
21
- import { Completion } from '../src/completion/Completion';
20
+
21
+ import { expect, oneEvent } from '@open-wc/testing';
22
22
 
23
23
  let clock: any;
24
24
  mockNow('2021-03-31T00:31:00.000-00:00');
@@ -48,13 +48,12 @@ const getResponseSuccessFiles = (attachments: Attachment[]) => {
48
48
  });
49
49
  return response_attachments;
50
50
  };
51
- const responseTextError = 'Maximum allowed text is 640 characters.';
52
- const responseAttachmentError = 'Maximum allowed attachments is 10 files.';
53
51
 
54
- describe('temba-contact-chat - contact tests', () => {
52
+ describe('temba-contact-chat', () => {
55
53
  // map requests for contact history to our static files
56
54
  // we'll just us the same historylist for everybody for now
57
55
  beforeEach(() => {
56
+ clearMockPosts();
58
57
  mockGET(
59
58
  /\/contact\/history\/contact-.*/,
60
59
  '/test-assets/contacts/history.json'
@@ -66,16 +65,6 @@ describe('temba-contact-chat - contact tests', () => {
66
65
  clock.restore();
67
66
  });
68
67
 
69
- it('can be created', async () => {
70
- // we are a StoreElement, so load a store first
71
- await loadStore();
72
- const chat: ContactChat = await getContactChat({
73
- contact: 'contact-dave-active'
74
- });
75
-
76
- await assertScreenshot('contacts/contact-active-default', getClip(chat));
77
- });
78
-
79
68
  it('show history and show chatbox if contact is active', async () => {
80
69
  // we are a StoreElement, so load a store first
81
70
  await loadStore();
@@ -83,10 +72,7 @@ describe('temba-contact-chat - contact tests', () => {
83
72
  contact: 'contact-dave-active'
84
73
  });
85
74
 
86
- await assertScreenshot(
87
- 'contacts/contact-active-show-chatbox',
88
- getClip(chat)
89
- );
75
+ await assertScreenshot('contacts/chat-for-active-contact', getClip(chat));
90
76
  });
91
77
 
92
78
  it('show history and hide chatbox if contact is archived', async () => {
@@ -96,10 +82,7 @@ describe('temba-contact-chat - contact tests', () => {
96
82
  contact: 'contact-barack-archived'
97
83
  });
98
84
 
99
- await assertScreenshot(
100
- 'contacts/contact-archived-hide-chatbox',
101
- getClip(chat)
102
- );
85
+ await assertScreenshot('contacts/chat-for-archived-contact', getClip(chat));
103
86
  });
104
87
 
105
88
  it('show history and hide chatbox if contact is blocked', async () => {
@@ -109,10 +92,7 @@ describe('temba-contact-chat - contact tests', () => {
109
92
  contact: 'contact-michelle-blocked'
110
93
  });
111
94
 
112
- await assertScreenshot(
113
- 'contacts/contact-blocked-hide-chatbox',
114
- getClip(chat)
115
- );
95
+ await assertScreenshot('contacts/chat-for-blocked-contact', getClip(chat));
116
96
  });
117
97
 
118
98
  it('show history and hide chatbox if contact is stopped', async () => {
@@ -122,28 +102,10 @@ describe('temba-contact-chat - contact tests', () => {
122
102
  contact: 'contact-tim-stopped'
123
103
  });
124
104
 
125
- await assertScreenshot(
126
- 'contacts/contact-stopped-hide-chatbox',
127
- getClip(chat)
128
- );
129
- });
130
- });
131
-
132
- describe('temba-contact-chat - contact tests - handle send tests - text no attachments', () => {
133
- beforeEach(() => {
134
- clearMockPosts();
135
- mockGET(
136
- /\/contact\/history\/contact-.*/,
137
- '/test-assets/contacts/history.json'
138
- );
139
- clock = useFakeTimers();
140
- });
141
-
142
- afterEach(function () {
143
- clock.restore();
105
+ await assertScreenshot('contacts/chat-for-stopped-contact', getClip(chat));
144
106
  });
145
107
 
146
- it('with text no attachments - success', async () => {
108
+ it('sends text without attachments', async () => {
147
109
  // we are a StoreElement, so load a store first
148
110
  await loadStore();
149
111
  const chat: ContactChat = await getContactChat({
@@ -160,64 +122,14 @@ describe('temba-contact-chat - contact tests - handle send tests - text no attac
160
122
  };
161
123
  mockPOST(/api\/v2\/messages\.json/, response_body);
162
124
 
163
- // press enter
164
- const chatbox = compose.shadowRoot.querySelector('.chatbox') as Completion;
165
- chatbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
166
-
167
- await assertScreenshot(
168
- 'contacts/compose-text-no-attachments-success',
169
- getClip(chat)
170
- );
171
- });
172
-
173
- it('with text no attachments - failure - more than 640 chars', async () => {
174
- // we are a StoreElement, so load a store first
175
- await loadStore();
176
- const chat: ContactChat = await getContactChat({
177
- contact: 'contact-dave-active'
178
- });
179
- const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;
180
- // set the chatbox to a string that is 640+ chars
181
- await updateComponent(compose, getInvalidText());
182
-
183
- const response_body = {
184
- text: [responseTextError]
185
- };
186
- const response_headers = {};
187
- const response_status = '400';
188
- mockPOST(
189
- /api\/v2\/messages\.json/,
190
- response_body,
191
- response_headers,
192
- response_status
193
- );
194
-
195
- // press enter
196
- const chatbox = compose.shadowRoot.querySelector('.chatbox') as Completion;
197
- chatbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
198
-
199
- await assertScreenshot(
200
- 'contacts/compose-text-no-attachments-failure',
201
- getClip(chat)
202
- );
203
- });
204
- });
205
-
206
- describe('temba-contact-chat - contact tests - handle send tests - attachments no text', () => {
207
- beforeEach(() => {
208
- clearMockPosts();
209
- mockGET(
210
- /\/contact\/history\/contact-.*/,
211
- '/test-assets/contacts/history.json'
212
- );
213
- clock = useFakeTimers();
214
- });
125
+ const listener = oneEvent(compose, CustomEventType.Submitted, false);
126
+ await typeInto('temba-contact-chat:temba-compose', text, true, true);
127
+ expect(await listener).to.exist;
215
128
 
216
- afterEach(function () {
217
- clock.restore();
129
+ await assertScreenshot('contacts/chat-sends-text-only', getClip(chat));
218
130
  });
219
131
 
220
- it('with attachments no text - success', async () => {
132
+ it('sends attachments without text', async () => {
221
133
  // we are a StoreElement, so load a store first
222
134
  await loadStore();
223
135
  const chat: ContactChat = await getContactChat({
@@ -241,63 +153,17 @@ describe('temba-contact-chat - contact tests - handle send tests - attachments n
241
153
  response_status
242
154
  );
243
155
 
244
- // press enter
245
- const chatbox = compose.shadowRoot.querySelector('.chatbox') as Completion;
246
- chatbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
247
-
248
- await assertScreenshot(
249
- 'contacts/compose-attachments-no-text-success',
250
- getClip(chat)
251
- );
252
- });
253
- it('with attachments no text - failure - more than 10 files', async () => {
254
- // we are a StoreElement, so load a store first
255
- await loadStore();
256
- const chat: ContactChat = await getContactChat({
257
- contact: 'contact-dave-active'
258
- });
259
- const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;
260
- // set the attachments to a list that is 10+ items
261
- await updateComponent(compose, null, getValidAttachments(11));
262
-
263
- const response_body = {
264
- attachments: [responseAttachmentError]
265
- };
266
- const response_headers = {};
267
- const response_status = '400';
268
- mockPOST(
269
- /api\/v2\/messages\.json/,
270
- response_body,
271
- response_headers,
272
- response_status
273
- );
274
-
275
- // press enter
276
- const chatbox = compose.shadowRoot.querySelector('.chatbox') as Completion;
277
- chatbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
156
+ const listener = oneEvent(compose, CustomEventType.Submitted, false);
157
+ await typeInto('temba-contact-chat:temba-compose', '', false, true);
158
+ expect(await listener).to.exist;
278
159
 
279
160
  await assertScreenshot(
280
- 'contacts/compose-attachments-no-text-failure',
161
+ 'contacts/chat-sends-attachments-only',
281
162
  getClip(chat)
282
163
  );
283
164
  });
284
- });
285
-
286
- describe('temba-contact-chat - contact tests - handle send tests - text and attachments', () => {
287
- beforeEach(() => {
288
- clearMockPosts();
289
- mockGET(
290
- /\/contact\/history\/contact-.*/,
291
- '/test-assets/contacts/history.json'
292
- );
293
- clock = useFakeTimers();
294
- });
295
-
296
- afterEach(function () {
297
- clock.restore();
298
- });
299
165
 
300
- it('with text and attachments - success', async () => {
166
+ it('sends text with attachments', async () => {
301
167
  // we are a StoreElement, so load a store first
302
168
  await loadStore();
303
169
  const chat: ContactChat = await getContactChat({
@@ -316,114 +182,17 @@ describe('temba-contact-chat - contact tests - handle send tests - text and atta
316
182
  mockPOST(/api\/v2\/messages\.json/, response_body);
317
183
 
318
184
  // press enter
319
- const chatbox = compose.shadowRoot.querySelector('.chatbox') as Completion;
320
- chatbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
321
-
322
- await assertScreenshot(
323
- 'contacts/compose-text-and-attachments-success',
324
- getClip(chat)
325
- );
326
- });
327
-
328
- it('with text and attachments - failure - more than 640 chars', async () => {
329
- // we are a StoreElement, so load a store first
330
- await loadStore();
331
- const chat: ContactChat = await getContactChat({
332
- contact: 'contact-dave-active'
333
- });
334
- const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;
335
- // set the chatbox to a string that is 640+ chars
336
- await updateComponent(compose, getInvalidText(), getValidAttachments());
337
-
338
- const response_body = {
339
- text: [responseTextError]
340
- };
341
- const response_headers = {};
342
- const response_status = '400';
343
- mockPOST(
344
- /api\/v2\/messages\.json/,
345
- response_body,
346
- response_headers,
347
- response_status
348
- );
349
-
350
- // press enter
351
- const chatbox = compose.shadowRoot.querySelector('.chatbox') as Completion;
352
- chatbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
353
-
354
- await assertScreenshot(
355
- 'contacts/compose-text-and-attachments-failure-text',
356
- getClip(chat)
357
- );
358
- });
359
-
360
- it('with text and attachments - failure - more than 10 files', async () => {
361
- // we are a StoreElement, so load a store first
362
- await loadStore();
363
- const chat: ContactChat = await getContactChat({
364
- contact: 'contact-dave-active'
365
- });
366
- const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;
367
- // set the attachments to a list that is 10+ items
368
- await updateComponent(compose, getValidText(), getValidAttachments(11));
369
-
370
- const response_body = {
371
- attachments: [responseAttachmentError]
372
- };
373
- const response_headers = {};
374
- const response_status = '400';
375
- mockPOST(
376
- /api\/v2\/messages\.json/,
377
- response_body,
378
- response_headers,
379
- response_status
380
- );
381
-
382
- // press enter
383
- const chatbox = compose.shadowRoot.querySelector('.chatbox') as Completion;
384
- chatbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
385
-
386
- await assertScreenshot(
387
- 'contacts/compose-text-and-attachments-failure-attachments',
388
- getClip(chat)
389
- );
390
- });
391
-
392
- it('with text and attachments - failure - more than 640 chars and more than 10 files', async () => {
393
- // we are a StoreElement, so load a store first
394
- await loadStore();
395
- const chat: ContactChat = await getContactChat({
396
- contact: 'contact-dave-active'
397
- });
398
- const compose = chat.shadowRoot.querySelector('temba-compose') as Compose;
399
- // set the chatbox to a string that is 640+ chars
400
- // set the attachments to a list that is 10+ items
401
- await updateComponent(compose, getInvalidText(), getValidAttachments(11));
402
-
403
- const response_body = {
404
- text: [responseTextError],
405
- attachments: [responseAttachmentError]
406
- };
407
- const response_headers = {};
408
- const response_status = '400';
409
- mockPOST(
410
- /api\/v2\/messages\.json/,
411
- response_body,
412
- response_headers,
413
- response_status
414
- );
415
-
416
- // press enter
417
- const chatbox = compose.shadowRoot.querySelector('.chatbox') as Completion;
418
- chatbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
185
+ const listener = oneEvent(compose, CustomEventType.Submitted, false);
186
+ await typeInto('temba-contact-chat:temba-compose', '', false, true);
187
+ expect(await listener).to.exist;
419
188
 
420
189
  await assertScreenshot(
421
- 'contacts/compose-text-and-attachments-failure-text-and-attachments',
190
+ 'contacts/chat-sends-text-and-attachments',
422
191
  getClip(chat)
423
192
  );
424
193
  });
425
194
 
426
- it('with text and attachments - failure - generic', async () => {
195
+ it('shows failure message with retry', async () => {
427
196
  // we are a StoreElement, so load a store first
428
197
  await loadStore();
429
198
  const chat: ContactChat = await getContactChat({
@@ -442,13 +211,11 @@ describe('temba-contact-chat - contact tests - handle send tests - text and atta
442
211
  response_status
443
212
  );
444
213
 
445
- // press enter
446
- const chatbox = compose.shadowRoot.querySelector('.chatbox') as Completion;
447
- chatbox.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
214
+ // press
215
+ const listener = oneEvent(compose, CustomEventType.Submitted, false);
216
+ await typeInto('temba-contact-chat:temba-compose', '', false, true);
217
+ expect(await listener).to.exist;
448
218
 
449
- await assertScreenshot(
450
- 'contacts/compose-text-and-attachments-failure-generic',
451
- getClip(chat)
452
- );
219
+ await assertScreenshot('contacts/chat-failure', getClip(chat));
453
220
  });
454
221
  });
@@ -333,6 +333,7 @@ export default {
333
333
  '--disable-web-security',
334
334
  '--force-device-scale-factor=1',
335
335
  '--no-sandbox',
336
+ '--disable-gpu',
336
337
  ],
337
338
  headless: true,
338
339
  },
@@ -1 +0,0 @@
1
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2.624 2.385 C 1.780 2.768,1.314 3.435,1.107 4.557 C 1.004 5.115,0.960 8.006,0.991 12.207 C 1.040 18.914,1.043 18.965,1.414 19.720 C 1.620 20.137,2.073 20.723,2.421 21.021 C 3.537 21.976,3.774 22.000,12.000 22.000 C 20.226 22.000,20.463 21.976,21.579 21.021 C 21.927 20.723,22.380 20.137,22.586 19.720 C 22.954 18.973,22.960 18.876,22.960 14.000 C 22.960 9.796,22.921 8.955,22.704 8.480 C 22.292 7.578,21.591 6.861,20.727 6.459 C 19.968 6.105,19.734 6.083,16.800 6.080 L 13.680 6.076 12.880 4.529 C 12.219 3.250,11.957 2.905,11.369 2.531 L 10.657 2.080 6.969 2.084 C 3.718 2.087,3.202 2.122,2.624 2.385 M10.393 4.313 C 10.678 4.598,11.360 5.784,11.360 5.994 C 11.360 6.041,9.488 6.080,7.200 6.080 L 3.040 6.080 3.040 5.289 C 3.040 4.038,3.153 4.000,6.916 4.000 C 9.844 4.000,10.103 4.023,10.393 4.313 M20.357 8.603 L 20.880 9.126 20.880 14.000 L 20.880 18.874 20.357 19.397 L 19.834 19.920 12.000 19.920 L 4.166 19.920 3.643 19.397 L 3.120 18.874 3.072 13.430 L 3.024 7.987 11.429 8.033 L 19.834 8.080 20.357 8.603 M11.520 9.557 C 10.582 9.700,8.297 10.623,8.136 10.924 C 8.035 11.113,7.990 11.989,8.024 13.100 C 8.075 14.785,8.121 15.030,8.519 15.707 C 9.036 16.586,10.294 17.730,11.291 18.228 L 12.000 18.582 12.709 18.228 C 13.706 17.730,14.964 16.586,15.481 15.707 C 15.879 15.030,15.925 14.785,15.976 13.100 C 16.010 11.989,15.965 11.113,15.864 10.924 C 15.757 10.726,15.174 10.428,14.288 10.120 C 12.762 9.589,12.140 9.463,11.520 9.557 M13.066 11.789 L 13.920 12.058 13.920 13.334 L 13.920 14.609 13.064 15.464 C 12.594 15.935,12.115 16.320,12.000 16.320 C 11.885 16.320,11.406 15.935,10.936 15.464 L 10.080 14.609 10.080 13.332 L 10.080 12.056 10.840 11.803 C 11.838 11.471,12.053 11.470,13.066 11.789 " stroke="none" fill-rule="evenodd" fill="black"></path></svg>
@@ -1,3 +0,0 @@
1
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M13 7L11.8845 4.76892C11.5634 4.1268 11.4029 3.80573 11.1634 3.57116C10.9516 3.36373 10.6963 3.20597 10.4161 3.10931C10.0992 3 9.74021 3 9.02229 3H5.2C4.0799 3 3.51984 3 3.09202 3.21799C2.71569 3.40973 2.40973 3.71569 2.21799 4.09202C2 4.51984 2 5.0799 2 6.2V7M2 7H17.2C18.8802 7 19.7202 7 20.362 7.32698C20.9265 7.6146 21.3854 8.07354 21.673 8.63803C22 9.27976 22 10.1198 22 11.8V16.2C22 17.8802 22 18.7202 21.673 19.362C21.3854 19.9265 20.9265 20.3854 20.362 20.673C19.7202 21 18.8802 21 17.2 21H6.8C5.11984 21 4.27976 21 3.63803 20.673C3.07354 20.3854 2.6146 19.9265 2.32698 19.362C2 18.7202 2 17.8802 2 16.2V7ZM12 17.5C12 17.5 15 16.0701 15 13.9252V11.4229L12.8124 10.6412C12.2868 10.4529 11.712 10.4529 11.1864 10.6412L9 11.4229V13.9252C9 16.0701 12 17.5 12 17.5Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3
- </svg>