@lobehub/chat 0.90.3 → 0.91.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/package.json +1 -1
- package/src/app/chat/features/ChatInputContent/ActionBar/ActionRight.tsx +13 -2
- package/src/app/chat/features/ChatInputContent/Footer/SaveTopic.tsx +10 -1
- package/src/app/chat/features/Conversation/ChatList/index.tsx +17 -0
- package/src/app/chat/features/PageTitle/index.tsx +1 -3
- package/src/app/chat/features/TopicListContent/SystemRole/index.tsx +13 -2
- package/src/app/chat/features/TopicListContent/Topic/TopicContent.tsx +10 -1
- package/src/app/chat/settings/features/EditPage.tsx +1 -4
- package/src/app/market/index.tsx +1 -3
- package/src/app/metadata.ts +1 -3
- package/src/app/settings/agent/index.tsx +1 -3
- package/src/app/settings/common/index.tsx +1 -3
- package/src/app/settings/llm/index.tsx +1 -3
- package/src/components/HotKeys/index.tsx +57 -0
- package/src/components/{PageTitle.tsx → PageTitle/index.tsx} +1 -1
- package/src/const/hotkeys.ts +4 -0
- package/src/utils/genSiteHeadTitle.ts +0 -1
- /package/src/components/{ResponsiveIndex.tsx → ResponsiveIndex/index.tsx} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 0.91.0](https://github.com/lobehub/lobe-chat/compare/v0.90.3...v0.91.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-10-17**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: Add hotkeys.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: Add hotkeys, closes [#286](https://github.com/lobehub/lobe-chat/issues/286) ([041054d](https://github.com/lobehub/lobe-chat/commit/041054d))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
### [Version 0.90.3](https://github.com/lobehub/lobe-chat/compare/v0.90.2...v0.90.3)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2023-10-17**</sup>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.91.0",
|
|
4
4
|
"description": "An open-source, extensible (Function Calling), high-performance chatbot framework. It supports one-click free deployment of your private ChatGPT/LLM web application",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chatbot",
|
|
@@ -3,8 +3,11 @@ import { Popconfirm } from 'antd';
|
|
|
3
3
|
import { useResponsive } from 'antd-style';
|
|
4
4
|
import { Eraser } from 'lucide-react';
|
|
5
5
|
import { memo } from 'react';
|
|
6
|
+
import { useHotkeys } from 'react-hotkeys-hook';
|
|
6
7
|
import { useTranslation } from 'react-i18next';
|
|
7
8
|
|
|
9
|
+
import HotKeys from '@/components/HotKeys';
|
|
10
|
+
import { CLEAN_MESSAGE_KEY, PREFIX_KEY } from '@/const/hotkeys';
|
|
8
11
|
import { useSessionStore } from '@/store/session';
|
|
9
12
|
|
|
10
13
|
import SaveTopic from '../Footer/SaveTopic';
|
|
@@ -13,6 +16,12 @@ const ActionsRight = memo(() => {
|
|
|
13
16
|
const { t } = useTranslation('setting');
|
|
14
17
|
const [clearMessage] = useSessionStore((s) => [s.clearMessage, s.updateAgentConfig]);
|
|
15
18
|
const { mobile } = useResponsive();
|
|
19
|
+
const hotkeys = [PREFIX_KEY, CLEAN_MESSAGE_KEY].join('+');
|
|
20
|
+
|
|
21
|
+
useHotkeys(hotkeys, clearMessage, {
|
|
22
|
+
preventDefault: true,
|
|
23
|
+
});
|
|
24
|
+
|
|
16
25
|
return (
|
|
17
26
|
<>
|
|
18
27
|
{mobile && <SaveTopic />}
|
|
@@ -20,14 +29,16 @@ const ActionsRight = memo(() => {
|
|
|
20
29
|
cancelText={t('cancel', { ns: 'common' })}
|
|
21
30
|
okButtonProps={{ danger: true }}
|
|
22
31
|
okText={t('ok', { ns: 'common' })}
|
|
23
|
-
onConfirm={
|
|
32
|
+
onConfirm={clearMessage}
|
|
24
33
|
placement={'topRight'}
|
|
25
34
|
title={t('confirmClearCurrentMessages', { ns: 'common' })}
|
|
26
35
|
>
|
|
27
36
|
<ActionIcon
|
|
28
37
|
icon={Eraser}
|
|
29
38
|
placement={'bottom'}
|
|
30
|
-
title={
|
|
39
|
+
title={
|
|
40
|
+
(<HotKeys desc={t('clearCurrentMessages', { ns: 'common' })} keys={hotkeys} />) as any
|
|
41
|
+
}
|
|
31
42
|
/>
|
|
32
43
|
</Popconfirm>
|
|
33
44
|
</>
|
|
@@ -3,8 +3,11 @@ import { Button } from 'antd';
|
|
|
3
3
|
import { useResponsive } from 'antd-style';
|
|
4
4
|
import { LucideGalleryVerticalEnd } from 'lucide-react';
|
|
5
5
|
import { memo } from 'react';
|
|
6
|
+
import { useHotkeys } from 'react-hotkeys-hook';
|
|
6
7
|
import { useTranslation } from 'react-i18next';
|
|
7
8
|
|
|
9
|
+
import HotKeys from '@/components/HotKeys';
|
|
10
|
+
import { PREFIX_KEY, SAVE_TOPIC_KEY } from '@/const/hotkeys';
|
|
8
11
|
import { useSessionStore } from '@/store/session';
|
|
9
12
|
|
|
10
13
|
const SaveTopic = memo(() => {
|
|
@@ -12,13 +15,19 @@ const SaveTopic = memo(() => {
|
|
|
12
15
|
const [hasTopic, saveToTopic] = useSessionStore((s) => [!!s.activeTopicId, s.saveToTopic]);
|
|
13
16
|
const { mobile } = useResponsive();
|
|
14
17
|
|
|
18
|
+
const hotkeys = [PREFIX_KEY, SAVE_TOPIC_KEY].join('+');
|
|
19
|
+
|
|
20
|
+
useHotkeys(hotkeys, saveToTopic, {
|
|
21
|
+
preventDefault: true,
|
|
22
|
+
});
|
|
23
|
+
|
|
15
24
|
if (hasTopic) return undefined;
|
|
16
25
|
|
|
17
26
|
const Render = mobile ? ActionIcon : Button;
|
|
18
27
|
const icon: any = mobile ? LucideGalleryVerticalEnd : <Icon icon={LucideGalleryVerticalEnd} />;
|
|
19
28
|
|
|
20
29
|
return (
|
|
21
|
-
<Tooltip title={t('topic.saveCurrentMessages')}>
|
|
30
|
+
<Tooltip title={<HotKeys desc={t('topic.saveCurrentMessages')} keys={hotkeys} />}>
|
|
22
31
|
<Render aria-label={t('topic.saveCurrentMessages')} icon={icon} onClick={saveToTopic} />
|
|
23
32
|
</Tooltip>
|
|
24
33
|
);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ChatList } from '@lobehub/ui';
|
|
2
2
|
import isEqual from 'fast-deep-equal';
|
|
3
3
|
import { memo } from 'react';
|
|
4
|
+
import { useHotkeys } from 'react-hotkeys-hook';
|
|
4
5
|
import { useTranslation } from 'react-i18next';
|
|
5
6
|
|
|
7
|
+
import { PREFIX_KEY, REGENERATE_KEY } from '@/const/hotkeys';
|
|
6
8
|
import { useSessionChatInit, useSessionStore } from '@/store/session';
|
|
7
9
|
import { agentSelectors, chatSelectors } from '@/store/session/selectors';
|
|
8
10
|
|
|
@@ -36,6 +38,21 @@ const List = memo(() => {
|
|
|
36
38
|
];
|
|
37
39
|
});
|
|
38
40
|
|
|
41
|
+
const hotkeys = [PREFIX_KEY, REGENERATE_KEY].join('+');
|
|
42
|
+
|
|
43
|
+
useHotkeys(
|
|
44
|
+
hotkeys,
|
|
45
|
+
() => {
|
|
46
|
+
console.log(111);
|
|
47
|
+
const lastMessage = data.at(-1);
|
|
48
|
+
if (!lastMessage || lastMessage.id === 'default' || lastMessage.role === 'system') return;
|
|
49
|
+
resendMessage(lastMessage.id);
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
preventDefault: true,
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
|
|
39
56
|
if (!init) return <SkeletonList />;
|
|
40
57
|
|
|
41
58
|
return (
|
|
@@ -5,15 +5,13 @@ import { memo } from 'react';
|
|
|
5
5
|
import PageTitle from '@/components/PageTitle';
|
|
6
6
|
import { useSessionStore } from '@/store/session';
|
|
7
7
|
import { agentSelectors } from '@/store/session/selectors';
|
|
8
|
-
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
9
8
|
|
|
10
9
|
const Title = memo(() => {
|
|
11
10
|
const [avatar, title] = useSessionStore((s) => [
|
|
12
11
|
agentSelectors.currentAgentAvatar(s),
|
|
13
12
|
agentSelectors.currentAgentTitle(s),
|
|
14
13
|
]);
|
|
15
|
-
const pageTitle = genSiteHeadTitle([avatar, title].filter(Boolean).join(' '));
|
|
16
14
|
|
|
17
|
-
return <PageTitle title={
|
|
15
|
+
return <PageTitle title={[avatar, title].filter(Boolean).join(' ')} />;
|
|
18
16
|
});
|
|
19
17
|
export default Title;
|
|
@@ -13,7 +13,7 @@ import { useStyles } from './style';
|
|
|
13
13
|
|
|
14
14
|
const SystemRole = memo(() => {
|
|
15
15
|
const [openModal, setOpenModal] = useState(false);
|
|
16
|
-
|
|
16
|
+
const [editing, setEditing] = useState(false);
|
|
17
17
|
const { styles } = useStyles();
|
|
18
18
|
const [systemRole, updateAgentConfig] = useSessionStore((s) => [
|
|
19
19
|
agentSelectors.currentAgentSystemRole(s),
|
|
@@ -35,7 +35,16 @@ const SystemRole = memo(() => {
|
|
|
35
35
|
}
|
|
36
36
|
title={t('settingAgent.prompt.title', { ns: 'setting' })}
|
|
37
37
|
/>
|
|
38
|
-
<Flexbox
|
|
38
|
+
<Flexbox
|
|
39
|
+
className={styles.promptBox}
|
|
40
|
+
height={200}
|
|
41
|
+
onDoubleClick={(e) => {
|
|
42
|
+
if (e.altKey) {
|
|
43
|
+
setOpenModal(true);
|
|
44
|
+
setEditing(true);
|
|
45
|
+
}
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
39
48
|
{!init ? (
|
|
40
49
|
<Skeleton
|
|
41
50
|
active
|
|
@@ -47,9 +56,11 @@ const SystemRole = memo(() => {
|
|
|
47
56
|
<>
|
|
48
57
|
<EditableMessage
|
|
49
58
|
classNames={{ markdown: styles.prompt }}
|
|
59
|
+
editing={editing}
|
|
50
60
|
onChange={(e) => {
|
|
51
61
|
updateAgentConfig({ systemRole: e });
|
|
52
62
|
}}
|
|
63
|
+
onEditingChange={setEditing}
|
|
53
64
|
onOpenChange={setOpenModal}
|
|
54
65
|
openModal={openModal}
|
|
55
66
|
placeholder={`${t('settingAgent.prompt.placeholder', { ns: 'setting' })}...`}
|
|
@@ -83,7 +83,16 @@ const TopicContent = memo<TopicContentProps>(({ id, title, fav }) => {
|
|
|
83
83
|
);
|
|
84
84
|
|
|
85
85
|
return (
|
|
86
|
-
<Flexbox
|
|
86
|
+
<Flexbox
|
|
87
|
+
align={'center'}
|
|
88
|
+
gap={8}
|
|
89
|
+
horizontal
|
|
90
|
+
justify={'space-between'}
|
|
91
|
+
onDoubleClick={(e) => {
|
|
92
|
+
if (!id) return;
|
|
93
|
+
if (e.altKey) toggleEditing(true);
|
|
94
|
+
}}
|
|
95
|
+
>
|
|
87
96
|
<ActionIcon
|
|
88
97
|
color={fav ? theme.colorWarning : undefined}
|
|
89
98
|
fill={fav ? theme.colorWarning : 'transparent'}
|
|
@@ -8,7 +8,6 @@ import PageTitle from '@/components/PageTitle';
|
|
|
8
8
|
import AgentSetting from '@/features/AgentSetting';
|
|
9
9
|
import { useSessionStore } from '@/store/session';
|
|
10
10
|
import { agentSelectors } from '@/store/session/selectors';
|
|
11
|
-
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
12
11
|
|
|
13
12
|
const EditPage = memo(() => {
|
|
14
13
|
const { t } = useTranslation('setting');
|
|
@@ -20,11 +19,9 @@ const EditPage = memo(() => {
|
|
|
20
19
|
agentSelectors.currentAgentTitle(s),
|
|
21
20
|
]);
|
|
22
21
|
|
|
23
|
-
const pageTitle = genSiteHeadTitle(t('header.sessionWithName', { name: title }));
|
|
24
|
-
|
|
25
22
|
return (
|
|
26
23
|
<>
|
|
27
|
-
<PageTitle title={
|
|
24
|
+
<PageTitle title={t('header.sessionWithName', { name: title })} />
|
|
28
25
|
<AgentSetting
|
|
29
26
|
config={config}
|
|
30
27
|
meta={meta}
|
package/src/app/market/index.tsx
CHANGED
|
@@ -5,13 +5,11 @@ import { useTranslation } from 'react-i18next';
|
|
|
5
5
|
|
|
6
6
|
import PageTitle from '@/components/PageTitle';
|
|
7
7
|
import { useMarketStore } from '@/store/market';
|
|
8
|
-
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
9
8
|
|
|
10
9
|
import AgentSearchBar from './features/AgentSearchBar';
|
|
11
10
|
|
|
12
11
|
const Market = memo(() => {
|
|
13
12
|
const { t } = useTranslation('common');
|
|
14
|
-
const pageTitle = genSiteHeadTitle(t('tab.market'));
|
|
15
13
|
|
|
16
14
|
useEffect(() => {
|
|
17
15
|
// refs: https://github.com/pmndrs/zustand/blob/main/docs/integrations/persisting-store-data.md#hashydrated
|
|
@@ -20,7 +18,7 @@ const Market = memo(() => {
|
|
|
20
18
|
|
|
21
19
|
return (
|
|
22
20
|
<>
|
|
23
|
-
<PageTitle title={
|
|
21
|
+
<PageTitle title={t('tab.market')} />
|
|
24
22
|
<AgentSearchBar />
|
|
25
23
|
</>
|
|
26
24
|
);
|
package/src/app/metadata.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Metadata } from 'next';
|
|
2
2
|
|
|
3
|
-
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
4
|
-
|
|
5
3
|
import pkg from '../../package.json';
|
|
6
4
|
|
|
7
|
-
const title =
|
|
5
|
+
const title = 'LobeChat';
|
|
8
6
|
const { description, homepage } = pkg;
|
|
9
7
|
const metadata: Metadata = {
|
|
10
8
|
appleWebApp: {
|
|
@@ -6,17 +6,15 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
import PageTitle from '@/components/PageTitle';
|
|
7
7
|
import { useSwitchSideBarOnInit } from '@/store/global/hooks/useSwitchSettingsOnInit';
|
|
8
8
|
import { SettingsTabs } from '@/store/global/initialState';
|
|
9
|
-
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
10
9
|
|
|
11
10
|
import Agent from './Agent';
|
|
12
11
|
|
|
13
12
|
export default memo(() => {
|
|
14
13
|
useSwitchSideBarOnInit(SettingsTabs.Agent);
|
|
15
14
|
const { t } = useTranslation('setting');
|
|
16
|
-
const pageTitle = genSiteHeadTitle(t('tab.agent'));
|
|
17
15
|
return (
|
|
18
16
|
<>
|
|
19
|
-
<PageTitle title={
|
|
17
|
+
<PageTitle title={t('tab.agent')} />
|
|
20
18
|
<Agent />
|
|
21
19
|
</>
|
|
22
20
|
);
|
|
@@ -7,7 +7,6 @@ import PageTitle from '@/components/PageTitle';
|
|
|
7
7
|
import { CURRENT_VERSION } from '@/const/version';
|
|
8
8
|
import { useSwitchSideBarOnInit } from '@/store/global/hooks/useSwitchSettingsOnInit';
|
|
9
9
|
import { SettingsTabs } from '@/store/global/initialState';
|
|
10
|
-
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
11
10
|
|
|
12
11
|
import Footer from '../features/Footer';
|
|
13
12
|
import Common from './Common';
|
|
@@ -15,11 +14,10 @@ import Common from './Common';
|
|
|
15
14
|
export default memo(() => {
|
|
16
15
|
useSwitchSideBarOnInit(SettingsTabs.Common);
|
|
17
16
|
const { t } = useTranslation('setting');
|
|
18
|
-
const pageTitle = genSiteHeadTitle(t('tab.common'));
|
|
19
17
|
|
|
20
18
|
return (
|
|
21
19
|
<>
|
|
22
|
-
<PageTitle title={
|
|
20
|
+
<PageTitle title={t('tab.common')} />
|
|
23
21
|
<Common />
|
|
24
22
|
<Footer>LobeChat v{CURRENT_VERSION}</Footer>
|
|
25
23
|
</>
|
|
@@ -8,17 +8,15 @@ import Footer from '@/app/settings/features/Footer';
|
|
|
8
8
|
import PageTitle from '@/components/PageTitle';
|
|
9
9
|
import { useSwitchSideBarOnInit } from '@/store/global/hooks/useSwitchSettingsOnInit';
|
|
10
10
|
import { SettingsTabs } from '@/store/global/initialState';
|
|
11
|
-
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
12
11
|
|
|
13
12
|
import LLM from './LLM';
|
|
14
13
|
|
|
15
14
|
export default memo(() => {
|
|
16
15
|
useSwitchSideBarOnInit(SettingsTabs.LLM);
|
|
17
16
|
const { t } = useTranslation('setting');
|
|
18
|
-
const pageTitle = genSiteHeadTitle(t('tab.llm'));
|
|
19
17
|
return (
|
|
20
18
|
<>
|
|
21
|
-
<PageTitle title={
|
|
19
|
+
<PageTitle title={t('tab.llm')} />
|
|
22
20
|
<LLM />
|
|
23
21
|
<Footer>
|
|
24
22
|
<Trans i18nKey="llm.waitingForMore" ns={'setting'}>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createStyles } from 'antd-style';
|
|
2
|
+
import { Fragment, memo } from 'react';
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
|
|
5
|
+
const useStyles = createStyles(
|
|
6
|
+
({ css, token }) => css`
|
|
7
|
+
font-size: 12px;
|
|
8
|
+
|
|
9
|
+
span {
|
|
10
|
+
font-weight: 600;
|
|
11
|
+
opacity: 0.5;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
kbd {
|
|
15
|
+
padding: 3px 5px;
|
|
16
|
+
|
|
17
|
+
line-height: 1;
|
|
18
|
+
color: ${token.colorTextSecondary};
|
|
19
|
+
|
|
20
|
+
background: ${token.colorBgContainer};
|
|
21
|
+
border: 1px solid ${token.colorBorderSecondary};
|
|
22
|
+
border-bottom-color: ${token.colorBorder};
|
|
23
|
+
border-radius: ${token.borderRadius}px;
|
|
24
|
+
box-shadow: inset 0 -1px 0 ${token.colorBorder};
|
|
25
|
+
}
|
|
26
|
+
`,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export interface HotKeysProps {
|
|
30
|
+
desc?: string;
|
|
31
|
+
keys: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const HotKeys = memo<HotKeysProps>(({ keys, desc }) => {
|
|
35
|
+
const { styles } = useStyles();
|
|
36
|
+
const keysGroup = keys.split('+').filter(Boolean);
|
|
37
|
+
const content = (
|
|
38
|
+
<Flexbox align={'center'} className={styles} gap={2} horizontal>
|
|
39
|
+
{keysGroup.map((key, index) => (
|
|
40
|
+
<Fragment key={index}>
|
|
41
|
+
<kbd>{key.toUpperCase()}</kbd>
|
|
42
|
+
{index + 1 < keysGroup.length && <span>+</span>}
|
|
43
|
+
</Fragment>
|
|
44
|
+
))}
|
|
45
|
+
</Flexbox>
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
if (!desc) return content;
|
|
49
|
+
return (
|
|
50
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
51
|
+
{content}
|
|
52
|
+
{desc}
|
|
53
|
+
</Flexbox>
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export default HotKeys;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const genSiteHeadTitle = (title?: string) => (title ? `${title} · LobeChat` : 'LobeChat');
|
|
File without changes
|