Files
llm-in-text/src/stores/settings.js
T

85 lines
4.3 KiB
JavaScript
Raw Normal View History

import { defineStore } from 'pinia'
import { ref, watch, computed } from 'vue'
import { translations } from '../utils/i18n'
// Settings persisted in localStorage under 'llm-in-text-settings'
const SETTINGS_KEY = 'llm-in-text-settings'
export const useSettingsStore = defineStore('settings', () => {
// --- Reactive state (all auto-tracked by watch below) ---
const theme = ref('system') // 'light' | 'dark' | 'system'
const modelThinking = ref('low') // 'low' | 'medium' | 'high'
const debounceMs = ref(1000) // 1000 - 5000
const proThinking = ref('medium') // 'low' | 'medium' | 'high'
const privacyMode = ref(true)
const language = ref('auto')
const currency = ref('auto')
const backgroundType = ref('default') // 'default' | 'warm' | 'reading' | 'image'
const backgroundImage = ref('')
const backgroundOpacity = ref(0.2) // 0.05 - 0.50
const ttsInstruct = ref('')
// --- Computed getters (derived from reactive state) ---
const uiLanguage = computed(() => {
if (language.value !== 'auto') return language.value
const sysLang = (navigator.language || navigator.userLanguage || 'en').split('-')[0]
return ['zh', 'en', 'ja', 'ko', 'de', 'fr'].includes(sysLang) ? sysLang : 'en'
})
const detectedTimezone = computed(() => Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC')
const t = computed(() => ({ ...translations['en'], ...(translations[uiLanguage.value] || {}) }))
const initialMarkdown = computed(() => translations[uiLanguage.value]?.initialMarkdown || translations['en']?.initialMarkdown || '')
// --- localStorage persistence ---
const loadSettings = () => {
try {
const stored = localStorage.getItem(SETTINGS_KEY)
if (!stored) return
const data = JSON.parse(stored)
// Restore each field with type guards
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 === 'color') backgroundType.value = 'default'
else if (data.backgroundType) 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 { /* use defaults */ }
}
const saveSettings = () => {
try {
localStorage.setItem(SETTINGS_KEY, JSON.stringify({
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,
}))
} catch { /* silently fail */ }
}
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()
}
// Watch all reactive refs and auto-save on change
watch([theme, modelThinking, debounceMs, proThinking, privacyMode, language, currency
, backgroundType, backgroundImage, backgroundOpacity, ttsInstruct], saveSettings)
loadSettings() // Initialize from localStorage
return { theme, modelThinking, debounceMs, proThinking, privacyMode, language
, currency, backgroundType, backgroundImage, backgroundOpacity, ttsInstruct
, detectedTimezone, uiLanguage, t, initialMarkdown, resetSettings }
})