@lobehub/chat 1.75.5 → 1.76.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.
- package/CHANGELOG.md +25 -0
- package/changelog/v1.json +9 -0
- package/docs/developer/database-schema.dbml +1 -0
- package/locales/ar/hotkey.json +46 -0
- package/locales/ar/setting.json +12 -0
- package/locales/bg-BG/hotkey.json +46 -0
- package/locales/bg-BG/setting.json +12 -0
- package/locales/de-DE/hotkey.json +46 -0
- package/locales/de-DE/setting.json +12 -0
- package/locales/en-US/hotkey.json +46 -0
- package/locales/en-US/setting.json +12 -0
- package/locales/es-ES/hotkey.json +46 -0
- package/locales/es-ES/setting.json +12 -0
- package/locales/fa-IR/hotkey.json +46 -0
- package/locales/fa-IR/setting.json +12 -0
- package/locales/fr-FR/hotkey.json +46 -0
- package/locales/fr-FR/setting.json +12 -0
- package/locales/it-IT/hotkey.json +46 -0
- package/locales/it-IT/setting.json +12 -0
- package/locales/ja-JP/hotkey.json +46 -0
- package/locales/ja-JP/setting.json +12 -0
- package/locales/ko-KR/hotkey.json +46 -0
- package/locales/ko-KR/setting.json +12 -0
- package/locales/nl-NL/hotkey.json +46 -0
- package/locales/nl-NL/setting.json +12 -0
- package/locales/pl-PL/hotkey.json +46 -0
- package/locales/pl-PL/setting.json +12 -0
- package/locales/pt-BR/hotkey.json +46 -0
- package/locales/pt-BR/setting.json +12 -0
- package/locales/ru-RU/hotkey.json +46 -0
- package/locales/ru-RU/setting.json +12 -0
- package/locales/tr-TR/hotkey.json +46 -0
- package/locales/tr-TR/setting.json +12 -0
- package/locales/vi-VN/hotkey.json +46 -0
- package/locales/vi-VN/setting.json +12 -0
- package/locales/zh-CN/hotkey.json +46 -0
- package/locales/zh-CN/setting.json +12 -0
- package/locales/zh-TW/hotkey.json +46 -0
- package/locales/zh-TW/setting.json +12 -0
- package/package.json +3 -3
- package/src/app/[variants]/(main)/(mobile)/me/(home)/features/Category.tsx +1 -1
- package/src/app/[variants]/(main)/(mobile)/me/(home)/layout.tsx +3 -2
- package/src/app/[variants]/(main)/(mobile)/me/data/features/Category.tsx +1 -1
- package/src/app/[variants]/(main)/(mobile)/me/profile/features/Category.tsx +1 -1
- package/src/app/[variants]/(main)/(mobile)/me/settings/features/Category.tsx +1 -1
- package/src/app/[variants]/(main)/_layout/Desktop/RegisterHotkeys.tsx +11 -0
- package/src/app/[variants]/(main)/_layout/Desktop/SideBar/PinList/index.tsx +6 -23
- package/src/app/[variants]/(main)/_layout/Desktop/SideBar/TopActions.test.tsx +2 -0
- package/src/app/[variants]/(main)/_layout/Desktop/index.tsx +11 -4
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/SendMore.tsx +6 -21
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/ShortcutHint.tsx +13 -34
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/index.tsx +1 -1
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ZenModeToast/Toast.tsx +7 -4
- package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/HeaderAction.tsx +12 -8
- package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/Main.tsx +24 -30
- package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/index.tsx +0 -2
- package/src/app/[variants]/(main)/chat/(workspace)/features/SettingButton.tsx +12 -7
- package/src/app/[variants]/(main)/chat/@session/features/SessionSearchBar.tsx +5 -1
- package/src/app/[variants]/(main)/chat/_layout/Desktop/RegisterHotkeys.tsx +10 -0
- package/src/app/[variants]/(main)/chat/_layout/Desktop/index.tsx +5 -0
- package/src/app/[variants]/(main)/chat/_layout/Mobile.tsx +1 -1
- package/src/app/[variants]/(main)/discover/features/StoreSearchBar.tsx +5 -1
- package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +31 -21
- package/src/app/[variants]/(main)/settings/hotkey/features/HotkeySetting.tsx +80 -0
- package/src/app/[variants]/(main)/settings/hotkey/index.tsx +9 -0
- package/src/app/[variants]/(main)/settings/hotkey/page.tsx +15 -0
- package/src/app/[variants]/layout.tsx +16 -13
- package/src/const/hotkeys.ts +80 -10
- package/src/const/settings/hotkey.ts +10 -0
- package/src/const/settings/index.ts +3 -0
- package/src/database/client/migrations.json +46 -32
- package/src/database/migrations/0019_add_hotkey_user_settings.sql +2 -0
- package/src/database/migrations/meta/0019_snapshot.json +4218 -0
- package/src/database/migrations/meta/_journal.json +7 -0
- package/src/database/schemas/user.ts +1 -0
- package/src/database/server/models/user.ts +2 -0
- package/src/features/ChatInput/Desktop/InputArea/index.tsx +8 -0
- package/src/features/ChatInput/Desktop/index.tsx +0 -1
- package/src/features/ChatInput/Topic/index.tsx +10 -15
- package/src/features/FileManager/Header/FilesSearchBar.tsx +6 -2
- package/src/features/HotkeyHelperPanel/HotkeyContent.tsx +62 -0
- package/src/features/HotkeyHelperPanel/index.tsx +59 -0
- package/src/hooks/useHotkeys/chatScope.ts +105 -0
- package/src/hooks/useHotkeys/globalScope.ts +69 -0
- package/src/hooks/useHotkeys/index.ts +2 -0
- package/src/hooks/useHotkeys/useHotkeyById.test.ts +194 -0
- package/src/hooks/useHotkeys/useHotkeyById.ts +57 -0
- package/src/locales/default/hotkey.ts +50 -0
- package/src/locales/default/index.ts +2 -0
- package/src/locales/default/setting.ts +12 -0
- package/src/store/global/initialState.ts +3 -0
- package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +79 -0
- package/src/store/user/slices/settings/selectors/settings.test.ts +131 -0
- package/src/store/user/slices/settings/selectors/settings.ts +6 -0
- package/src/types/hotkey.ts +59 -0
- package/src/types/user/settings/hotkey.ts +3 -0
- package/src/types/user/settings/index.ts +3 -0
- package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/HotKeys.tsx +0 -44
- package/src/components/HotKeys/index.tsx +0 -77
@@ -0,0 +1,46 @@
|
|
1
|
+
{
|
2
|
+
"addUserMessage": {
|
3
|
+
"desc": "將當前輸入內容添加為使用者消息,但不觸發生成",
|
4
|
+
"title": "添加一條使用者消息"
|
5
|
+
},
|
6
|
+
"editMessage": {
|
7
|
+
"desc": "通過按住 Alt 並雙擊消息進入編輯模式",
|
8
|
+
"title": "編輯消息"
|
9
|
+
},
|
10
|
+
"openChatSettings": {
|
11
|
+
"desc": "查看和修改當前會話的設定",
|
12
|
+
"title": "打開會話設定"
|
13
|
+
},
|
14
|
+
"openHotkeyHelper": {
|
15
|
+
"desc": "查看所有快捷鍵的使用說明",
|
16
|
+
"title": "打開快捷鍵幫助"
|
17
|
+
},
|
18
|
+
"regenerateMessage": {
|
19
|
+
"desc": "重新生成最後一條消息",
|
20
|
+
"title": "重新生成消息"
|
21
|
+
},
|
22
|
+
"saveTopic": {
|
23
|
+
"desc": "保存當前話題並打開新話題",
|
24
|
+
"title": "開啟新話題"
|
25
|
+
},
|
26
|
+
"search": {
|
27
|
+
"desc": "喚起當前頁面主要搜尋框",
|
28
|
+
"title": "搜尋"
|
29
|
+
},
|
30
|
+
"switchAgent": {
|
31
|
+
"desc": "通過按住 Ctrl 加數字 0~9 切換固定在側邊欄的助手",
|
32
|
+
"title": "快捷切換助手"
|
33
|
+
},
|
34
|
+
"toggleLeftPanel": {
|
35
|
+
"desc": "顯示或隱藏左側助手面板",
|
36
|
+
"title": "顯示/隱藏助手面板"
|
37
|
+
},
|
38
|
+
"toggleRightPanel": {
|
39
|
+
"desc": "顯示或隱藏右側話題面板",
|
40
|
+
"title": "顯示/隱藏話題面板"
|
41
|
+
},
|
42
|
+
"toggleZenMode": {
|
43
|
+
"desc": "專注模式下,只顯示當前會話,隱藏其他 UI",
|
44
|
+
"title": "切換專注模式"
|
45
|
+
}
|
46
|
+
}
|
@@ -42,6 +42,17 @@
|
|
42
42
|
"sessionWithName": "對話設定 · {{name}}",
|
43
43
|
"title": "設定"
|
44
44
|
},
|
45
|
+
"hotkey": {
|
46
|
+
"conflicts": "與現有快捷鍵衝突",
|
47
|
+
"group": {
|
48
|
+
"conversation": "對話",
|
49
|
+
"essential": "基本"
|
50
|
+
},
|
51
|
+
"invalidCombination": "快捷鍵需要至少包含一個修飾鍵 (Ctrl, Alt, Shift) 和一個常規鍵",
|
52
|
+
"record": "按下按鍵以錄製快捷鍵",
|
53
|
+
"reset": "重置為預設快捷鍵",
|
54
|
+
"title": "快速鍵"
|
55
|
+
},
|
45
56
|
"llm": {
|
46
57
|
"aesGcm": "您的金鑰與代理地址等將使用 <1>AES-GCM</1> 加密演算法進行加密",
|
47
58
|
"apiKey": {
|
@@ -425,6 +436,7 @@
|
|
425
436
|
"agent": "默認助手",
|
426
437
|
"common": "通用設置",
|
427
438
|
"experiment": "實驗",
|
439
|
+
"hotkey": "快速鍵",
|
428
440
|
"llm": "語言模型",
|
429
441
|
"provider": "AI 服務商",
|
430
442
|
"sync": "雲端同步",
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@lobehub/chat",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.76.0",
|
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",
|
@@ -135,7 +135,7 @@
|
|
135
135
|
"@lobehub/chat-plugins-gateway": "^1.9.0",
|
136
136
|
"@lobehub/icons": "^1.73.1",
|
137
137
|
"@lobehub/tts": "^1.28.0",
|
138
|
-
"@lobehub/ui": "^1.
|
138
|
+
"@lobehub/ui": "^1.169.2",
|
139
139
|
"@neondatabase/serverless": "^0.10.4",
|
140
140
|
"@next/third-parties": "15.2.3",
|
141
141
|
"@react-spring/web": "^9.7.5",
|
@@ -192,7 +192,7 @@
|
|
192
192
|
"next-mdx-remote": "^5.0.0",
|
193
193
|
"nextjs-toploader": "^3.7.15",
|
194
194
|
"numeral": "^2.0.6",
|
195
|
-
"nuqs": "^
|
195
|
+
"nuqs": "^2.4.1",
|
196
196
|
"officeparser": "^5.1.1",
|
197
197
|
"ollama": "^0.5.11",
|
198
198
|
"openai": "^4.77.3",
|
@@ -9,7 +9,7 @@ import { useCategory } from './useCategory';
|
|
9
9
|
const Category = memo(() => {
|
10
10
|
const items = useCategory();
|
11
11
|
|
12
|
-
return items?.map((item, index) => <Cell key={
|
12
|
+
return items?.map(({ key, ...item }, index) => <Cell key={key || index} {...item} />);
|
13
13
|
});
|
14
14
|
|
15
15
|
export default Category;
|
@@ -1,5 +1,6 @@
|
|
1
|
-
import { PropsWithChildren } from 'react';
|
1
|
+
import { PropsWithChildren, Suspense } from 'react';
|
2
2
|
|
3
|
+
import Loading from '@/components/Loading/BrandTextLoading';
|
3
4
|
import MobileContentLayout from '@/components/server/MobileNavLayout';
|
4
5
|
import InitClientDB from '@/features/InitClientDB';
|
5
6
|
|
@@ -8,7 +9,7 @@ import Header from './features/Header';
|
|
8
9
|
const Layout = ({ children }: PropsWithChildren) => {
|
9
10
|
return (
|
10
11
|
<MobileContentLayout header={<Header />} withNav>
|
11
|
-
{children}
|
12
|
+
<Suspense fallback={<Loading />}>{children}</Suspense>
|
12
13
|
<InitClientDB />
|
13
14
|
</MobileContentLayout>
|
14
15
|
);
|
@@ -56,7 +56,7 @@ const Category = memo(() => {
|
|
56
56
|
},
|
57
57
|
].filter(Boolean) as CellProps[];
|
58
58
|
|
59
|
-
return items?.map((item, index) => <Cell key={
|
59
|
+
return items?.map(({ key, ...item }, index) => <Cell key={key || index} {...item} />);
|
60
60
|
});
|
61
61
|
|
62
62
|
export default Category;
|
@@ -9,7 +9,7 @@ import { useCategory } from './useCategory';
|
|
9
9
|
const Category = memo(() => {
|
10
10
|
const items = useCategory();
|
11
11
|
|
12
|
-
return items?.map((item, index) => <Cell
|
12
|
+
return items?.map(({ key, ...item }, index) => <Cell key={key || index} {...item} />);
|
13
13
|
});
|
14
14
|
|
15
15
|
export default Category;
|
@@ -3,14 +3,15 @@ import { Divider } from 'antd';
|
|
3
3
|
import { createStyles } from 'antd-style';
|
4
4
|
import isEqual from 'fast-deep-equal';
|
5
5
|
import { parseAsBoolean, useQueryState } from 'nuqs';
|
6
|
-
import { useHotkeys } from 'react-hotkeys-hook';
|
7
6
|
import { Flexbox } from 'react-layout-kit';
|
8
7
|
|
9
|
-
import HotKeys from '@/components/HotKeys';
|
10
8
|
import { useSwitchSession } from '@/hooks/useSwitchSession';
|
11
9
|
import { useSessionStore } from '@/store/session';
|
12
10
|
import { sessionHelpers } from '@/store/session/helpers';
|
13
11
|
import { sessionSelectors } from '@/store/session/selectors';
|
12
|
+
import { useUserStore } from '@/store/user';
|
13
|
+
import { settingsSelectors } from '@/store/user/selectors';
|
14
|
+
import { HotkeyEnum, KeyEnum } from '@/types/hotkey';
|
14
15
|
|
15
16
|
const useStyles = createStyles(({ css, token }) => ({
|
16
17
|
avatar: css`
|
@@ -52,7 +53,7 @@ const PinList = () => {
|
|
52
53
|
const list = useSessionStore(sessionSelectors.pinnedSessions, isEqual);
|
53
54
|
const [activeId] = useSessionStore((s) => [s.activeId]);
|
54
55
|
const switchSession = useSwitchSession();
|
55
|
-
|
56
|
+
const hotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.SwitchAgent));
|
56
57
|
const hasList = list.length > 0;
|
57
58
|
const [isPinned, setPinned] = useQueryState('pinned', parseAsBoolean);
|
58
59
|
|
@@ -61,20 +62,6 @@ const PinList = () => {
|
|
61
62
|
setPinned(true);
|
62
63
|
};
|
63
64
|
|
64
|
-
useHotkeys(
|
65
|
-
list.slice(0, 9).map((e, i) => `ctrl+${i + 1}`),
|
66
|
-
(keyboardEvent, hotkeysEvent) => {
|
67
|
-
if (!hotkeysEvent.keys?.[0]) return;
|
68
|
-
|
69
|
-
const index = parseInt(hotkeysEvent.keys?.[0]) - 1;
|
70
|
-
const item = list[index];
|
71
|
-
if (!item) return;
|
72
|
-
|
73
|
-
switchAgent(item.id);
|
74
|
-
},
|
75
|
-
{ enableOnFormTags: true, preventDefault: true },
|
76
|
-
);
|
77
|
-
|
78
65
|
return (
|
79
66
|
hasList && (
|
80
67
|
<>
|
@@ -83,13 +70,9 @@ const PinList = () => {
|
|
83
70
|
{list.slice(0, 9).map((item, index) => (
|
84
71
|
<Flexbox key={item.id} style={{ position: 'relative' }}>
|
85
72
|
<Tooltip
|
73
|
+
hotkey={hotkey.replaceAll(KeyEnum.Number, String(index + 1))}
|
86
74
|
placement={'right'}
|
87
|
-
title={
|
88
|
-
<Flexbox gap={8} horizontal>
|
89
|
-
{sessionHelpers.getTitle(item.meta)}
|
90
|
-
<HotKeys inverseTheme keys={`ctrl+${index + 1}`} />
|
91
|
-
</Flexbox>
|
92
|
-
}
|
75
|
+
title={sessionHelpers.getTitle(item.meta)}
|
93
76
|
>
|
94
77
|
<Flexbox
|
95
78
|
className={cx(
|
@@ -36,6 +36,8 @@ vi.mock('next/link', () => ({
|
|
36
36
|
|
37
37
|
vi.mock('@lobehub/ui', () => ({
|
38
38
|
ActionIcon: vi.fn(({ title }) => <div>{title}</div>),
|
39
|
+
combineKeys: vi.fn((keys) => keys.join('+')),
|
40
|
+
KeyMapEnum: { Alt: 'alt', Ctrl: 'ctrl', Shift: 'shift' },
|
39
41
|
}));
|
40
42
|
|
41
43
|
vi.mock('react-i18next', () => ({
|
@@ -2,13 +2,17 @@
|
|
2
2
|
|
3
3
|
import { useTheme } from 'antd-style';
|
4
4
|
import dynamic from 'next/dynamic';
|
5
|
-
import { PropsWithChildren, memo } from 'react';
|
5
|
+
import { PropsWithChildren, Suspense, memo } from 'react';
|
6
|
+
import { HotkeysProvider } from 'react-hotkeys-hook';
|
6
7
|
import { Flexbox } from 'react-layout-kit';
|
7
8
|
|
8
9
|
import { BANNER_HEIGHT } from '@/features/AlertBanner/CloudBanner';
|
10
|
+
import HotkeyHelperPanel from '@/features/HotkeyHelperPanel';
|
9
11
|
import { usePlatform } from '@/hooks/usePlatform';
|
10
12
|
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
13
|
+
import { HotkeyScopeEnum } from '@/types/hotkey';
|
11
14
|
|
15
|
+
import RegisterHotkeys from './RegisterHotkeys';
|
12
16
|
import SideBar from './SideBar';
|
13
17
|
|
14
18
|
const CloudBanner = dynamic(() => import('@/features/AlertBanner/CloudBanner'));
|
@@ -16,11 +20,10 @@ const CloudBanner = dynamic(() => import('@/features/AlertBanner/CloudBanner'));
|
|
16
20
|
const Layout = memo<PropsWithChildren>(({ children }) => {
|
17
21
|
const { isPWA } = usePlatform();
|
18
22
|
const theme = useTheme();
|
19
|
-
|
20
23
|
const { showCloudPromotion } = useServerConfigStore(featureFlagsSelectors);
|
21
24
|
|
22
25
|
return (
|
23
|
-
|
26
|
+
<HotkeysProvider initiallyActiveScopes={[HotkeyScopeEnum.Global]}>
|
24
27
|
{showCloudPromotion && <CloudBanner />}
|
25
28
|
<Flexbox
|
26
29
|
height={showCloudPromotion ? `calc(100% - ${BANNER_HEIGHT}px)` : '100%'}
|
@@ -34,7 +37,11 @@ const Layout = memo<PropsWithChildren>(({ children }) => {
|
|
34
37
|
<SideBar />
|
35
38
|
{children}
|
36
39
|
</Flexbox>
|
37
|
-
|
40
|
+
<HotkeyHelperPanel />
|
41
|
+
<Suspense>
|
42
|
+
<RegisterHotkeys />
|
43
|
+
</Suspense>
|
44
|
+
</HotkeysProvider>
|
38
45
|
);
|
39
46
|
});
|
40
47
|
|
@@ -1,18 +1,16 @@
|
|
1
|
-
import { Icon } from '@lobehub/ui';
|
1
|
+
import { Hotkey, Icon } from '@lobehub/ui';
|
2
2
|
import { Button, Dropdown } from 'antd';
|
3
3
|
import { createStyles } from 'antd-style';
|
4
4
|
import { BotMessageSquare, LucideCheck, LucideChevronDown, MessageSquarePlus } from 'lucide-react';
|
5
5
|
import { memo } from 'react';
|
6
|
-
import { useHotkeys } from 'react-hotkeys-hook';
|
7
6
|
import { useTranslation } from 'react-i18next';
|
8
7
|
import { Flexbox } from 'react-layout-kit';
|
9
8
|
|
10
|
-
import HotKeys from '@/components/HotKeys';
|
11
|
-
import { ALT_KEY } from '@/const/hotkeys';
|
12
9
|
import { useSendMessage } from '@/features/ChatInput/useSend';
|
13
10
|
import { useChatStore } from '@/store/chat';
|
14
11
|
import { useUserStore } from '@/store/user';
|
15
|
-
import { preferenceSelectors } from '@/store/user/selectors';
|
12
|
+
import { preferenceSelectors, settingsSelectors } from '@/store/user/selectors';
|
13
|
+
import { HotkeyEnum } from '@/types/hotkey';
|
16
14
|
|
17
15
|
const useStyles = createStyles(({ css, prefixCls }) => {
|
18
16
|
return {
|
@@ -31,7 +29,7 @@ interface SendMoreProps {
|
|
31
29
|
|
32
30
|
const SendMore = memo<SendMoreProps>(({ disabled, isMac }) => {
|
33
31
|
const { t } = useTranslation('chat');
|
34
|
-
|
32
|
+
const hotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.AddUserMessage));
|
35
33
|
const { styles } = useStyles();
|
36
34
|
|
37
35
|
const [useCmdEnterToSend, updatePreference] = useUserStore((s) => [
|
@@ -42,19 +40,6 @@ const SendMore = memo<SendMoreProps>(({ disabled, isMac }) => {
|
|
42
40
|
|
43
41
|
const { send: sendMessage } = useSendMessage();
|
44
42
|
|
45
|
-
const hotKey = [ALT_KEY, 'enter'].join('+');
|
46
|
-
useHotkeys(
|
47
|
-
hotKey,
|
48
|
-
(keyboardEvent, hotkeysEvent) => {
|
49
|
-
console.log(keyboardEvent, hotkeysEvent);
|
50
|
-
sendMessage({ onlyAddUserMessage: true });
|
51
|
-
},
|
52
|
-
{
|
53
|
-
enableOnFormTags: true,
|
54
|
-
preventDefault: true,
|
55
|
-
},
|
56
|
-
);
|
57
|
-
|
58
43
|
return (
|
59
44
|
<Dropdown
|
60
45
|
disabled={disabled}
|
@@ -91,9 +76,9 @@ const SendMore = memo<SendMoreProps>(({ disabled, isMac }) => {
|
|
91
76
|
icon: <Icon icon={MessageSquarePlus} />,
|
92
77
|
key: 'addUser',
|
93
78
|
label: (
|
94
|
-
<Flexbox gap={24} horizontal>
|
79
|
+
<Flexbox align={'center'} gap={24} horizontal>
|
95
80
|
{t('input.addUser')}
|
96
|
-
<
|
81
|
+
<Hotkey keys={hotkey} />
|
97
82
|
</Flexbox>
|
98
83
|
),
|
99
84
|
onClick: () => {
|
@@ -1,58 +1,37 @@
|
|
1
|
-
import {
|
2
|
-
import { Skeleton } from 'antd';
|
1
|
+
import { Hotkey, combineKeys } from '@lobehub/ui';
|
3
2
|
import { useTheme } from 'antd-style';
|
4
|
-
import {
|
5
|
-
import { memo, useEffect, useState } from 'react';
|
3
|
+
import { memo } from 'react';
|
6
4
|
import { useTranslation } from 'react-i18next';
|
7
|
-
import {
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
8
6
|
|
9
7
|
import { useUserStore } from '@/store/user';
|
10
8
|
import { preferenceSelectors } from '@/store/user/selectors';
|
11
|
-
import {
|
9
|
+
import { KeyEnum } from '@/types/hotkey';
|
12
10
|
|
13
11
|
const ShortcutHint = memo(() => {
|
14
12
|
const { t } = useTranslation('chat');
|
15
13
|
const theme = useTheme();
|
16
14
|
const useCmdEnterToSend = useUserStore(preferenceSelectors.useCmdEnterToSend);
|
17
|
-
const [isMac, setIsMac] = useState<boolean>();
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
const sendShortcut = useCmdEnterToSend
|
17
|
+
? combineKeys([KeyEnum.Mod, KeyEnum.Enter])
|
18
|
+
: KeyEnum.Enter;
|
22
19
|
|
23
|
-
const
|
24
|
-
|
25
|
-
|
26
|
-
<Icon icon={isMac ? LucideCommand : ChevronUp} />
|
27
|
-
) : (
|
28
|
-
<Skeleton.Node active style={{ height: '100%', width: 12 }}>
|
29
|
-
{' '}
|
30
|
-
</Skeleton.Node>
|
31
|
-
)}
|
32
|
-
<Icon icon={CornerDownLeft} />
|
33
|
-
</Flexbox>
|
34
|
-
);
|
35
|
-
|
36
|
-
const enter = (
|
37
|
-
<Center>
|
38
|
-
<Icon icon={CornerDownLeft} />
|
39
|
-
</Center>
|
40
|
-
);
|
41
|
-
|
42
|
-
const sendShortcut = useCmdEnterToSend ? cmdEnter : enter;
|
43
|
-
|
44
|
-
const wrapperShortcut = useCmdEnterToSend ? enter : cmdEnter;
|
20
|
+
const wrapperShortcut = useCmdEnterToSend
|
21
|
+
? KeyEnum.Enter
|
22
|
+
: combineKeys([KeyEnum.Mod, KeyEnum.Enter]);
|
45
23
|
|
46
24
|
return (
|
47
25
|
<Flexbox
|
26
|
+
align={'center'}
|
48
27
|
gap={4}
|
49
28
|
horizontal
|
50
29
|
style={{ color: theme.colorTextDescription, fontSize: 12, marginRight: 12 }}
|
51
30
|
>
|
52
|
-
{sendShortcut}
|
31
|
+
<Hotkey keys={sendShortcut} style={{ color: 'inherit' }} variant={'pure'} />
|
53
32
|
<span>{t('input.send')}</span>
|
54
33
|
<span>/</span>
|
55
|
-
{wrapperShortcut}
|
34
|
+
<Hotkey keys={wrapperShortcut} style={{ color: 'inherit' }} variant={'pure'} />
|
56
35
|
<span>{t('input.warp')}</span>
|
57
36
|
</Flexbox>
|
58
37
|
);
|
package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ZenModeToast/Toast.tsx
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
|
+
import { Hotkey } from '@lobehub/ui';
|
3
4
|
import { createStyles } from 'antd-style';
|
4
5
|
import { useEffect, useState } from 'react';
|
5
6
|
import { useTranslation } from 'react-i18next';
|
6
7
|
import { Flexbox } from 'react-layout-kit';
|
7
8
|
|
8
|
-
import
|
9
|
-
import {
|
9
|
+
import { useUserStore } from '@/store/user';
|
10
|
+
import { settingsSelectors } from '@/store/user/selectors';
|
11
|
+
import { HotkeyEnum } from '@/types/hotkey';
|
10
12
|
|
11
13
|
const useStyles = createStyles(({ css, token }) => ({
|
12
14
|
closeButton: css`
|
@@ -62,6 +64,7 @@ const Toast = () => {
|
|
62
64
|
const { t } = useTranslation('chat');
|
63
65
|
const { styles } = useStyles();
|
64
66
|
const [isVisible, setIsVisible] = useState(true);
|
67
|
+
const hotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.ToggleZenMode));
|
65
68
|
|
66
69
|
useEffect(() => {
|
67
70
|
const timer = setTimeout(() => {
|
@@ -76,8 +79,8 @@ const Toast = () => {
|
|
76
79
|
return (
|
77
80
|
<div className={styles.container}>
|
78
81
|
<div className={styles.toast}>
|
79
|
-
<Flexbox className={styles.text} gap={
|
80
|
-
{t('zenMode')} <
|
82
|
+
<Flexbox align={'center'} className={styles.text} gap={8} horizontal>
|
83
|
+
{t('zenMode')} <Hotkey inverseTheme keys={hotkey} />
|
81
84
|
</Flexbox>
|
82
85
|
</div>
|
83
86
|
</div>
|
package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/HeaderAction.tsx
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
|
-
import { ActionIcon } from '@lobehub/ui';
|
3
|
+
import { ActionIcon, Tooltip } from '@lobehub/ui';
|
4
4
|
import { PanelRightClose, PanelRightOpen } from 'lucide-react';
|
5
5
|
import { memo } from 'react';
|
6
6
|
import { useTranslation } from 'react-i18next';
|
@@ -10,13 +10,16 @@ import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
|
10
10
|
import { useGlobalStore } from '@/store/global';
|
11
11
|
import { systemStatusSelectors } from '@/store/global/selectors';
|
12
12
|
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
13
|
+
import { useUserStore } from '@/store/user';
|
14
|
+
import { settingsSelectors } from '@/store/user/selectors';
|
15
|
+
import { HotkeyEnum } from '@/types/hotkey';
|
13
16
|
|
14
17
|
import SettingButton from '../../../features/SettingButton';
|
15
18
|
import ShareButton from '../../../features/ShareButton';
|
16
19
|
|
17
20
|
const HeaderAction = memo(() => {
|
18
21
|
const { t } = useTranslation('chat');
|
19
|
-
|
22
|
+
const hotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.ToggleRightPanel));
|
20
23
|
const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
|
21
24
|
systemStatusSelectors.showChatSideBar(s),
|
22
25
|
s.toggleChatSideBar,
|
@@ -27,12 +30,13 @@ const HeaderAction = memo(() => {
|
|
27
30
|
return (
|
28
31
|
<Flexbox gap={4} horizontal>
|
29
32
|
<ShareButton />
|
30
|
-
<
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
<Tooltip hotkey={hotkey} title={t('toggleRightPanel.title', { ns: 'hotkey' })}>
|
34
|
+
<ActionIcon
|
35
|
+
icon={showAgentSettings ? PanelRightClose : PanelRightOpen}
|
36
|
+
onClick={() => toggleConfig()}
|
37
|
+
size={DESKTOP_HEADER_ICON_SIZE}
|
38
|
+
/>
|
39
|
+
</Tooltip>
|
36
40
|
{isAgentEditable && <SettingButton />}
|
37
41
|
</Flexbox>
|
38
42
|
);
|
@@ -1,6 +1,6 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
|
-
import { ActionIcon, Avatar } from '@lobehub/ui';
|
3
|
+
import { ActionIcon, Avatar, Tooltip } from '@lobehub/ui';
|
4
4
|
import { Skeleton } from 'antd';
|
5
5
|
import { createStyles } from 'antd-style';
|
6
6
|
import { PanelLeftClose, PanelLeftOpen } from 'lucide-react';
|
@@ -16,6 +16,9 @@ import { useGlobalStore } from '@/store/global';
|
|
16
16
|
import { systemStatusSelectors } from '@/store/global/selectors';
|
17
17
|
import { useSessionStore } from '@/store/session';
|
18
18
|
import { sessionMetaSelectors, sessionSelectors } from '@/store/session/selectors';
|
19
|
+
import { useUserStore } from '@/store/user';
|
20
|
+
import { settingsSelectors } from '@/store/user/selectors';
|
21
|
+
import { HotkeyEnum } from '@/types/hotkey';
|
19
22
|
|
20
23
|
import Tags from './Tags';
|
21
24
|
|
@@ -42,7 +45,9 @@ const useStyles = createStyles(({ css }) => ({
|
|
42
45
|
}));
|
43
46
|
|
44
47
|
const Main = memo(() => {
|
45
|
-
const
|
48
|
+
const hotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.ToggleLeftPanel));
|
49
|
+
|
50
|
+
const { t } = useTranslation(['chat', 'hotkey']);
|
46
51
|
const { styles } = useStyles();
|
47
52
|
useInitAgentConfig();
|
48
53
|
const [isPinned] = useQueryState('pinned', parseAsBoolean);
|
@@ -61,23 +66,25 @@ const Main = memo(() => {
|
|
61
66
|
const showSessionPanel = useGlobalStore(systemStatusSelectors.showSessionPanel);
|
62
67
|
const updateSystemStatus = useGlobalStore((s) => s.updateSystemStatus);
|
63
68
|
|
69
|
+
const ToggleAction = (
|
70
|
+
<Tooltip hotkey={hotkey} title={t('toggleLeftPanel.title', { ns: 'hotkey' })}>
|
71
|
+
<ActionIcon
|
72
|
+
icon={showSessionPanel ? PanelLeftClose : PanelLeftOpen}
|
73
|
+
onClick={() => {
|
74
|
+
updateSystemStatus({
|
75
|
+
sessionsWidth: showSessionPanel ? 0 : 320,
|
76
|
+
showSessionPanel: !showSessionPanel,
|
77
|
+
});
|
78
|
+
}}
|
79
|
+
size={DESKTOP_HEADER_ICON_SIZE}
|
80
|
+
/>
|
81
|
+
</Tooltip>
|
82
|
+
);
|
83
|
+
|
64
84
|
if (!init)
|
65
85
|
return (
|
66
86
|
<Flexbox align={'center'} gap={8} horizontal>
|
67
|
-
{!isPinned &&
|
68
|
-
<ActionIcon
|
69
|
-
aria-label={t('agents')}
|
70
|
-
icon={showSessionPanel ? PanelLeftClose : PanelLeftOpen}
|
71
|
-
onClick={() => {
|
72
|
-
updateSystemStatus({
|
73
|
-
sessionsWidth: showSessionPanel ? 0 : 320,
|
74
|
-
showSessionPanel: !showSessionPanel,
|
75
|
-
});
|
76
|
-
}}
|
77
|
-
size={DESKTOP_HEADER_ICON_SIZE}
|
78
|
-
title={t('agents')}
|
79
|
-
/>
|
80
|
-
)}
|
87
|
+
{!isPinned && ToggleAction}
|
81
88
|
<Skeleton
|
82
89
|
active
|
83
90
|
avatar={{ shape: 'circle', size: 28 }}
|
@@ -89,20 +96,7 @@ const Main = memo(() => {
|
|
89
96
|
|
90
97
|
return (
|
91
98
|
<Flexbox align={'center'} gap={4} horizontal>
|
92
|
-
{!isPinned &&
|
93
|
-
<ActionIcon
|
94
|
-
aria-label={t('agents')}
|
95
|
-
icon={showSessionPanel ? PanelLeftClose : PanelLeftOpen}
|
96
|
-
onClick={() => {
|
97
|
-
updateSystemStatus({
|
98
|
-
sessionsWidth: showSessionPanel ? 0 : 320,
|
99
|
-
showSessionPanel: !showSessionPanel,
|
100
|
-
});
|
101
|
-
}}
|
102
|
-
size={DESKTOP_HEADER_ICON_SIZE}
|
103
|
-
title={t('agents')}
|
104
|
-
/>
|
105
|
-
)}
|
99
|
+
{!isPinned && ToggleAction}
|
106
100
|
<Avatar
|
107
101
|
avatar={avatar}
|
108
102
|
background={backgroundColor}
|
@@ -5,7 +5,6 @@ import BrandTextLoading from '@/components/Loading/BrandTextLoading';
|
|
5
5
|
|
6
6
|
import { LayoutProps } from '../type';
|
7
7
|
import ChatHeader from './ChatHeader';
|
8
|
-
import HotKeys from './HotKeys';
|
9
8
|
import Portal from './Portal';
|
10
9
|
import TopicPanel from './TopicPanel';
|
11
10
|
|
@@ -32,7 +31,6 @@ const Layout = ({ children, topic, conversation, portal }: LayoutProps) => {
|
|
32
31
|
</Portal>
|
33
32
|
<TopicPanel>{topic}</TopicPanel>
|
34
33
|
</Flexbox>
|
35
|
-
<HotKeys />
|
36
34
|
</>
|
37
35
|
);
|
38
36
|
};
|