@lobehub/chat 0.116.0 → 0.116.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/CHANGELOG.md +50 -0
- package/README.md +3 -0
- package/package.json +2 -1
- package/src/app/chat/(mobile)/features/TopicList.tsx +6 -1
- package/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx +23 -77
- package/src/app/chat/features/ChatHeader/ShareButton/ShareModal.tsx +141 -0
- package/src/app/chat/features/ChatHeader/ShareButton/index.tsx +3 -11
- package/src/app/chat/features/ChatHeader/ShareButton/type.ts +14 -0
- package/src/app/chat/features/ChatHeader/ShareButton/useScreenshot.ts +60 -0
- package/src/app/chat/features/SystemRole/index.tsx +0 -1
- package/src/app/chat/features/TopicListContent/index.tsx +3 -9
- package/src/app/chat/settings/features/SubmitAgentButton/{Inner.tsx → SubmitAgentModal.tsx} +23 -17
- package/src/app/chat/settings/features/SubmitAgentButton/index.tsx +3 -10
- package/src/app/market/(mobile)/features/AgentDetail.tsx +7 -1
- package/src/app/market/features/ShareAgentButton/Inner.tsx +2 -3
- package/src/features/PluginDetailModal/index.tsx +27 -29
- package/src/features/PluginDevModal/PluginPreview.tsx +1 -1
- package/src/features/PluginDevModal/index.tsx +73 -76
- package/src/features/PluginSettings/PluginSettingRender.tsx +22 -2
- package/src/features/PluginSettings/index.tsx +7 -1
- package/src/features/PluginStore/InstalledPluginList.tsx +2 -2
- package/src/features/PluginStore/OnlineList.tsx +2 -2
- package/src/features/PluginStore/index.tsx +17 -22
- package/src/app/chat/features/ChatHeader/ShareButton/Inner.tsx +0 -125
- package/src/components/MobilePadding/index.tsx +0 -32
- package/src/features/PluginStore/StoreSetting.tsx +0 -56
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.116.2](https://github.com/lobehub/lobe-chat/compare/v0.116.1...v0.116.2)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-12-26**</sup>
|
|
8
|
+
|
|
9
|
+
#### 💄 Styles
|
|
10
|
+
|
|
11
|
+
- **misc**: Update Modal style.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Styles
|
|
19
|
+
|
|
20
|
+
- **misc**: Update Modal style ([ac7d309](https://github.com/lobehub/lobe-chat/commit/ac7d309))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 0.116.1](https://github.com/lobehub/lobe-chat/compare/v0.116.0...v0.116.1)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2023-12-26**</sup>
|
|
33
|
+
|
|
34
|
+
#### 💄 Styles
|
|
35
|
+
|
|
36
|
+
- **misc**: Support slider and select plugin setting render.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Styles
|
|
44
|
+
|
|
45
|
+
- **misc**: Support slider and select plugin setting render, closes [#819](https://github.com/lobehub/lobe-chat/issues/819) ([3190b44](https://github.com/lobehub/lobe-chat/commit/3190b44))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
## [Version 0.116.0](https://github.com/lobehub/lobe-chat/compare/v0.115.13...v0.116.0)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2023-12-26**</sup>
|
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ Supports one-click free deployment of your private ChatGPT/LLM web application.
|
|
|
37
37
|
[![][share-reddit-shield]][share-reddit-link]
|
|
38
38
|
[![][share-weibo-shield]][share-weibo-link]
|
|
39
39
|
[![][share-mastodon-shield]][share-mastodon-link]
|
|
40
|
+
[![][share-linkedin-shield]][share-linkedin-link]
|
|
40
41
|
|
|
41
42
|
<sup>Pioneering the new age of thinking and creating. Built for you, the Super Individual.</sup>
|
|
42
43
|
|
|
@@ -626,6 +627,8 @@ This project is [MIT](./LICENSE) licensed.
|
|
|
626
627
|
[pr-welcome-link]: https://github.com/lobehub/lobe-chat/pulls
|
|
627
628
|
[pr-welcome-shield]: https://img.shields.io/badge/🤯_pr_welcome-%E2%86%92-ffcb47?labelColor=black&style=for-the-badge
|
|
628
629
|
[profile-link]: https://github.com/lobehub
|
|
630
|
+
[share-linkedin-link]: https://linkedin.com/feed
|
|
631
|
+
[share-linkedin-shield]: https://img.shields.io/badge/-share%20on%20linkedin-black?labelColor=black&logo=linkedin&logoColor=white&style=flat-square
|
|
629
632
|
[share-mastodon-link]: https://mastodon.social/share?text=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source,%20extensible%20(Function%20Calling),%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT/LLM%20web%20application.%20https://github.com/lobehub/lobe-chat%20#chatbot%20#chatGPT%20#openAI
|
|
630
633
|
[share-mastodon-shield]: https://img.shields.io/badge/-share%20on%20mastodon-black?labelColor=black&logo=mastodon&logoColor=white&style=flat-square
|
|
631
634
|
[share-reddit-link]: https://www.reddit.com/submit?title=Check%20this%20GitHub%20repository%20out%20%F0%9F%A4%AF%20LobeChat%20-%20An%20open-source%2C%20extensible%20%28Function%20Calling%29%2C%20high-performance%20chatbot%20framework.%20It%20supports%20one-click%20free%20deployment%20of%20your%20private%20ChatGPT%2FLLM%20web%20application.%20%23chatbot%20%23chatGPT%20%23openAI&url=https%3A%2F%2Fgithub.com%2Flobehub%2Flobe-chat
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.116.
|
|
3
|
+
"version": "0.116.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",
|
|
@@ -140,6 +140,7 @@
|
|
|
140
140
|
"@testing-library/jest-dom": "^6",
|
|
141
141
|
"@testing-library/react": "^14",
|
|
142
142
|
"@types/chroma-js": "^2",
|
|
143
|
+
"@types/json-schema": "^7.0.15",
|
|
143
144
|
"@types/lodash": "^4",
|
|
144
145
|
"@types/lodash-es": "^4",
|
|
145
146
|
"@types/node": "^20",
|
|
@@ -15,7 +15,12 @@ const Topics = memo(() => {
|
|
|
15
15
|
const { t } = useTranslation('chat');
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
|
-
<Modal
|
|
18
|
+
<Modal
|
|
19
|
+
allowFullscreen
|
|
20
|
+
onCancel={() => toggleConfig(false)}
|
|
21
|
+
open={showAgentSettings}
|
|
22
|
+
title={t('topic.title')}
|
|
23
|
+
>
|
|
19
24
|
<TopicListContent mobile />
|
|
20
25
|
</Modal>
|
|
21
26
|
);
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { SiOpenai } from '@icons-pack/react-simple-icons';
|
|
2
2
|
import { Avatar, ChatHeaderTitle, Logo, Markdown, Tag } from '@lobehub/ui';
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import { domToJpeg, domToPng, domToSvg, domToWebp } from 'modern-screenshot';
|
|
6
|
-
import { memo, useCallback, useState } from 'react';
|
|
3
|
+
import { SegmentedProps } from 'antd';
|
|
4
|
+
import { memo } from 'react';
|
|
7
5
|
import { useTranslation } from 'react-i18next';
|
|
8
6
|
import { Flexbox } from 'react-layout-kit';
|
|
9
7
|
|
|
@@ -14,6 +12,7 @@ import { agentSelectors, sessionSelectors } from '@/store/session/selectors';
|
|
|
14
12
|
|
|
15
13
|
import PluginTag from '../../ChatHeader/PluginTag';
|
|
16
14
|
import { useStyles } from './style';
|
|
15
|
+
import { FieldType } from './type';
|
|
17
16
|
|
|
18
17
|
export enum ImageType {
|
|
19
18
|
JPG = 'jpg',
|
|
@@ -41,75 +40,25 @@ export const imageTypeOptions: SegmentedProps['options'] = [
|
|
|
41
40
|
},
|
|
42
41
|
];
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
agentSelectors.currentAgentAvatar(s),
|
|
59
|
-
agentSelectors.currentAgentBackgroundColor(s),
|
|
60
|
-
agentSelectors.currentAgentModel(s),
|
|
61
|
-
agentSelectors.currentAgentPlugins(s),
|
|
62
|
-
agentSelectors.currentAgentSystemRole(s),
|
|
63
|
-
]);
|
|
64
|
-
const { t } = useTranslation('chat');
|
|
65
|
-
const { styles } = useStyles(withBackground);
|
|
66
|
-
|
|
67
|
-
const displayTitle = isInbox ? t('inbox.title') : title;
|
|
68
|
-
const displayDesc = isInbox ? t('inbox.desc') : description;
|
|
43
|
+
const Preview = memo<FieldType & { title?: string }>(
|
|
44
|
+
({ title, withSystemRole, withBackground, withFooter }) => {
|
|
45
|
+
const [isInbox, description, avatar, backgroundColor, model, plugins, systemRole] =
|
|
46
|
+
useSessionStore((s) => [
|
|
47
|
+
sessionSelectors.isInboxSession(s),
|
|
48
|
+
agentSelectors.currentAgentDescription(s),
|
|
49
|
+
agentSelectors.currentAgentAvatar(s),
|
|
50
|
+
agentSelectors.currentAgentBackgroundColor(s),
|
|
51
|
+
agentSelectors.currentAgentModel(s),
|
|
52
|
+
agentSelectors.currentAgentPlugins(s),
|
|
53
|
+
agentSelectors.currentAgentSystemRole(s),
|
|
54
|
+
]);
|
|
55
|
+
const { t } = useTranslation('chat');
|
|
56
|
+
const { styles } = useStyles(withBackground);
|
|
69
57
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
let screenshotFn: any;
|
|
74
|
-
switch (imageType) {
|
|
75
|
-
case ImageType.JPG: {
|
|
76
|
-
screenshotFn = domToJpeg;
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
case ImageType.PNG: {
|
|
80
|
-
screenshotFn = domToPng;
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
case ImageType.SVG: {
|
|
84
|
-
screenshotFn = domToSvg;
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
case ImageType.WEBP: {
|
|
88
|
-
screenshotFn = domToWebp;
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
58
|
+
const displayTitle = isInbox ? t('inbox.title') : title;
|
|
59
|
+
const displayDesc = isInbox ? t('inbox.desc') : description;
|
|
92
60
|
|
|
93
|
-
|
|
94
|
-
features: {
|
|
95
|
-
// 不启用移除控制符,否则会导致 safari emoji 报错
|
|
96
|
-
removeControlCharacter: false,
|
|
97
|
-
},
|
|
98
|
-
scale: 2,
|
|
99
|
-
});
|
|
100
|
-
const link = document.createElement('a');
|
|
101
|
-
link.download = `LobeChat_${title}_${dayjs().format('YYYY-MM-DD')}.${imageType}`;
|
|
102
|
-
link.href = dataUrl;
|
|
103
|
-
link.click();
|
|
104
|
-
setLoading(false);
|
|
105
|
-
} catch (error) {
|
|
106
|
-
console.error('Failed to download image', error);
|
|
107
|
-
setLoading(false);
|
|
108
|
-
}
|
|
109
|
-
}, [imageType, title]);
|
|
110
|
-
|
|
111
|
-
return (
|
|
112
|
-
<>
|
|
61
|
+
return (
|
|
113
62
|
<div className={styles.preview}>
|
|
114
63
|
<div className={withBackground ? styles.background : undefined} id={'preview'}>
|
|
115
64
|
<Flexbox className={styles.container} gap={16}>
|
|
@@ -145,11 +94,8 @@ const Preview = memo<PreviewProps>(({ withSystemRole, imageType, withBackground,
|
|
|
145
94
|
</Flexbox>
|
|
146
95
|
</div>
|
|
147
96
|
</div>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
</>
|
|
152
|
-
);
|
|
153
|
-
});
|
|
97
|
+
);
|
|
98
|
+
},
|
|
99
|
+
);
|
|
154
100
|
|
|
155
101
|
export default Preview;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Form, type FormItemProps, Modal, type ModalProps } from '@lobehub/ui';
|
|
2
|
+
import { Button, Segmented, SegmentedProps, Switch } from 'antd';
|
|
3
|
+
import { memo, useMemo, useState } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import { useScreenshot } from '@/app/chat/features/ChatHeader/ShareButton/useScreenshot';
|
|
8
|
+
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
9
|
+
import { useChatStore } from '@/store/chat';
|
|
10
|
+
import { useGlobalStore } from '@/store/global';
|
|
11
|
+
|
|
12
|
+
import Preview, { ImageType, imageTypeOptions } from './Preview';
|
|
13
|
+
import { FieldType } from './type';
|
|
14
|
+
|
|
15
|
+
enum Tab {
|
|
16
|
+
Screenshot = 'screenshot',
|
|
17
|
+
ShareGPT = 'sharegpt',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const DEFAULT_FIELD_VALUE: FieldType = {
|
|
21
|
+
imageType: ImageType.JPG,
|
|
22
|
+
withBackground: true,
|
|
23
|
+
withFooter: false,
|
|
24
|
+
withPluginInfo: false,
|
|
25
|
+
withSystemRole: false,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const ShareModal = memo<ModalProps>(({ onCancel, open }) => {
|
|
29
|
+
const [fieldValue, setFieldValue] = useState<FieldType>(DEFAULT_FIELD_VALUE);
|
|
30
|
+
const [tab, setTab] = useState<Tab>(Tab.Screenshot);
|
|
31
|
+
const { t } = useTranslation('chat');
|
|
32
|
+
const avatar = useGlobalStore((s) => s.settings.avatar);
|
|
33
|
+
const [shareLoading, shareToShareGPT] = useChatStore((s) => [s.shareLoading, s.shareToShareGPT]);
|
|
34
|
+
const { loading, onDwnload, title } = useScreenshot(fieldValue.imageType);
|
|
35
|
+
|
|
36
|
+
const options: SegmentedProps['options'] = useMemo(
|
|
37
|
+
() => [
|
|
38
|
+
{
|
|
39
|
+
label: t('shareModal.screenshot'),
|
|
40
|
+
value: Tab.Screenshot,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: 'ShareGPT',
|
|
44
|
+
value: Tab.ShareGPT,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
[],
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const settings: FormItemProps[] = useMemo(
|
|
51
|
+
() =>
|
|
52
|
+
[
|
|
53
|
+
{
|
|
54
|
+
children: <Switch />,
|
|
55
|
+
label: t('shareModal.withSystemRole'),
|
|
56
|
+
minWidth: undefined,
|
|
57
|
+
name: 'withSystemRole',
|
|
58
|
+
valuePropName: 'checked',
|
|
59
|
+
},
|
|
60
|
+
tab === Tab.Screenshot && {
|
|
61
|
+
children: <Switch />,
|
|
62
|
+
label: t('shareModal.withBackground'),
|
|
63
|
+
minWidth: undefined,
|
|
64
|
+
name: 'withBackground',
|
|
65
|
+
valuePropName: 'checked',
|
|
66
|
+
},
|
|
67
|
+
tab === Tab.Screenshot && {
|
|
68
|
+
children: <Switch />,
|
|
69
|
+
label: t('shareModal.withFooter'),
|
|
70
|
+
minWidth: undefined,
|
|
71
|
+
name: 'withFooter',
|
|
72
|
+
valuePropName: 'checked',
|
|
73
|
+
},
|
|
74
|
+
tab === Tab.Screenshot && {
|
|
75
|
+
children: <Segmented options={imageTypeOptions} />,
|
|
76
|
+
label: t('shareModal.imageType'),
|
|
77
|
+
minWidth: undefined,
|
|
78
|
+
name: 'imageType',
|
|
79
|
+
},
|
|
80
|
+
tab === Tab.ShareGPT && {
|
|
81
|
+
children: <Switch />,
|
|
82
|
+
label: t('shareModal.withPluginInfo'),
|
|
83
|
+
minWidth: undefined,
|
|
84
|
+
name: 'withPluginInfo',
|
|
85
|
+
valuePropName: 'checked',
|
|
86
|
+
},
|
|
87
|
+
].filter(Boolean) as FormItemProps[],
|
|
88
|
+
[],
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Modal
|
|
93
|
+
allowFullscreen
|
|
94
|
+
centered={false}
|
|
95
|
+
footer={
|
|
96
|
+
<>
|
|
97
|
+
{tab === Tab.Screenshot && (
|
|
98
|
+
<Button block loading={loading} onClick={onDwnload} size={'large'} type={'primary'}>
|
|
99
|
+
{t('shareModal.download')}
|
|
100
|
+
</Button>
|
|
101
|
+
)}
|
|
102
|
+
{tab === Tab.ShareGPT && (
|
|
103
|
+
<Button
|
|
104
|
+
block
|
|
105
|
+
loading={shareLoading}
|
|
106
|
+
onClick={() => shareToShareGPT({ avatar, ...fieldValue })}
|
|
107
|
+
size={'large'}
|
|
108
|
+
type={'primary'}
|
|
109
|
+
>
|
|
110
|
+
{t('shareModal.shareToShareGPT')}
|
|
111
|
+
</Button>
|
|
112
|
+
)}
|
|
113
|
+
</>
|
|
114
|
+
}
|
|
115
|
+
maxHeight={false}
|
|
116
|
+
onCancel={onCancel}
|
|
117
|
+
open={open}
|
|
118
|
+
title={t('share', { ns: 'common' })}
|
|
119
|
+
>
|
|
120
|
+
<Flexbox gap={16}>
|
|
121
|
+
<Segmented
|
|
122
|
+
block
|
|
123
|
+
onChange={(value) => setTab(value as Tab)}
|
|
124
|
+
options={options}
|
|
125
|
+
style={{ width: '100%' }}
|
|
126
|
+
value={tab}
|
|
127
|
+
/>
|
|
128
|
+
<Form
|
|
129
|
+
initialValues={DEFAULT_FIELD_VALUE}
|
|
130
|
+
items={settings}
|
|
131
|
+
itemsType={'flat'}
|
|
132
|
+
onValuesChange={(_, v) => setFieldValue(v)}
|
|
133
|
+
{...FORM_STYLE}
|
|
134
|
+
/>
|
|
135
|
+
{tab === Tab.Screenshot && <Preview title={title} {...fieldValue} />}
|
|
136
|
+
</Flexbox>
|
|
137
|
+
</Modal>
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
export default ShareModal;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionIcon
|
|
1
|
+
import { ActionIcon } from '@lobehub/ui';
|
|
2
2
|
import { Share2 } from 'lucide-react';
|
|
3
3
|
import dynamic from 'next/dynamic';
|
|
4
4
|
import { memo } from 'react';
|
|
@@ -8,7 +8,7 @@ import useMergeState from 'use-merge-value';
|
|
|
8
8
|
import { DESKTOP_HEADER_ICON_SIZE, MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
|
9
9
|
import { useChatStore } from '@/store/chat';
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const ShareModal = dynamic(() => import('./ShareModal'));
|
|
12
12
|
interface ShareButtonProps {
|
|
13
13
|
mobile?: boolean;
|
|
14
14
|
open?: boolean;
|
|
@@ -34,15 +34,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
|
|
|
34
34
|
title={t('share')}
|
|
35
35
|
/>
|
|
36
36
|
|
|
37
|
-
<
|
|
38
|
-
centered={false}
|
|
39
|
-
footer={null}
|
|
40
|
-
onCancel={() => setIsModalOpen(false)}
|
|
41
|
-
open={isModalOpen}
|
|
42
|
-
title={t('share')}
|
|
43
|
-
>
|
|
44
|
-
<Inner />
|
|
45
|
-
</Modal>
|
|
37
|
+
<ShareModal onCancel={() => setIsModalOpen(false)} open={isModalOpen} />
|
|
46
38
|
</>
|
|
47
39
|
);
|
|
48
40
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export enum ImageType {
|
|
2
|
+
JPG = 'jpg',
|
|
3
|
+
PNG = 'png',
|
|
4
|
+
SVG = 'svg',
|
|
5
|
+
WEBP = 'webp',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type FieldType = {
|
|
9
|
+
imageType: ImageType;
|
|
10
|
+
withBackground: boolean;
|
|
11
|
+
withFooter: boolean;
|
|
12
|
+
withPluginInfo: boolean;
|
|
13
|
+
withSystemRole: boolean;
|
|
14
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import { domToJpeg, domToPng, domToSvg, domToWebp } from 'modern-screenshot';
|
|
3
|
+
import { useCallback, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import { useSessionStore } from '@/store/session';
|
|
6
|
+
import { agentSelectors } from '@/store/session/slices/agent';
|
|
7
|
+
|
|
8
|
+
import { ImageType } from './type';
|
|
9
|
+
|
|
10
|
+
export const useScreenshot = (imageType: ImageType) => {
|
|
11
|
+
const [loading, setLoading] = useState(false);
|
|
12
|
+
const title = useSessionStore(agentSelectors.currentAgentTitle);
|
|
13
|
+
|
|
14
|
+
const handleDownload = useCallback(async () => {
|
|
15
|
+
setLoading(true);
|
|
16
|
+
try {
|
|
17
|
+
let screenshotFn: any;
|
|
18
|
+
switch (imageType) {
|
|
19
|
+
case ImageType.JPG: {
|
|
20
|
+
screenshotFn = domToJpeg;
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
case ImageType.PNG: {
|
|
24
|
+
screenshotFn = domToPng;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
case ImageType.SVG: {
|
|
28
|
+
screenshotFn = domToSvg;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case ImageType.WEBP: {
|
|
32
|
+
screenshotFn = domToWebp;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const dataUrl = await screenshotFn(document.querySelector('#preview') as HTMLDivElement, {
|
|
38
|
+
features: {
|
|
39
|
+
// 不启用移除控制符,否则会导致 safari emoji 报错
|
|
40
|
+
removeControlCharacter: false,
|
|
41
|
+
},
|
|
42
|
+
scale: 2,
|
|
43
|
+
});
|
|
44
|
+
const link = document.createElement('a');
|
|
45
|
+
link.download = `LobeChat_${title}_${dayjs().format('YYYY-MM-DD')}.${imageType}`;
|
|
46
|
+
link.href = dataUrl;
|
|
47
|
+
link.click();
|
|
48
|
+
setLoading(false);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error('Failed to download image', error);
|
|
51
|
+
setLoading(false);
|
|
52
|
+
}
|
|
53
|
+
}, [imageType, title]);
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
loading,
|
|
57
|
+
onDwnload: handleDownload,
|
|
58
|
+
title,
|
|
59
|
+
};
|
|
60
|
+
};
|
|
@@ -7,17 +7,11 @@ import TopicSearchBar from './TopicSearchBar';
|
|
|
7
7
|
|
|
8
8
|
const TopicListContent = memo<{ mobile?: boolean }>(({ mobile }) => {
|
|
9
9
|
return (
|
|
10
|
-
<Flexbox height={'100%'} style={{ overflow: 'hidden' }}>
|
|
11
|
-
{mobile ?
|
|
12
|
-
<Flexbox padding={'12px 16px'}>
|
|
13
|
-
<TopicSearchBar />
|
|
14
|
-
</Flexbox>
|
|
15
|
-
) : (
|
|
16
|
-
<Header />
|
|
17
|
-
)}
|
|
10
|
+
<Flexbox gap={mobile ? 8 : 0} height={'100%'} style={{ overflow: 'hidden' }}>
|
|
11
|
+
{mobile ? <TopicSearchBar /> : <Header />}
|
|
18
12
|
<Flexbox
|
|
19
13
|
gap={16}
|
|
20
|
-
paddingInline={mobile ?
|
|
14
|
+
paddingInline={mobile ? 0 : 8}
|
|
21
15
|
style={{ overflowY: 'auto', paddingTop: 6, position: 'relative' }}
|
|
22
16
|
>
|
|
23
17
|
<Topic />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Alert } from '@lobehub/ui';
|
|
1
|
+
import { Alert, Modal, type ModalProps } from '@lobehub/ui';
|
|
2
2
|
import { Button, Divider, Input } from 'antd';
|
|
3
3
|
import { useTheme } from 'antd-style';
|
|
4
4
|
import isEqual from 'fast-deep-equal';
|
|
@@ -8,14 +8,13 @@ import { memo, useState } from 'react';
|
|
|
8
8
|
import { useTranslation } from 'react-i18next';
|
|
9
9
|
import { Flexbox } from 'react-layout-kit';
|
|
10
10
|
|
|
11
|
-
import MobilePadding from '@/components/MobilePadding';
|
|
12
11
|
import { AGENTS_INDEX_GITHUB_ISSUE } from '@/const/url';
|
|
13
12
|
import AgentInfo from '@/features/AgentInfo';
|
|
14
13
|
import { useGlobalStore } from '@/store/global';
|
|
15
14
|
import { useSessionStore } from '@/store/session';
|
|
16
15
|
import { agentSelectors } from '@/store/session/selectors';
|
|
17
16
|
|
|
18
|
-
const
|
|
17
|
+
const SubmitAgentModal = memo<ModalProps>(({ open, onCancel }) => {
|
|
19
18
|
const { t } = useTranslation('setting');
|
|
20
19
|
const [identifier, setIdentifier] = useState('');
|
|
21
20
|
const systemRole = useSessionStore(agentSelectors.currentAgentSystemRole);
|
|
@@ -54,8 +53,24 @@ const Inner = memo(() => {
|
|
|
54
53
|
};
|
|
55
54
|
|
|
56
55
|
return (
|
|
57
|
-
<
|
|
58
|
-
|
|
56
|
+
<Modal
|
|
57
|
+
allowFullscreen
|
|
58
|
+
footer={
|
|
59
|
+
<Button
|
|
60
|
+
block
|
|
61
|
+
disabled={!isMetaPass || !identifier}
|
|
62
|
+
onClick={handleSubmit}
|
|
63
|
+
size={'large'}
|
|
64
|
+
type={'primary'}
|
|
65
|
+
>
|
|
66
|
+
{t('submitAgentModal.button')}
|
|
67
|
+
</Button>
|
|
68
|
+
}
|
|
69
|
+
onCancel={onCancel}
|
|
70
|
+
open={open}
|
|
71
|
+
title={t('submitAgentModal.tooltips')}
|
|
72
|
+
>
|
|
73
|
+
<Flexbox gap={16}>
|
|
59
74
|
{!isMetaPass && (
|
|
60
75
|
<Alert message={t('submitAgentModal.metaMiss')} showIcon type={'warning'} />
|
|
61
76
|
)}
|
|
@@ -70,18 +85,9 @@ const Inner = memo(() => {
|
|
|
70
85
|
placeholder={t('submitAgentModal.placeholder')}
|
|
71
86
|
value={identifier}
|
|
72
87
|
/>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
disabled={!isMetaPass || !identifier}
|
|
76
|
-
onClick={handleSubmit}
|
|
77
|
-
size={'large'}
|
|
78
|
-
type={'primary'}
|
|
79
|
-
>
|
|
80
|
-
{t('submitAgentModal.button')}
|
|
81
|
-
</Button>
|
|
82
|
-
</MobilePadding>
|
|
83
|
-
</Flexbox>
|
|
88
|
+
</Flexbox>
|
|
89
|
+
</Modal>
|
|
84
90
|
);
|
|
85
91
|
});
|
|
86
92
|
|
|
87
|
-
export default
|
|
93
|
+
export default SubmitAgentModal;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionIcon
|
|
1
|
+
import { ActionIcon } from '@lobehub/ui';
|
|
2
2
|
import { useResponsive } from 'antd-style';
|
|
3
3
|
import { Share2 } from 'lucide-react';
|
|
4
4
|
import { memo, useState } from 'react';
|
|
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
|
|
7
7
|
import { HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
|
8
8
|
|
|
9
|
-
import
|
|
9
|
+
import SubmitAgentModal from './SubmitAgentModal';
|
|
10
10
|
|
|
11
11
|
const SubmitAgentButton = memo(() => {
|
|
12
12
|
const { t } = useTranslation('setting');
|
|
@@ -20,14 +20,7 @@ const SubmitAgentButton = memo(() => {
|
|
|
20
20
|
size={HEADER_ICON_SIZE(mobile)}
|
|
21
21
|
title={t('submitAgentModal.tooltips')}
|
|
22
22
|
/>
|
|
23
|
-
<
|
|
24
|
-
footer={null}
|
|
25
|
-
onCancel={() => setIsModalOpen(false)}
|
|
26
|
-
open={isModalOpen}
|
|
27
|
-
title={t('submitAgentModal.tooltips')}
|
|
28
|
-
>
|
|
29
|
-
<Inner />
|
|
30
|
-
</Modal>
|
|
23
|
+
<SubmitAgentModal onCancel={() => setIsModalOpen(false)} open={isModalOpen} />
|
|
31
24
|
</>
|
|
32
25
|
);
|
|
33
26
|
});
|
|
@@ -15,7 +15,13 @@ const AgentDetail = memo(() => {
|
|
|
15
15
|
const { t } = useTranslation('market');
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
|
-
<Modal
|
|
18
|
+
<Modal
|
|
19
|
+
allowFullscreen
|
|
20
|
+
onCancel={deactivateAgent}
|
|
21
|
+
open={showAgentSidebar}
|
|
22
|
+
styles={{ body: { padding: 0 } }}
|
|
23
|
+
title={t('sidebar.title')}
|
|
24
|
+
>
|
|
19
25
|
<AgentDetailContent />
|
|
20
26
|
</Modal>
|
|
21
27
|
);
|
|
@@ -5,13 +5,12 @@ import Image from 'next/image';
|
|
|
5
5
|
import { memo } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
|
|
8
|
-
import MobilePadding from '@/components/MobilePadding';
|
|
9
8
|
import { AGENTS_INDEX_GITHUB } from '@/const/url';
|
|
10
9
|
|
|
11
10
|
const Inner = memo(() => {
|
|
12
11
|
const { t } = useTranslation('market');
|
|
13
12
|
return (
|
|
14
|
-
|
|
13
|
+
<>
|
|
15
14
|
<Image
|
|
16
15
|
alt={'banner'}
|
|
17
16
|
height={602}
|
|
@@ -46,7 +45,7 @@ const Inner = memo(() => {
|
|
|
46
45
|
>
|
|
47
46
|
{t('guide.func2.button')}
|
|
48
47
|
</Button>
|
|
49
|
-
|
|
48
|
+
</>
|
|
50
49
|
);
|
|
51
50
|
});
|
|
52
51
|
|