@lobehub/chat 1.62.4 → 1.62.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/ar/plugin.json +4 -0
  4. package/locales/bg-BG/plugin.json +4 -0
  5. package/locales/de-DE/plugin.json +4 -0
  6. package/locales/en-US/plugin.json +4 -0
  7. package/locales/es-ES/plugin.json +4 -0
  8. package/locales/fa-IR/plugin.json +4 -0
  9. package/locales/fr-FR/plugin.json +4 -0
  10. package/locales/it-IT/plugin.json +4 -0
  11. package/locales/ja-JP/plugin.json +4 -0
  12. package/locales/ko-KR/plugin.json +4 -0
  13. package/locales/nl-NL/plugin.json +4 -0
  14. package/locales/pl-PL/plugin.json +4 -0
  15. package/locales/pt-BR/plugin.json +4 -0
  16. package/locales/ru-RU/plugin.json +4 -0
  17. package/locales/tr-TR/plugin.json +4 -0
  18. package/locales/vi-VN/plugin.json +4 -0
  19. package/locales/zh-CN/plugin.json +5 -1
  20. package/locales/zh-TW/plugin.json +4 -0
  21. package/package.json +3 -3
  22. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +1 -1
  23. package/src/app/[variants]/(main)/settings/agent/index.tsx +2 -1
  24. package/src/database/server/models/aiProvider.ts +22 -9
  25. package/src/database/server/models/topic.ts +2 -0
  26. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/Debug.tsx +43 -0
  27. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/Loader.tsx +58 -0
  28. package/src/features/Conversation/Messages/Assistant/Tool/Inspector/index.tsx +151 -0
  29. package/src/features/Conversation/Messages/Assistant/Tool/Render/Arguments.tsx +165 -0
  30. package/src/features/Conversation/Messages/Assistant/{ToolCallItem/Tool.tsx → Tool/Render/CustomRender.tsx} +34 -35
  31. package/src/features/Conversation/Messages/Assistant/Tool/Render/index.tsx +39 -0
  32. package/src/features/Conversation/Messages/Assistant/Tool/index.tsx +70 -0
  33. package/src/features/Conversation/Messages/Assistant/index.tsx +19 -27
  34. package/src/features/Conversation/components/ChatItem/index.tsx +1 -0
  35. package/src/features/InitClientDB/PGliteIcon.tsx +2 -2
  36. package/src/features/PluginsUI/Render/index.tsx +2 -11
  37. package/src/locales/default/plugin.ts +4 -0
  38. package/src/styles/loading.ts +27 -0
  39. package/src/tools/dalle/Render/GalleyGrid.tsx +60 -0
  40. package/src/tools/dalle/Render/index.tsx +1 -1
  41. package/src/utils/errorResponse.test.ts +6 -0
  42. package/src/features/Conversation/Messages/Assistant/ToolCallItem/Inspector/index.tsx +0 -166
  43. package/src/features/Conversation/Messages/Assistant/ToolCallItem/Inspector/style.ts +0 -35
  44. package/src/features/Conversation/Messages/Assistant/ToolCallItem/index.tsx +0 -89
  45. package/src/features/Conversation/Messages/Assistant/ToolCallItem/style.ts +0 -35
  46. package/src/features/Conversation/Messages/components/Arguments.tsx +0 -22
  47. /package/src/features/Conversation/Messages/Assistant/{ToolCallItem → Tool}/Inspector/PluginResultJSON.tsx +0 -0
  48. /package/src/features/Conversation/Messages/Assistant/{ToolCallItem → Tool}/Inspector/Settings.tsx +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.62.6](https://github.com/lobehub/lobe-chat/compare/v1.62.5...v1.62.6)
6
+
7
+ <sup>Released on **2025-02-21**</sup>
8
+
9
+ #### 💄 Styles
10
+
11
+ - **misc**: Refactor the plugin render style.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Styles
19
+
20
+ - **misc**: Refactor the plugin render style, closes [#6390](https://github.com/lobehub/lobe-chat/issues/6390) ([3ecdba1](https://github.com/lobehub/lobe-chat/commit/3ecdba1))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ### [Version 1.62.5](https://github.com/lobehub/lobe-chat/compare/v1.62.4...v1.62.5)
31
+
32
+ <sup>Released on **2025-02-21**</sup>
33
+
34
+ #### 🐛 Bug Fixes
35
+
36
+ - **misc**: Fix default agent loading.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's fixed
44
+
45
+ - **misc**: Fix default agent loading, closes [#6393](https://github.com/lobehub/lobe-chat/issues/6393) ([7841122](https://github.com/lobehub/lobe-chat/commit/7841122))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 1.62.4](https://github.com/lobehub/lobe-chat/compare/v1.62.3...v1.62.4)
6
56
 
7
57
  <sup>Released on **2025-02-20**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Refactor the plugin render style."
6
+ ]
7
+ },
8
+ "date": "2025-02-21",
9
+ "version": "1.62.6"
10
+ },
11
+ {
12
+ "children": {
13
+ "fixes": [
14
+ "Fix default agent loading."
15
+ ]
16
+ },
17
+ "date": "2025-02-21",
18
+ "version": "1.62.5"
19
+ },
2
20
  {
3
21
  "children": {
4
22
  "fixes": [
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "فشل تحديث الإضافة {{name}}",
119
119
  "urlError": "الرابط لا يعيد محتوى بتنسيق JSON، يرجى التأكد من صحة الرابط"
120
120
  },
121
+ "inspector": {
122
+ "args": "عرض قائمة المعلمات",
123
+ "pluginRender": "عرض واجهة المكون الإضافي"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "مهجور",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Неуспешно опресняване на плъгина {{name}}",
119
119
  "urlError": "Връзката не върна съдържание във формат JSON. Моля, уверете се, че е валидна връзка."
120
120
  },
121
+ "inspector": {
122
+ "args": "Преглед на списъка с параметри",
123
+ "pluginRender": "Преглед на интерфейса на плъгина"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Изтрит",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Fehler beim Aktualisieren des Plugins {{name}}.",
119
119
  "urlError": "Der Link hat keine JSON-Format-Inhalte zurückgegeben. Stellen Sie sicher, dass der Link gültig ist."
120
120
  },
121
+ "inspector": {
122
+ "args": "Parameterliste anzeigen",
123
+ "pluginRender": "Plugin-Oberfläche anzeigen"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Veraltet",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Failed to refresh plugin {{name}}",
119
119
  "urlError": "The link did not return content in JSON format. Please ensure it is a valid link."
120
120
  },
121
+ "inspector": {
122
+ "args": "View parameter list",
123
+ "pluginRender": "View plugin interface"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Deleted",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Error al volver a instalar el complemento {{name}}.",
119
119
  "urlError": "El enlace no devuelve contenido en formato JSON. Asegúrese de que sea un enlace válido."
120
120
  },
121
+ "inspector": {
122
+ "args": "Ver lista de parámetros",
123
+ "pluginRender": "Ver interfaz del plugin"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Obsoleto",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "بروزرسانی افزونه {{name}} ناموفق بود.",
119
119
  "urlError": "این لینک محتوای JSON بازنگرداند، لطفاً از معتبر بودن لینک اطمینان حاصل کنید."
120
120
  },
121
+ "inspector": {
122
+ "args": "مشاهده لیست پارامترها",
123
+ "pluginRender": "مشاهده رابط کاربری پلاگین"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "حذف شده",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Échec de la mise à jour du plugin {{name}}",
119
119
  "urlError": "Ce lien ne renvoie pas de contenu au format JSON. Veuillez vous assurer qu'il s'agit d'un lien valide."
120
120
  },
121
+ "inspector": {
122
+ "args": "Voir la liste des paramètres",
123
+ "pluginRender": "Voir l'interface du plugin"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Obsolète",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Ricaricamento del plugin {{name}} fallito",
119
119
  "urlError": "Il collegamento non restituisce contenuti nel formato JSON. Assicurati che il collegamento sia valido"
120
120
  },
121
+ "inspector": {
122
+ "args": "Visualizza l'elenco dei parametri",
123
+ "pluginRender": "Visualizza l'interfaccia del plugin"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Deprecato",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "プラグイン{{name}}の再インストールに失敗しました",
119
119
  "urlError": "このリンクはJSON形式のコンテンツを返していません。有効なリンクであることを確認してください"
120
120
  },
121
+ "inspector": {
122
+ "args": "パラメーターリストを表示",
123
+ "pluginRender": "プラグインインターフェースを表示"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "削除済み",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "플러그인 {{name}} 다시 설치 중 오류가 발생했습니다.",
119
119
  "urlError": "이 링크는 JSON 형식의 내용을 반환하지 않습니다. 유효한 링크인지 확인하세요."
120
120
  },
121
+ "inspector": {
122
+ "args": "매개변수 목록 보기",
123
+ "pluginRender": "플러그인 인터페이스 보기"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "삭제됨",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Vernieuwen van de plugin {{name}} is mislukt.",
119
119
  "urlError": "De link retourneert geen JSON-indeling. Zorg ervoor dat het een geldige link is."
120
120
  },
121
+ "inspector": {
122
+ "args": "Bekijk parameterlijst",
123
+ "pluginRender": "Bekijk plugininterface"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Verouderd",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Nie udało się odświeżyć wtyczki {{name}}",
119
119
  "urlError": "Link nie zwrócił treści w formacie JSON. Upewnij się, że jest to poprawny link."
120
120
  },
121
+ "inspector": {
122
+ "args": "Zobacz listę parametrów",
123
+ "pluginRender": "Zobacz interfejs wtyczki"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Usunięte",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Falha ao atualizar o plugin {{name}}",
119
119
  "urlError": "O link não retornou conteúdo no formato JSON. Certifique-se de que o link é válido."
120
120
  },
121
+ "inspector": {
122
+ "args": "Ver parâmetros",
123
+ "pluginRender": "Ver interface do plugin"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Obsoleto",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Ошибка при обновлении плагина {{name}}",
119
119
  "urlError": "Ссылка не возвращает данные в формате JSON. Проверьте правильность ссылки"
120
120
  },
121
+ "inspector": {
122
+ "args": "Просмотреть список параметров",
123
+ "pluginRender": "Просмотреть интерфейс плагина"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Устарел",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "{{name}} eklentisi yenilenemedi",
119
119
  "urlError": "Bağlantı JSON formatında içerik döndürmedi. Lütfen geçerli bir bağlantı olduğundan emin olun"
120
120
  },
121
+ "inspector": {
122
+ "args": "Parametre listesini görüntüle",
123
+ "pluginRender": "Eklenti arayüzünü görüntüle"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Eski",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "Làm mới plugin {{name}} thất bại",
119
119
  "urlError": "Liên kết này không trả về nội dung dạng JSON, vui lòng đảm bảo rằng đó là một liên kết hợp lệ"
120
120
  },
121
+ "inspector": {
122
+ "args": "Xem danh sách tham số",
123
+ "pluginRender": "Xem giao diện plugin"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "Đã loại bỏ",
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "插件 {{name}} 刷新失败",
119
119
  "urlError": "该链接没有返回 JSON 格式的内容, 请确保是有效的链接"
120
120
  },
121
+ "inspector": {
122
+ "args": "查看参数列表",
123
+ "pluginRender": "查看插件界面"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "已删除",
@@ -163,4 +167,4 @@
163
167
  "title": "插件商店"
164
168
  },
165
169
  "unknownPlugin": "未知插件"
166
- }
170
+ }
@@ -118,6 +118,10 @@
118
118
  "reinstallError": "插件 {{name}} 刷新失敗",
119
119
  "urlError": "該連結沒有返回 JSON 格式的內容, 請確保是有效的連結"
120
120
  },
121
+ "inspector": {
122
+ "args": "查看參數列表",
123
+ "pluginRender": "查看插件介面"
124
+ },
121
125
  "list": {
122
126
  "item": {
123
127
  "deprecated.title": "已刪除",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.62.4",
3
+ "version": "1.62.6",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -129,7 +129,7 @@
129
129
  "@lobehub/chat-plugins-gateway": "^1.9.0",
130
130
  "@lobehub/icons": "^1.73.1",
131
131
  "@lobehub/tts": "^1.28.0",
132
- "@lobehub/ui": "^1.165.0",
132
+ "@lobehub/ui": "^1.165.2",
133
133
  "@neondatabase/serverless": "^0.10.4",
134
134
  "@next/third-parties": "^15.1.4",
135
135
  "@react-spring/web": "^9.7.5",
@@ -224,7 +224,7 @@
224
224
  "shiki": "^1.26.1",
225
225
  "stripe": "^16.12.0",
226
226
  "superjson": "^2.2.2",
227
- "svix": "~1.57.0",
227
+ "svix": "^1.59.1",
228
228
  "swr": "^2.3.0",
229
229
  "systemjs": "^6.15.1",
230
230
  "ts-md5": "^1.3.1",
@@ -14,10 +14,10 @@ const leftActions = [
14
14
  'model',
15
15
  'fileUpload',
16
16
  'knowledgeBase',
17
+ 'params',
17
18
  'history',
18
19
  'stt',
19
20
  'tools',
20
- 'params',
21
21
  'mainToken',
22
22
  ] as ActionKeys[];
23
23
 
@@ -12,11 +12,12 @@ const Page = memo(() => {
12
12
  const config = useUserStore(settingsSelectors.defaultAgentConfig, isEqual);
13
13
  const meta = useUserStore(settingsSelectors.defaultAgentMeta, isEqual);
14
14
  const [updateAgent] = useUserStore((s) => [s.updateDefaultAgent]);
15
-
15
+ const isUserStateInit = useUserStore((s) => s.isUserStateInit);
16
16
  return (
17
17
  <AgentSettings
18
18
  config={config}
19
19
  id={INBOX_SESSION_ID}
20
+ loading={!isUserStateInit}
20
21
  meta={meta}
21
22
  onConfigChange={(config) => {
22
23
  updateAgent({ config });
@@ -115,21 +115,34 @@ export class AiProviderModel {
115
115
  const encrypt = encryptor ?? defaultSerialize;
116
116
  const keyVaults = await encrypt(JSON.stringify(value.keyVaults));
117
117
 
118
+ const commonFields = {
119
+ checkModel: value.checkModel,
120
+ fetchOnClient: value.fetchOnClient,
121
+ keyVaults,
122
+ };
123
+
118
124
  return this.db
119
- .update(aiProviders)
120
- .set({ ...value, keyVaults, updatedAt: new Date() })
121
- .where(and(eq(aiProviders.id, id), eq(aiProviders.userId, this.userId)));
125
+ .insert(aiProviders)
126
+ .values({
127
+ ...commonFields,
128
+ id,
129
+ source: this.getProviderSource(id),
130
+ updatedAt: new Date(),
131
+ userId: this.userId,
132
+ })
133
+ .onConflictDoUpdate({
134
+ set: { ...commonFields, updatedAt: new Date() },
135
+ target: [aiProviders.id, aiProviders.userId],
136
+ });
122
137
  };
123
138
 
124
139
  toggleProviderEnabled = async (id: string, enabled: boolean) => {
125
- const isBuiltin = Object.values(ModelProvider).includes(id as any);
126
-
127
140
  return this.db
128
141
  .insert(aiProviders)
129
142
  .values({
130
143
  enabled,
131
144
  id,
132
- source: isBuiltin ? 'builtin' : 'custom',
145
+ source: this.getProviderSource(id),
133
146
  updatedAt: new Date(),
134
147
  userId: this.userId,
135
148
  })
@@ -142,15 +155,13 @@ export class AiProviderModel {
142
155
  updateOrder = async (sortMap: { id: string; sort: number }[]) => {
143
156
  await this.db.transaction(async (tx) => {
144
157
  const updates = sortMap.map(({ id, sort }) => {
145
- const isBuiltin = Object.values(ModelProvider).includes(id as any);
146
-
147
158
  return tx
148
159
  .insert(aiProviders)
149
160
  .values({
150
161
  enabled: true,
151
162
  id,
152
163
  sort,
153
- source: isBuiltin ? 'builtin' : 'custom',
164
+ source: this.getProviderSource(id),
154
165
  updatedAt: new Date(),
155
166
  userId: this.userId,
156
167
  })
@@ -238,4 +249,6 @@ export class AiProviderModel {
238
249
  };
239
250
 
240
251
  private isBuiltInProvider = (id: string) => Object.values(ModelProvider).includes(id as any);
252
+
253
+ private getProviderSource = (id: string) => (this.isBuiltInProvider(id) ? 'builtin' : 'custom');
241
254
  }
@@ -224,6 +224,7 @@ export class TopicModel {
224
224
  .insert(topics)
225
225
  .values({
226
226
  ...originalTopic,
227
+ clientId: null,
227
228
  id: this.genId(),
228
229
  title: newTitle || originalTopic?.title,
229
230
  })
@@ -242,6 +243,7 @@ export class TopicModel {
242
243
  .insert(messages)
243
244
  .values({
244
245
  ...message,
246
+ clientId: null,
245
247
  id: idGenerator('messages'),
246
248
  topicId: duplicatedTopic.id,
247
249
  })
@@ -0,0 +1,43 @@
1
+ import { Highlighter } from '@lobehub/ui';
2
+ import { Tabs } from 'antd';
3
+ import { memo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ interface DebugProps {
7
+ payload: object;
8
+ requestArgs?: string;
9
+ }
10
+
11
+ const Debug = memo<DebugProps>(({ payload, requestArgs }) => {
12
+ const { t } = useTranslation('plugin');
13
+ let params;
14
+ try {
15
+ params = JSON.stringify(JSON.parse(requestArgs || ''), null, 2);
16
+ } catch {
17
+ params = '';
18
+ }
19
+
20
+ return (
21
+ <Tabs
22
+ items={[
23
+ {
24
+ children: <Highlighter language={'json'}>{params}</Highlighter>,
25
+ key: 'arguments',
26
+ label: t('debug.arguments'),
27
+ },
28
+ {
29
+ children: <Highlighter language={'json'}>{JSON.stringify(payload, null, 2)}</Highlighter>,
30
+ key: 'function_call',
31
+ label: t('debug.function_call'),
32
+ },
33
+ // {
34
+ // children: <PluginResult content={content} />,
35
+ // key: 'response',
36
+ // label: t('debug.response'),
37
+ // },
38
+ ]}
39
+ style={{ display: 'grid', maxWidth: 800, minWidth: 400 }}
40
+ />
41
+ );
42
+ });
43
+ export default Debug;
@@ -0,0 +1,58 @@
1
+ import { createStyles } from 'antd-style';
2
+
3
+ export const useStyles = createStyles(({ css, token }, borderWidth: number = 2.5) => ({
4
+ background: css`
5
+ position: absolute;
6
+ inset: 0;
7
+
8
+ aspect-ratio: 1;
9
+ width: 100%;
10
+ border-radius: 50%;
11
+
12
+ background: ${token.colorFill};
13
+
14
+ mask: radial-gradient(farthest-side, #0000 calc(100% - ${borderWidth}px), #000 0);
15
+ `,
16
+ container: css`
17
+ position: relative;
18
+ width: 13px;
19
+ height: 13px;
20
+ `,
21
+
22
+ loader: css`
23
+ position: absolute;
24
+ inset: 0;
25
+
26
+ aspect-ratio: 1;
27
+ width: 100%;
28
+ border-radius: 50%;
29
+
30
+ background:
31
+ radial-gradient(farthest-side, ${token.colorTextSecondary} 94%, #0000) top/ ${borderWidth}px
32
+ ${borderWidth}px no-repeat,
33
+ conic-gradient(#0000 50%, ${token.colorTextSecondary});
34
+
35
+ mask: radial-gradient(farthest-side, #0000 calc(100% - ${borderWidth}px), #000 0);
36
+
37
+ animation: small-loader-anim 1s infinite linear;
38
+
39
+ @keyframes small-loader-anim {
40
+ 100% {
41
+ transform: rotate(1turn);
42
+ }
43
+ }
44
+ `,
45
+ }));
46
+
47
+ const Loader = () => {
48
+ const { styles } = useStyles();
49
+
50
+ return (
51
+ <div className={styles.container}>
52
+ <div className={styles.loader} />
53
+ <div className={styles.background} />
54
+ </div>
55
+ );
56
+ };
57
+
58
+ export default Loader;