import { create } from 'zustand' import { createLogger } from '../utils/logger' import { DEFAULT_KEYWORD_HIGHLIGHT_RULES, type KeywordHighlightRule, } from '../utils/keywordHighlight' const logger = createLogger('SettingsStore') export interface AppSettings { // 外观 theme: 'dark' | 'light' | 'system' sidebarWidth: number // 终端 fontFamily: string fontSize: number terminalTheme: 'dracula' | 'monokai' | 'solarized' | 'one-dark' // SSH keepAlive: boolean timeout: number // 专业连接管理 maxConnections: number maxBackgroundConnections: number idleTimeoutMs: number suspendTimeoutMs: number autoReconnect: boolean maxReconnectAttempts: number reconnectBaseDelayMs: number // 终端增强 scrollback: number keywordHighlightEnabled: boolean keywordHighlightRules: KeywordHighlightRule[] } const defaultSettings: AppSettings = { theme: 'dark', sidebarWidth: 256, // Prefer Nerd Font so local zsh powerline prompts render correctly fontFamily: 'MesloLGS NF', fontSize: 14, terminalTheme: 'dracula', keepAlive: true, timeout: 30, // 专业连接管理默认值 maxConnections: 10, maxBackgroundConnections: 5, idleTimeoutMs: 5 * 60 * 1000, // 5 分钟 suspendTimeoutMs: 30 * 60 * 1000, // 30 分钟 autoReconnect: true, maxReconnectAttempts: 5, reconnectBaseDelayMs: 1500, scrollback: 10000, keywordHighlightEnabled: true, keywordHighlightRules: DEFAULT_KEYWORD_HIGHLIGHT_RULES, } export function normalizeAppSettings(value: unknown): AppSettings { const source = value && typeof value === 'object' ? value as Record : {} const normalized: Record = {} for (const key of Object.keys(defaultSettings) as Array) { const candidate = source[key] const fallback = defaultSettings[key] normalized[key] = typeof candidate === typeof fallback ? candidate : fallback } return normalized as unknown as AppSettings } interface SettingsState { settings: AppSettings isLoaded: boolean setSetting: (key: K, value: AppSettings[K]) => Promise loadSettings: () => Promise saveSettings: (settings: Partial) => Promise } export const useSettingsStore = create((set, get) => ({ settings: defaultSettings, isLoaded: false, loadSettings: async () => { try { const result = await window.opsxApi?.settingsGet('app-settings') if (result?.success && result.value) { const settings = normalizeAppSettings(result.value) set({ settings, isLoaded: true }) const storedKeys = Object.keys(result.value as Record) const currentKeys = new Set(Object.keys(defaultSettings)) if (storedKeys.some((key) => !currentKeys.has(key))) { await window.opsxApi?.settingsSet('app-settings', settings) } } else { set({ isLoaded: true }) } } catch (error) { logger.error('Failed to load settings:', error) set({ isLoaded: true }) } }, setSetting: async (key, value) => { const newSettings = { ...get().settings, [key]: value } set({ settings: newSettings }) await window.opsxApi?.settingsSet('app-settings', newSettings) }, saveSettings: async (newSettings) => { const merged = { ...get().settings, ...newSettings } set({ settings: merged }) await window.opsxApi?.settingsSet('app-settings', merged) }, }))