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

150 lines
4.7 KiB
JavaScript
Raw Normal View History

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
// 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
// --- 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[uiLanguage.value] || translations['en']
})
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 (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
}
} catch {
// Failed to load settings, use defaults
}
}
// Save to localStorage
const saveSettings = () => {
try {
const data = {
theme: theme.value,
modelThinking: modelThinking.value,
debounceMs: debounceMs.value,
privacyMode: privacyMode.value,
language: language.value,
currency: currency.value,
backgroundType: backgroundType.value,
backgroundImage: backgroundImage.value,
backgroundOpacity: backgroundOpacity.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
privacyMode.value = false
language.value = 'auto'
currency.value = 'auto'
backgroundType.value = 'default'
backgroundImage.value = ''
backgroundOpacity.value = 0.2
saveSettings()
}
// Auto-save watchers
watch(
[
theme,
modelThinking,
debounceMs,
privacyMode,
language,
currency,
backgroundType,
backgroundImage,
backgroundOpacity,
],
() => {
saveSettings()
}
)
// Initialize
loadSettings()
return {
theme,
modelThinking,
debounceMs,
privacyMode,
language,
currency,
backgroundType,
backgroundImage,
backgroundOpacity,
uiLanguage,
t,
initialMarkdown,
resetSettings
}
})