@lobehub/chat 0.111.0 → 0.111.2

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/.i18nrc.js CHANGED
@@ -1,8 +1,6 @@
1
- const { description } = require('./package.json');
2
1
  const { defineConfig } = require('@lobehub/i18n-cli');
3
2
 
4
3
  module.exports = defineConfig({
5
- reference: description,
6
4
  entry: 'locales/zh_CN',
7
5
  entryLocale: 'zh_CN',
8
6
  output: 'locales',
package/CHANGELOG.md CHANGED
@@ -2,6 +2,64 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.111.2](https://github.com/lobehub/lobe-chat/compare/v0.111.1...v0.111.2)
6
+
7
+ <sup>Released on **2023-12-13**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Change topic-deletion hotkey.
12
+
13
+ #### 💄 Styles
14
+
15
+ - **misc**: Fix image display in safari (fix.
16
+
17
+ <br/>
18
+
19
+ <details>
20
+ <summary><kbd>Improvements and Fixes</kbd></summary>
21
+
22
+ #### What's fixed
23
+
24
+ - **misc**: Change topic-deletion hotkey, closes [#616](https://github.com/lobehub/lobe-chat/issues/616) ([912ff45](https://github.com/lobehub/lobe-chat/commit/912ff45))
25
+
26
+ #### Styles
27
+
28
+ - **misc**: Fix image display in safari (fix, closes [#571](https://github.com/lobehub/lobe-chat/issues/571) ([4beefa7](https://github.com/lobehub/lobe-chat/commit/4beefa7))
29
+
30
+ </details>
31
+
32
+ <div align="right">
33
+
34
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
35
+
36
+ </div>
37
+
38
+ ### [Version 0.111.1](https://github.com/lobehub/lobe-chat/compare/v0.111.0...v0.111.1)
39
+
40
+ <sup>Released on **2023-12-13**</sup>
41
+
42
+ #### 🐛 Bug Fixes
43
+
44
+ - **misc**: Fix locale typo.
45
+
46
+ <br/>
47
+
48
+ <details>
49
+ <summary><kbd>Improvements and Fixes</kbd></summary>
50
+
51
+ #### What's fixed
52
+
53
+ - **misc**: Fix locale typo ([f44b41e](https://github.com/lobehub/lobe-chat/commit/f44b41e))
54
+
55
+ </details>
56
+
57
+ <div align="right">
58
+
59
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
60
+
61
+ </div>
62
+
5
63
  ## [Version 0.111.0](https://github.com/lobehub/lobe-chat/compare/v0.110.10...v0.111.0)
6
64
 
7
65
  <sup>Released on **2023-12-13**</sup>
@@ -123,6 +123,7 @@
123
123
  "installed": "Installed"
124
124
  },
125
125
  "title": "Plugin Store",
126
- "uninstall": "Uninstall"
126
+ "uninstall": "Uninstall",
127
+ "placeholder": "Search for plugin name, description, or keywords..."
127
128
  }
128
129
  }
@@ -123,6 +123,7 @@
123
123
  "installed": "Installés"
124
124
  },
125
125
  "title": "Boutique de plugins",
126
- "uninstall": "Désinstaller"
126
+ "uninstall": "Désinstaller",
127
+ "placeholder": "Rechercher le nom ou les mots-clés de l'extension..."
127
128
  }
128
129
  }
@@ -123,6 +123,7 @@
123
123
  "installed": "インストール済み"
124
124
  },
125
125
  "title": "プラグインストア",
126
- "uninstall": "アンインストール"
126
+ "uninstall": "アンインストール",
127
+ "placeholder": "プラグイン名、説明、またはキーワードで検索..."
127
128
  }
128
129
  }
@@ -123,6 +123,7 @@
123
123
  "installed": "설치됨"
124
124
  },
125
125
  "title": "플러그인 상점",
126
- "uninstall": "제거"
126
+ "uninstall": "제거",
127
+ "placeholder": "플러그인 이름 또는 키워드로 검색..."
127
128
  }
128
129
  }
@@ -1,128 +1,129 @@
1
1
  {
2
2
  "debug": {
3
- "arguments": "调用参数",
4
- "function_call": "函数调用",
5
- "off": "关闭调试",
6
- "on": "查看插件调用信息",
7
- "response": "返回结果"
3
+ "arguments": "Аргументы вызова",
4
+ "function_call": "Вызов функции",
5
+ "off": "Отключить отладку",
6
+ "on": "Показать информацию о вызове плагина",
7
+ "response": "Ответ"
8
8
  },
9
9
  "dev": {
10
- "confirmDeleteDevPlugin": "即将删除该本地插件,删除后将无法找回,是否删除该插件?",
11
- "deleteSuccess": "插件删除成功",
10
+ "confirmDeleteDevPlugin": "Вы уверены, что хотите удалить этот локальный плагин? После удаления его будет невозможно восстановить.",
11
+ "deleteSuccess": "Плагин успешно удален",
12
12
  "manifest": {
13
13
  "identifier": {
14
- "desc": "插件的唯一标识",
15
- "label": "标识符"
14
+ "desc": "Уникальный идентификатор плагина",
15
+ "label": "Идентификатор"
16
16
  },
17
17
  "mode": {
18
- "local": "可视化配置",
19
- "local-tooltip": "暂时不支持可视化配置",
20
- "url": "在线链接"
18
+ "local": "Локальная настройка",
19
+ "local-tooltip": "Визуальная настройка временно не поддерживается",
20
+ "url": "Онлайн-ссылка"
21
21
  },
22
22
  "name": {
23
- "desc": "插件标题",
24
- "label": "标题",
25
- "placeholder": "搜索引擎"
23
+ "desc": "Название плагина",
24
+ "label": "Название",
25
+ "placeholder": "Поиск поисковой системы"
26
26
  }
27
27
  },
28
28
  "meta": {
29
29
  "author": {
30
- "desc": "插件的作者",
31
- "label": "作者"
30
+ "desc": "Автор плагина",
31
+ "label": "Автор"
32
32
  },
33
33
  "avatar": {
34
- "desc": "插件的图标,可以使用 Emoji,也可以使用 URL",
35
- "label": "图标"
34
+ "desc": "Иконка плагина, можно использовать Emoji или URL",
35
+ "label": "Иконка"
36
36
  },
37
37
  "description": {
38
- "desc": "插件描述",
39
- "label": "描述",
40
- "placeholder": "查询搜索引擎获取信息"
38
+ "desc": "Описание плагина",
39
+ "label": "Описание",
40
+ "placeholder": "Получение информации из поисковой системы"
41
41
  },
42
- "formFieldRequired": "该字段为必填项",
42
+ "formFieldRequired": "Это обязательное поле",
43
43
  "homepage": {
44
- "desc": "插件的首页",
45
- "label": "首页"
44
+ "desc": "Домашняя страница плагина",
45
+ "label": "Домашняя страница"
46
46
  },
47
47
  "identifier": {
48
- "desc": "插件的唯一标识,将从 manifest 中自动识别",
49
- "errorDuplicate": "标识符和已有插件重复,请修改标识符",
50
- "label": "标识符",
51
- "pattenErrorMessage": "只能输入英文字符、数字 、- 和_ 这两个符号"
48
+ "desc": "Уникальный идентификатор плагина, будет автоматически определен из манифеста",
49
+ "errorDuplicate": "Идентификатор совпадает с существующим плагином, измените идентификатор",
50
+ "label": "Идентификатор",
51
+ "pattenErrorMessage": "Можно вводить только буквы, цифры, - и _"
52
52
  },
53
53
  "manifest": {
54
- "desc": "LobeChat 将会通过该链接安装插件",
55
- "label": "插件描述文件 (Manifest) URL",
56
- "preview": "预览 Manifest",
57
- "refresh": "刷新"
54
+ "desc": "LobeChat установит плагин через эту ссылку",
55
+ "label": "URL манифеста плагина",
56
+ "preview": "Предпросмотр манифеста",
57
+ "refresh": "Обновить"
58
58
  },
59
59
  "title": {
60
- "desc": "插件标题",
61
- "label": "标题",
62
- "placeholder": "搜索引擎"
60
+ "desc": "Название плагина",
61
+ "label": "Название",
62
+ "placeholder": "Поиск поисковой системы"
63
63
  }
64
64
  },
65
- "metaConfig": "插件元信息配置",
66
- "modalDesc": "添加自定义插件后,可用于插件开发验证,也可直接在会话中使用。插件开发请参考<1>开发文档↗</>",
65
+ "metaConfig": "Настройка метаданных плагина",
66
+ "modalDesc": "После добавления пользовательского плагина его можно использовать для проверки разработки плагина или непосредственно в сеансе. См. <1>документацию по разработке↗</> для разработки плагинов.",
67
67
  "preview": {
68
- "card": "预览插件展示效果",
69
- "desc": "预览插件描述",
70
- "title": "插件名称预览"
68
+ "card": "Предпросмотр отображения плагина",
69
+ "desc": "Предпросмотр описания плагина",
70
+ "title": "Предпросмотр названия плагина"
71
71
  },
72
- "save": "安装插件",
73
- "saveSuccess": "插件设置保存成功",
72
+ "save": "Установить плагин",
73
+ "saveSuccess": "Настройки плагина успешно сохранены",
74
74
  "tabs": {
75
- "manifest": "功能描述清单 (Manifest)",
76
- "meta": "插件元信息"
75
+ "manifest": "Описание функций (манифест)",
76
+ "meta": "Метаданные плагина"
77
77
  },
78
- "title": "添加自定义插件",
79
- "update": "更新",
80
- "updateSuccess": "插件设置更新成功"
78
+ "title": "Добавить пользовательский плагин",
79
+ "update": "Обновить",
80
+ "updateSuccess": "Настройки плагина успешно обновлены"
81
81
  },
82
82
  "error": {
83
- "fetchError": "请求该 manifest 链接失败,请确保链接的有效性,并检查链接是否允许跨域访问",
84
- "installError": "插件 {{name}} 安装失败",
85
- "manifestInvalid": " manifest 不符合规范,校验结果: \n\n {{error}}",
86
- "noManifest": "描述文件不存在",
87
- "reinstallError": "插件 {{name}} 刷新失败",
88
- "urlError": "该链接没有返回 JSON 格式的内容, 请确保是有效的链接"
83
+ "fetchError": "Не удалось получить доступ к этой ссылке на манифест. Убедитесь, что ссылка действительна, и проверьте, разрешен ли кросс-доменный доступ.",
84
+ "installError": "Ошибка установки плагина {{name}}",
85
+ "manifestInvalid": "Манифест не соответствует стандартам. Результат проверки: \n\n {{error}}",
86
+ "noManifest": "Файл манифеста не существует",
87
+ "reinstallError": "Ошибка обновления плагина {{name}}",
88
+ "urlError": "Эта ссылка не возвращает содержимое в формате JSON. Убедитесь, что ссылка действительна."
89
89
  },
90
90
  "list": {
91
91
  "item": {
92
- "deprecated.title": "已删除",
93
- "local.config": "配置",
94
- "local.title": "自定义"
92
+ "deprecated.title": "Удалено",
93
+ "local.config": "Настройка",
94
+ "local.title": "Пользовательский"
95
95
  }
96
96
  },
97
97
  "loading": {
98
- "content": "调用插件中...",
99
- "plugin": "插件运行中..."
98
+ "content": "Вызов плагина...",
99
+ "plugin": "Выполнение плагина..."
100
100
  },
101
- "pluginList": "插件列表",
101
+ "pluginList": "Список плагинов",
102
102
  "plugins": {
103
- "loading": "检测插件中...",
104
- "unknown": "未知插件"
103
+ "loading": "Проверка плагинов...",
104
+ "unknown": "Неизвестный плагин"
105
105
  },
106
- "setting": "插件设置",
106
+ "setting": "Настройки плагина",
107
107
  "settings": {
108
108
  "indexUrl": {
109
- "title": "市场索引",
110
- "tooltip": "暂不支持在线编辑,请通过部署时环境变量进行设置"
109
+ "title": "Индекс рынка",
110
+ "tooltip": "В настоящее время не поддерживается онлайн-редактирование. Установите через переменные среды при развертывании"
111
111
  },
112
- "modalDesc": "配置插件市场的地址后,可以使用自定义的插件市场",
113
- "title": "设置插件市场"
112
+ "modalDesc": "После настройки адреса рынка плагинов можно использовать настраиваемый рынок плагинов",
113
+ "title": "Настройки рынка плагинов"
114
114
  },
115
115
  "store": {
116
- "empty": "暂无已安装插件",
117
- "install": "安装",
118
- "installAllPlugins": "安装全部",
119
- "networkError": "获取插件商店失败,请检测网络连接后重试",
120
- "releasedAt": "发布于 {{createdAt}}",
116
+ "empty": "Пока нет установленных плагинов",
117
+ "install": "Установить",
118
+ "installAllPlugins": "Установить все",
119
+ "networkError": "Не удалось получить доступ к магазину плагинов. Пожалуйста, проверьте подключение к сети и повторите попытку",
120
+ "releasedAt": "Опубликовано {{createdAt}}",
121
121
  "tabs": {
122
- "all": "全部",
123
- "installed": "已安装"
122
+ "all": "Все",
123
+ "installed": "Установленные"
124
124
  },
125
- "title": "插件商店",
126
- "uninstall": "卸载"
125
+ "title": "Магазин плагинов",
126
+ "uninstall": "Удалить",
127
+ "placeholder": "Введите название или ключевое слово плагина..."
127
128
  }
128
129
  }
@@ -117,6 +117,7 @@
117
117
  "install": "安装",
118
118
  "installAllPlugins": "安装全部",
119
119
  "networkError": "获取插件商店失败,请检测网络连接后重试",
120
+ "placeholder": "搜索插件名称介绍或关键词...",
120
121
  "releasedAt": "发布于 {{createdAt}}",
121
122
  "tabs": {
122
123
  "all": "全部",
@@ -123,6 +123,7 @@
123
123
  "installed": "已安裝"
124
124
  },
125
125
  "title": "插件商店",
126
- "uninstall": "卸載"
126
+ "uninstall": "卸載",
127
+ "placeholder": "搜尋插件名稱介紹或關鍵字..."
127
128
  }
128
129
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.111.0",
3
+ "version": "0.111.2",
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",
@@ -6,7 +6,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
8
8
  import HotKeys from '@/components/HotKeys';
9
- import { CLEAN_MESSAGE_KEY, PREFIX_KEY } from '@/const/hotkeys';
9
+ import { CLEAN_MESSAGE_KEY, META_KEY, PREFIX_KEY } from '@/const/hotkeys';
10
10
  import { useChatStore } from '@/store/chat';
11
11
  import { useFileStore } from '@/store/file';
12
12
 
@@ -14,7 +14,7 @@ const Clear = memo(() => {
14
14
  const { t } = useTranslation('setting');
15
15
  const [clearMessage] = useChatStore((s) => [s.clearMessage]);
16
16
  const [clearImageList] = useFileStore((s) => [s.clearImageList]);
17
- const hotkeys = [PREFIX_KEY, CLEAN_MESSAGE_KEY].join('+');
17
+ const hotkeys = [META_KEY, PREFIX_KEY, CLEAN_MESSAGE_KEY].join('+');
18
18
 
19
19
  const resetConversation = useCallback(() => {
20
20
  clearMessage();
@@ -1,6 +1,6 @@
1
1
  import { Icon } from '@lobehub/ui';
2
2
  import { Button, Result } from 'antd';
3
- import { BadgeCheck, CpuIcon } from 'lucide-react';
3
+ import { CheckCircle, CpuIcon } from 'lucide-react';
4
4
  import { memo, useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { Center } from 'react-layout-kit';
@@ -48,7 +48,7 @@ const MigrationModal = memo<MigrationModalProps>(({ setOpen, open, state: dbStat
48
48
  {t('dbV1.action.start')}
49
49
  </Button>
50
50
  }
51
- icon={<Icon icon={BadgeCheck} />}
51
+ icon={<Icon icon={CheckCircle} />}
52
52
  status={'success'}
53
53
  style={{ paddingBlock: 24 }}
54
54
  subTitle={t('dbV1.upgrade.success.subTitle')}
@@ -62,9 +62,11 @@ const FileItem = memo<FileItemProps>(({ editable, id, alwaysShowClose }) => {
62
62
  }
63
63
  alt={data?.name || id || ''}
64
64
  alwaysShowActions={alwaysShowClose}
65
+ height={'auto'}
65
66
  isLoading={isLoading}
66
67
  size={IMAGE_SIZE as any}
67
68
  src={data?.url}
69
+ style={{ height: 'auto' }}
68
70
  wrapperClassName={cx(styles.image, editable && styles.editableImage)}
69
71
  />
70
72
  );
@@ -1,10 +1,13 @@
1
1
  'use client';
2
2
 
3
+ import { Icon } from '@lobehub/ui';
3
4
  import { createStyles } from 'antd-style';
5
+ import { isString } from 'lodash-es';
6
+ import { Command, Delete, Option } from 'lucide-react';
4
7
  import { memo, useEffect, useState } from 'react';
5
8
  import { Flexbox } from 'react-layout-kit';
6
9
 
7
- import { CLEAN_MESSAGE_KEY, PREFIX_KEY } from '@/const/hotkeys';
10
+ import { CLEAN_MESSAGE_KEY, META_KEY, PREFIX_KEY } from '@/const/hotkeys';
8
11
  import { isApplePlatform } from '@/utils/platform';
9
12
 
10
13
  const useStyles = createStyles(
@@ -13,14 +16,15 @@ const useStyles = createStyles(
13
16
 
14
17
  span {
15
18
  font-weight: 600;
16
- opacity: 0.5;
17
19
  }
18
20
 
19
21
  kbd {
20
- padding: 3px 5px;
22
+ min-width: 16px;
23
+ padding: 3px 6px;
21
24
 
22
25
  line-height: 1;
23
- color: ${token.colorTextSecondary};
26
+ color: ${token.colorTextDescription};
27
+ text-align: center;
24
28
 
25
29
  background: ${token.colorBgContainer};
26
30
  border: 1px solid ${token.colorBorderSecondary};
@@ -42,9 +46,10 @@ const HotKeys = memo<HotKeysProps>(({ keys, desc }) => {
42
46
  const visibility = typeof window === 'undefined' ? 'hidden' : 'visible';
43
47
 
44
48
  useEffect(() => {
45
- const mapping: Record<string, string> = {
46
- [CLEAN_MESSAGE_KEY]: isApplePlatform() ? '⌫' : 'backspace',
47
- [PREFIX_KEY]: isApplePlatform() ? '⌥' : 'alt',
49
+ const mapping: Record<string, any> = {
50
+ [CLEAN_MESSAGE_KEY]: isApplePlatform() ? <Icon icon={Delete} /> : 'backspace',
51
+ [META_KEY]: isApplePlatform() ? <Icon icon={Command} /> : 'ctrl',
52
+ [PREFIX_KEY]: isApplePlatform() ? <Icon icon={Option} /> : 'alt',
48
53
  };
49
54
  const newValue = keys
50
55
  .split('+')
@@ -57,7 +62,7 @@ const HotKeys = memo<HotKeysProps>(({ keys, desc }) => {
57
62
  <Flexbox align={'center'} className={styles} gap={2} horizontal>
58
63
  {keysGroup.map((key, index) => (
59
64
  <kbd key={index}>
60
- <span style={{ visibility }}>{key.toUpperCase()}</span>
65
+ <span style={{ visibility }}>{isString(key) ? key.toUpperCase() : key}</span>
61
66
  </kbd>
62
67
  ))}
63
68
  </Flexbox>
@@ -1,4 +1,5 @@
1
1
  export const PREFIX_KEY = 'alt';
2
+ export const META_KEY = 'mod';
2
3
  export const SAVE_TOPIC_KEY = 'n';
3
4
  export const CLEAN_MESSAGE_KEY = 'backspace';
4
5
  export const REGENERATE_KEY = 'r';
@@ -1,7 +1,7 @@
1
1
  import { Icon } from '@lobehub/ui';
2
2
  import { Button, Result, Table, Upload } from 'antd';
3
3
  import { createStyles } from 'antd-style';
4
- import { BadgeCheck, ImportIcon } from 'lucide-react';
4
+ import { CheckCircle, ImportIcon } from 'lucide-react';
5
5
  import React, { ReactNode, memo, useState } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { Center, Flexbox } from 'react-layout-kit';
@@ -169,7 +169,7 @@ const DataImporter = memo<DataImporterProps>(({ children, onFinishImport }) => {
169
169
  {t('importModal.finish.start')}
170
170
  </Button>
171
171
  }
172
- icon={<Icon icon={BadgeCheck} />}
172
+ icon={<Icon icon={CheckCircle} />}
173
173
  status={'success'}
174
174
  style={{ paddingBlock: 24 }}
175
175
  subTitle={
@@ -25,6 +25,8 @@ const PluginSettingsModal = memo<PluginSettingsModalProps>(({ schema, onClose, i
25
25
  const theme = useTheme();
26
26
  return (
27
27
  <Modal
28
+ cancelText={t('cancel', { ns: 'common' })}
29
+ okText={t('ok', { ns: 'common' })}
28
30
  onCancel={onClose}
29
31
  onOk={() => {
30
32
  onClose();
@@ -1,7 +1,8 @@
1
1
  import { LobeChatPluginMeta } from '@lobehub/chat-plugin-sdk';
2
- import { Avatar, Tag } from '@lobehub/ui';
2
+ import { Avatar, Icon, Tag } from '@lobehub/ui';
3
3
  import { Button } from 'antd';
4
- import { createStyles } from 'antd-style';
4
+ import { createStyles, useResponsive } from 'antd-style';
5
+ import { BadgeCheck, CircleUser } from 'lucide-react';
5
6
  import Link from 'next/link';
6
7
  import { memo } from 'react';
7
8
  import { useTranslation } from 'react-i18next';
@@ -14,13 +15,13 @@ import PluginSettings from './PluginSettings';
14
15
 
15
16
  const useStyles = createStyles(({ css, token }) => ({
16
17
  desc: css`
17
- color: ${token.colorTextSecondary};
18
+ color: ${token.colorTextDescription};
18
19
  `,
19
20
  link: css`
20
- color: ${token.colorTextDescription};
21
+ color: ${token.colorText};
21
22
  `,
22
23
  tag: css`
23
- font-weight: normal;
24
+ color: ${token.colorTextSecondary};
24
25
  `,
25
26
  title: css`
26
27
  font-size: ${token.fontSizeLG}px;
@@ -28,52 +29,52 @@ const useStyles = createStyles(({ css, token }) => ({
28
29
  line-height: 2;
29
30
  `,
30
31
  }));
31
- const PluginItem = memo<LobeChatPluginMeta>(({ identifier, createdAt, homepage, author, meta }) => {
32
+ const PluginItem = memo<LobeChatPluginMeta>(({ identifier, homepage, author, meta }) => {
32
33
  const [installed, installing, installPlugin, unInstallPlugin] = useToolStore((s) => [
33
34
  pluginSelectors.isPluginInstalled(identifier)(s),
34
35
  pluginStoreSelectors.isPluginInstallLoading(identifier)(s),
35
36
  s.installPlugin,
36
37
  s.uninstallPlugin,
37
38
  ]);
39
+ const { mobile } = useResponsive();
38
40
  const { styles } = useStyles();
39
41
 
40
42
  const { t } = useTranslation('plugin');
41
43
  return (
42
- <Flexbox gap={8} padding={16}>
43
- <Flexbox horizontal justify={'space-between'}>
44
- <Avatar avatar={meta.avatar} size={56} style={{ flex: 'none' }} />
45
-
46
- <Flexbox gap={8} horizontal>
47
- <PluginSettings identifier={identifier} />
48
- <Button
49
- loading={installing}
50
- onClick={() => {
51
- if (installed) {
52
- unInstallPlugin(identifier);
53
- } else installPlugin(identifier);
54
- }}
55
- type={installed ? 'default' : 'primary'}
56
- >
57
- {t(installed ? 'store.uninstall' : 'store.install')}
58
- </Button>
59
- </Flexbox>
60
- </Flexbox>
61
-
62
- <Flexbox gap={4}>
63
- <Flexbox align={'center'} gap={8} horizontal>
64
- <div className={styles.title}>{meta.title}</div>
65
- <Tag className={styles.tag}> {identifier}</Tag>
66
- </Flexbox>
67
- <div className={styles.desc}>{meta.description}</div>
68
- <Flexbox className={styles.link} gap={8} horizontal>
69
- {author && (
44
+ <Flexbox align={'center'} gap={8} horizontal justify={'space-between'}>
45
+ <Flexbox align={'center'} gap={8} horizontal>
46
+ <Avatar avatar={meta.avatar} size={mobile ? 40 : 56} style={{ flex: 'none' }} />
47
+ <Flexbox gap={4}>
48
+ <Flexbox align={'center'} gap={8} horizontal>
70
49
  <Link className={styles.link} href={homepage} target={'_blank'}>
71
- @{author}
50
+ <div className={styles.title}>{meta.title}</div>
72
51
  </Link>
73
- )}
74
- {t('store.releasedAt', { createdAt })}
52
+
53
+ <Tag
54
+ className={styles.tag}
55
+ icon={<Icon icon={author === 'LobeHub' ? BadgeCheck : CircleUser} />}
56
+ >
57
+ {author}
58
+ </Tag>
59
+ </Flexbox>
60
+ <div className={styles.desc}>{meta.description} </div>
75
61
  </Flexbox>
76
62
  </Flexbox>
63
+ <Flexbox align={'center'} gap={8} horizontal>
64
+ <PluginSettings identifier={identifier} />
65
+ <Button
66
+ loading={installing}
67
+ onClick={() => {
68
+ if (installed) {
69
+ unInstallPlugin(identifier);
70
+ } else installPlugin(identifier);
71
+ }}
72
+ size={mobile ? 'small' : undefined}
73
+ type={installed ? 'default' : 'primary'}
74
+ >
75
+ {t(installed ? 'store.uninstall' : 'store.install')}
76
+ </Button>
77
+ </Flexbox>
77
78
  </Flexbox>
78
79
  );
79
80
  });
@@ -1,5 +1,5 @@
1
1
  import { ActionIcon } from '@lobehub/ui';
2
- import { SettingsIcon } from 'lucide-react';
2
+ import { Settings2 } from 'lucide-react';
3
3
  import { memo, useState } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
@@ -19,7 +19,7 @@ const PluginSettings = memo<{ identifier: string }>(({ identifier }) => {
19
19
  return (
20
20
  <>
21
21
  <ActionIcon
22
- icon={SettingsIcon}
22
+ icon={Settings2}
23
23
  onClick={() => {
24
24
  setOpen(true);
25
25
  }}
@@ -1,8 +1,9 @@
1
- import { Icon, Modal, SpotlightCard, TabsNav } from '@lobehub/ui';
2
- import { Button, Empty } from 'antd';
1
+ import { Icon, Modal, SearchBar } from '@lobehub/ui';
2
+ import { Button, Empty, Segmented } from 'antd';
3
+ import { createStyles } from 'antd-style';
3
4
  import isEqual from 'fast-deep-equal';
4
5
  import { ServerCrash } from 'lucide-react';
5
- import { memo } from 'react';
6
+ import { memo, useState } from 'react';
6
7
  import { useTranslation } from 'react-i18next';
7
8
  import { Center, Flexbox } from 'react-layout-kit';
8
9
 
@@ -13,13 +14,24 @@ import { pluginStoreSelectors } from '@/store/tool/selectors';
13
14
  import Loading from './Loading';
14
15
  import PluginItem from './PluginItem';
15
16
 
17
+ const useStyles = createStyles(({ css, token }) => ({
18
+ header: css`
19
+ color: ${token.colorTextDescription};
20
+
21
+ > div {
22
+ flex: 1;
23
+ }
24
+ `,
25
+ }));
26
+
16
27
  interface PluginStoreProps {
17
28
  open?: boolean;
18
29
  setOpen: (open: boolean) => void;
19
30
  }
20
31
  export const PluginStore = memo<PluginStoreProps>(({ setOpen, open }) => {
32
+ const [keywords, setKeywords] = useState<string>();
21
33
  const { t } = useTranslation('plugin');
22
-
34
+ const { styles } = useStyles();
23
35
  const [listType, useFetchPluginList, installPlugins] = useToolStore((s) => [
24
36
  s.listType,
25
37
  s.useFetchPluginStore,
@@ -43,28 +55,19 @@ export const PluginStore = memo<PluginStoreProps>(({ setOpen, open }) => {
43
55
  <MobilePadding>
44
56
  <Center>
45
57
  <Flexbox gap={24} width={'100%'}>
46
- <Flexbox align={'center'} horizontal justify={'space-between'}>
47
- <TabsNav
48
- activeKey={listType}
49
- items={[
50
- { key: 'all', label: t('store.tabs.all') },
51
- { key: 'installed', label: t('store.tabs.installed') },
52
- ]}
58
+ <Flexbox align={'center'} gap={8} horizontal justify={'space-between'}>
59
+ <Segmented
60
+ block
53
61
  onChange={(v) => {
54
62
  useToolStore.setState({ listType: v as any });
55
63
  }}
64
+ options={[
65
+ { label: t('store.tabs.all'), value: 'all' },
66
+ { label: t('store.tabs.installed'), value: 'installed' },
67
+ ]}
68
+ style={{ flex: 1 }}
69
+ value={listType}
56
70
  />
57
- <Flexbox gap={8} horizontal>
58
- {listType === 'all' && (
59
- <Button
60
- onClick={() => {
61
- installPlugins(pluginStoreList.map((item) => item.identifier));
62
- }}
63
- >
64
- {t('store.installAllPlugins')}
65
- </Button>
66
- )}
67
- </Flexbox>
68
71
  </Flexbox>
69
72
  {isLoading ? (
70
73
  <Loading />
@@ -83,7 +86,37 @@ export const PluginStore = memo<PluginStoreProps>(({ setOpen, open }) => {
83
86
  )}
84
87
  </Center>
85
88
  ) : (
86
- <SpotlightCard columns={2} gap={16} items={pluginStoreList} renderItem={PluginItem} />
89
+ <>
90
+ <Flexbox className={styles.header} gap={8} horizontal>
91
+ <SearchBar
92
+ allowClear
93
+ onChange={(e) => setKeywords(e.target.value)}
94
+ placeholder={t('store.placeholder')}
95
+ type={'block'}
96
+ value={keywords}
97
+ />
98
+ {listType === 'all' && (
99
+ <Button
100
+ onClick={() => {
101
+ installPlugins(pluginStoreList.map((item) => item.identifier));
102
+ }}
103
+ >
104
+ {t('store.installAllPlugins')}
105
+ </Button>
106
+ )}
107
+ </Flexbox>
108
+
109
+ {pluginStoreList
110
+ .filter((item) =>
111
+ [item.meta.title, item.meta.description, item.author, ...(item.meta.tags || [])]
112
+ .join('')
113
+ .toLowerCase()
114
+ .includes((keywords || '')?.toLowerCase()),
115
+ )
116
+ .map((item) => (
117
+ <PluginItem key={item.identifier} {...item} />
118
+ ))}
119
+ </>
87
120
  )}
88
121
  </Flexbox>
89
122
  </Center>
@@ -15,7 +15,7 @@ const InnerLocale = memo<LocaleLayoutProps>(({ children, lang }) => {
15
15
  const { data: locale } = useSWR(
16
16
  lang,
17
17
  async () =>
18
- await import(`antd/locale/${lang?.includes('-') ? lang?.replace('-', '_') : 'en-US'}.js`),
18
+ await import(`antd/locale/${lang?.includes('-') ? lang?.replace('-', '_') : 'en_US'}.js`),
19
19
  { revalidateOnFocus: false },
20
20
  );
21
21
  const [i18n] = useState(createI18nNext(lang));
@@ -118,6 +118,7 @@ export default {
118
118
  install: '安装',
119
119
  installAllPlugins: '安装全部',
120
120
  networkError: '获取插件商店失败,请检测网络连接后重试',
121
+ placeholder: '搜索插件名称介绍或关键词...',
121
122
  releasedAt: '发布于 {{createdAt}}',
122
123
  tabs: {
123
124
  all: '全部',
@@ -13,8 +13,6 @@ export const createKeyMapper = (options: HyperStorageOptions) => {
13
13
 
14
14
  let storageKey: string | undefined;
15
15
 
16
- if (!selectors) return key;
17
-
18
16
  for (const selector of selectors) {
19
17
  if (typeof selector === 'string') {
20
18
  if (selector === key) storageKey = key;