2026-02-19 10:22:27 +08:00
|
|
|
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(false)
|
|
|
|
|
|
|
|
|
|
// 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']
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// --- 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
|
|
|
|
|
}
|
2026-03-10 23:26:18 +08:00
|
|
|
} catch {
|
|
|
|
|
// Failed to load settings, use defaults
|
2026-02-19 10:22:27 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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))
|
2026-03-10 23:26:18 +08:00
|
|
|
} catch {
|
|
|
|
|
// Failed to save settings
|
2026-02-19 10:22:27 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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,
|
|
|
|
|
resetSettings
|
|
|
|
|
}
|
|
|
|
|
})
|