@lobehub/chat 0.151.9 → 0.151.11
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/locales/ar/common.json +5 -0
- package/locales/bg-BG/common.json +5 -0
- package/locales/de-DE/common.json +5 -0
- package/locales/en-US/common.json +5 -0
- package/locales/es-ES/common.json +5 -0
- package/locales/fr-FR/common.json +5 -0
- package/locales/it-IT/common.json +5 -0
- package/locales/ja-JP/common.json +5 -0
- package/locales/ko-KR/common.json +5 -0
- package/locales/nl-NL/common.json +5 -0
- package/locales/pl-PL/common.json +5 -0
- package/locales/pt-BR/common.json +5 -0
- package/locales/ru-RU/common.json +5 -0
- package/locales/tr-TR/common.json +5 -0
- package/locales/vi-VN/common.json +5 -0
- package/locales/zh-CN/common.json +5 -0
- package/locales/zh-TW/common.json +5 -0
- package/package.json +32 -32
- package/src/app/(main)/chat/features/TelemetryNotification/index.tsx +3 -1
- package/src/app/(main)/settings/agent/Agent.tsx +1 -3
- package/src/app/(main)/welcome/_layout/Desktop.tsx +21 -19
- package/src/app/(main)/welcome/_layout/Mobile.tsx +9 -6
- package/src/app/(main)/welcome/features/Actions.tsx +39 -0
- package/src/app/(main)/welcome/features/Hero.tsx +63 -0
- package/src/app/(main)/welcome/features/Logo.tsx +30 -0
- package/src/app/(main)/welcome/{layout.ts → layout.tsx} +2 -0
- package/src/app/(main)/welcome/page.tsx +16 -9
- package/src/const/url.ts +3 -0
- package/src/features/ChatInput/ActionBar/Temperature.tsx +1 -1
- package/src/features/Follow/index.tsx +64 -0
- package/src/locales/default/common.ts +7 -0
- package/src/services/session/client.test.ts +26 -0
- package/src/services/session/client.ts +1 -1
- package/src/store/global/action.test.ts +38 -0
- package/src/store/global/action.ts +6 -3
- package/src/store/user/slices/preference/action.test.ts +22 -1
- package/src/store/user/slices/preference/action.ts +1 -3
- package/src/store/user/slices/preference/initialState.ts +2 -0
- package/src/store/user/slices/preference/selectors.ts +2 -0
- package/src/store/user/slices/settings/actions/llm.test.ts +3 -9
- package/src/store/user/slices/settings/selectors/settings.ts +3 -1
- package/src/app/(main)/welcome/(desktop)/features/Footer.tsx +0 -45
- package/src/app/(main)/welcome/(desktop)/features/Showcase.tsx +0 -23
- package/src/app/(main)/welcome/(desktop)/index.tsx +0 -17
- package/src/app/(main)/welcome/(mobile)/index.tsx +0 -16
- package/src/app/(main)/welcome/features/Banner/AgentCard.tsx +0 -71
- package/src/app/(main)/welcome/features/Banner/AgentTemplate.tsx +0 -43
- package/src/app/(main)/welcome/features/Banner/Hero.tsx +0 -50
- package/src/app/(main)/welcome/features/Banner/index.tsx +0 -56
- package/src/app/(main)/welcome/features/Banner/style.ts +0 -71
|
@@ -4,6 +4,7 @@ import { withSWR } from '~test-utils';
|
|
|
4
4
|
|
|
5
5
|
import { globalService } from '@/services/global';
|
|
6
6
|
import { useGlobalStore } from '@/store/global/index';
|
|
7
|
+
import { initialState } from '@/store/global/initialState';
|
|
7
8
|
|
|
8
9
|
vi.mock('zustand/traditional');
|
|
9
10
|
|
|
@@ -141,4 +142,41 @@ describe('createPreferenceSlice', () => {
|
|
|
141
142
|
expect(useGlobalStore.getState().latestVersion).toBe(latestVersion);
|
|
142
143
|
});
|
|
143
144
|
});
|
|
145
|
+
|
|
146
|
+
describe('useInitGlobalPreference', () => {
|
|
147
|
+
it('should init global preference if there is empty object', async () => {
|
|
148
|
+
vi.spyOn(
|
|
149
|
+
useGlobalStore.getState().preferenceStorage,
|
|
150
|
+
'getFromLocalStorage',
|
|
151
|
+
).mockReturnValueOnce({} as any);
|
|
152
|
+
|
|
153
|
+
const { result } = renderHook(() => useGlobalStore().useInitGlobalPreference(), {
|
|
154
|
+
wrapper: withSWR,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
await waitFor(() => {
|
|
158
|
+
expect(result.current.data).toEqual({});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
expect(useGlobalStore.getState().preference).toEqual(initialState.preference);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should update with data', async () => {
|
|
165
|
+
const { result } = renderHook(() => useGlobalStore());
|
|
166
|
+
vi.spyOn(
|
|
167
|
+
useGlobalStore.getState().preferenceStorage,
|
|
168
|
+
'getFromLocalStorage',
|
|
169
|
+
).mockReturnValueOnce({ inputHeight: 300 } as any);
|
|
170
|
+
|
|
171
|
+
const { result: hooks } = renderHook(() => result.current.useInitGlobalPreference(), {
|
|
172
|
+
wrapper: withSWR,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
await waitFor(() => {
|
|
176
|
+
expect(hooks.current.data).toEqual({ inputHeight: 300 });
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
expect(result.current.preference.inputHeight).toEqual(300);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
144
182
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import isEqual from 'fast-deep-equal';
|
|
1
2
|
import { produce } from 'immer';
|
|
2
3
|
import { gt } from 'semver';
|
|
3
4
|
import useSWR, { SWRResponse } from 'swr';
|
|
@@ -94,9 +95,11 @@ export const globalActionSlice: StateCreator<
|
|
|
94
95
|
() => get().preferenceStorage.getFromLocalStorage(),
|
|
95
96
|
{
|
|
96
97
|
onSuccess: (preference) => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
const nextPreference = merge(get().preference, preference);
|
|
99
|
+
|
|
100
|
+
if (isEqual(get().preference, nextPreference)) return;
|
|
101
|
+
|
|
102
|
+
set({ preference: nextPreference }, false, n('initPreference'));
|
|
100
103
|
},
|
|
101
104
|
},
|
|
102
105
|
),
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { act, renderHook } from '@testing-library/react';
|
|
1
|
+
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { withSWR } from '~test-utils';
|
|
3
4
|
|
|
5
|
+
import { globalService } from '@/services/global';
|
|
4
6
|
import { useUserStore } from '@/store/user';
|
|
5
7
|
|
|
6
8
|
import { type Guide } from './initialState';
|
|
@@ -38,4 +40,23 @@ describe('createPreferenceSlice', () => {
|
|
|
38
40
|
expect(result.current.preference.hideSyncAlert).toEqual(true);
|
|
39
41
|
});
|
|
40
42
|
});
|
|
43
|
+
|
|
44
|
+
describe('useInitPreference', () => {
|
|
45
|
+
it('should return false when userId is empty', async () => {
|
|
46
|
+
const { result } = renderHook(() => useUserStore());
|
|
47
|
+
|
|
48
|
+
vi.spyOn(result.current.preferenceStorage, 'getFromLocalStorage').mockResolvedValueOnce(
|
|
49
|
+
{} as any,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const { result: prefernce } = renderHook(() => result.current.useInitPreference(), {
|
|
53
|
+
wrapper: withSWR,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
await waitFor(() => {
|
|
57
|
+
expect(prefernce.current.data).toEqual({});
|
|
58
|
+
expect(result.current.isPreferenceInit).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
41
62
|
});
|
|
@@ -41,9 +41,7 @@ export const createPreferenceSlice: StateCreator<
|
|
|
41
41
|
() => get().preferenceStorage.getFromLocalStorage(),
|
|
42
42
|
{
|
|
43
43
|
onSuccess: (preference) => {
|
|
44
|
-
|
|
45
|
-
set({ preference }, false, n('initPreference'));
|
|
46
|
-
}
|
|
44
|
+
set({ isPreferenceInit: true, preference }, false, n('initPreference'));
|
|
47
45
|
},
|
|
48
46
|
},
|
|
49
47
|
),
|
|
@@ -16,6 +16,7 @@ export interface UserPreference {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export interface UserPreferenceState {
|
|
19
|
+
isPreferenceInit: boolean;
|
|
19
20
|
/**
|
|
20
21
|
* the user preference, which only store in local storage
|
|
21
22
|
*/
|
|
@@ -24,6 +25,7 @@ export interface UserPreferenceState {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export const initialPreferenceState: UserPreferenceState = {
|
|
28
|
+
isPreferenceInit: false,
|
|
27
29
|
preference: {
|
|
28
30
|
guide: {},
|
|
29
31
|
telemetry: null,
|
|
@@ -5,9 +5,11 @@ const useCmdEnterToSend = (s: UserStore): boolean => s.preference.useCmdEnterToS
|
|
|
5
5
|
const userAllowTrace = (s: UserStore) => s.preference.telemetry;
|
|
6
6
|
|
|
7
7
|
const hideSyncAlert = (s: UserStore) => s.preference.hideSyncAlert;
|
|
8
|
+
const isPreferenceInit = (s: UserStore) => s.isPreferenceInit;
|
|
8
9
|
|
|
9
10
|
export const preferenceSelectors = {
|
|
10
11
|
hideSyncAlert,
|
|
12
|
+
isPreferenceInit,
|
|
11
13
|
useCmdEnterToSend,
|
|
12
14
|
userAllowTrace,
|
|
13
15
|
};
|
|
@@ -2,17 +2,11 @@ import { act, renderHook } from '@testing-library/react';
|
|
|
2
2
|
import { describe, expect, it, vi } from 'vitest';
|
|
3
3
|
|
|
4
4
|
import { userService } from '@/services/user';
|
|
5
|
-
import {
|
|
6
|
-
import { UserSettingsState, initialSettingsState } from '@/store/user/slices/settings/initialState';
|
|
7
|
-
import {
|
|
8
|
-
modelConfigSelectors,
|
|
9
|
-
modelProviderSelectors,
|
|
10
|
-
settingsSelectors,
|
|
11
|
-
} from '@/store/user/slices/settings/selectors';
|
|
5
|
+
import { useUserStore } from '@/store/user';
|
|
12
6
|
import { GeneralModelProviderConfig } from '@/types/settings';
|
|
13
|
-
import { merge } from '@/utils/merge';
|
|
14
7
|
|
|
15
|
-
import { CustomModelCardDispatch
|
|
8
|
+
import { CustomModelCardDispatch } from '../reducers/customModelCard';
|
|
9
|
+
import { modelProviderSelectors, settingsSelectors } from '../selectors';
|
|
16
10
|
|
|
17
11
|
// Mock userService
|
|
18
12
|
vi.mock('@/services/user', () => ({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_LANG } from '@/const/locale';
|
|
2
2
|
import { DEFAULT_AGENT_META } from '@/const/meta';
|
|
3
|
-
import { DEFAULT_AGENT, DEFAULT_TTS_CONFIG } from '@/const/settings';
|
|
3
|
+
import { DEFAULT_AGENT, DEFAULT_AGENT_CONFIG, DEFAULT_TTS_CONFIG } from '@/const/settings';
|
|
4
4
|
import { Locales } from '@/locales/resources';
|
|
5
5
|
import { GeneralModelProviderConfig, GlobalLLMProviderKey, GlobalSettings } from '@/types/settings';
|
|
6
6
|
import { isOnServerSide } from '@/utils/env';
|
|
@@ -21,6 +21,7 @@ const password = (s: UserStore) => currentSettings(s).password;
|
|
|
21
21
|
const currentTTS = (s: UserStore) => merge(DEFAULT_TTS_CONFIG, currentSettings(s).tts);
|
|
22
22
|
|
|
23
23
|
const defaultAgent = (s: UserStore) => merge(DEFAULT_AGENT, currentSettings(s).defaultAgent);
|
|
24
|
+
const defaultAgentConfig = (s: UserStore) => merge(DEFAULT_AGENT_CONFIG, defaultAgent(s).config);
|
|
24
25
|
|
|
25
26
|
const defaultAgentMeta = (s: UserStore) => merge(DEFAULT_AGENT_META, defaultAgent(s).meta);
|
|
26
27
|
|
|
@@ -53,6 +54,7 @@ export const settingsSelectors = {
|
|
|
53
54
|
currentTTS,
|
|
54
55
|
dalleConfig,
|
|
55
56
|
defaultAgent,
|
|
57
|
+
defaultAgentConfig,
|
|
56
58
|
defaultAgentMeta,
|
|
57
59
|
exportSettings,
|
|
58
60
|
isDalleAutoGenerating,
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { ActionIcon, DiscordIcon } from '@lobehub/ui';
|
|
4
|
-
import { useTheme } from 'antd-style';
|
|
5
|
-
import { Book, Github } from 'lucide-react';
|
|
6
|
-
import { memo } from 'react';
|
|
7
|
-
import { useTranslation } from 'react-i18next';
|
|
8
|
-
import { Flexbox } from 'react-layout-kit';
|
|
9
|
-
|
|
10
|
-
import { DISCORD, DOCUMENTS, GITHUB } from '@/const/url';
|
|
11
|
-
|
|
12
|
-
const Footer = memo(() => {
|
|
13
|
-
const theme = useTheme();
|
|
14
|
-
const { t } = useTranslation('common');
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<Flexbox align={'center'} horizontal justify={'space-between'} style={{ padding: 16 }}>
|
|
18
|
-
<span style={{ color: theme.colorTextDescription }}>
|
|
19
|
-
© 2023 - {new Date().getFullYear()} LobeHub, LLC
|
|
20
|
-
</span>
|
|
21
|
-
<Flexbox horizontal>
|
|
22
|
-
<ActionIcon
|
|
23
|
-
icon={DiscordIcon}
|
|
24
|
-
onClick={() => window.open(DISCORD, '__blank')}
|
|
25
|
-
size={'site'}
|
|
26
|
-
title={'Discord'}
|
|
27
|
-
/>
|
|
28
|
-
<ActionIcon
|
|
29
|
-
icon={Book}
|
|
30
|
-
onClick={() => window.open(DOCUMENTS, '__blank')}
|
|
31
|
-
size={'site'}
|
|
32
|
-
title={t('document')}
|
|
33
|
-
/>
|
|
34
|
-
<ActionIcon
|
|
35
|
-
icon={Github}
|
|
36
|
-
onClick={() => window.open(GITHUB, '__blank')}
|
|
37
|
-
size={'site'}
|
|
38
|
-
title={'GitHub'}
|
|
39
|
-
/>
|
|
40
|
-
</Flexbox>
|
|
41
|
-
</Flexbox>
|
|
42
|
-
);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
export default Footer;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { GridShowcase } from '@lobehub/ui';
|
|
4
|
-
import { memo } from 'react';
|
|
5
|
-
import { Flexbox } from 'react-layout-kit';
|
|
6
|
-
|
|
7
|
-
import Banner from '@/app/(main)/welcome/features/Banner';
|
|
8
|
-
|
|
9
|
-
const Showcase = memo(() => (
|
|
10
|
-
<Flexbox
|
|
11
|
-
flex={1}
|
|
12
|
-
justify={'center'}
|
|
13
|
-
style={{ height: '100%', position: 'relative', width: '100%' }}
|
|
14
|
-
>
|
|
15
|
-
<GridShowcase>
|
|
16
|
-
<Banner />
|
|
17
|
-
</GridShowcase>
|
|
18
|
-
{/*TODO:暂时隐藏,待模板完成后再补回*/}
|
|
19
|
-
{/*<AgentTemplate width={width} />*/}
|
|
20
|
-
</Flexbox>
|
|
21
|
-
));
|
|
22
|
-
|
|
23
|
-
export default Showcase;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { memo } from 'react';
|
|
4
|
-
|
|
5
|
-
import ClientResponsiveContent from '@/components/client/ClientResponsiveContent';
|
|
6
|
-
|
|
7
|
-
import Footer from './features/Footer';
|
|
8
|
-
import Showcase from './features/Showcase';
|
|
9
|
-
|
|
10
|
-
const Desktop = memo(() => (
|
|
11
|
-
<>
|
|
12
|
-
<Showcase />
|
|
13
|
-
<Footer />
|
|
14
|
-
</>
|
|
15
|
-
));
|
|
16
|
-
|
|
17
|
-
export default ClientResponsiveContent({ Desktop, Mobile: () => import('../(mobile)') });
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { memo } from 'react';
|
|
2
|
-
import { Center, Flexbox } from 'react-layout-kit';
|
|
3
|
-
|
|
4
|
-
import Banner from '../features/Banner';
|
|
5
|
-
|
|
6
|
-
const Showcase = memo(() => (
|
|
7
|
-
<Flexbox align={'center'} justify={'center'} style={{ height: 'calc(100% - 44px)' }}>
|
|
8
|
-
<Center gap={16}>
|
|
9
|
-
<Banner mobile />
|
|
10
|
-
</Center>
|
|
11
|
-
{/*TODO:暂时隐藏,待模板完成后再补回*/}
|
|
12
|
-
{/*<AgentTemplate width={width} />*/}
|
|
13
|
-
</Flexbox>
|
|
14
|
-
));
|
|
15
|
-
|
|
16
|
-
export default Showcase;
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { Avatar, Spotlight } from '@lobehub/ui';
|
|
2
|
-
import { Typography } from 'antd';
|
|
3
|
-
import { createStyles } from 'antd-style';
|
|
4
|
-
import { rgba } from 'polished';
|
|
5
|
-
import { memo } from 'react';
|
|
6
|
-
import { Flexbox } from 'react-layout-kit';
|
|
7
|
-
|
|
8
|
-
import { LobeAgentSession } from '@/types/session';
|
|
9
|
-
|
|
10
|
-
const { Paragraph, Title } = Typography;
|
|
11
|
-
|
|
12
|
-
const useStyles = createStyles(({ css, token, cx, stylish }) => ({
|
|
13
|
-
container: cx(
|
|
14
|
-
stylish.blur,
|
|
15
|
-
css`
|
|
16
|
-
cursor: pointer;
|
|
17
|
-
|
|
18
|
-
position: relative;
|
|
19
|
-
|
|
20
|
-
overflow: hidden;
|
|
21
|
-
flex: 1;
|
|
22
|
-
|
|
23
|
-
padding: 16px;
|
|
24
|
-
|
|
25
|
-
background-color: ${rgba(token.colorBgContainer, 0.5)};
|
|
26
|
-
border: 1px solid ${rgba(token.colorText, 0.2)};
|
|
27
|
-
border-radius: ${token.borderRadiusLG}px;
|
|
28
|
-
|
|
29
|
-
transition: all 400ms ${token.motionEaseOut};
|
|
30
|
-
|
|
31
|
-
&:hover {
|
|
32
|
-
background-color: ${rgba(token.colorBgElevated, 0.2)};
|
|
33
|
-
border-color: ${token.colorText};
|
|
34
|
-
box-shadow: 0 0 0 1px ${token.colorText};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
,
|
|
38
|
-
&:active {
|
|
39
|
-
scale: 0.98;
|
|
40
|
-
}
|
|
41
|
-
`,
|
|
42
|
-
),
|
|
43
|
-
desc: css`
|
|
44
|
-
margin: 0 !important;
|
|
45
|
-
`,
|
|
46
|
-
title: css`
|
|
47
|
-
margin: 0 !important;
|
|
48
|
-
`,
|
|
49
|
-
}));
|
|
50
|
-
|
|
51
|
-
export interface AgentCardProps {
|
|
52
|
-
meta: LobeAgentSession['meta'];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const AgentCard = memo<AgentCardProps>(({ meta }) => {
|
|
56
|
-
const { styles } = useStyles();
|
|
57
|
-
return (
|
|
58
|
-
<Flexbox className={styles.container} gap={8}>
|
|
59
|
-
<Spotlight size={200} />
|
|
60
|
-
<Avatar avatar={meta.avatar} background={meta.backgroundColor} />
|
|
61
|
-
<Title className={styles.title} ellipsis level={5}>
|
|
62
|
-
{meta.title}
|
|
63
|
-
</Title>
|
|
64
|
-
<Paragraph className={styles.desc} ellipsis={{ rows: 2 }} type="secondary">
|
|
65
|
-
{meta.description}
|
|
66
|
-
</Paragraph>
|
|
67
|
-
</Flexbox>
|
|
68
|
-
);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
export default AgentCard;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { useResponsive } from 'antd-style';
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
import { Flexbox } from 'react-layout-kit';
|
|
4
|
-
|
|
5
|
-
import AgentCard, { type AgentCardProps } from './AgentCard';
|
|
6
|
-
import { useStyles } from './style';
|
|
7
|
-
|
|
8
|
-
const items: AgentCardProps['meta'][] = [
|
|
9
|
-
{
|
|
10
|
-
avatar: '😀',
|
|
11
|
-
description: 'dddddd',
|
|
12
|
-
title: 'Title',
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
avatar: '😀',
|
|
16
|
-
description: 'dddddd',
|
|
17
|
-
title: 'Title',
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
avatar: '😀',
|
|
21
|
-
description: 'dddddd',
|
|
22
|
-
title: 'Title',
|
|
23
|
-
},
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
const AgentTemplate = memo<{ width: number }>(({ width }) => {
|
|
27
|
-
const { styles } = useStyles();
|
|
28
|
-
const { mobile } = useResponsive();
|
|
29
|
-
return (
|
|
30
|
-
<Flexbox
|
|
31
|
-
className={styles.templateContainer}
|
|
32
|
-
gap={16}
|
|
33
|
-
horizontal={!mobile}
|
|
34
|
-
style={{ marginTop: -width / 20 }}
|
|
35
|
-
>
|
|
36
|
-
{items.map((meta, index) => (
|
|
37
|
-
<AgentCard key={index} meta={meta} />
|
|
38
|
-
))}
|
|
39
|
-
</Flexbox>
|
|
40
|
-
);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
export default AgentTemplate;
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import dynamic from 'next/dynamic';
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
import { useTranslation } from 'react-i18next';
|
|
4
|
-
import { Flexbox } from 'react-layout-kit';
|
|
5
|
-
|
|
6
|
-
import { genSize, useStyles } from './style';
|
|
7
|
-
|
|
8
|
-
const LogoThree = dynamic(() => import('@lobehub/ui/es/LogoThree'));
|
|
9
|
-
const LogoSpline = dynamic(() => import('@lobehub/ui/es/LogoThree/LogoSpline'));
|
|
10
|
-
|
|
11
|
-
const Hero = memo<{ mobile?: boolean; width: number }>(({ width, mobile }) => {
|
|
12
|
-
const size: any = {
|
|
13
|
-
base: genSize(width / 3.5, 240),
|
|
14
|
-
desc: genSize(width / 50, 14),
|
|
15
|
-
logo: genSize(width / 2.5, 180),
|
|
16
|
-
title: genSize(width / 20, 32),
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
size.marginTop = mobile ? -size.logo / 9 : -size.logo / 3;
|
|
20
|
-
size.marginBottom = mobile ? -size.logo / 9 : -size.logo / 4;
|
|
21
|
-
|
|
22
|
-
const { styles } = useStyles(size.base);
|
|
23
|
-
|
|
24
|
-
const { t } = useTranslation('welcome');
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<>
|
|
28
|
-
<Flexbox
|
|
29
|
-
style={{
|
|
30
|
-
height: size.logo,
|
|
31
|
-
marginBottom: size.marginBottom,
|
|
32
|
-
marginTop: size.marginTop,
|
|
33
|
-
position: 'relative',
|
|
34
|
-
}}
|
|
35
|
-
>
|
|
36
|
-
{mobile ? <LogoThree size={size.logo} /> : <LogoSpline height={'100%'} width={'100%'} />}
|
|
37
|
-
</Flexbox>
|
|
38
|
-
<div className={styles.title} style={{ fontSize: size.title }}>
|
|
39
|
-
<strong style={mobile ? { fontSize: '1.2em' } : {}}>LobeChat</strong>
|
|
40
|
-
{mobile ? <br /> : ' '}
|
|
41
|
-
{t('slogan.title')}
|
|
42
|
-
</div>
|
|
43
|
-
<div className={styles.desc} style={{ fontSize: size.desc }}>
|
|
44
|
-
{t('slogan.desc1')}
|
|
45
|
-
</div>
|
|
46
|
-
</>
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
export default Hero;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { Icon } from '@lobehub/ui';
|
|
4
|
-
import { Button } from 'antd';
|
|
5
|
-
import { SendHorizonal } from 'lucide-react';
|
|
6
|
-
import Link from 'next/link';
|
|
7
|
-
import { useRouter } from 'next/navigation';
|
|
8
|
-
import { memo } from 'react';
|
|
9
|
-
import { useTranslation } from 'react-i18next';
|
|
10
|
-
import { Flexbox } from 'react-layout-kit';
|
|
11
|
-
|
|
12
|
-
import { useGlobalStore } from '@/store/global';
|
|
13
|
-
|
|
14
|
-
import Hero from './Hero';
|
|
15
|
-
import { useStyles } from './style';
|
|
16
|
-
|
|
17
|
-
const Banner = memo<{ mobile?: boolean }>(({ mobile }) => {
|
|
18
|
-
const { t } = useTranslation('welcome');
|
|
19
|
-
const router = useRouter();
|
|
20
|
-
const { styles } = useStyles();
|
|
21
|
-
const [switchBackToChat, isMobile] = useGlobalStore((s) => [s.switchBackToChat, s.isMobile]);
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<>
|
|
25
|
-
<div className={styles.container}>
|
|
26
|
-
<Hero mobile={mobile} width={mobile ? 640 : 1024} />
|
|
27
|
-
</div>
|
|
28
|
-
<Flexbox
|
|
29
|
-
className={styles.buttonGroup}
|
|
30
|
-
gap={16}
|
|
31
|
-
horizontal={!mobile}
|
|
32
|
-
justify={'center'}
|
|
33
|
-
width={'100%'}
|
|
34
|
-
>
|
|
35
|
-
<Link href={'/market'}>
|
|
36
|
-
<Button block={mobile} size={'large'} type={'default'}>
|
|
37
|
-
{t('button.market')}
|
|
38
|
-
</Button>
|
|
39
|
-
</Link>
|
|
40
|
-
<Button
|
|
41
|
-
block={mobile}
|
|
42
|
-
onClick={() => (isMobile ? router.push('/chat') : switchBackToChat())}
|
|
43
|
-
size={'large'}
|
|
44
|
-
type={'primary'}
|
|
45
|
-
>
|
|
46
|
-
<Flexbox align={'center'} gap={4} horizontal justify={'center'}>
|
|
47
|
-
{t('button.start')}
|
|
48
|
-
<Icon icon={SendHorizonal} />
|
|
49
|
-
</Flexbox>
|
|
50
|
-
</Button>
|
|
51
|
-
</Flexbox>
|
|
52
|
-
</>
|
|
53
|
-
);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
export default Banner;
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { createStyles } from 'antd-style';
|
|
2
|
-
import { rgba } from 'polished';
|
|
3
|
-
|
|
4
|
-
export const useStyles = createStyles(({ css, token, stylish, cx, prefixCls }) => {
|
|
5
|
-
return {
|
|
6
|
-
buttonGroup: css`
|
|
7
|
-
.${prefixCls}-upload {
|
|
8
|
-
width: 100% !important;
|
|
9
|
-
}
|
|
10
|
-
`,
|
|
11
|
-
container: css`
|
|
12
|
-
z-index: 10;
|
|
13
|
-
|
|
14
|
-
display: flex;
|
|
15
|
-
flex-direction: column;
|
|
16
|
-
align-items: center;
|
|
17
|
-
|
|
18
|
-
width: 100%;
|
|
19
|
-
margin-bottom: 24px;
|
|
20
|
-
`,
|
|
21
|
-
desc: css`
|
|
22
|
-
font-weight: 400;
|
|
23
|
-
color: ${rgba(token.colorText, 0.8)};
|
|
24
|
-
text-align: center;
|
|
25
|
-
`,
|
|
26
|
-
layout: css`
|
|
27
|
-
background: ${token.colorBgContainer};
|
|
28
|
-
`,
|
|
29
|
-
logo: css`
|
|
30
|
-
position: absolute;
|
|
31
|
-
top: 16px;
|
|
32
|
-
left: 16px;
|
|
33
|
-
fill: ${token.colorText};
|
|
34
|
-
`,
|
|
35
|
-
note: css`
|
|
36
|
-
z-index: 10;
|
|
37
|
-
margin-top: 16px;
|
|
38
|
-
color: ${token.colorTextDescription};
|
|
39
|
-
`,
|
|
40
|
-
skip: css`
|
|
41
|
-
color: ${token.colorTextDescription};
|
|
42
|
-
`,
|
|
43
|
-
templateContainer: css`
|
|
44
|
-
flex-wrap: wrap;
|
|
45
|
-
width: 100%;
|
|
46
|
-
padding: 16px;
|
|
47
|
-
`,
|
|
48
|
-
title: css`
|
|
49
|
-
margin-bottom: 0.25em;
|
|
50
|
-
font-weight: 800;
|
|
51
|
-
line-height: 1.4;
|
|
52
|
-
text-align: center;
|
|
53
|
-
`,
|
|
54
|
-
view: cx(
|
|
55
|
-
stylish.noScrollbar,
|
|
56
|
-
css`
|
|
57
|
-
position: relative;
|
|
58
|
-
|
|
59
|
-
overflow: hidden auto;
|
|
60
|
-
|
|
61
|
-
max-width: 1024px;
|
|
62
|
-
height: 100%;
|
|
63
|
-
padding: 32px 16px;
|
|
64
|
-
`,
|
|
65
|
-
),
|
|
66
|
-
};
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
export const genSize = (size: number, minSize: number) => {
|
|
70
|
-
return size < minSize ? minSize : size;
|
|
71
|
-
};
|