import { defineStore } from 'pinia' import { ref, watch, computed } from 'vue' import { translations } from '../utils/i18n' export const useSettingsStore = defineStore('settings', () => { // --- State --- // 1. Theme (handled partly by useTheme, but we keep a ref here for the UI) const theme = ref('system') // 'light' | 'dark' | 'system' // 2. Model Behavior const modelThinking = ref('low') // 'low' | 'medium' | 'high' const debounceMs = ref(1000) // 1000 - 5000 const proThinking = ref('medium') // 'low' | 'medium' | 'high' // 3. Privacy const privacyMode = ref(true) // 4. Preferences const language = ref('auto') const currency = ref('auto') // 5. Background const backgroundType = ref('default') // 'default' | 'warm' | 'reading' | 'image' const backgroundImage = ref('') const backgroundOpacity = ref(0.2) // 0.05 - 0.50 // TTS Voice const ttsInstruct = ref('') // --- Getters --- const uiLanguage = computed(() => { if (language.value !== 'auto') { return language.value } const sysLang = (navigator.language || navigator.userLanguage || 'en').split('-')[0] const supported = ['zh', 'en', 'ja', 'ko', 'de', 'fr'] return supported.includes(sysLang) ? sysLang : 'en' }) const detectedTimezone = computed(() => { return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC' }) // We can't easily detect currency by IP on the frontend without an external API. // We will let the backend handle 'auto' currency if needed, or stick to auto label. const t = computed(() => { return { ...translations['en'], ...(translations[uiLanguage.value] || {}), } }) const initialMarkdown = computed(() => { const lang = uiLanguage.value return translations[lang]?.initialMarkdown || translations['en']?.initialMarkdown || '' }) // --- Actions/Logic --- // Load from localStorage const loadSettings = () => { try { const stored = localStorage.getItem('llm-in-text-settings') if (stored) { const data = JSON.parse(stored) if (data.theme) theme.value = data.theme if (data.modelThinking) modelThinking.value = data.modelThinking if (data.debounceMs) debounceMs.value = data.debounceMs if (data.proThinking) proThinking.value = data.proThinking if (typeof data.privacyMode === 'boolean') privacyMode.value = data.privacyMode if (data.language) language.value = data.language if (data.currency) currency.value = data.currency if (data.backgroundType) { if (data.backgroundType === 'color') backgroundType.value = 'default' else backgroundType.value = data.backgroundType } if (data.backgroundImage) backgroundImage.value = data.backgroundImage if (data.backgroundOpacity) backgroundOpacity.value = data.backgroundOpacity if (typeof data.ttsInstruct === 'string') ttsInstruct.value = data.ttsInstruct } } catch { // Failed to load settings, use defaults } } // Save to localStorage const saveSettings = () => { try { const data = { theme: theme.value, modelThinking: modelThinking.value, debounceMs: debounceMs.value, proThinking: proThinking.value, privacyMode: privacyMode.value, language: language.value, currency: currency.value, backgroundType: backgroundType.value, backgroundImage: backgroundImage.value, backgroundOpacity: backgroundOpacity.value, ttsInstruct: ttsInstruct.value, } localStorage.setItem('llm-in-text-settings', JSON.stringify(data)) } catch { // Failed to save settings } } // Reset to defaults const resetSettings = () => { theme.value = 'system' modelThinking.value = 'low' debounceMs.value = 1000 proThinking.value = 'medium' privacyMode.value = false language.value = 'auto' currency.value = 'auto' backgroundType.value = 'default' backgroundImage.value = '' backgroundOpacity.value = 0.2 ttsInstruct.value = '' saveSettings() } // Auto-save watchers watch( [ theme, modelThinking, debounceMs, proThinking, privacyMode, language, currency, backgroundType, backgroundImage, backgroundOpacity, ttsInstruct, ], () => { saveSettings() } ) // Initialize loadSettings() return { theme, modelThinking, debounceMs, proThinking, privacyMode, language, currency, backgroundType, backgroundImage, backgroundOpacity, ttsInstruct, detectedTimezone, uiLanguage, t, initialMarkdown, resetSettings } })