@lobehub/chat 1.119.2 → 1.120.1

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.
Files changed (74) hide show
  1. package/.vscode/settings.json +2 -3
  2. package/CHANGELOG.md +58 -0
  3. package/changelog/v1.json +21 -0
  4. package/locales/ar/models.json +24 -3
  5. package/locales/bg-BG/models.json +24 -3
  6. package/locales/de-DE/models.json +24 -3
  7. package/locales/en-US/models.json +24 -3
  8. package/locales/es-ES/models.json +24 -3
  9. package/locales/fa-IR/models.json +24 -3
  10. package/locales/fr-FR/models.json +24 -3
  11. package/locales/it-IT/models.json +24 -3
  12. package/locales/ja-JP/models.json +24 -3
  13. package/locales/ko-KR/models.json +24 -3
  14. package/locales/nl-NL/models.json +24 -3
  15. package/locales/pl-PL/models.json +24 -3
  16. package/locales/pt-BR/models.json +24 -3
  17. package/locales/ru-RU/models.json +24 -3
  18. package/locales/tr-TR/models.json +24 -3
  19. package/locales/vi-VN/models.json +24 -3
  20. package/locales/zh-CN/models.json +24 -3
  21. package/locales/zh-TW/models.json +24 -3
  22. package/package.json +2 -5
  23. package/packages/database/src/models/__tests__/generationBatch.test.ts +47 -1
  24. package/packages/database/src/models/generationBatch.ts +8 -1
  25. package/packages/model-bank/src/aiModels/aihubmix.ts +1 -1
  26. package/packages/model-bank/src/aiModels/google.ts +4 -4
  27. package/packages/model-bank/src/aiModels/openrouter.ts +2 -2
  28. package/packages/model-bank/src/aiModels/qwen.ts +3 -1
  29. package/packages/model-bank/src/aiModels/siliconcloud.ts +6 -0
  30. package/packages/model-bank/src/aiModels/vertexai.ts +2 -2
  31. package/packages/model-runtime/src/google/createImage.ts +52 -24
  32. package/packages/model-runtime/src/qwen/index.ts +1 -1
  33. package/packages/model-runtime/src/siliconcloud/index.ts +1 -1
  34. package/src/app/[variants]/(main)/(mobile)/me/settings/features/useCategory.tsx +2 -16
  35. package/src/app/[variants]/(main)/chat/@session/_layout/Desktop/SessionHeader.tsx +1 -3
  36. package/src/app/[variants]/(main)/chat/@session/_layout/Mobile/SessionHeader.tsx +1 -3
  37. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +3 -21
  38. package/src/config/featureFlags/schema.test.ts +1 -2
  39. package/src/config/featureFlags/schema.ts +0 -6
  40. package/src/config/featureFlags/utils/parser.test.ts +7 -7
  41. package/src/database/_deprecated/core/index.ts +0 -1
  42. package/src/database/_deprecated/core/model.ts +4 -38
  43. package/src/database/_deprecated/models/message.ts +1 -1
  44. package/src/layout/GlobalProvider/StoreInitialization.tsx +0 -3
  45. package/src/store/serverConfig/selectors.test.ts +0 -1
  46. package/src/store/user/initialState.ts +1 -4
  47. package/src/store/user/selectors.ts +0 -1
  48. package/src/store/user/store.ts +1 -4
  49. package/docs/self-hosting/advanced/webrtc.mdx +0 -86
  50. package/docs/self-hosting/advanced/webrtc.zh-CN.mdx +0 -80
  51. package/src/app/[variants]/(main)/settings/sync/features/Alert.tsx +0 -53
  52. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/Card.tsx +0 -42
  53. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/DeviceName.tsx +0 -62
  54. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/SystemIcon.tsx +0 -31
  55. package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/index.tsx +0 -103
  56. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/ChannelNameInput.tsx +0 -45
  57. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/SyncSwitch/index.css +0 -238
  58. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/SyncSwitch/index.tsx +0 -79
  59. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/generateRandomRoomName.ts +0 -4
  60. package/src/app/[variants]/(main)/settings/sync/features/WebRTC/index.tsx +0 -103
  61. package/src/app/[variants]/(main)/settings/sync/index.tsx +0 -17
  62. package/src/app/[variants]/(main)/settings/sync/page.tsx +0 -29
  63. package/src/database/_deprecated/core/sync.ts +0 -321
  64. package/src/features/SyncStatusInspector/DisableSync.tsx +0 -79
  65. package/src/features/SyncStatusInspector/EnableSync.tsx +0 -132
  66. package/src/features/SyncStatusInspector/EnableTag.tsx +0 -66
  67. package/src/features/SyncStatusInspector/index.tsx +0 -27
  68. package/src/hooks/useSyncData.ts +0 -50
  69. package/src/services/__tests__/sync.test.ts +0 -56
  70. package/src/services/sync.ts +0 -19
  71. package/src/store/user/slices/sync/action.test.ts +0 -164
  72. package/src/store/user/slices/sync/action.ts +0 -101
  73. package/src/store/user/slices/sync/initialState.ts +0 -13
  74. package/src/store/user/slices/sync/selectors.ts +0 -20
@@ -1,103 +0,0 @@
1
- 'use client';
2
-
3
- import { Text } from '@lobehub/ui';
4
- import { createStyles } from 'antd-style';
5
- import { rgba } from 'polished';
6
- import { memo } from 'react';
7
- import { useTranslation } from 'react-i18next';
8
- import { Flexbox } from 'react-layout-kit';
9
-
10
- import { BrowserIcon } from '@/components/BrowserIcon';
11
- import { MAX_WIDTH } from '@/const/layoutTokens';
12
-
13
- import Card from './Card';
14
- import DeviceName from './DeviceName';
15
- import SystemIcon from './SystemIcon';
16
-
17
- const useStyles = createStyles(({ css, cx, responsive, isDarkMode, token, stylish }) => ({
18
- container: css`
19
- position: relative;
20
- width: 100%;
21
- border-radius: ${token.borderRadiusLG}px;
22
- `,
23
- content: css`
24
- z-index: 2;
25
- padding: 8px;
26
- border-radius: ${token.borderRadiusLG - 1}px;
27
- background: ${rgba(token.colorBgContainer, isDarkMode ? 0.7 : 1)};
28
- `,
29
- glow: cx(
30
- stylish.gradientAnimation,
31
- css`
32
- pointer-events: none;
33
- opacity: 0.5;
34
- background-image: linear-gradient(
35
- -45deg,
36
- ${isDarkMode ? token.geekblue4 : token.geekblue},
37
- ${isDarkMode ? token.cyan4 : token.cyan}
38
- );
39
- animation-duration: 10s;
40
- `,
41
- ),
42
- wrapper: css`
43
- ${responsive.mobile} {
44
- padding-block: 8px;
45
- padding-inline: 4px;
46
- }
47
- `,
48
- }));
49
-
50
- interface DeviceCardProps {
51
- browser?: string;
52
- os?: string;
53
- }
54
-
55
- const DeviceCard = memo<DeviceCardProps>(({ browser, os }) => {
56
- const { styles } = useStyles();
57
- const { t } = useTranslation('setting');
58
-
59
- return (
60
- <Flexbox
61
- className={styles.wrapper}
62
- style={{ maxWidth: MAX_WIDTH, position: 'relative' }}
63
- width={'100%'}
64
- >
65
- <Flexbox className={styles.container} padding={4}>
66
- <Flexbox horizontal paddingBlock={8} paddingInline={12}>
67
- <div>
68
- <Text strong style={{ fontSize: 18 }}>
69
- {t('sync.device.title')}
70
- </Text>
71
- </div>
72
- </Flexbox>
73
- <Flexbox
74
- align={'center'}
75
- className={styles.content}
76
- flex={1}
77
- gap={16}
78
- horizontal
79
- justify={'space-between'}
80
- padding={12}
81
- wrap={'wrap'}
82
- >
83
- <DeviceName />
84
- <Flexbox flex={1} gap={12} horizontal>
85
- <Card icon={<SystemIcon title={os} />} title={os || t('sync.device.unknownOS')} />
86
- <Card
87
- icon={browser && <BrowserIcon browser={browser} size={24} />}
88
- title={browser || t('sync.device.unknownBrowser')}
89
- />
90
- </Flexbox>
91
- </Flexbox>
92
- <Flexbox
93
- className={styles.glow}
94
- height={'100%'}
95
- style={{ left: 0, position: 'absolute', top: 0 }}
96
- width={'100%'}
97
- />
98
- </Flexbox>
99
- </Flexbox>
100
- );
101
- });
102
-
103
- export default DeviceCard;
@@ -1,45 +0,0 @@
1
- import { ActionIcon, Input, InputProps } from '@lobehub/ui';
2
- import { FormInstance } from 'antd/es/form/hooks/useForm';
3
- import { LucideDices } from 'lucide-react';
4
- import { memo, useState } from 'react';
5
- import { useTranslation } from 'react-i18next';
6
-
7
- import { generateRandomRoomName } from './generateRandomRoomName';
8
-
9
- interface ChannelNameInputProps extends Omit<InputProps, 'form'> {
10
- form: FormInstance;
11
- }
12
-
13
- const ChannelNameInput = memo<ChannelNameInputProps>(({ form, ...rest }) => {
14
- const { t } = useTranslation('setting');
15
- const [loading, setLoading] = useState(false);
16
-
17
- return (
18
- <Input
19
- placeholder={t('sync.webrtc.channelName.placeholder')}
20
- suffix={
21
- <ActionIcon
22
- active
23
- icon={LucideDices}
24
- loading={loading}
25
- onClick={async () => {
26
- setLoading(true);
27
- const name = await generateRandomRoomName();
28
- setLoading(false);
29
- form.setFieldValue(['sync', 'webrtc', 'channelName'], name);
30
- form.setFieldValue(['sync', 'webrtc', 'enabled'], false);
31
- form.submit();
32
- }}
33
- size={'small'}
34
- style={{
35
- marginRight: -4,
36
- }}
37
- title={t('sync.webrtc.channelName.shuffle')}
38
- />
39
- }
40
- {...rest}
41
- />
42
- );
43
- });
44
-
45
- export default ChannelNameInput;
@@ -1,238 +0,0 @@
1
- /* stylelint-disable */
2
- .wrapper {
3
- --hue: 223;
4
- --off-hue: 3;
5
- --on-hue1: 123;
6
- --on-hue2: 168;
7
- --fg: hsl(var(--hue), 10%, 90%);
8
- --primary: hsl(var(--hue), 90%, 50%);
9
- --trans-dur: 0.6s;
10
- --trans-timing: cubic-bezier(0.65, 0, 0.35, 1);
11
-
12
- font-size: 14px;
13
- }
14
-
15
- .switch,
16
- .switch__input {
17
- -webkit-tap-highlight-color: #0000;
18
- }
19
-
20
- .switch {
21
- position: relative;
22
-
23
- display: block;
24
-
25
- width: 5em;
26
- height: 3em;
27
- margin: auto;
28
- }
29
-
30
- .switch__base-outer,
31
- .switch__base-inner {
32
- position: absolute;
33
- display: block;
34
- }
35
-
36
- .switch__base-outer {
37
- top: 0.125em;
38
- left: 0.125em;
39
-
40
- width: 4.75em;
41
- height: 2.75em;
42
-
43
- border-radius: 1.25em;
44
- box-shadow:
45
- -0.125em -0.125em 0.25em hsl(var(--hue), 10%, 30%),
46
- 0.125em 0.125em 0.125em hsl(var(--hue), 10%, 30%) inset,
47
- 0.125em 0.125em 0.25em hsl(0deg, 0%, 0%),
48
- -0.125em -0.125em 0.125em hsl(var(--hue), 10%, 5%) inset;
49
- }
50
-
51
- .switch__base-inner {
52
- top: 0.375em;
53
- left: 0.375em;
54
-
55
- width: 4.25em;
56
- height: 2.25em;
57
-
58
- border-radius: 1.125em;
59
- box-shadow:
60
- -0.25em -0.25em 0.25em hsl(var(--hue), 10%, 30%) inset,
61
- 0.0625em 0.0625em 0.125em hsla(var(--hue), 10%, 30%),
62
- 0.125em 0.25em 0.25em hsl(var(--hue), 10%, 5%) inset,
63
- -0.0625em -0.0625em 0.125em hsla(var(--hue), 10%, 5%);
64
- }
65
-
66
- .switch__base-neon {
67
- position: absolute;
68
- top: 0;
69
- left: 0;
70
-
71
- overflow: visible;
72
- display: block;
73
-
74
- width: 100%;
75
- height: auto;
76
- }
77
-
78
- .switch__base-neon path {
79
- stroke-dasharray: 0 104.26 0;
80
- transition: stroke-dasharray var(--trans-dur) var(--trans-timing);
81
- }
82
-
83
- .switch__input {
84
- position: relative;
85
-
86
- width: 100%;
87
- height: 100%;
88
- appearance: none;
89
- outline: transparent;
90
- }
91
-
92
- .switch__input::before {
93
- content: '';
94
-
95
- position: absolute;
96
- inset: -0.125em;
97
-
98
- display: block;
99
-
100
- border-radius: 0.125em;
101
- box-shadow: 0 0 0 0.125em hsla(var(--hue), 90%, 50%, 0%);
102
-
103
- transition: box-shadow 0.15s linear;
104
- }
105
-
106
- .switch__input:focus-visible::before {
107
- box-shadow: 0 0 0 0.125em var(--primary);
108
- }
109
-
110
- .switch__knob,
111
- .switch__knob-container {
112
- position: absolute;
113
- display: block;
114
- border-radius: 1em;
115
- }
116
-
117
- .switch__knob {
118
- width: 2em;
119
- height: 2em;
120
-
121
- background-color: hsl(var(--hue), 10%, 15%);
122
- background-image:
123
- radial-gradient(
124
- 88% 88% at 50% 50%,
125
- hsl(var(--hue), 10%, 20%) 47%,
126
- hsla(var(--hue), 10%, 20%, 0%) 50%
127
- ),
128
- radial-gradient(
129
- 88% 88% at 47% 47%,
130
- hsl(var(--hue), 10%, 85%) 45%,
131
- hsla(var(--hue), 10%, 85%, 0%) 50%
132
- ),
133
- radial-gradient(
134
- 65% 70% at 40% 60%,
135
- hsl(var(--hue), 10%, 20%) 46%,
136
- hsla(var(--hue), 10%, 20%, 0%) 50%
137
- );
138
- box-shadow:
139
- -0.0625em -0.0625em 0.0625em hsl(var(--hue), 10%, 15%) inset,
140
- -0.125em -0.125em 0.0625em hsl(var(--hue), 10%, 5%) inset,
141
- 0.75em 0.25em 0.125em hsla(0deg, 0%, 0%, 80%);
142
-
143
- transition: transform var(--trans-dur) var(--trans-timing);
144
- }
145
-
146
- .switch__knob-container {
147
- top: 0.5em;
148
- left: 0.5em;
149
-
150
- overflow: hidden;
151
-
152
- width: 4em;
153
- height: 2em;
154
- }
155
-
156
- .switch__knob-neon {
157
- display: block;
158
- width: 2em;
159
- height: auto;
160
- }
161
-
162
- .switch__knob-neon circle {
163
- opacity: 0;
164
- stroke-dasharray: 0 90.32 0 54.19;
165
- transition:
166
- opacity var(--trans-dur) steps(1, end),
167
- stroke-dasharray var(--trans-dur) var(--trans-timing);
168
- }
169
-
170
- .switch__knob-shadow {
171
- position: absolute;
172
- top: 0.5em;
173
- left: 0.5em;
174
-
175
- display: block;
176
-
177
- width: 2em;
178
- height: 2em;
179
-
180
- border-radius: 50%;
181
- box-shadow: 0.125em 0.125em 0.125em hsla(0deg, 0%, 0%, 90%);
182
-
183
- transition: transform var(--trans-dur) var(--trans-timing);
184
- }
185
-
186
- .switch__led {
187
- position: absolute;
188
- top: 0;
189
- left: 0;
190
-
191
- display: block;
192
-
193
- width: 0.25em;
194
- height: 0.25em;
195
-
196
- background-color: hsl(var(--off-hue), 90%, 70%);
197
- border-radius: 50%;
198
- box-shadow:
199
- 0 -0.0625em 0.0625em hsl(var(--off-hue), 90%, 40%) inset,
200
- 0 0 0.125em hsla(var(--off-hue), 90%, 70%, 30%),
201
- 0 0 0.125em hsla(var(--off-hue), 90%, 70%, 30%),
202
- 0.125em 0.125em 0.125em hsla(0deg, 0%, 0%, 50%);
203
-
204
- transition:
205
- background-color var(--trans-dur) var(--trans-timing),
206
- box-shadow var(--trans-dur) var(--trans-timing);
207
- }
208
-
209
- .switch__text {
210
- position: absolute;
211
- overflow: hidden;
212
- width: 1px;
213
- height: 1px;
214
- }
215
-
216
- .switch__input:checked ~ .switch__led {
217
- background-color: hsl(var(--on-hue1), 90%, 70%);
218
- box-shadow:
219
- 0 -0.0625em 0.0625em hsl(var(--on-hue1), 90%, 40%) inset,
220
- 0 -0.125em 0.125em hsla(var(--on-hue1), 90%, 70%, 30%),
221
- 0 0.125em 0.125em hsla(var(--on-hue1), 90%, 70%, 30%),
222
- 0.125em 0.125em 0.125em hsla(0deg, 0%, 0%, 50%);
223
- }
224
-
225
- .switch__input:checked ~ .switch__base-neon path {
226
- stroke-dasharray: 52.13 0 52.13;
227
- }
228
-
229
- .switch__input:checked ~ .switch__knob-shadow,
230
- .switch__input:checked ~ .switch__knob-container .switch__knob {
231
- transform: translateX(100%);
232
- }
233
-
234
- .switch__input:checked ~ .switch__knob-container .switch__knob-neon circle {
235
- opacity: 1;
236
- stroke-dasharray: 45.16 0 45.16 54.19;
237
- transition-timing-function: steps(1, start), var(--trans-timing);
238
- }
@@ -1,79 +0,0 @@
1
- import { memo } from 'react';
2
-
3
- import './index.css';
4
-
5
- interface SyncSwitchProps {
6
- onChange?: (checked: boolean) => void;
7
- value?: boolean;
8
- }
9
- const SyncSwitch = memo<SyncSwitchProps>(({ value, onChange }) => {
10
- return (
11
- <div className={'wrapper'}>
12
- <label className="switch">
13
- <input
14
- checked={value}
15
- className="switch__input"
16
- onChange={(e) => {
17
- onChange?.(e.target.checked);
18
- }}
19
- role="switch"
20
- type="checkbox"
21
- />
22
- <span className="switch__base-outer" />
23
- <span className="switch__base-inner" />
24
- <svg className="switch__base-neon" height="24px" viewBox="0 0 40 24" width="40px">
25
- <defs>
26
- <filter id="switch-glow">
27
- <feGaussianBlur result="coloredBlur" stdDeviation="1" />
28
- <feMerge>
29
- <feMergeNode in="coloredBlur" />
30
- <feMergeNode in="SourceGraphic" />
31
- </feMerge>
32
- </filter>
33
- <linearGradient id="switch-gradient1" x1="0" x2="1" y1="0" y2="0">
34
- <stop offset="0%" stopColor="hsl(var(--on-hue1),90%,70%)" />
35
- <stop offset="100%" stopColor="hsl(var(--on-hue2),90%,70%)" />
36
- </linearGradient>
37
- <linearGradient id="switch-gradient2" x1="0.7" x2="0.3" y1="0" y2="1">
38
- <stop offset="25%" stopColor="hsla(var(--on-hue1),90%,70%,0)" />
39
- <stop offset="50%" stopColor="hsla(var(--on-hue1),90%,70%,0.3)" />
40
- <stop offset="100%" stopColor="hsla(var(--on-hue2),90%,70%,0.3)" />
41
- </linearGradient>
42
- </defs>
43
- <path
44
- d="m.5,12C.5,5.649,5.649.5,12,.5h16c6.351,0,11.5,5.149,11.5,11.5s-5.149,11.5-11.5,11.5H12C5.649,23.5.5,18.351.5,12Z"
45
- fill="none"
46
- filter="url(#switch-glow)"
47
- stroke="url(#switch-gradient1)"
48
- strokeDasharray="0 104.26 0"
49
- strokeDashoffset="0.01"
50
- strokeLinecap="round"
51
- strokeWidth="1"
52
- />
53
- </svg>
54
- <span className="switch__knob-shadow" />
55
- <span className="switch__knob-container">
56
- <span className="switch__knob">
57
- <svg className="switch__knob-neon" height="48px" viewBox="0 0 48 48" width="48px">
58
- <circle
59
- cx="24"
60
- cy="24"
61
- fill="none"
62
- r="23"
63
- stroke="url(#switch-gradient2)"
64
- strokeDasharray="0 90.32 0 54.19"
65
- strokeLinecap="round"
66
- strokeWidth="1"
67
- transform="rotate(-112.5,24,24)"
68
- />
69
- </svg>
70
- </span>
71
- </span>
72
- <span className="switch__led" />
73
- <span className="switch__text">Power</span>
74
- </label>
75
- </div>
76
- );
77
- });
78
-
79
- export default SyncSwitch;
@@ -1,4 +0,0 @@
1
- export const generateRandomRoomName = async () => {
2
- const { generate } = await import('random-words');
3
- return (generate(3) as string[]).join('-');
4
- };
@@ -1,103 +0,0 @@
1
- 'use client';
2
-
3
- import { SiWebrtc } from '@icons-pack/react-simple-icons';
4
- import { Form, type FormGroupItemType, Input, InputPassword, Text, Tooltip } from '@lobehub/ui';
5
- import { Form as AntForm, Switch } from 'antd';
6
- import { memo } from 'react';
7
- import { useTranslation } from 'react-i18next';
8
- import { Flexbox } from 'react-layout-kit';
9
-
10
- import { useSyncSettings } from '@/app/[variants]/(main)/settings/hooks/useSyncSettings';
11
- import { FORM_STYLE } from '@/const/layoutTokens';
12
- import SyncStatusInspector from '@/features/SyncStatusInspector';
13
- import { useUserStore } from '@/store/user';
14
-
15
- import ChannelNameInput from './ChannelNameInput';
16
-
17
- const WebRTC = memo(() => {
18
- const { t } = useTranslation('setting');
19
- const [form] = Form.useForm();
20
-
21
- const [setSettings] = useUserStore((s) => [s.setSettings]);
22
-
23
- useSyncSettings(form);
24
-
25
- const channelName = AntForm.useWatch(['sync', 'webrtc', 'channelName'], form);
26
- const signaling = AntForm.useWatch(['sync', 'webrtc', 'signaling'], form);
27
-
28
- const config: FormGroupItemType = {
29
- children: [
30
- {
31
- children: <Input placeholder={t('sync.webrtc.signaling.placeholder')} />,
32
- desc: t('sync.webrtc.signaling.desc'),
33
- label: t('sync.webrtc.signaling.title'),
34
- name: ['sync', 'webrtc', 'signaling'],
35
- },
36
- {
37
- children: <ChannelNameInput form={form} />,
38
- desc: t('sync.webrtc.channelName.desc'),
39
- label: t('sync.webrtc.channelName.title'),
40
- name: ['sync', 'webrtc', 'channelName'],
41
- },
42
- {
43
- children: (
44
- <InputPassword
45
- autoComplete={'nw-password'}
46
- placeholder={t('sync.webrtc.channelPassword.placeholder')}
47
- />
48
- ),
49
- desc: t('sync.webrtc.channelPassword.desc'),
50
- label: t('sync.webrtc.channelPassword.title'),
51
- name: ['sync', 'webrtc', 'channelPassword'],
52
- },
53
- {
54
- children:
55
- !channelName || !signaling ? (
56
- <Tooltip title={t('sync.webrtc.enabled.invalid')}>
57
- <Switch disabled />
58
- </Tooltip>
59
- ) : (
60
- <Switch />
61
- ),
62
-
63
- label: t('sync.webrtc.enabled.title'),
64
- minWidth: undefined,
65
- name: ['sync', 'webrtc', 'enabled'],
66
- },
67
- ],
68
- extra: (
69
- <div
70
- onClick={(e) => {
71
- e.stopPropagation();
72
- }}
73
- >
74
- <SyncStatusInspector hiddenActions hiddenEnableGuide />
75
- </div>
76
- ),
77
- title: (
78
- <Flexbox align={'center'} gap={12} horizontal wrap={'wrap'}>
79
- <Flexbox align={'center'} gap={8} horizontal>
80
- <SiWebrtc style={{ flex: 'none' }} />
81
- {t('sync.webrtc.title')}
82
- </Flexbox>
83
- <Text style={{ fontWeight: 'normal' }} type={'secondary'}>
84
- {t('sync.webrtc.desc')}
85
- </Text>
86
- </Flexbox>
87
- ),
88
- };
89
-
90
- return (
91
- <Form
92
- form={form}
93
- items={[config]}
94
- itemsType={'group'}
95
- onFinish={setSettings}
96
- onValuesChange={setSettings}
97
- variant={'borderless'}
98
- {...FORM_STYLE}
99
- />
100
- );
101
- });
102
-
103
- export default WebRTC;
@@ -1,17 +0,0 @@
1
- import Alert from './features/Alert';
2
- import DeviceInfo from './features/DeviceInfo';
3
- import WebRTC from './features/WebRTC';
4
-
5
- const Page = ({ browser, os, mobile }: { browser?: string; mobile?: boolean; os?: string }) => {
6
- return (
7
- <>
8
- <DeviceInfo browser={browser} os={os} />
9
- <WebRTC />
10
- <Alert mobile={mobile} />
11
- </>
12
- );
13
- };
14
-
15
- Page.displayName = 'SyncSetting';
16
-
17
- export default Page;
@@ -1,29 +0,0 @@
1
- import { gerServerDeviceInfo } from '@lobechat/utils/server';
2
- import { notFound } from 'next/navigation';
3
-
4
- import { serverFeatureFlags } from '@/config/featureFlags';
5
- import { metadataModule } from '@/server/metadata';
6
- import { translation } from '@/server/translation';
7
- import { DynamicLayoutProps } from '@/types/next';
8
- import { RouteVariants } from '@/utils/server/routeVariants';
9
-
10
- import Page from './index';
11
-
12
- export const generateMetadata = async (props: DynamicLayoutProps) => {
13
- const locale = await RouteVariants.getLocale(props);
14
- const { t } = await translation('setting', locale);
15
- return metadataModule.generate({
16
- description: t('header.desc'),
17
- title: t('tab.sync'),
18
- url: '/settings/sync',
19
- });
20
- };
21
- export default async (props: DynamicLayoutProps) => {
22
- const enableWebrtc = serverFeatureFlags().enableWebrtc;
23
- if (!enableWebrtc) return notFound();
24
-
25
- const isMobile = await RouteVariants.getIsMobile(props);
26
- const { os, browser } = await gerServerDeviceInfo();
27
-
28
- return <Page browser={browser} mobile={isMobile} os={os} />;
29
- };