@lobehub/lobehub 2.0.0-next.213 → 2.0.0-next.215
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/.github/workflows/e2e.yml +1 -1
- package/.github/workflows/pr-build-desktop.yml +2 -2
- package/.github/workflows/release-desktop-beta.yml +2 -2
- package/.github/workflows/release.yml +1 -1
- package/.github/workflows/test.yml +2 -2
- package/CHANGELOG.md +51 -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 +14 -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/Portal/Document/Header.tsx +11 -9
- 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
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
ThemeProvider,
|
|
9
9
|
} from '@lobehub/ui';
|
|
10
10
|
import { message as antdMessage } from 'antd';
|
|
11
|
-
import {
|
|
11
|
+
import { createStaticStyles, cx, useTheme } from 'antd-style';
|
|
12
12
|
import 'antd/dist/reset.css';
|
|
13
13
|
import { AppConfigContext } from 'antd/es/app/context';
|
|
14
14
|
import * as motion from 'motion/react-m';
|
|
@@ -17,13 +17,10 @@ import Link from 'next/link';
|
|
|
17
17
|
import { type ReactNode, memo, useEffect, useMemo, useState } from 'react';
|
|
18
18
|
|
|
19
19
|
import AntdStaticMethods from '@/components/AntdStaticMethods';
|
|
20
|
-
import {
|
|
21
|
-
LOBE_THEME_APPEARANCE,
|
|
22
|
-
LOBE_THEME_NEUTRAL_COLOR,
|
|
23
|
-
LOBE_THEME_PRIMARY_COLOR,
|
|
24
|
-
} from '@/const/theme';
|
|
20
|
+
import { LOBE_THEME_NEUTRAL_COLOR, LOBE_THEME_PRIMARY_COLOR } from '@/const/theme';
|
|
25
21
|
import { isDesktop } from '@/const/version';
|
|
26
22
|
import { TITLE_BAR_HEIGHT } from '@/features/ElectronTitlebar';
|
|
23
|
+
import { useIsDark } from '@/hooks/useIsDark';
|
|
27
24
|
import { getUILocaleAndResources } from '@/libs/getUILocaleAndResources';
|
|
28
25
|
import { useGlobalStore } from '@/store/global';
|
|
29
26
|
import { systemStatusSelectors } from '@/store/global/selectors';
|
|
@@ -92,7 +89,6 @@ export interface AppThemeProps {
|
|
|
92
89
|
children?: ReactNode;
|
|
93
90
|
customFontFamily?: string;
|
|
94
91
|
customFontURL?: string;
|
|
95
|
-
defaultAppearance?: ThemeAppearance;
|
|
96
92
|
defaultNeutralColor?: NeutralColors;
|
|
97
93
|
defaultPrimaryColor?: PrimaryColors;
|
|
98
94
|
globalCDN?: boolean;
|
|
@@ -101,16 +97,16 @@ export interface AppThemeProps {
|
|
|
101
97
|
const AppTheme = memo<AppThemeProps>(
|
|
102
98
|
({
|
|
103
99
|
children,
|
|
104
|
-
defaultAppearance,
|
|
105
100
|
defaultPrimaryColor,
|
|
106
101
|
defaultNeutralColor,
|
|
107
102
|
globalCDN,
|
|
108
103
|
customFontURL,
|
|
109
104
|
customFontFamily,
|
|
110
105
|
}) => {
|
|
111
|
-
const themeMode = useGlobalStore(systemStatusSelectors.themeMode);
|
|
112
106
|
const language = useGlobalStore(systemStatusSelectors.language);
|
|
113
|
-
const
|
|
107
|
+
const antdTheme = useTheme();
|
|
108
|
+
const isDark = useIsDark();
|
|
109
|
+
|
|
114
110
|
const [primaryColor, neutralColor, animationMode] = useUserStore((s) => [
|
|
115
111
|
userGeneralSettingsSelectors.primaryColor(s),
|
|
116
112
|
userGeneralSettingsSelectors.neutralColor(s),
|
|
@@ -154,29 +150,29 @@ const AppTheme = memo<AppThemeProps>(
|
|
|
154
150
|
antdMessage.config({ top: messageTop });
|
|
155
151
|
}, [messageTop]);
|
|
156
152
|
|
|
153
|
+
const currentAppearence = isDark ? 'dark' : 'light';
|
|
154
|
+
|
|
157
155
|
return (
|
|
158
156
|
<AppConfigContext.Provider value={appConfig}>
|
|
159
157
|
<ThemeProvider
|
|
160
|
-
appearance={
|
|
158
|
+
appearance={currentAppearence}
|
|
161
159
|
className={cx(styles.app, styles.scrollbar, styles.scrollbarPolyfill)}
|
|
162
160
|
customTheme={{
|
|
163
161
|
neutralColor: neutralColor ?? defaultNeutralColor,
|
|
164
162
|
primaryColor: primaryColor ?? defaultPrimaryColor,
|
|
165
163
|
}}
|
|
166
|
-
defaultAppearance={
|
|
167
|
-
|
|
168
|
-
if (themeMode !== 'auto') return;
|
|
169
|
-
|
|
170
|
-
setCookie(LOBE_THEME_APPEARANCE, appearance);
|
|
171
|
-
}}
|
|
164
|
+
defaultAppearance={currentAppearence}
|
|
165
|
+
defaultThemeMode={currentAppearence}
|
|
172
166
|
theme={{
|
|
167
|
+
cssVar: { key: 'lobe-vars' },
|
|
173
168
|
token: {
|
|
174
|
-
fontFamily: customFontFamily
|
|
169
|
+
fontFamily: customFontFamily
|
|
170
|
+
? `${customFontFamily},${antdTheme.fontFamily}`
|
|
171
|
+
: undefined,
|
|
175
172
|
motion: animationMode !== 'disabled',
|
|
176
173
|
motionUnit: animationMode === 'agile' ? 0.05 : 0.1,
|
|
177
174
|
},
|
|
178
175
|
}}
|
|
179
|
-
themeMode={themeMode}
|
|
180
176
|
>
|
|
181
177
|
{!!customFontURL && <FontLoader url={customFontURL} />}
|
|
182
178
|
<GlobalStyle />
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ThemeProvider as NextThemesProvider } from 'next-themes';
|
|
4
|
+
import { type ReactNode } from 'react';
|
|
5
|
+
|
|
6
|
+
interface NextThemeProviderProps {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function NextThemeProvider({ children }: NextThemeProviderProps) {
|
|
11
|
+
return (
|
|
12
|
+
<NextThemesProvider
|
|
13
|
+
attribute="data-theme"
|
|
14
|
+
defaultTheme="system"
|
|
15
|
+
disableTransitionOnChange
|
|
16
|
+
enableSystem
|
|
17
|
+
forcedTheme={undefined}
|
|
18
|
+
>
|
|
19
|
+
{children}
|
|
20
|
+
</NextThemesProvider>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { StyleProvider
|
|
3
|
+
import { StyleProvider } from 'antd-style';
|
|
4
4
|
import { useServerInsertedHTML } from 'next/navigation';
|
|
5
|
-
import { type PropsWithChildren
|
|
5
|
+
import { type PropsWithChildren } from 'react';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
const isInsert = useRef(false);
|
|
7
|
+
import { isDesktop } from '@/const/version';
|
|
9
8
|
|
|
9
|
+
const StyleRegistry = ({ children }: PropsWithChildren) => {
|
|
10
10
|
useServerInsertedHTML(() => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
return (
|
|
12
|
+
<style
|
|
13
|
+
dangerouslySetInnerHTML={{
|
|
14
|
+
__html: `
|
|
15
|
+
html body {background: #f8f8f8;}
|
|
16
|
+
html[data-theme="dark"] body { background-color: #000; }
|
|
17
|
+
${isDesktop ? 'html body, html { background: none; }' : ''}
|
|
18
|
+
${isDesktop ? 'html[data-theme="dark"] body { background: color-mix(in srgb, #000 86%, transparent); }' : ''}
|
|
19
|
+
${isDesktop ? 'html[data-theme="light"] body { background: color-mix(in srgb, #f8f8f8 86%, transparent); }' : ''}
|
|
20
|
+
`,
|
|
21
|
+
}}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
19
24
|
});
|
|
20
25
|
|
|
21
|
-
return <StyleProvider
|
|
26
|
+
return <StyleProvider>{children}</StyleProvider>;
|
|
22
27
|
};
|
|
23
28
|
|
|
24
29
|
export default StyleRegistry;
|
|
@@ -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