From 8c124b29e940aab5389072598c204216c9a288b0 Mon Sep 17 00:00:00 2001 From: DHX <2587450776@qq.com> Date: Wed, 13 May 2026 22:02:38 +0800 Subject: [PATCH] feat(settings): add UI zoom slider to General Settings - Add uiZoom field to UserSettings type and settingsStore with localStorage persistence - Apply CSS zoom to AppShell root div for full-window scaling - Add zoom slider in GeneralSettings (50%-200%, step 5%, centered at bottom-left) - Export UI_ZOOM_MIN/MAX/STEP constants for consistent range control - Add i18n support for UI zoom label and description (en/zh) Co-Authored-By: Claude Opus 4.7 --- desktop/src/components/layout/AppShell.tsx | 3 ++- desktop/src/components/layout/Sidebar.tsx | 2 +- desktop/src/i18n/locales/en.ts | 2 ++ desktop/src/i18n/locales/zh.ts | 2 ++ desktop/src/pages/Settings.tsx | 30 +++++++++++++++++++++- desktop/src/stores/settingsStore.ts | 24 +++++++++++++++++ desktop/src/types/settings.ts | 1 + 7 files changed, 61 insertions(+), 3 deletions(-) diff --git a/desktop/src/components/layout/AppShell.tsx b/desktop/src/components/layout/AppShell.tsx index c9e578ab..af09547b 100644 --- a/desktop/src/components/layout/AppShell.tsx +++ b/desktop/src/components/layout/AppShell.tsx @@ -28,6 +28,7 @@ function isChatTab(tab: Tab | undefined) { export function AppShell() { const fetchSettings = useSettingsStore((s) => s.fetchAll) + const uiZoom = useSettingsStore((s) => s.uiZoom) const sidebarOpen = useUIStore((s) => s.sidebarOpen) const toggleSidebar = useUIStore((s) => s.toggleSidebar) const setSidebarOpen = useUIStore((s) => s.setSidebarOpen) @@ -194,7 +195,7 @@ export function AppShell() { } return ( -
+
{isMobileShell && effectiveSidebarOpen ? (
+ {/* UI Zoom */} +
+

{t('settings.general.uiZoom')}

+

{t('settings.general.uiZoomDescription')}

+
+
+ + {Math.round(uiZoom * 100)}% + +
+
+ {Math.round(UI_ZOOM_MIN * 100)}% + setUiZoom(parseFloat(e.target.value))} + onMouseUp={(e) => e.currentTarget.blur()} + className="flex-1" + /> + {Math.round(UI_ZOOM_MAX * 100)}% +
+
+
) diff --git a/desktop/src/stores/settingsStore.ts b/desktop/src/stores/settingsStore.ts index afdd4a9d..81b7e9ee 100644 --- a/desktop/src/stores/settingsStore.ts +++ b/desktop/src/stores/settingsStore.ts @@ -8,6 +8,10 @@ import type { Locale } from '../i18n' import { useUIStore } from './uiStore' const LOCALE_STORAGE_KEY = 'cc-haha-locale' +const UI_ZOOM_STORAGE_KEY = 'cc-haha-ui-zoom' +export const UI_ZOOM_MIN = 0.5 +export const UI_ZOOM_MAX = 2.0 +export const UI_ZOOM_STEP = 0.05 let desktopNotificationsSaveQueue: Promise = Promise.resolve() function getStoredLocale(): Locale { @@ -18,6 +22,17 @@ function getStoredLocale(): Locale { return 'zh' } +function getStoredUiZoom(): number { + try { + const stored = localStorage.getItem(UI_ZOOM_STORAGE_KEY) + if (stored === null) return 1.0 + const parsed = parseFloat(stored) + if (isNaN(parsed)) return 1.0 + return Math.min(UI_ZOOM_MAX, Math.max(UI_ZOOM_MIN, parsed)) + } catch { /* localStorage unavailable */ } + return 1.0 +} + type SettingsStore = { permissionMode: PermissionMode currentModel: ModelInfo | null @@ -33,6 +48,7 @@ type SettingsStore = { h5Access: H5AccessSettings h5AccessError: string | null responseLanguage: string + uiZoom: number isLoading: boolean error: string | null @@ -55,6 +71,7 @@ type SettingsStore = { publicBaseUrl?: string | null }) => Promise setResponseLanguage: (language: string) => Promise + setUiZoom: (zoom: number) => void } const DEFAULT_H5_ACCESS_SETTINGS: H5AccessSettings = { @@ -79,9 +96,16 @@ export const useSettingsStore = create((set, get) => ({ h5Access: DEFAULT_H5_ACCESS_SETTINGS, h5AccessError: null, responseLanguage: '', + uiZoom: getStoredUiZoom(), isLoading: false, error: null, + setUiZoom: (zoom: number) => { + const clamped = Math.min(UI_ZOOM_MAX, Math.max(UI_ZOOM_MIN, zoom)) + set({ uiZoom: clamped }) + try { localStorage.setItem(UI_ZOOM_STORAGE_KEY, String(clamped)) } catch { /* noop */ } + }, + fetchAll: async () => { set({ isLoading: true, error: null }) try { diff --git a/desktop/src/types/settings.ts b/desktop/src/types/settings.ts index 4a5b247a..7a2e5393 100644 --- a/desktop/src/types/settings.ts +++ b/desktop/src/types/settings.ts @@ -43,5 +43,6 @@ export type UserSettings = { desktopNotificationsEnabled?: boolean webSearch?: WebSearchSettings language?: string + uiZoom?: number [key: string]: unknown }