diff --git a/desktop/src/i18n/locales/en.ts b/desktop/src/i18n/locales/en.ts
index 46de2bb2..7589cc80 100644
--- a/desktop/src/i18n/locales/en.ts
+++ b/desktop/src/i18n/locales/en.ts
@@ -677,9 +677,10 @@ export const en = {
// Settings > General
'settings.general.appearanceTitle': 'Appearance',
- 'settings.general.appearanceDescription': 'Switch between the original light workspace and the new dark workspace.',
- 'settings.general.appearance.light': 'Light',
+ 'settings.general.appearanceDescription': 'Switch between the warm classic workspace, dark workspace, and a pure white workspace.',
+ 'settings.general.appearance.light': 'Warm Classic',
'settings.general.appearance.dark': 'Dark',
+ 'settings.general.appearance.white': 'Pure White',
'settings.general.languageTitle': 'Language',
'settings.general.languageDescription': 'Choose the display language for the application.',
'settings.general.responseLangTitle': 'Response Language',
diff --git a/desktop/src/i18n/locales/zh.ts b/desktop/src/i18n/locales/zh.ts
index c2e46a9e..d8ec51f9 100644
--- a/desktop/src/i18n/locales/zh.ts
+++ b/desktop/src/i18n/locales/zh.ts
@@ -679,9 +679,10 @@ export const zh: Record
= {
// Settings > General
'settings.general.appearanceTitle': '配色主题',
- 'settings.general.appearanceDescription': '在亮色与暗色工作区之间切换,不影响原有亮色主题。',
- 'settings.general.appearance.light': '亮色',
+ 'settings.general.appearanceDescription': '在经典暖色、暗色与纯白工作区之间切换。',
+ 'settings.general.appearance.light': '经典暖色',
'settings.general.appearance.dark': '暗色',
+ 'settings.general.appearance.white': '纯白',
'settings.general.languageTitle': '语言',
'settings.general.languageDescription': '选择应用程序的显示语言。',
'settings.general.responseLangTitle': '回复语言',
diff --git a/desktop/src/lib/desktopRuntime.test.ts b/desktop/src/lib/desktopRuntime.test.ts
index 867d68d3..0e39c865 100644
--- a/desktop/src/lib/desktopRuntime.test.ts
+++ b/desktop/src/lib/desktopRuntime.test.ts
@@ -158,6 +158,26 @@ describe('desktopRuntime browser H5 bootstrap', () => {
})
})
+ it('prefers an explicit Vite desktop server URL over a remembered H5 server URL', async () => {
+ clientMocks.defaultBaseUrl = 'http://127.0.0.1:55189'
+ clientMocks.explicitDefaultBaseUrl = true
+ window.history.pushState({}, '', '/')
+ window.localStorage.setItem(H5_SERVER_URL_STORAGE_KEY, 'http://192.168.0.102:3456')
+ window.localStorage.setItem(H5_TOKEN_STORAGE_KEY, 'stale-h5-token')
+ globalThis.fetch = vi.fn().mockResolvedValue(
+ healthOkResponse(),
+ ) as typeof fetch
+
+ await expect(initializeDesktopServerUrl()).resolves.toBe('http://127.0.0.1:55189')
+
+ expect(clientMocks.setBaseUrl).toHaveBeenLastCalledWith('http://127.0.0.1:55189')
+ expect(clientMocks.setAuthToken).toHaveBeenLastCalledWith(null)
+ expect(clientMocks.postVerify).not.toHaveBeenCalled()
+ expect(globalThis.fetch).toHaveBeenCalledWith('http://127.0.0.1:55189/api/status', {
+ cache: 'no-store',
+ })
+ })
+
it('normalizes unreachable remote browser startup into a recoverable H5 error', async () => {
vi.useFakeTimers()
globalThis.fetch = vi.fn().mockRejectedValue(new TypeError('Failed to fetch')) as typeof fetch
diff --git a/desktop/src/lib/desktopRuntime.ts b/desktop/src/lib/desktopRuntime.ts
index 07d850ae..f39ff09b 100644
--- a/desktop/src/lib/desktopRuntime.ts
+++ b/desktop/src/lib/desktopRuntime.ts
@@ -137,10 +137,11 @@ async function initializeBrowserServerUrl(fallbackUrl: string) {
const queryUrl = query?.get('serverUrl') ?? null
const queryToken = normalizeToken(query?.get('h5Token') ?? query?.get('token'))
const stored = readStoredH5Connection()
+ const configuredUrl = getConfiguredBrowserServerUrl(fallbackUrl)
const requestedUrl =
normalizeServerUrl(queryUrl) ??
+ configuredUrl ??
stored.serverUrl ??
- getConfiguredBrowserServerUrl(fallbackUrl) ??
fallbackUrl
const token = queryToken ?? stored.token
const browserH5Runtime = requiresH5AuthForServerUrl(requestedUrl)
diff --git a/desktop/src/lib/persistenceMigrations.test.ts b/desktop/src/lib/persistenceMigrations.test.ts
index 107ca10e..a461ed91 100644
--- a/desktop/src/lib/persistenceMigrations.test.ts
+++ b/desktop/src/lib/persistenceMigrations.test.ts
@@ -56,6 +56,15 @@ describe('desktop persistence migrations', () => {
expect(window.localStorage.getItem('cc-haha-theme')).toBeNull()
})
+ test('preserves the pure white theme as a valid persisted theme', () => {
+ window.localStorage.setItem('cc-haha-theme', 'white')
+
+ const report = runDesktopPersistenceMigrations()
+
+ expect(report.migratedKeys).not.toContain('cc-haha-theme')
+ expect(window.localStorage.getItem('cc-haha-theme')).toBe('white')
+ })
+
test('does not throw if schema version persistence is blocked', () => {
const storage = {
getItem: window.localStorage.getItem.bind(window.localStorage),
diff --git a/desktop/src/lib/persistenceMigrations.ts b/desktop/src/lib/persistenceMigrations.ts
index a8c4cf7d..5c889ebd 100644
--- a/desktop/src/lib/persistenceMigrations.ts
+++ b/desktop/src/lib/persistenceMigrations.ts
@@ -1,3 +1,5 @@
+import { THEME_MODES } from '../types/settings'
+
export const CURRENT_DESKTOP_PERSISTENCE_SCHEMA_VERSION = 1
export const DESKTOP_PERSISTENCE_VERSION_KEY = 'cc-haha.persistence.schemaVersion'
@@ -138,7 +140,7 @@ export function runDesktopPersistenceMigrations(storage: StorageLike | null = ge
runMigrationStep(report, TAB_STORAGE_KEY, () => migrateTabs(storage, report))
runMigrationStep(report, SESSION_RUNTIME_STORAGE_KEY, () => migrateSessionRuntime(storage, report))
- runMigrationStep(report, THEME_STORAGE_KEY, () => normalizeEnumKey(storage, THEME_STORAGE_KEY, ['light', 'dark'], report))
+ runMigrationStep(report, THEME_STORAGE_KEY, () => normalizeEnumKey(storage, THEME_STORAGE_KEY, [...THEME_MODES], report))
runMigrationStep(report, LOCALE_STORAGE_KEY, () => normalizeEnumKey(storage, LOCALE_STORAGE_KEY, ['zh', 'en'], report))
try {
storage.setItem(DESKTOP_PERSISTENCE_VERSION_KEY, String(CURRENT_DESKTOP_PERSISTENCE_SCHEMA_VERSION))
diff --git a/desktop/src/pages/ActivitySettings.tsx b/desktop/src/pages/ActivitySettings.tsx
index 3cbd71e3..88d0c594 100644
--- a/desktop/src/pages/ActivitySettings.tsx
+++ b/desktop/src/pages/ActivitySettings.tsx
@@ -31,10 +31,10 @@ const HEAT_CELL_MAX = 22
const TOOLTIP_WIDTH = 172
const HEAT_COLORS = [
'var(--color-surface-container)',
- '#f5d4c4',
- '#eea47f',
- '#df6b47',
- '#bd432c',
+ 'var(--color-primary-fixed)',
+ 'var(--color-primary-fixed-dim)',
+ 'var(--color-primary-container)',
+ 'var(--color-primary)',
]
const DATE_LOCALES: Record = {
en: 'en-US',
@@ -401,11 +401,11 @@ export function ActivitySettings() {