@lobehub/chat 0.22.2 → 0.23.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 +6 -0
- package/package.json +5 -3
- package/src/components/HeaderTitle/index.tsx +6 -1
- package/src/components/SliderWithInput/index.tsx +32 -7
- package/src/features/SideBar/index.tsx +103 -4
- package/src/locales/default/common.ts +13 -1
- package/src/pages/chat/SessionList/List/SessionItem.tsx +70 -64
- package/src/pages/chat/[id]/Conversation/Input/Action.tsx +4 -1
- package/src/pages/chat/[id]/edit/Header.tsx +24 -7
- package/src/pages/setting/Header.tsx +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
# [0.23.0](https://github.com/lobehub/lobe-chat/compare/v0.22.2...v0.23.0) (2023-07-26)
|
|
6
|
+
|
|
7
|
+
### ✨ Features
|
|
8
|
+
|
|
9
|
+
- Add new features, update URLs, customize appearance, and implement components ([4b61bf4](https://github.com/lobehub/lobe-chat/commit/4b61bf4))
|
|
10
|
+
|
|
5
11
|
### [Version 0.22.2](https://github.com/lobehub/lobe-chat/compare/v0.22.1...v0.22.2)
|
|
6
12
|
|
|
7
13
|
<sup>Released on **2023-07-26**</sup>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chatbot",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
],
|
|
12
12
|
"homepage": "https://github.com/lobehub/lobe-chat",
|
|
13
13
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/lobehub/lobe-chat/issues/new"
|
|
14
|
+
"url": "https://github.com/lobehub/lobe-chat/issues/new/choose"
|
|
15
15
|
},
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"lint:style": "stylelint \"{src,tests}/**/*.{js,jsx,ts,tsx}\" --fix",
|
|
31
31
|
"prepare": "husky install",
|
|
32
32
|
"prettier": "prettier -c --write \"**/**\"",
|
|
33
|
+
"pull": "git pull",
|
|
33
34
|
"release": "semantic-release",
|
|
34
35
|
"start": "next start",
|
|
35
36
|
"stylelint": "stylelint \"src/**/*.{js,jsx,ts,tsx}\" --fix",
|
|
@@ -141,5 +142,6 @@
|
|
|
141
142
|
"publishConfig": {
|
|
142
143
|
"access": "public",
|
|
143
144
|
"registry": "https://registry.npmjs.org"
|
|
144
|
-
}
|
|
145
|
+
},
|
|
146
|
+
"changelog": "https://github.com/lobehub/lobe-chat"
|
|
145
147
|
}
|
|
@@ -36,7 +36,12 @@ const HeaderTitle = memo<HeaderTitleProps>(({ title, desc, tag }) => {
|
|
|
36
36
|
</Flexbox>
|
|
37
37
|
</Flexbox>
|
|
38
38
|
);
|
|
39
|
-
return
|
|
39
|
+
return (
|
|
40
|
+
<Flexbox align={'center'} className={styles.title} gap={8} horizontal>
|
|
41
|
+
{title}
|
|
42
|
+
{tag}
|
|
43
|
+
</Flexbox>
|
|
44
|
+
);
|
|
40
45
|
});
|
|
41
46
|
|
|
42
47
|
export default HeaderTitle;
|
|
@@ -1,36 +1,61 @@
|
|
|
1
|
-
import { InputNumber, Slider } from 'antd';
|
|
1
|
+
import { InputNumber, type InputNumberProps, Slider } from 'antd';
|
|
2
2
|
import { SliderSingleProps } from 'antd/es/slider';
|
|
3
3
|
import { isNull } from 'lodash-es';
|
|
4
4
|
import { memo, useCallback } from 'react';
|
|
5
5
|
import { Flexbox } from 'react-layout-kit';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
export interface SliderWithInputProps extends SliderSingleProps {
|
|
8
|
+
controls?: InputNumberProps['controls'];
|
|
9
|
+
size?: InputNumberProps['size'];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const SliderWithInput = memo<SliderWithInputProps>(
|
|
13
|
+
({
|
|
14
|
+
step,
|
|
15
|
+
value,
|
|
16
|
+
onChange,
|
|
17
|
+
max,
|
|
18
|
+
min,
|
|
19
|
+
defaultValue,
|
|
20
|
+
size,
|
|
21
|
+
controls,
|
|
22
|
+
style,
|
|
23
|
+
className,
|
|
24
|
+
...props
|
|
25
|
+
}) => {
|
|
9
26
|
const handleOnchange = useCallback((value: number | null) => {
|
|
10
27
|
if (Number.isNaN(value) || isNull(value)) return;
|
|
11
28
|
onChange?.(value);
|
|
12
29
|
}, []);
|
|
13
30
|
|
|
14
31
|
return (
|
|
15
|
-
<Flexbox
|
|
32
|
+
<Flexbox
|
|
33
|
+
align={'center'}
|
|
34
|
+
className={className}
|
|
35
|
+
direction={'horizontal'}
|
|
36
|
+
gap={8}
|
|
37
|
+
style={style}
|
|
38
|
+
>
|
|
16
39
|
<Slider
|
|
17
40
|
defaultValue={defaultValue}
|
|
18
41
|
max={max}
|
|
19
42
|
min={min}
|
|
20
43
|
onChange={handleOnchange}
|
|
21
44
|
step={step}
|
|
22
|
-
style={{ flex: 1 }}
|
|
23
|
-
tooltip={{
|
|
45
|
+
style={size === 'small' ? { flex: 1, margin: 0 } : { flex: 1 }}
|
|
46
|
+
tooltip={{ open: false }}
|
|
24
47
|
value={typeof value === 'number' ? value : 0}
|
|
25
48
|
{...props}
|
|
26
49
|
/>
|
|
27
50
|
<InputNumber
|
|
51
|
+
controls={size !== 'small' || controls}
|
|
28
52
|
defaultValue={defaultValue}
|
|
29
53
|
max={max}
|
|
30
54
|
min={min}
|
|
31
55
|
onChange={handleOnchange}
|
|
56
|
+
size={size}
|
|
32
57
|
step={Number.isNaN(step) || isNull(step) ? undefined : step}
|
|
33
|
-
style={{ flex: 1, maxWidth: 64 }}
|
|
58
|
+
style={{ flex: 1, maxWidth: size === 'small' ? 40 : 64 }}
|
|
34
59
|
value={typeof value === 'number' ? value : 0}
|
|
35
60
|
/>
|
|
36
61
|
</Flexbox>
|
|
@@ -1,18 +1,117 @@
|
|
|
1
|
-
import { ActionIcon, SideNav } from '@lobehub/ui';
|
|
2
|
-
import {
|
|
1
|
+
import { ActionIcon, Icon, SideNav } from '@lobehub/ui';
|
|
2
|
+
import { Dropdown, type MenuProps } from 'antd';
|
|
3
|
+
import {
|
|
4
|
+
Feather,
|
|
5
|
+
FileClock,
|
|
6
|
+
FolderInput,
|
|
7
|
+
FolderOutput,
|
|
8
|
+
Github,
|
|
9
|
+
Heart,
|
|
10
|
+
MessageSquare,
|
|
11
|
+
Settings,
|
|
12
|
+
Settings2,
|
|
13
|
+
Sticker,
|
|
14
|
+
} from 'lucide-react';
|
|
3
15
|
import Router from 'next/router';
|
|
4
|
-
import { memo } from 'react';
|
|
16
|
+
import { memo, useMemo } from 'react';
|
|
17
|
+
import { useTranslation } from 'react-i18next';
|
|
5
18
|
import { shallow } from 'zustand/shallow';
|
|
6
19
|
|
|
20
|
+
import { bugs, homepage } from '@/../package.json';
|
|
7
21
|
import AvatarWithUpload from '@/features/AvatarWithUpload';
|
|
8
22
|
import { useSettings } from '@/store/settings';
|
|
9
23
|
|
|
10
24
|
export default memo(() => {
|
|
11
25
|
const [tab, setTab] = useSettings((s) => [s.sidebarKey, s.switchSideBar], shallow);
|
|
26
|
+
const { t } = useTranslation('common');
|
|
27
|
+
const items: MenuProps['items'] = useMemo(
|
|
28
|
+
() => [
|
|
29
|
+
{
|
|
30
|
+
icon: <Icon icon={FolderInput} />,
|
|
31
|
+
key: 'import',
|
|
32
|
+
label: <div>{t('import')}</div>,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
children: [
|
|
36
|
+
{
|
|
37
|
+
key: 'allAgent',
|
|
38
|
+
label: <div>{t('exportType.allAgent')}</div>,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
key: 'allAgentWithMessage',
|
|
42
|
+
label: <div>{t('exportType.allAgentWithMessage')}</div>,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
key: 'globalSetting',
|
|
46
|
+
label: <div>{t('exportType.globalSetting')}</div>,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
type: 'divider',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: 'all',
|
|
53
|
+
label: <div>{t('exportType.all')}</div>,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
icon: <Icon icon={FolderOutput} />,
|
|
57
|
+
key: 'export',
|
|
58
|
+
label: t('export'),
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'divider',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
icon: <Icon icon={Feather} />,
|
|
65
|
+
key: 'feedback',
|
|
66
|
+
label: (
|
|
67
|
+
<a href={bugs.url} rel="noreferrer" target={'_blank'}>
|
|
68
|
+
{t('feedback')}
|
|
69
|
+
</a>
|
|
70
|
+
),
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
icon: <Icon icon={FileClock} />,
|
|
74
|
+
key: 'changelog',
|
|
75
|
+
label: (
|
|
76
|
+
<a href={`${homepage}/blob/master/CHANGELOG.md`} rel="noreferrer" target={'_blank'}>
|
|
77
|
+
{t('changelog')}
|
|
78
|
+
</a>
|
|
79
|
+
),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
icon: <Icon icon={Heart} />,
|
|
83
|
+
key: 'about',
|
|
84
|
+
label: (
|
|
85
|
+
<a href={homepage} rel="noreferrer" target={'_blank'}>
|
|
86
|
+
{t('about')}
|
|
87
|
+
</a>
|
|
88
|
+
),
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
type: 'divider',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
icon: <Icon icon={Settings} />,
|
|
95
|
+
key: 'setting',
|
|
96
|
+
label: <div onClick={() => Router.push('/setting')}>{t('setting')}</div>,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
[],
|
|
100
|
+
);
|
|
101
|
+
|
|
12
102
|
return (
|
|
13
103
|
<SideNav
|
|
14
104
|
avatar={<AvatarWithUpload />}
|
|
15
|
-
bottomActions={
|
|
105
|
+
bottomActions={
|
|
106
|
+
<>
|
|
107
|
+
<a href={homepage} rel="noreferrer" target={'_blank'}>
|
|
108
|
+
<ActionIcon icon={Github} />
|
|
109
|
+
</a>
|
|
110
|
+
<Dropdown arrow={false} menu={{ items }} trigger={['click']}>
|
|
111
|
+
<ActionIcon icon={Settings2} />
|
|
112
|
+
</Dropdown>
|
|
113
|
+
</>
|
|
114
|
+
}
|
|
16
115
|
style={{ height: '100vh' }}
|
|
17
116
|
topActions={
|
|
18
117
|
<>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export default {
|
|
2
|
+
about: '关于',
|
|
2
3
|
advanceSettings: '高级设置',
|
|
3
4
|
agentMaxToken: '会话最大长度',
|
|
4
5
|
agentModel: '模型',
|
|
@@ -7,6 +8,7 @@ export default {
|
|
|
7
8
|
autoGenerate: '自动补全',
|
|
8
9
|
autoGenerateTooltip: '基于提示词自动补全助手描述',
|
|
9
10
|
cancel: '取消',
|
|
11
|
+
changelog: '更新日志',
|
|
10
12
|
clearCurrentMessages: '清空当前会话消息',
|
|
11
13
|
close: '关闭',
|
|
12
14
|
confirmClearCurrentMessages: '即将清空当前会话消息,清空后将无法找回,请确认你的操作',
|
|
@@ -14,7 +16,17 @@ export default {
|
|
|
14
16
|
defaultAgent: '默认助手',
|
|
15
17
|
defaultSession: '默认对话',
|
|
16
18
|
edit: '编辑',
|
|
17
|
-
export: '
|
|
19
|
+
export: '导出配置',
|
|
20
|
+
exportType: {
|
|
21
|
+
agent: '导出助手设定',
|
|
22
|
+
agentWithMessage: '导出助手和消息',
|
|
23
|
+
all: '导出全局设置和所有助手数据',
|
|
24
|
+
allAgent: '导出所有助手设定',
|
|
25
|
+
allAgentWithMessage: '导出所有助手和消息',
|
|
26
|
+
globalSetting: '导出全局设置',
|
|
27
|
+
},
|
|
28
|
+
feedback: '反馈与建议',
|
|
29
|
+
import: '导入配置',
|
|
18
30
|
newAgent: '新建助手',
|
|
19
31
|
noDescription: '暂无描述',
|
|
20
32
|
ok: '确定',
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ActionIcon, Avatar, List } from '@lobehub/ui';
|
|
2
|
+
import { useHover } from 'ahooks';
|
|
2
3
|
import { Popconfirm, Tag } from 'antd';
|
|
3
4
|
import { X } from 'lucide-react';
|
|
4
|
-
import { FC, memo } from 'react';
|
|
5
|
+
import { FC, memo, useRef } from 'react';
|
|
5
6
|
import { useTranslation } from 'react-i18next';
|
|
6
7
|
import { Flexbox } from 'react-layout-kit';
|
|
7
8
|
import { shallow } from 'zustand/shallow';
|
|
@@ -20,6 +21,8 @@ interface SessionItemProps {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading }) => {
|
|
24
|
+
const ref = useRef(null);
|
|
25
|
+
const isHovering = useHover(ref);
|
|
23
26
|
const { t } = useTranslation('common');
|
|
24
27
|
const { styles, theme, cx } = useStyles();
|
|
25
28
|
const [defaultModel] = useSettings((s) => [s.settings.model], shallow);
|
|
@@ -55,71 +58,74 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading })
|
|
|
55
58
|
const showChatLength = chatLength > 0;
|
|
56
59
|
|
|
57
60
|
return (
|
|
58
|
-
<
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
61
|
+
<div ref={ref}>
|
|
62
|
+
<Flexbox className={styles.container} style={{ position: 'relative' }}>
|
|
63
|
+
<Item
|
|
64
|
+
active={active}
|
|
65
|
+
avatar={
|
|
66
|
+
<Avatar
|
|
67
|
+
animation={isHovering}
|
|
68
|
+
avatar={avatar}
|
|
69
|
+
background={avatarBackground}
|
|
70
|
+
shape="circle"
|
|
71
|
+
size={46}
|
|
72
|
+
title={title}
|
|
73
|
+
/>
|
|
74
|
+
}
|
|
75
|
+
classNames={{ time: cx('session-time', styles.time) }}
|
|
76
|
+
date={updateAt}
|
|
77
|
+
description={
|
|
78
|
+
<Flexbox gap={4}>
|
|
79
|
+
<Flexbox>{description || systemRole}</Flexbox>
|
|
75
80
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
/>
|
|
100
|
-
<Popconfirm
|
|
101
|
-
arrow={false}
|
|
102
|
-
cancelText={t('cancel')}
|
|
103
|
-
okButtonProps={{ danger: true }}
|
|
104
|
-
okText={t('ok')}
|
|
105
|
-
onConfirm={(e) => {
|
|
106
|
-
e?.stopPropagation();
|
|
107
|
-
removeSession(id);
|
|
108
|
-
}}
|
|
109
|
-
overlayStyle={{ width: 280 }}
|
|
110
|
-
title={t('confirmRemoveSessionItemAlert')}
|
|
111
|
-
>
|
|
112
|
-
<ActionIcon
|
|
113
|
-
className="session-remove"
|
|
114
|
-
icon={X}
|
|
115
|
-
onClick={(e) => {
|
|
116
|
-
e.preventDefault();
|
|
117
|
-
e.stopPropagation();
|
|
118
|
-
}}
|
|
119
|
-
size={'small'}
|
|
81
|
+
{!(showModel || showChatLength) ? undefined : (
|
|
82
|
+
<Flexbox horizontal>
|
|
83
|
+
{showModel && (
|
|
84
|
+
<Tag bordered={false} style={{ color: theme.colorTextSecondary }}>
|
|
85
|
+
{model}
|
|
86
|
+
</Tag>
|
|
87
|
+
)}
|
|
88
|
+
{/*{showChatLength && (*/}
|
|
89
|
+
{/* <Tag*/}
|
|
90
|
+
{/* bordered={false}*/}
|
|
91
|
+
{/* style={{ color: theme.colorTextSecondary, display: 'flex', gap: 4 }}*/}
|
|
92
|
+
{/* >*/}
|
|
93
|
+
{/* <Icon icon={LucideMessageCircle} />*/}
|
|
94
|
+
{/* {chatLength}*/}
|
|
95
|
+
{/* </Tag>*/}
|
|
96
|
+
{/*)}*/}
|
|
97
|
+
</Flexbox>
|
|
98
|
+
)}
|
|
99
|
+
</Flexbox>
|
|
100
|
+
}
|
|
101
|
+
loading={loading}
|
|
102
|
+
style={{ color: theme.colorText }}
|
|
103
|
+
title={title}
|
|
120
104
|
/>
|
|
121
|
-
|
|
122
|
-
|
|
105
|
+
<Popconfirm
|
|
106
|
+
arrow={false}
|
|
107
|
+
cancelText={t('cancel')}
|
|
108
|
+
okButtonProps={{ danger: true }}
|
|
109
|
+
okText={t('ok')}
|
|
110
|
+
onConfirm={(e) => {
|
|
111
|
+
e?.stopPropagation();
|
|
112
|
+
removeSession(id);
|
|
113
|
+
}}
|
|
114
|
+
overlayStyle={{ width: 280 }}
|
|
115
|
+
title={t('confirmRemoveSessionItemAlert')}
|
|
116
|
+
>
|
|
117
|
+
<ActionIcon
|
|
118
|
+
className="session-remove"
|
|
119
|
+
icon={X}
|
|
120
|
+
onClick={(e) => {
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
e.stopPropagation();
|
|
123
|
+
}}
|
|
124
|
+
size={'small'}
|
|
125
|
+
/>
|
|
126
|
+
</Popconfirm>
|
|
127
|
+
</Flexbox>
|
|
128
|
+
</div>
|
|
123
129
|
);
|
|
124
130
|
}, shallow);
|
|
125
131
|
|
|
@@ -39,15 +39,18 @@ const InputActions = memo(() => {
|
|
|
39
39
|
<ActionIcon icon={BrainCog} placement={'bottom'} title={t('settingModel.model.title')} />
|
|
40
40
|
</Dropdown>
|
|
41
41
|
<Popover
|
|
42
|
+
arrow={false}
|
|
42
43
|
content={
|
|
43
44
|
<SliderWithInput
|
|
45
|
+
controls={false}
|
|
44
46
|
max={1}
|
|
45
47
|
min={0}
|
|
46
48
|
onChange={(v) => {
|
|
47
49
|
updateAgentConfig({ params: { temperature: v } });
|
|
48
50
|
}}
|
|
51
|
+
size={'small'}
|
|
49
52
|
step={0.1}
|
|
50
|
-
style={{ width:
|
|
53
|
+
style={{ width: 160 }}
|
|
51
54
|
value={temperature}
|
|
52
55
|
/>
|
|
53
56
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ActionIcon, ChatHeader } from '@lobehub/ui';
|
|
2
|
-
import {
|
|
2
|
+
import { Dropdown, MenuProps } from 'antd';
|
|
3
|
+
import { FolderOutput, Share2 } from 'lucide-react';
|
|
3
4
|
import Router from 'next/router';
|
|
4
|
-
import { memo } from 'react';
|
|
5
|
+
import { memo, useMemo } from 'react';
|
|
5
6
|
import { useTranslation } from 'react-i18next';
|
|
6
7
|
|
|
7
8
|
import HeaderTitle from '@/components/HeaderTitle';
|
|
@@ -9,6 +10,20 @@ import HeaderTitle from '@/components/HeaderTitle';
|
|
|
9
10
|
const Header = memo(() => {
|
|
10
11
|
const { t } = useTranslation('setting');
|
|
11
12
|
|
|
13
|
+
const items: MenuProps['items'] = useMemo(
|
|
14
|
+
() => [
|
|
15
|
+
{
|
|
16
|
+
key: 'agent',
|
|
17
|
+
label: <div>{t('exportType.agent', { ns: 'common' })}</div>,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
key: 'agentWithMessage',
|
|
21
|
+
label: <div>{t('exportType.agentWithMessage', { ns: 'common' })}</div>,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
[],
|
|
25
|
+
);
|
|
26
|
+
|
|
12
27
|
return (
|
|
13
28
|
<ChatHeader
|
|
14
29
|
left={<HeaderTitle title={t('header.session')} />}
|
|
@@ -16,11 +31,13 @@ const Header = memo(() => {
|
|
|
16
31
|
right={
|
|
17
32
|
<>
|
|
18
33
|
<ActionIcon icon={Share2} size={{ fontSize: 24 }} title={t('share', { ns: 'common' })} />
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
34
|
+
<Dropdown arrow={false} menu={{ items }} trigger={['click']}>
|
|
35
|
+
<ActionIcon
|
|
36
|
+
icon={FolderOutput}
|
|
37
|
+
size={{ fontSize: 24 }}
|
|
38
|
+
title={t('export', { ns: 'common' })}
|
|
39
|
+
/>
|
|
40
|
+
</Dropdown>
|
|
24
41
|
</>
|
|
25
42
|
}
|
|
26
43
|
showBackButton
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ChatHeader } from '@lobehub/ui';
|
|
2
|
+
import { Tag } from 'antd';
|
|
2
3
|
import Router from 'next/router';
|
|
3
4
|
import { memo } from 'react';
|
|
4
5
|
import { useTranslation } from 'react-i18next';
|
|
5
6
|
|
|
7
|
+
import { version } from '@/../package.json';
|
|
6
8
|
import HeaderTitle from '@/components/HeaderTitle';
|
|
7
9
|
|
|
8
10
|
const Header = memo(() => {
|
|
@@ -10,7 +12,7 @@ const Header = memo(() => {
|
|
|
10
12
|
|
|
11
13
|
return (
|
|
12
14
|
<ChatHeader
|
|
13
|
-
left={<HeaderTitle title={t('header.global')} />}
|
|
15
|
+
left={<HeaderTitle tag={<Tag>{`v${version}`}</Tag>} title={t('header.global')} />}
|
|
14
16
|
onBackClick={() => Router.back()}
|
|
15
17
|
showBackButton
|
|
16
18
|
/>
|