@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.
- package/.vscode/settings.json +2 -3
- package/CHANGELOG.md +58 -0
- package/changelog/v1.json +21 -0
- package/locales/ar/models.json +24 -3
- package/locales/bg-BG/models.json +24 -3
- package/locales/de-DE/models.json +24 -3
- package/locales/en-US/models.json +24 -3
- package/locales/es-ES/models.json +24 -3
- package/locales/fa-IR/models.json +24 -3
- package/locales/fr-FR/models.json +24 -3
- package/locales/it-IT/models.json +24 -3
- package/locales/ja-JP/models.json +24 -3
- package/locales/ko-KR/models.json +24 -3
- package/locales/nl-NL/models.json +24 -3
- package/locales/pl-PL/models.json +24 -3
- package/locales/pt-BR/models.json +24 -3
- package/locales/ru-RU/models.json +24 -3
- package/locales/tr-TR/models.json +24 -3
- package/locales/vi-VN/models.json +24 -3
- package/locales/zh-CN/models.json +24 -3
- package/locales/zh-TW/models.json +24 -3
- package/package.json +2 -5
- package/packages/database/src/models/__tests__/generationBatch.test.ts +47 -1
- package/packages/database/src/models/generationBatch.ts +8 -1
- package/packages/model-bank/src/aiModels/aihubmix.ts +1 -1
- package/packages/model-bank/src/aiModels/google.ts +4 -4
- package/packages/model-bank/src/aiModels/openrouter.ts +2 -2
- package/packages/model-bank/src/aiModels/qwen.ts +3 -1
- package/packages/model-bank/src/aiModels/siliconcloud.ts +6 -0
- package/packages/model-bank/src/aiModels/vertexai.ts +2 -2
- package/packages/model-runtime/src/google/createImage.ts +52 -24
- package/packages/model-runtime/src/qwen/index.ts +1 -1
- package/packages/model-runtime/src/siliconcloud/index.ts +1 -1
- package/src/app/[variants]/(main)/(mobile)/me/settings/features/useCategory.tsx +2 -16
- package/src/app/[variants]/(main)/chat/@session/_layout/Desktop/SessionHeader.tsx +1 -3
- package/src/app/[variants]/(main)/chat/@session/_layout/Mobile/SessionHeader.tsx +1 -3
- package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +3 -21
- package/src/config/featureFlags/schema.test.ts +1 -2
- package/src/config/featureFlags/schema.ts +0 -6
- package/src/config/featureFlags/utils/parser.test.ts +7 -7
- package/src/database/_deprecated/core/index.ts +0 -1
- package/src/database/_deprecated/core/model.ts +4 -38
- package/src/database/_deprecated/models/message.ts +1 -1
- package/src/layout/GlobalProvider/StoreInitialization.tsx +0 -3
- package/src/store/serverConfig/selectors.test.ts +0 -1
- package/src/store/user/initialState.ts +1 -4
- package/src/store/user/selectors.ts +0 -1
- package/src/store/user/store.ts +1 -4
- package/docs/self-hosting/advanced/webrtc.mdx +0 -86
- package/docs/self-hosting/advanced/webrtc.zh-CN.mdx +0 -80
- package/src/app/[variants]/(main)/settings/sync/features/Alert.tsx +0 -53
- package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/Card.tsx +0 -42
- package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/DeviceName.tsx +0 -62
- package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/SystemIcon.tsx +0 -31
- package/src/app/[variants]/(main)/settings/sync/features/DeviceInfo/index.tsx +0 -103
- package/src/app/[variants]/(main)/settings/sync/features/WebRTC/ChannelNameInput.tsx +0 -45
- package/src/app/[variants]/(main)/settings/sync/features/WebRTC/SyncSwitch/index.css +0 -238
- package/src/app/[variants]/(main)/settings/sync/features/WebRTC/SyncSwitch/index.tsx +0 -79
- package/src/app/[variants]/(main)/settings/sync/features/WebRTC/generateRandomRoomName.ts +0 -4
- package/src/app/[variants]/(main)/settings/sync/features/WebRTC/index.tsx +0 -103
- package/src/app/[variants]/(main)/settings/sync/index.tsx +0 -17
- package/src/app/[variants]/(main)/settings/sync/page.tsx +0 -29
- package/src/database/_deprecated/core/sync.ts +0 -321
- package/src/features/SyncStatusInspector/DisableSync.tsx +0 -79
- package/src/features/SyncStatusInspector/EnableSync.tsx +0 -132
- package/src/features/SyncStatusInspector/EnableTag.tsx +0 -66
- package/src/features/SyncStatusInspector/index.tsx +0 -27
- package/src/hooks/useSyncData.ts +0 -50
- package/src/services/__tests__/sync.test.ts +0 -56
- package/src/services/sync.ts +0 -19
- package/src/store/user/slices/sync/action.test.ts +0 -164
- package/src/store/user/slices/sync/action.ts +0 -101
- package/src/store/user/slices/sync/initialState.ts +0 -13
- 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,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
|
-
};
|