import { writable, derived } from "svelte/store"; import { invoke } from "@tauri-apps/api/core"; export type Theme = "dark" | "light" | "high-contrast"; export interface HikariConfig { model: string | null; api_key: string | null; custom_instructions: string | null; mcp_servers_json: string | null; auto_granted_tools: string[]; theme: Theme; greeting_enabled: boolean; greeting_custom_prompt: string | null; notifications_enabled: boolean; notification_volume: number; always_on_top: boolean; minimize_to_tray: boolean; update_checks_enabled: boolean; character_panel_width: number | null; font_size: number; } const defaultConfig: HikariConfig = { model: null, api_key: null, custom_instructions: null, mcp_servers_json: null, auto_granted_tools: [], theme: "dark", greeting_enabled: true, greeting_custom_prompt: null, notifications_enabled: true, notification_volume: 0.7, always_on_top: false, minimize_to_tray: false, update_checks_enabled: true, character_panel_width: null, font_size: 14, }; function createConfigStore() { const config = writable(defaultConfig); const isLoading = writable(true); const isSidebarOpen = writable(false); const saveError = writable(null); async function loadConfig() { isLoading.set(true); try { const savedConfig = await invoke("get_config"); config.set(savedConfig); } catch (error) { console.error("Failed to load config:", error); config.set(defaultConfig); } finally { isLoading.set(false); } } async function saveConfig(newConfig: HikariConfig) { saveError.set(null); try { await invoke("save_config", { config: newConfig }); config.set(newConfig); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); saveError.set(errorMessage); console.error("Failed to save config:", error); throw error; } } async function updateConfig(updates: Partial) { let currentConfig: HikariConfig = defaultConfig; config.subscribe((c) => (currentConfig = c))(); const newConfig = { ...currentConfig, ...updates }; await saveConfig(newConfig); } return { config: { subscribe: config.subscribe }, isLoading: { subscribe: isLoading.subscribe }, isSidebarOpen: { subscribe: isSidebarOpen.subscribe }, saveError: { subscribe: saveError.subscribe }, loadConfig, saveConfig, updateConfig, openSidebar: () => isSidebarOpen.set(true), closeSidebar: () => isSidebarOpen.set(false), toggleSidebar: () => isSidebarOpen.update((open) => !open), setTheme: async (theme: Theme) => { await updateConfig({ theme }); applyTheme(theme); }, setFontSize: async (size: number) => { const clampedSize = Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, size)); await updateConfig({ font_size: clampedSize }); applyFontSize(clampedSize); }, increaseFontSize: async () => { let currentConfig: HikariConfig = defaultConfig; config.subscribe((c) => (currentConfig = c))(); const newSize = Math.min(MAX_FONT_SIZE, currentConfig.font_size + 2); await updateConfig({ font_size: newSize }); applyFontSize(newSize); }, decreaseFontSize: async () => { let currentConfig: HikariConfig = defaultConfig; config.subscribe((c) => (currentConfig = c))(); const newSize = Math.max(MIN_FONT_SIZE, currentConfig.font_size - 2); await updateConfig({ font_size: newSize }); applyFontSize(newSize); }, resetFontSize: async () => { await updateConfig({ font_size: DEFAULT_FONT_SIZE }); applyFontSize(DEFAULT_FONT_SIZE); }, addAutoGrantedTool: async (tool: string) => { let currentConfig: HikariConfig = defaultConfig; config.subscribe((c) => (currentConfig = c))(); if (!currentConfig.auto_granted_tools.includes(tool)) { const newTools = [...currentConfig.auto_granted_tools, tool]; await updateConfig({ auto_granted_tools: newTools }); } }, removeAutoGrantedTool: async (tool: string) => { let currentConfig: HikariConfig = defaultConfig; config.subscribe((c) => (currentConfig = c))(); const newTools = currentConfig.auto_granted_tools.filter((t) => t !== tool); await updateConfig({ auto_granted_tools: newTools }); }, getConfig: (): HikariConfig => { let currentConfig: HikariConfig = defaultConfig; config.subscribe((c) => (currentConfig = c))(); return currentConfig; }, }; } export function applyTheme(theme: Theme) { if (typeof document !== "undefined") { document.documentElement.setAttribute("data-theme", theme); } } const MIN_FONT_SIZE = 10; const MAX_FONT_SIZE = 24; const DEFAULT_FONT_SIZE = 14; export function applyFontSize(size: number) { if (typeof document !== "undefined") { const clampedSize = Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, size)); document.documentElement.style.setProperty("--terminal-font-size", `${clampedSize}px`); } } export function clampFontSize(size: number): number { return Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, size)); } export { MIN_FONT_SIZE, MAX_FONT_SIZE, DEFAULT_FONT_SIZE }; export const configStore = createConfigStore(); export const isDarkTheme = derived(configStore.config, ($config) => $config.theme === "dark");