@memori.ai/memori-react 8.6.7 → 8.7.1

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 (79) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/components/Header/Header.css +24 -0
  3. package/dist/components/Header/Header.d.ts +3 -0
  4. package/dist/components/Header/Header.js +51 -2
  5. package/dist/components/Header/Header.js.map +1 -1
  6. package/dist/components/LoginDrawer/LoginDrawer.css +1372 -238
  7. package/dist/components/MemoriWidget/MemoriWidget.js +25 -13
  8. package/dist/components/MemoriWidget/MemoriWidget.js.map +1 -1
  9. package/dist/components/icons/Logout.d.ts +6 -0
  10. package/dist/components/icons/Logout.js +6 -0
  11. package/dist/components/icons/Logout.js.map +1 -0
  12. package/dist/components/layouts/HiddenChat.js +3 -1
  13. package/dist/components/layouts/HiddenChat.js.map +1 -1
  14. package/dist/components/layouts/hidden-chat.css +4 -0
  15. package/dist/components/ui/Dropdown.css +173 -0
  16. package/dist/components/ui/Dropdown.d.ts +11 -0
  17. package/dist/components/ui/Dropdown.js +33 -0
  18. package/dist/components/ui/Dropdown.js.map +1 -0
  19. package/dist/helpers/error.js +3 -0
  20. package/dist/helpers/error.js.map +1 -1
  21. package/dist/helpers/tts/useTTS.js +3 -0
  22. package/dist/helpers/tts/useTTS.js.map +1 -1
  23. package/dist/locales/en.json +48 -1
  24. package/dist/locales/es.json +30 -0
  25. package/dist/locales/fr.json +30 -0
  26. package/dist/locales/it.json +44 -0
  27. package/dist/styles.css +1 -0
  28. package/esm/components/Header/Header.css +24 -0
  29. package/esm/components/Header/Header.d.ts +3 -0
  30. package/esm/components/Header/Header.js +52 -3
  31. package/esm/components/Header/Header.js.map +1 -1
  32. package/esm/components/LoginDrawer/LoginDrawer.css +1372 -238
  33. package/esm/components/MemoriWidget/MemoriWidget.js +25 -13
  34. package/esm/components/MemoriWidget/MemoriWidget.js.map +1 -1
  35. package/esm/components/icons/Logout.d.ts +6 -0
  36. package/esm/components/icons/Logout.js +4 -0
  37. package/esm/components/icons/Logout.js.map +1 -0
  38. package/esm/components/layouts/HiddenChat.js +3 -1
  39. package/esm/components/layouts/HiddenChat.js.map +1 -1
  40. package/esm/components/layouts/hidden-chat.css +4 -0
  41. package/esm/components/ui/Dropdown.css +173 -0
  42. package/esm/components/ui/Dropdown.d.ts +11 -0
  43. package/esm/components/ui/Dropdown.js +30 -0
  44. package/esm/components/ui/Dropdown.js.map +1 -0
  45. package/esm/helpers/error.js +3 -0
  46. package/esm/helpers/error.js.map +1 -1
  47. package/esm/helpers/tts/useTTS.js +3 -0
  48. package/esm/helpers/tts/useTTS.js.map +1 -1
  49. package/esm/locales/en.json +48 -1
  50. package/esm/locales/es.json +30 -0
  51. package/esm/locales/fr.json +30 -0
  52. package/esm/locales/it.json +44 -0
  53. package/esm/styles.css +1 -0
  54. package/package.json +2 -2
  55. package/src/__snapshots__/index.test.tsx.snap +19 -0
  56. package/src/components/Header/Header.css +24 -0
  57. package/src/components/Header/Header.test.tsx +15 -1
  58. package/src/components/Header/Header.tsx +146 -10
  59. package/src/components/Header/__snapshots__/Header.test.tsx.snap +53 -37
  60. package/src/components/LoginDrawer/LoginDrawer.css +1372 -238
  61. package/src/components/LoginDrawer/LoginDrawer.test.tsx +12 -1
  62. package/src/components/MemoriWidget/MemoriWidget.tsx +83 -44
  63. package/src/components/icons/Logout.tsx +27 -0
  64. package/src/components/layouts/HiddenChat.tsx +3 -1
  65. package/src/components/layouts/__snapshots__/HiddenChat.test.tsx.snap +1 -1
  66. package/src/components/layouts/hidden-chat.css +4 -0
  67. package/src/components/ui/Dropdown.css +173 -0
  68. package/src/components/ui/Dropdown.tsx +63 -0
  69. package/src/helpers/error.ts +3 -0
  70. package/src/helpers/tts/useTTS.ts +9 -4
  71. package/src/index.stories.tsx +1 -0
  72. package/src/index.test.tsx +17 -0
  73. package/src/locales/en.json +48 -1
  74. package/src/locales/es.json +30 -0
  75. package/src/locales/fr.json +30 -0
  76. package/src/locales/it.json +44 -0
  77. package/src/styles.css +1 -0
  78. package/src/components/AccountForm/AccountForm.test.tsx +0 -27
  79. package/src/components/AccountForm/__snapshots__/AccountForm.test.tsx.snap +0 -202
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { render } from '@testing-library/react';
3
3
  import { memori, history, user } from '../../mocks/data';
4
4
  import Header from './Header';
5
+ import memoriApiClient from '@memori.ai/memori-api-client';
5
6
 
6
7
  it('renders Header unchanged', () => {
7
8
  const { container } = render(
@@ -20,6 +21,7 @@ it('renders Header unchanged', () => {
20
21
  showSettings={false}
21
22
  clearHistory={jest.fn()}
22
23
  setShowLoginDrawer={jest.fn()}
24
+ apiClient={memoriApiClient()}
23
25
  />
24
26
  );
25
27
  expect(container).toMatchSnapshot();
@@ -50,6 +52,7 @@ it('renders Header with position unchanged', () => {
50
52
  showSettings={false}
51
53
  clearHistory={jest.fn()}
52
54
  setShowLoginDrawer={jest.fn()}
55
+ apiClient={memoriApiClient()}
53
56
  />
54
57
  );
55
58
  expect(container).toMatchSnapshot();
@@ -72,6 +75,7 @@ it('renders Header with speaker muted unchanged', () => {
72
75
  clearHistory={jest.fn()}
73
76
  setShowLoginDrawer={jest.fn()}
74
77
  setShowChatHistoryDrawer={jest.fn()}
78
+ apiClient={memoriApiClient()}
75
79
  />
76
80
  );
77
81
  expect(container).toMatchSnapshot();
@@ -95,6 +99,7 @@ it('renders Header with audio disabled unchanged', () => {
95
99
  clearHistory={jest.fn()}
96
100
  setShowLoginDrawer={jest.fn()}
97
101
  setShowChatHistoryDrawer={jest.fn()}
102
+ apiClient={memoriApiClient()}
98
103
  />
99
104
  );
100
105
  expect(container).toMatchSnapshot();
@@ -117,6 +122,7 @@ it('renders Header with share button unchanged', () => {
117
122
  clearHistory={jest.fn()}
118
123
  setShowLoginDrawer={jest.fn()}
119
124
  setShowChatHistoryDrawer={jest.fn()}
125
+ apiClient={memoriApiClient()}
120
126
  />
121
127
  );
122
128
  expect(container).toMatchSnapshot();
@@ -139,6 +145,7 @@ it('renders Header with settings button unchanged', () => {
139
145
  clearHistory={jest.fn()}
140
146
  setShowLoginDrawer={jest.fn()}
141
147
  setShowChatHistoryDrawer={jest.fn()}
148
+ apiClient={memoriApiClient()}
142
149
  />
143
150
  );
144
151
  expect(container).toMatchSnapshot();
@@ -162,6 +169,7 @@ it('renders Header with clear button unchanged', () => {
162
169
  clearHistory={jest.fn()}
163
170
  setShowLoginDrawer={jest.fn()}
164
171
  setShowChatHistoryDrawer={jest.fn()}
172
+ apiClient={memoriApiClient()}
165
173
  />
166
174
  );
167
175
  expect(container).toMatchSnapshot();
@@ -184,6 +192,7 @@ it('renders Header with user activated speak unchanged', () => {
184
192
  clearHistory={jest.fn()}
185
193
  setShowLoginDrawer={jest.fn()}
186
194
  setShowChatHistoryDrawer={jest.fn()}
195
+ apiClient={memoriApiClient()}
187
196
  />
188
197
  );
189
198
  expect(container).toMatchSnapshot();
@@ -210,6 +219,7 @@ it('renders Header with deep thought unlogged unchanged', () => {
210
219
  clearHistory={jest.fn()}
211
220
  showLogin
212
221
  setShowLoginDrawer={jest.fn()}
222
+ apiClient={memoriApiClient()}
213
223
  />
214
224
  );
215
225
  expect(container).toMatchSnapshot();
@@ -230,7 +240,7 @@ it('renders Header with deep thought logged but without permission flag unchange
230
240
  speakerMuted={false}
231
241
  setSpeakerMuted={jest.fn()}
232
242
  hasUserActivatedSpeak={false}
233
-
243
+ apiClient={memoriApiClient()}
234
244
  showShare={false}
235
245
  showSettings={false}
236
246
  clearHistory={jest.fn()}
@@ -264,6 +274,7 @@ it('renders Header with deep thought logged with permission flag unchanged', ()
264
274
  showShare={false}
265
275
  showSettings={false}
266
276
  clearHistory={jest.fn()}
277
+ apiClient={memoriApiClient()}
267
278
  loginToken="abcd"
268
279
  user={{
269
280
  ...user,
@@ -295,6 +306,7 @@ it('renders Header with deep thought and session open unchanged', () => {
295
306
  showSettings={false}
296
307
  clearHistory={jest.fn()}
297
308
  sessionID="1234"
309
+ apiClient={memoriApiClient()}
298
310
  loginToken="abcd"
299
311
  setShowLoginDrawer={jest.fn()}
300
312
  setShowChatHistoryDrawer={jest.fn()}
@@ -323,6 +335,7 @@ it('renders Header for board of experts unchanged', () => {
323
335
  clearHistory={jest.fn()}
324
336
  loginToken="abcd"
325
337
  setShowLoginDrawer={jest.fn()}
338
+ apiClient={memoriApiClient()}
326
339
  setShowChatHistoryDrawer={jest.fn()}
327
340
  />
328
341
  );
@@ -350,6 +363,7 @@ it('renders Header for board of experts with session open unchanged', () => {
350
363
  sessionID="1234"
351
364
  loginToken="abcd"
352
365
  setShowLoginDrawer={jest.fn()}
366
+ apiClient={memoriApiClient()}
353
367
  setShowChatHistoryDrawer={jest.fn()}
354
368
  />
355
369
  );
@@ -8,6 +8,7 @@ import {
8
8
  User,
9
9
  } from '@memori.ai/memori-api-client/dist/types';
10
10
  import Button from '../ui/Button';
11
+ import Dropdown from '../ui/Dropdown';
11
12
  import MapMarker from '../icons/MapMarker';
12
13
  import SoundDeactivated from '../icons/SoundDeactivated';
13
14
  import Sound from '../icons/Sound';
@@ -22,6 +23,12 @@ import DeepThought from '../icons/DeepThought';
22
23
  import Group from '../icons/Group';
23
24
  import UserIcon from '../icons/User';
24
25
  import MessageIcon from '../icons/Message';
26
+ import Logout from '../icons/Logout';
27
+ import { getErrori18nKey } from '../../helpers/error';
28
+ import toast from 'react-hot-toast';
29
+ import memoriApiClient from '@memori.ai/memori-api-client';
30
+
31
+ const imgMimeTypes = ['image/jpeg', 'image/png', 'image/jpg', 'image/gif'];
25
32
 
26
33
  export interface Props {
27
34
  className?: string;
@@ -51,6 +58,8 @@ export interface Props {
51
58
  sessionID?: string;
52
59
  baseUrl?: string;
53
60
  fullScreenHandler?: (e: React.MouseEvent<HTMLButtonElement>) => void;
61
+ onLogout?: () => void;
62
+ apiClient: ReturnType<typeof memoriApiClient>;
54
63
  }
55
64
 
56
65
  const Header: React.FC<Props> = ({
@@ -81,8 +90,14 @@ const Header: React.FC<Props> = ({
81
90
  showChatHistory = true,
82
91
  fullScreenHandler,
83
92
  baseUrl,
93
+ onLogout,
94
+ apiClient,
84
95
  }) => {
85
96
  const { t } = useTranslation();
97
+ const {
98
+ uploadAsset,
99
+ pwlUpdateUser,
100
+ } = apiClient.backend;
86
101
  const [fullScreenAvailable, setFullScreenAvailable] = useState(false);
87
102
  const [fullScreen, setFullScreen] = useState(false);
88
103
  useEffect(() => {
@@ -91,6 +106,52 @@ const Header: React.FC<Props> = ({
91
106
  }
92
107
  }, []);
93
108
 
109
+ const updateAvatar = async (avatar: Blob) => {
110
+ console.log('[updateAvatar] Starting avatar update', { avatar });
111
+ if (avatar && loginToken) {
112
+ const reader = new FileReader();
113
+ reader.onload = async e => {
114
+ console.log('[updateAvatar] FileReader loaded', { result: e.target?.result });
115
+ try {
116
+ console.log('[updateAvatar] Uploading asset...');
117
+ const { asset: avatarAsset, ...resp } = await uploadAsset(
118
+ avatar.name ?? 'avatar',
119
+ e.target?.result as string,
120
+ loginToken ?? ''
121
+ );
122
+ console.log('[updateAvatar] Upload response:', { avatarAsset, resp });
123
+
124
+ if (resp.resultCode !== 0) {
125
+ console.error('[updateAvatar] Upload failed:', resp);
126
+ toast.error(t(getErrori18nKey(resp.resultCode)));
127
+ } else if (avatarAsset) {
128
+ console.log('[updateAvatar] Upload successful, updating user...');
129
+ let newUser: Partial<User> = {
130
+ userID: user?.userID,
131
+ avatarURL: avatarAsset.assetURL,
132
+ };
133
+
134
+ const { user: patchedUser, ...resp } = await pwlUpdateUser(
135
+ loginToken ?? '',
136
+ user?.userID ?? '',
137
+ newUser
138
+ );
139
+ console.log('[updateAvatar] User update complete', { patchedUser, resp });
140
+ }
141
+ } catch (e) {
142
+ let err = e as Error;
143
+ console.error('[updateAvatar] Error:', err);
144
+
145
+ if (err?.message) toast.error(err.message);
146
+ }
147
+ };
148
+ reader.readAsDataURL(avatar as Blob);
149
+ } else {
150
+ console.error('[updateAvatar] Missing avatar or login token', { avatar, loginToken });
151
+ toast.error(t('login.avatarUploadError'));
152
+ }
153
+ };
154
+
94
155
  return (
95
156
  <div className={cx('memori-header', className)}>
96
157
  {memori.needsPosition && position && (
@@ -244,16 +305,91 @@ const Header: React.FC<Props> = ({
244
305
  />
245
306
  )}
246
307
  {showLogin && (
247
- <Button
248
- primary
249
- shape="circle"
250
- className="memori-header--button memori-header--button-login"
251
- icon={<UserIcon />}
252
- onClick={() => setShowLoginDrawer(true)}
253
- title={
254
- loginToken ? t('login.user') || 'User' : t('login.login') || 'Login'
255
- }
256
- />
308
+ <>
309
+ {loginToken && user ? (
310
+ <Dropdown
311
+ placement="bottom-right"
312
+ trigger={
313
+ <Button
314
+ primary
315
+ shape="circle"
316
+ className="memori-header--button memori-header--button-login"
317
+ icon={<UserIcon />}
318
+ title={t('login.user') || 'User'}
319
+ />
320
+ }
321
+ >
322
+ <div className="memori-dropdown--user-profile">
323
+ <div className="memori-dropdown--user-info">
324
+ {user.avatarURL ? (
325
+ <>
326
+ <img
327
+ src={user.avatarURL}
328
+ alt={user.userName || user.eMail}
329
+ className="memori-dropdown--avatar"
330
+ />
331
+ <input
332
+ type="file"
333
+ name="avatar"
334
+ id="avatar"
335
+ className="memori-dropdown--avatar-input"
336
+ onChange={e => updateAvatar(e.target.files?.[0] ?? null as unknown as Blob)}
337
+ accept={imgMimeTypes.join(', ')}
338
+ />
339
+ </>
340
+ ) : (
341
+ <div className="memori-dropdown--avatar-placeholder">
342
+ <span>
343
+ {(user.userName || user.eMail || 'U')
344
+ .charAt(0)
345
+ .toUpperCase()}
346
+ </span>
347
+ <input
348
+ type="file"
349
+ name="avatar"
350
+ id="avatar"
351
+ className="memori-dropdown--avatar-input"
352
+ onChange={e => updateAvatar(e.target.files?.[0] ?? null as unknown as Blob)}
353
+ accept={imgMimeTypes.join(', ')}
354
+ />
355
+ </div>
356
+ )}
357
+
358
+ <div className="memori-dropdown--user-details">
359
+ <h3 className="memori-dropdown--user-name">
360
+ {user.userName || t('login.welcomeUser')}
361
+ </h3>
362
+ <p className="memori-dropdown--user-email">{user.eMail}</p>
363
+ <div className="memori-dropdown--user-badge">
364
+ {user.birthDate
365
+ ? new Date(user.birthDate).toLocaleDateString()
366
+ : t('login.notSet')}
367
+ </div>
368
+ </div>
369
+ </div>
370
+ </div>
371
+
372
+ <div className="memori-dropdown--actions">
373
+ <button
374
+ className="memori-dropdown--action-button memori-dropdown--action-button--logout"
375
+ onClick={onLogout}
376
+ >
377
+ <Logout className="memori-dropdown--action-icon" />
378
+ {t('login.logout') || 'Logout'}
379
+ </button>
380
+ </div>
381
+ </Dropdown>
382
+ ) : (
383
+ <Button
384
+ primary
385
+ shape="circle"
386
+ className="memori-header--button memori-header--button-login"
387
+ icon={<UserIcon />}
388
+ onClick={() => setShowLoginDrawer(true)}
389
+ title={t('login.login') || 'Login'}
390
+ />
391
+ )}
392
+ </>
257
393
  )}
258
394
  </div>
259
395
  );
@@ -75,7 +75,7 @@ exports[`renders Header for board of experts unchanged 1`] = `
75
75
  </button>
76
76
  <button
77
77
  class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button memori-header--button-login"
78
- title="login.user"
78
+ title="login.login"
79
79
  >
80
80
  <span
81
81
  class="memori-button--icon"
@@ -171,7 +171,7 @@ exports[`renders Header for board of experts with session open unchanged 1`] = `
171
171
  </button>
172
172
  <button
173
173
  class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button memori-header--button-login"
174
- title="login.user"
174
+ title="login.login"
175
175
  >
176
176
  <span
177
177
  class="memori-button--icon"
@@ -387,7 +387,7 @@ exports[`renders Header with deep thought and session open unchanged 1`] = `
387
387
  </button>
388
388
  <button
389
389
  class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button memori-header--button-login"
390
- title="login.user"
390
+ title="login.login"
391
391
  >
392
392
  <span
393
393
  class="memori-button--icon"
@@ -454,26 +454,34 @@ exports[`renders Header with deep thought logged but without permission flag unc
454
454
  </svg>
455
455
  </span>
456
456
  </button>
457
- <button
458
- class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button memori-header--button-login"
459
- title="login.user"
457
+ <div
458
+ class="memori-dropdown"
460
459
  >
461
- <span
462
- class="memori-button--icon"
460
+ <div
461
+ class="memori-dropdown--trigger"
463
462
  >
464
- <svg
465
- aria-hidden="true"
466
- focusable="false"
467
- role="img"
468
- viewBox="0 0 1024 1024"
469
- xmlns="http://www.w3.org/2000/svg"
463
+ <button
464
+ class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button memori-header--button-login"
465
+ title="login.user"
470
466
  >
471
- <path
472
- d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
473
- />
474
- </svg>
475
- </span>
476
- </button>
467
+ <span
468
+ class="memori-button--icon"
469
+ >
470
+ <svg
471
+ aria-hidden="true"
472
+ focusable="false"
473
+ role="img"
474
+ viewBox="0 0 1024 1024"
475
+ xmlns="http://www.w3.org/2000/svg"
476
+ >
477
+ <path
478
+ d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
479
+ />
480
+ </svg>
481
+ </span>
482
+ </button>
483
+ </div>
484
+ </div>
477
485
  </div>
478
486
  </div>
479
487
  `;
@@ -567,26 +575,34 @@ exports[`renders Header with deep thought logged with permission flag unchanged
567
575
  </svg>
568
576
  </span>
569
577
  </button>
570
- <button
571
- class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button memori-header--button-login"
572
- title="login.user"
578
+ <div
579
+ class="memori-dropdown"
573
580
  >
574
- <span
575
- class="memori-button--icon"
581
+ <div
582
+ class="memori-dropdown--trigger"
576
583
  >
577
- <svg
578
- aria-hidden="true"
579
- focusable="false"
580
- role="img"
581
- viewBox="0 0 1024 1024"
582
- xmlns="http://www.w3.org/2000/svg"
584
+ <button
585
+ class="memori-button memori-button--primary memori-button--circle memori-button--padded memori-button--icon-only memori-header--button memori-header--button-login"
586
+ title="login.user"
583
587
  >
584
- <path
585
- d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
586
- />
587
- </svg>
588
- </span>
589
- </button>
588
+ <span
589
+ class="memori-button--icon"
590
+ >
591
+ <svg
592
+ aria-hidden="true"
593
+ focusable="false"
594
+ role="img"
595
+ viewBox="0 0 1024 1024"
596
+ xmlns="http://www.w3.org/2000/svg"
597
+ >
598
+ <path
599
+ d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
600
+ />
601
+ </svg>
602
+ </span>
603
+ </button>
604
+ </div>
605
+ </div>
590
606
  </div>
591
607
  </div>
592
608
  `;