@lobehub/lobehub 2.0.0-next.213 → 2.0.0-next.214
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 +25 -0
- package/apps/desktop/package.json +3 -2
- package/apps/desktop/src/main/const/store.ts +1 -1
- package/apps/desktop/src/main/controllers/SystemCtr.ts +2 -3
- package/apps/desktop/src/main/core/App.ts +10 -3
- package/apps/desktop/src/main/types/store.ts +1 -1
- package/changelog/v1.json +5 -0
- package/package.json +4 -3
- package/packages/builtin-tool-knowledge-base/src/client/Render/SearchKnowledgeBase/Item/index.tsx +4 -2
- package/packages/builtin-tool-local-system/src/client/Intervention/EditLocalFile/index.tsx +3 -2
- package/packages/builtin-tool-local-system/src/client/Render/EditLocalFile/index.tsx +3 -2
- package/packages/const/src/theme.ts +0 -2
- package/packages/desktop-bridge/src/routeVariants.ts +2 -9
- package/packages/electron-client-ipc/src/types/system.ts +1 -1
- package/scripts/electronWorkflow/modifiers/nextConfig.mts +41 -13
- package/src/app/[variants]/(auth)/_layout/index.tsx +3 -2
- package/src/app/[variants]/(auth)/_layout/style.ts +8 -18
- package/src/app/[variants]/(auth)/layout.tsx +7 -3
- package/src/app/[variants]/(desktop)/desktop-onboarding/_layout/index.tsx +4 -2
- package/src/app/[variants]/(desktop)/desktop-onboarding/_layout/style.ts +3 -0
- package/src/app/[variants]/(main)/_layout/DesktopLayoutContainer.tsx +3 -2
- package/src/app/[variants]/(main)/chat/profile/features/ProfileEditor/PluginTag.tsx +3 -2
- package/src/app/[variants]/(main)/community/(list)/_layout/Footer.tsx +3 -2
- package/src/app/[variants]/(main)/group/features/Conversation/ChatItem/Thread.tsx +3 -2
- package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/index.tsx +0 -1
- package/src/app/[variants]/(main)/group/profile/features/ProfileEditor/PluginTag.tsx +3 -2
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentItem/Editing.tsx +2 -2
- package/src/app/[variants]/(main)/home/_layout/Footer/index.tsx +1 -1
- package/src/app/[variants]/(main)/home/_layout/index.tsx +3 -2
- package/src/app/[variants]/(main)/home/features/CommunityAgents/Item.tsx +3 -2
- package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/AspectRatioSelect/index.tsx +4 -2
- package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/ModelSelect/ImageModelItem.tsx +3 -2
- package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/Select/index.tsx +4 -2
- package/src/app/[variants]/(main)/image/features/PromptInput/index.tsx +3 -2
- package/src/app/[variants]/(main)/memory/features/TimeLineView/index.tsx +9 -4
- package/src/app/[variants]/(main)/page/_layout/Body/List/Item/Editing.tsx +2 -2
- package/src/app/[variants]/(main)/settings/common/features/Common/Common.tsx +11 -11
- package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +3 -2
- package/src/app/[variants]/(main)/settings/stats/features/overview/ShareButton/TotalCard.tsx +4 -2
- package/src/app/[variants]/(mobile)/me/(home)/features/Header.tsx +6 -8
- package/src/app/[variants]/layout.tsx +10 -15
- package/src/app/[variants]/onboarding/_layout/index.tsx +3 -2
- package/src/app/[variants]/onboarding/features/ModeSelectionStep.tsx +3 -2
- package/src/app/[variants]/router/index.tsx +12 -8
- package/src/components/Cell/Divider.tsx +4 -2
- package/src/components/DataStyleModal/index.tsx +4 -2
- package/src/components/FeatureList/index.tsx +4 -2
- package/src/components/FileParsingStatus/EmbeddingStatus.tsx +3 -2
- package/src/components/FileParsingStatus/index.tsx +3 -2
- package/src/components/Notification/index.tsx +4 -2
- package/src/components/client/ClientOnly.tsx +17 -0
- package/src/features/AlertBanner/CloudBanner.tsx +4 -3
- package/src/features/CommandMenu/ThemeMenu.tsx +1 -1
- package/src/features/CommandMenu/types.ts +5 -2
- package/src/features/CommandMenu/useCommandMenu.ts +3 -2
- package/src/features/Conversation/Markdown/plugins/LobeArtifact/Render/index.tsx +3 -2
- package/src/features/Conversation/Messages/components/FileChunks/ChunkItem.tsx +3 -2
- package/src/features/Conversation/Messages/components/FileChunks/index.tsx +4 -2
- package/src/features/Conversation/Messages/components/SearchGrounding.tsx +3 -2
- package/src/features/ElectronTitlebar/hooks/useWatchThemeUpdate.ts +21 -38
- package/src/features/GroupChatSettings/AgentCard.tsx +3 -2
- package/src/features/GroupChatSettings/HostMemberCard.tsx +3 -2
- package/src/features/PageEditor/DiffAllToolbar.tsx +4 -2
- package/src/features/User/UserPanel/ThemeButton.tsx +18 -29
- package/src/hooks/useIsDark.ts +11 -0
- package/src/layout/AuthProvider/Clerk/useAppearance.ts +4 -2
- package/src/layout/AuthProvider/MarketAuth/MarketAuthConfirmModal.tsx +3 -2
- package/src/layout/GlobalProvider/AppTheme.tsx +15 -19
- package/src/layout/GlobalProvider/NextThemeProvider.tsx +22 -0
- package/src/layout/GlobalProvider/StyleRegistry.tsx +18 -13
- package/src/layout/GlobalProvider/index.tsx +38 -36
- package/src/libs/next/proxy/define-config.ts +2 -11
- package/src/store/global/action.test.ts +0 -15
- package/src/store/global/actions/__tests__/general.test.ts +0 -37
- package/src/store/global/actions/general.ts +0 -21
- package/src/store/global/initialState.ts +0 -6
- package/src/store/global/selectors/systemStatus.test.ts +0 -20
- package/src/store/global/selectors/systemStatus.ts +0 -2
- package/src/styles/global.ts +0 -2
- package/src/utils/server/routeVariants.test.ts +17 -51
- package/src/utils/server/routeVariants.ts +0 -1
|
@@ -17,12 +17,12 @@ import AppTheme from './AppTheme';
|
|
|
17
17
|
import { GroupWizardProvider } from './GroupWizardProvider';
|
|
18
18
|
import ImportSettings from './ImportSettings';
|
|
19
19
|
import Locale from './Locale';
|
|
20
|
+
import NextThemeProvider from './NextThemeProvider';
|
|
20
21
|
import QueryProvider from './Query';
|
|
21
22
|
import StoreInitialization from './StoreInitialization';
|
|
22
23
|
import StyleRegistry from './StyleRegistry';
|
|
23
24
|
|
|
24
25
|
interface GlobalLayoutProps {
|
|
25
|
-
appearance: string;
|
|
26
26
|
children: ReactNode;
|
|
27
27
|
isMobile: boolean;
|
|
28
28
|
locale: string;
|
|
@@ -36,7 +36,7 @@ const GlobalLayout = async ({
|
|
|
36
36
|
neutralColor,
|
|
37
37
|
primaryColor,
|
|
38
38
|
locale: userLocale,
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
isMobile,
|
|
41
41
|
variants,
|
|
42
42
|
}: GlobalLayoutProps) => {
|
|
@@ -45,44 +45,46 @@ const GlobalLayout = async ({
|
|
|
45
45
|
// get default feature flags to use with ssr
|
|
46
46
|
const serverFeatureFlags = getServerFeatureFlagsValue();
|
|
47
47
|
const serverConfig = await getServerGlobalConfig();
|
|
48
|
+
|
|
48
49
|
return (
|
|
49
50
|
<StyleRegistry>
|
|
50
51
|
<Locale antdLocale={antdLocale} defaultLang={userLocale}>
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
>
|
|
59
|
-
<ServerConfigStoreProvider
|
|
60
|
-
featureFlags={serverFeatureFlags}
|
|
61
|
-
isMobile={isMobile}
|
|
62
|
-
segmentVariants={variants}
|
|
63
|
-
serverConfig={serverConfig}
|
|
52
|
+
<NextThemeProvider>
|
|
53
|
+
<AppTheme
|
|
54
|
+
customFontFamily={appEnv.CUSTOM_FONT_FAMILY}
|
|
55
|
+
customFontURL={appEnv.CUSTOM_FONT_URL}
|
|
56
|
+
defaultNeutralColor={neutralColor as any}
|
|
57
|
+
defaultPrimaryColor={primaryColor as any}
|
|
58
|
+
globalCDN={appEnv.CDN_USE_GLOBAL}
|
|
64
59
|
>
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
60
|
+
<ServerConfigStoreProvider
|
|
61
|
+
featureFlags={serverFeatureFlags}
|
|
62
|
+
isMobile={isMobile}
|
|
63
|
+
segmentVariants={variants}
|
|
64
|
+
serverConfig={serverConfig}
|
|
65
|
+
>
|
|
66
|
+
<QueryProvider>
|
|
67
|
+
<GroupWizardProvider>
|
|
68
|
+
<DragUploadProvider>
|
|
69
|
+
<LazyMotion features={domMax}>
|
|
70
|
+
<TooltipGroup layoutAnimation={false}>
|
|
71
|
+
<LobeAnalyticsProviderWrapper>{children}</LobeAnalyticsProviderWrapper>
|
|
72
|
+
</TooltipGroup>
|
|
73
|
+
<ModalHost />
|
|
74
|
+
<ContextMenuHost />
|
|
75
|
+
</LazyMotion>
|
|
76
|
+
</DragUploadProvider>
|
|
77
|
+
</GroupWizardProvider>
|
|
78
|
+
</QueryProvider>
|
|
79
|
+
<StoreInitialization />
|
|
80
|
+
<Suspense>
|
|
81
|
+
{ENABLE_BUSINESS_FEATURES ? <ReferralProvider /> : null}
|
|
82
|
+
<ImportSettings />
|
|
83
|
+
{process.env.NODE_ENV === 'development' && <DevPanel />}
|
|
84
|
+
</Suspense>
|
|
85
|
+
</ServerConfigStoreProvider>
|
|
86
|
+
</AppTheme>
|
|
87
|
+
</NextThemeProvider>
|
|
86
88
|
</Locale>
|
|
87
89
|
</StyleRegistry>
|
|
88
90
|
);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
|
|
2
|
-
import { parseDefaultThemeFromCountry } from '@lobechat/utils/server';
|
|
3
2
|
import debug from 'debug';
|
|
4
3
|
import { type NextRequest, NextResponse } from 'next/server';
|
|
5
4
|
import { UAParser } from 'ua-parser-js';
|
|
@@ -8,7 +7,6 @@ import urlJoin from 'url-join';
|
|
|
8
7
|
import { auth } from '@/auth';
|
|
9
8
|
import { OAUTH_AUTHORIZED } from '@/const/auth';
|
|
10
9
|
import { LOBE_LOCALE_COOKIE } from '@/const/locale';
|
|
11
|
-
import { LOBE_THEME_APPEARANCE } from '@/const/theme';
|
|
12
10
|
import { isDesktop } from '@/const/version';
|
|
13
11
|
import { appEnv } from '@/envs/app';
|
|
14
12
|
import { authEnv } from '@/envs/auth';
|
|
@@ -39,10 +37,6 @@ export function defineConfig() {
|
|
|
39
37
|
return NextResponse.next();
|
|
40
38
|
}
|
|
41
39
|
|
|
42
|
-
// 1. Read user preferences from cookies
|
|
43
|
-
const theme = (request.cookies.get(LOBE_THEME_APPEARANCE)?.value ||
|
|
44
|
-
parseDefaultThemeFromCountry(request)) as 'dark' | 'light';
|
|
45
|
-
|
|
46
40
|
// locale has three levels
|
|
47
41
|
// 1. search params
|
|
48
42
|
// 2. cookie
|
|
@@ -67,17 +61,14 @@ export function defineConfig() {
|
|
|
67
61
|
deviceType: device.type,
|
|
68
62
|
hasCookies: {
|
|
69
63
|
locale: !!request.cookies.get(LOBE_LOCALE_COOKIE)?.value,
|
|
70
|
-
theme: !!request.cookies.get(LOBE_THEME_APPEARANCE)?.value,
|
|
71
64
|
},
|
|
72
65
|
locale,
|
|
73
|
-
theme,
|
|
74
66
|
});
|
|
75
67
|
|
|
76
68
|
// 2. Create normalized preference values
|
|
77
69
|
const route = RouteVariants.serializeVariants({
|
|
78
70
|
isMobile: device.type === 'mobile',
|
|
79
71
|
locale,
|
|
80
|
-
theme,
|
|
81
72
|
});
|
|
82
73
|
|
|
83
74
|
logDefault('Serialized route variant: %s', route);
|
|
@@ -99,8 +90,8 @@ export function defineConfig() {
|
|
|
99
90
|
|
|
100
91
|
// refs: https://github.com/lobehub/lobe-chat/pull/5866
|
|
101
92
|
// new handle segment rewrite: /${route}${originalPathname}
|
|
102
|
-
// / -> /zh-
|
|
103
|
-
// /discover -> /zh-
|
|
93
|
+
// / -> /zh-CN__0
|
|
94
|
+
// /discover -> /zh-CN__0/discover
|
|
104
95
|
// All SPA routes that use react-router-dom should be rewritten to just /${route}
|
|
105
96
|
const spaRoutes = [
|
|
106
97
|
'/chat',
|
|
@@ -408,19 +408,4 @@ describe('createPreferenceSlice', () => {
|
|
|
408
408
|
expect(result.current.status.noWideScreen).toEqual(false);
|
|
409
409
|
});
|
|
410
410
|
});
|
|
411
|
-
|
|
412
|
-
describe('switchThemeMode', () => {
|
|
413
|
-
it('should switch theme mode', async () => {
|
|
414
|
-
const { result } = renderHook(() => useGlobalStore());
|
|
415
|
-
|
|
416
|
-
// Perform the action
|
|
417
|
-
act(() => {
|
|
418
|
-
useGlobalStore.setState({ isStatusInit: true });
|
|
419
|
-
result.current.switchThemeMode('light');
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
// Assert that updateUserSettings was called with the correct theme mode
|
|
423
|
-
expect(result.current.status.themeMode).toEqual('light');
|
|
424
|
-
});
|
|
425
|
-
});
|
|
426
411
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { act, renderHook } from '@testing-library/react';
|
|
2
|
-
import { ThemeMode } from 'antd-style';
|
|
3
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
3
|
import { withSWR } from '~test-utils';
|
|
5
4
|
|
|
@@ -117,42 +116,6 @@ describe('generalActionSlice', () => {
|
|
|
117
116
|
});
|
|
118
117
|
});
|
|
119
118
|
|
|
120
|
-
describe('switchThemeMode', () => {
|
|
121
|
-
it('should update theme mode in system status', () => {
|
|
122
|
-
const { result } = renderHook(() => useGlobalStore());
|
|
123
|
-
const themeMode: ThemeMode = 'dark';
|
|
124
|
-
|
|
125
|
-
act(() => {
|
|
126
|
-
useGlobalStore.setState({ isStatusInit: true });
|
|
127
|
-
result.current.switchThemeMode(themeMode);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
expect(result.current.status.themeMode).toBe(themeMode);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('should not update theme mode if status is not initialized', () => {
|
|
134
|
-
const { result } = renderHook(() => useGlobalStore());
|
|
135
|
-
const themeMode: ThemeMode = 'dark';
|
|
136
|
-
|
|
137
|
-
act(() => {
|
|
138
|
-
result.current.switchThemeMode(themeMode);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
expect(result.current.status.themeMode).toBe(initialState.status.themeMode);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('should handle light theme mode', () => {
|
|
145
|
-
const { result } = renderHook(() => useGlobalStore());
|
|
146
|
-
|
|
147
|
-
act(() => {
|
|
148
|
-
useGlobalStore.setState({ isStatusInit: true });
|
|
149
|
-
result.current.switchThemeMode('light');
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
expect(result.current.status.themeMode).toBe('light');
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
|
|
156
119
|
describe('useInitSystemStatus', () => {
|
|
157
120
|
it('should reset transient UI states when loading from localStorage', async () => {
|
|
158
121
|
const mockStatus = {
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import { type ThemeMode } from 'antd-style';
|
|
2
1
|
import isEqual from 'fast-deep-equal';
|
|
3
2
|
import { gt, parse, valid } from 'semver';
|
|
4
3
|
import { type SWRResponse } from 'swr';
|
|
5
4
|
import type { StateCreator } from 'zustand/vanilla';
|
|
6
5
|
|
|
7
|
-
import { LOBE_THEME_APPEARANCE } from '@/const/theme';
|
|
8
6
|
import { CURRENT_VERSION, isDesktop } from '@/const/version';
|
|
9
7
|
import { useOnlyFetchOnceSWR } from '@/libs/swr';
|
|
10
8
|
import { globalService } from '@/services/global';
|
|
11
9
|
import type { SystemStatus } from '@/store/global/initialState';
|
|
12
10
|
import { type LocaleMode } from '@/types/locale';
|
|
13
|
-
import { setCookie } from '@/utils/client/cookie';
|
|
14
11
|
import { switchLang } from '@/utils/client/switchLang';
|
|
15
12
|
import { merge } from '@/utils/merge';
|
|
16
13
|
import { setNamespace } from '@/utils/storeDebug';
|
|
@@ -23,7 +20,6 @@ export interface GlobalGeneralAction {
|
|
|
23
20
|
openAgentInNewWindow: (agentId: string) => Promise<void>;
|
|
24
21
|
openTopicInNewWindow: (agentId: string, topicId: string) => Promise<void>;
|
|
25
22
|
switchLocale: (locale: LocaleMode, params?: { skipBroadcast?: boolean }) => void;
|
|
26
|
-
switchThemeMode: (themeMode: ThemeMode, params?: { skipBroadcast?: boolean }) => void;
|
|
27
23
|
updateSystemStatus: (status: Partial<SystemStatus>, action?: any) => void;
|
|
28
24
|
useCheckLatestVersion: (enabledCheck?: boolean) => SWRResponse<string>;
|
|
29
25
|
useInitSystemStatus: () => SWRResponse;
|
|
@@ -114,23 +110,6 @@ export const generalActionSlice: StateCreator<
|
|
|
114
110
|
})();
|
|
115
111
|
}
|
|
116
112
|
},
|
|
117
|
-
switchThemeMode: (themeMode, { skipBroadcast } = {}) => {
|
|
118
|
-
get().updateSystemStatus({ themeMode });
|
|
119
|
-
|
|
120
|
-
setCookie(LOBE_THEME_APPEARANCE, themeMode === 'auto' ? undefined : themeMode);
|
|
121
|
-
|
|
122
|
-
if (isDesktop && !skipBroadcast) {
|
|
123
|
-
(async () => {
|
|
124
|
-
try {
|
|
125
|
-
const { ensureElectronIpc } = await import('@/utils/electron/ipc');
|
|
126
|
-
|
|
127
|
-
await ensureElectronIpc().system.updateThemeModeHandler(themeMode);
|
|
128
|
-
} catch (error) {
|
|
129
|
-
console.error('Failed to update theme in main process:', error);
|
|
130
|
-
}
|
|
131
|
-
})();
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
113
|
updateSystemStatus: (status, action) => {
|
|
135
114
|
if (!get().isStatusInit) return;
|
|
136
115
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ThemeMode } from 'antd-style';
|
|
2
1
|
import type { NavigateFunction } from 'react-router-dom';
|
|
3
2
|
|
|
4
3
|
import { DatabaseLoadingState, type MigrationSQL, type MigrationTableItem } from '@/types/clientDB';
|
|
@@ -129,10 +128,6 @@ export interface SystemStatus {
|
|
|
129
128
|
showRightPanel?: boolean;
|
|
130
129
|
showSystemRole?: boolean;
|
|
131
130
|
systemRoleExpandedMap: Record<string, boolean>;
|
|
132
|
-
/**
|
|
133
|
-
* theme mode
|
|
134
|
-
*/
|
|
135
|
-
themeMode?: ThemeMode;
|
|
136
131
|
/**
|
|
137
132
|
* 是否使用短格式显示 token
|
|
138
133
|
*/
|
|
@@ -196,7 +191,6 @@ export const INITIAL_STATUS = {
|
|
|
196
191
|
showRightPanel: true,
|
|
197
192
|
showSystemRole: false,
|
|
198
193
|
systemRoleExpandedMap: {},
|
|
199
|
-
themeMode: 'auto',
|
|
200
194
|
tokenDisplayFormatShort: true,
|
|
201
195
|
topicPageSize: 20,
|
|
202
196
|
zenMode: false,
|
|
@@ -87,24 +87,4 @@ describe('systemStatusSelectors', () => {
|
|
|
87
87
|
expect(systemStatusSelectors.portalWidth(noPortalWidth)).toBe(400);
|
|
88
88
|
});
|
|
89
89
|
});
|
|
90
|
-
|
|
91
|
-
describe('theme mode', () => {
|
|
92
|
-
it('should return the correct theme', () => {
|
|
93
|
-
const s: GlobalState = merge(initialState, {
|
|
94
|
-
status: {
|
|
95
|
-
themeMode: 'light',
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
expect(systemStatusSelectors.themeMode(s)).toBe('light');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should return auto if not set', () => {
|
|
102
|
-
const s: GlobalState = merge(initialState, {
|
|
103
|
-
status: {
|
|
104
|
-
themeMode: undefined,
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
expect(systemStatusSelectors.themeMode(s)).toBe('auto');
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
90
|
});
|
|
@@ -23,7 +23,6 @@ const showImagePanel = (s: GlobalState) => s.status.showImagePanel;
|
|
|
23
23
|
const showImageTopicPanel = (s: GlobalState) => s.status.showImageTopicPanel;
|
|
24
24
|
const hidePWAInstaller = (s: GlobalState) => s.status.hidePWAInstaller;
|
|
25
25
|
const isShowCredit = (s: GlobalState) => s.status.isShowCredit;
|
|
26
|
-
const themeMode = (s: GlobalState) => s.status.themeMode || 'auto';
|
|
27
26
|
const language = (s: GlobalState) => s.status.language || 'auto';
|
|
28
27
|
|
|
29
28
|
const showChatHeader = (s: GlobalState) => !s.status.zenMode;
|
|
@@ -80,7 +79,6 @@ export const systemStatusSelectors = {
|
|
|
80
79
|
showRightPanel,
|
|
81
80
|
showSystemRole,
|
|
82
81
|
systemStatus,
|
|
83
|
-
themeMode,
|
|
84
82
|
tokenDisplayFormatShort,
|
|
85
83
|
topicGroupKeys,
|
|
86
84
|
topicPageSize,
|
package/src/styles/global.ts
CHANGED
|
@@ -11,7 +11,6 @@ describe('RouteVariants', () => {
|
|
|
11
11
|
expect(DEFAULT_VARIANTS).toEqual({
|
|
12
12
|
isMobile: false,
|
|
13
13
|
locale: DEFAULT_LANG,
|
|
14
|
-
theme: 'light',
|
|
15
14
|
});
|
|
16
15
|
});
|
|
17
16
|
});
|
|
@@ -21,30 +20,27 @@ describe('RouteVariants', () => {
|
|
|
21
20
|
const variants: IRouteVariants = {
|
|
22
21
|
isMobile: false,
|
|
23
22
|
locale: 'en-US',
|
|
24
|
-
theme: 'light',
|
|
25
23
|
};
|
|
26
24
|
const result = RouteVariants.serializeVariants(variants);
|
|
27
|
-
expect(result).toBe('en-
|
|
25
|
+
expect(result).toBe('en-US__0');
|
|
28
26
|
});
|
|
29
27
|
|
|
30
28
|
it('should serialize variants with mobile enabled', () => {
|
|
31
29
|
const variants: IRouteVariants = {
|
|
32
30
|
isMobile: true,
|
|
33
31
|
locale: 'zh-CN',
|
|
34
|
-
theme: 'dark',
|
|
35
32
|
};
|
|
36
33
|
const result = RouteVariants.serializeVariants(variants);
|
|
37
|
-
expect(result).toBe('zh-
|
|
34
|
+
expect(result).toBe('zh-CN__1');
|
|
38
35
|
});
|
|
39
36
|
|
|
40
37
|
it('should serialize variants with different locales', () => {
|
|
41
38
|
const variants: IRouteVariants = {
|
|
42
39
|
isMobile: false,
|
|
43
40
|
locale: 'ja-JP',
|
|
44
|
-
theme: 'light',
|
|
45
41
|
};
|
|
46
42
|
const result = RouteVariants.serializeVariants(variants);
|
|
47
|
-
expect(result).toBe('ja-
|
|
43
|
+
expect(result).toBe('ja-JP__0');
|
|
48
44
|
});
|
|
49
45
|
|
|
50
46
|
it('should serialize variants with custom colors', () => {
|
|
@@ -53,31 +49,28 @@ describe('RouteVariants', () => {
|
|
|
53
49
|
locale: 'en-US',
|
|
54
50
|
neutralColor: '#cccccc',
|
|
55
51
|
primaryColor: '#ff0000',
|
|
56
|
-
theme: 'dark',
|
|
57
52
|
};
|
|
58
53
|
const result = RouteVariants.serializeVariants(variants);
|
|
59
|
-
expect(result).toBe('en-
|
|
54
|
+
expect(result).toBe('en-US__1');
|
|
60
55
|
});
|
|
61
56
|
});
|
|
62
57
|
|
|
63
58
|
describe('deserializeVariants', () => {
|
|
64
59
|
it('should deserialize valid serialized string', () => {
|
|
65
|
-
const serialized = 'en-
|
|
60
|
+
const serialized = 'en-US__0';
|
|
66
61
|
const result = RouteVariants.deserializeVariants(serialized);
|
|
67
62
|
expect(result).toEqual({
|
|
68
63
|
isMobile: false,
|
|
69
64
|
locale: 'en-US',
|
|
70
|
-
theme: 'light',
|
|
71
65
|
});
|
|
72
66
|
});
|
|
73
67
|
|
|
74
68
|
it('should deserialize mobile variants', () => {
|
|
75
|
-
const serialized = 'zh-
|
|
69
|
+
const serialized = 'zh-CN__1';
|
|
76
70
|
const result = RouteVariants.deserializeVariants(serialized);
|
|
77
71
|
expect(result).toEqual({
|
|
78
72
|
isMobile: true,
|
|
79
73
|
locale: 'zh-CN',
|
|
80
|
-
theme: 'dark',
|
|
81
74
|
});
|
|
82
75
|
});
|
|
83
76
|
|
|
@@ -94,22 +87,11 @@ describe('RouteVariants', () => {
|
|
|
94
87
|
});
|
|
95
88
|
|
|
96
89
|
it('should handle invalid locale by falling back to default', () => {
|
|
97
|
-
const serialized = 'invalid-
|
|
90
|
+
const serialized = 'invalid-locale__0';
|
|
98
91
|
const result = RouteVariants.deserializeVariants(serialized);
|
|
99
92
|
expect(result).toEqual({
|
|
100
93
|
isMobile: false,
|
|
101
94
|
locale: DEFAULT_LANG,
|
|
102
|
-
theme: 'light',
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should handle invalid theme by falling back to default', () => {
|
|
107
|
-
const serialized = 'en-US__0__invalid-theme';
|
|
108
|
-
const result = RouteVariants.deserializeVariants(serialized);
|
|
109
|
-
expect(result).toEqual({
|
|
110
|
-
isMobile: false,
|
|
111
|
-
locale: 'en-US',
|
|
112
|
-
theme: 'light',
|
|
113
95
|
});
|
|
114
96
|
});
|
|
115
97
|
|
|
@@ -120,19 +102,19 @@ describe('RouteVariants', () => {
|
|
|
120
102
|
});
|
|
121
103
|
|
|
122
104
|
it('should handle isMobile value correctly for "0"', () => {
|
|
123
|
-
const serialized = 'en-
|
|
105
|
+
const serialized = 'en-US__0';
|
|
124
106
|
const result = RouteVariants.deserializeVariants(serialized);
|
|
125
107
|
expect(result.isMobile).toBe(false);
|
|
126
108
|
});
|
|
127
109
|
|
|
128
110
|
it('should handle isMobile value correctly for "1"', () => {
|
|
129
|
-
const serialized = 'en-
|
|
111
|
+
const serialized = 'en-US__1';
|
|
130
112
|
const result = RouteVariants.deserializeVariants(serialized);
|
|
131
113
|
expect(result.isMobile).toBe(true);
|
|
132
114
|
});
|
|
133
115
|
|
|
134
116
|
it('should handle isMobile value correctly for other values', () => {
|
|
135
|
-
const serialized = 'en-
|
|
117
|
+
const serialized = 'en-US__2';
|
|
136
118
|
const result = RouteVariants.deserializeVariants(serialized);
|
|
137
119
|
expect(result.isMobile).toBe(false);
|
|
138
120
|
});
|
|
@@ -141,25 +123,23 @@ describe('RouteVariants', () => {
|
|
|
141
123
|
describe('getVariantsFromProps', () => {
|
|
142
124
|
it('should extract and deserialize variants from props', async () => {
|
|
143
125
|
const props: DynamicLayoutProps = {
|
|
144
|
-
params: Promise.resolve({ variants: 'en-
|
|
126
|
+
params: Promise.resolve({ variants: 'en-US__0' }),
|
|
145
127
|
};
|
|
146
128
|
const result = await RouteVariants.getVariantsFromProps(props);
|
|
147
129
|
expect(result).toEqual({
|
|
148
130
|
isMobile: false,
|
|
149
131
|
locale: 'en-US',
|
|
150
|
-
theme: 'light',
|
|
151
132
|
});
|
|
152
133
|
});
|
|
153
134
|
|
|
154
135
|
it('should handle mobile variants from props', async () => {
|
|
155
136
|
const props: DynamicLayoutProps = {
|
|
156
|
-
params: Promise.resolve({ variants: 'zh-
|
|
137
|
+
params: Promise.resolve({ variants: 'zh-CN__1' }),
|
|
157
138
|
};
|
|
158
139
|
const result = await RouteVariants.getVariantsFromProps(props);
|
|
159
140
|
expect(result).toEqual({
|
|
160
141
|
isMobile: true,
|
|
161
142
|
locale: 'zh-CN',
|
|
162
|
-
theme: 'dark',
|
|
163
143
|
});
|
|
164
144
|
});
|
|
165
145
|
|
|
@@ -175,7 +155,7 @@ describe('RouteVariants', () => {
|
|
|
175
155
|
describe('getIsMobile', () => {
|
|
176
156
|
it('should extract isMobile as false from props', async () => {
|
|
177
157
|
const props: DynamicLayoutProps = {
|
|
178
|
-
params: Promise.resolve({ variants: 'en-
|
|
158
|
+
params: Promise.resolve({ variants: 'en-US__0' }),
|
|
179
159
|
};
|
|
180
160
|
const result = await RouteVariants.getIsMobile(props);
|
|
181
161
|
expect(result).toBe(false);
|
|
@@ -183,7 +163,7 @@ describe('RouteVariants', () => {
|
|
|
183
163
|
|
|
184
164
|
it('should extract isMobile as true from props', async () => {
|
|
185
165
|
const props: DynamicLayoutProps = {
|
|
186
|
-
params: Promise.resolve({ variants: 'en-
|
|
166
|
+
params: Promise.resolve({ variants: 'en-US__1' }),
|
|
187
167
|
};
|
|
188
168
|
const result = await RouteVariants.getIsMobile(props);
|
|
189
169
|
expect(result).toBe(true);
|
|
@@ -201,7 +181,7 @@ describe('RouteVariants', () => {
|
|
|
201
181
|
describe('getLocale', () => {
|
|
202
182
|
it('should extract locale from props', async () => {
|
|
203
183
|
const props: DynamicLayoutProps = {
|
|
204
|
-
params: Promise.resolve({ variants: 'zh-
|
|
184
|
+
params: Promise.resolve({ variants: 'zh-CN__0' }),
|
|
205
185
|
};
|
|
206
186
|
const result = await RouteVariants.getLocale(props);
|
|
207
187
|
expect(result).toBe('zh-CN');
|
|
@@ -209,7 +189,7 @@ describe('RouteVariants', () => {
|
|
|
209
189
|
|
|
210
190
|
it('should extract different locale from props', async () => {
|
|
211
191
|
const props: DynamicLayoutProps = {
|
|
212
|
-
params: Promise.resolve({ variants: 'ja-
|
|
192
|
+
params: Promise.resolve({ variants: 'ja-JP__1' }),
|
|
213
193
|
};
|
|
214
194
|
const result = await RouteVariants.getLocale(props);
|
|
215
195
|
expect(result).toBe('ja-JP');
|
|
@@ -225,7 +205,7 @@ describe('RouteVariants', () => {
|
|
|
225
205
|
|
|
226
206
|
it('should return default locale for invalid locale in props', async () => {
|
|
227
207
|
const props: DynamicLayoutProps = {
|
|
228
|
-
params: Promise.resolve({ variants: 'invalid-
|
|
208
|
+
params: Promise.resolve({ variants: 'invalid-locale__0' }),
|
|
229
209
|
};
|
|
230
210
|
const result = await RouteVariants.getLocale(props);
|
|
231
211
|
expect(result).toBe(DEFAULT_LANG);
|
|
@@ -254,24 +234,14 @@ describe('RouteVariants', () => {
|
|
|
254
234
|
});
|
|
255
235
|
});
|
|
256
236
|
|
|
257
|
-
it('should create variants with custom theme', () => {
|
|
258
|
-
const result = RouteVariants.createVariants({ theme: 'dark' });
|
|
259
|
-
expect(result).toEqual({
|
|
260
|
-
...DEFAULT_VARIANTS,
|
|
261
|
-
theme: 'dark',
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
|
|
265
237
|
it('should create variants with multiple custom options', () => {
|
|
266
238
|
const result = RouteVariants.createVariants({
|
|
267
239
|
isMobile: true,
|
|
268
240
|
locale: 'ja-JP',
|
|
269
|
-
theme: 'dark',
|
|
270
241
|
});
|
|
271
242
|
expect(result).toEqual({
|
|
272
243
|
isMobile: true,
|
|
273
244
|
locale: 'ja-JP',
|
|
274
|
-
theme: 'dark',
|
|
275
245
|
});
|
|
276
246
|
});
|
|
277
247
|
|
|
@@ -293,14 +263,12 @@ describe('RouteVariants', () => {
|
|
|
293
263
|
locale: 'zh-CN',
|
|
294
264
|
neutralColor: '#aaaaaa',
|
|
295
265
|
primaryColor: '#00ff00',
|
|
296
|
-
theme: 'dark',
|
|
297
266
|
});
|
|
298
267
|
expect(result).toEqual({
|
|
299
268
|
isMobile: true,
|
|
300
269
|
locale: 'zh-CN',
|
|
301
270
|
neutralColor: '#aaaaaa',
|
|
302
271
|
primaryColor: '#00ff00',
|
|
303
|
-
theme: 'dark',
|
|
304
272
|
});
|
|
305
273
|
});
|
|
306
274
|
});
|
|
@@ -310,7 +278,6 @@ describe('RouteVariants', () => {
|
|
|
310
278
|
const original: IRouteVariants = {
|
|
311
279
|
isMobile: true,
|
|
312
280
|
locale: 'zh-CN',
|
|
313
|
-
theme: 'dark',
|
|
314
281
|
};
|
|
315
282
|
const serialized = RouteVariants.serializeVariants(original);
|
|
316
283
|
const deserialized = RouteVariants.deserializeVariants(serialized);
|
|
@@ -329,7 +296,6 @@ describe('RouteVariants', () => {
|
|
|
329
296
|
const original: IRouteVariants = {
|
|
330
297
|
isMobile: false,
|
|
331
298
|
locale: locale as any,
|
|
332
|
-
theme: 'light',
|
|
333
299
|
};
|
|
334
300
|
const serialized = RouteVariants.serializeVariants(original);
|
|
335
301
|
const deserialized = RouteVariants.deserializeVariants(serialized);
|
|
@@ -3,7 +3,6 @@ import { RouteVariants } from '@lobechat/desktop-bridge';
|
|
|
3
3
|
import { type DynamicLayoutProps } from '@/types/next';
|
|
4
4
|
|
|
5
5
|
export { LOBE_LOCALE_COOKIE } from '@/const/locale';
|
|
6
|
-
export { LOBE_THEME_APPEARANCE } from '@/const/theme';
|
|
7
6
|
export {
|
|
8
7
|
DEFAULT_LANG,
|
|
9
8
|
DEFAULT_VARIANTS,
|