feat: add privacy mode, thinking levels, PWA support, and i18n
- Add privacy mode to hide IP and user preferences from AI requests - Add model thinking levels (low/medium/high) for context analysis depth - Add PWA support with service worker, manifest, and app icons - Add SettingsPanel for user preferences (theme, background, language) - Add i18n translations for en/zh/ja/ko/de/fr - Add Pinia store for centralized settings management - Update backend to support user preferences and thinking levels - Update config to use absolute API URLs
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
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')
|
||||
// const timezone = ref('auto') // removed
|
||||
|
||||
// 5. Background
|
||||
const backgroundType = ref('default') // 'default' | 'warm' | 'reading' | 'image'
|
||||
// const backgroundColor = ref('#ffffff') // removed
|
||||
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.timezone) timezone.value = data.timezone // timezone legacy ignore
|
||||
if (data.backgroundType) {
|
||||
// migrate color to default if needed, or mapped
|
||||
if (data.backgroundType === 'color') backgroundType.value = 'default'
|
||||
else backgroundType.value = data.backgroundType
|
||||
}
|
||||
// if (data.backgroundColor) backgroundColor.value = data.backgroundColor // removed
|
||||
if (data.backgroundImage) backgroundImage.value = data.backgroundImage
|
||||
if (data.backgroundOpacity) backgroundOpacity.value = data.backgroundOpacity
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load settings', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
// timezone: timezone.value, // removed
|
||||
backgroundType: backgroundType.value,
|
||||
// backgroundColor: backgroundColor.value, // removed
|
||||
backgroundImage: backgroundImage.value,
|
||||
backgroundOpacity: backgroundOpacity.value,
|
||||
}
|
||||
localStorage.setItem('llm-in-text-settings', JSON.stringify(data))
|
||||
} catch (e) {
|
||||
console.error('Failed to save settings', e)
|
||||
}
|
||||
}
|
||||
|
||||
// Reset to defaults
|
||||
const resetSettings = () => {
|
||||
theme.value = 'system'
|
||||
modelThinking.value = 'low'
|
||||
debounceMs.value = 1000
|
||||
privacyMode.value = false
|
||||
language.value = 'auto'
|
||||
currency.value = 'auto'
|
||||
// timezone.value = 'auto' // removed
|
||||
backgroundType.value = 'default'
|
||||
// backgroundColor.value = '#ffffff' // removed
|
||||
backgroundImage.value = ''
|
||||
backgroundOpacity.value = 0.2
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
// Auto-save watchers
|
||||
watch(
|
||||
[
|
||||
theme,
|
||||
modelThinking,
|
||||
debounceMs,
|
||||
privacyMode,
|
||||
language,
|
||||
currency,
|
||||
// timezone, // removed
|
||||
backgroundType,
|
||||
// backgroundColor, // removed
|
||||
backgroundImage,
|
||||
backgroundOpacity,
|
||||
],
|
||||
() => {
|
||||
saveSettings()
|
||||
}
|
||||
)
|
||||
|
||||
// Initialize
|
||||
loadSettings()
|
||||
|
||||
return {
|
||||
theme,
|
||||
modelThinking,
|
||||
debounceMs,
|
||||
privacyMode,
|
||||
language,
|
||||
currency,
|
||||
// timezone, // removed
|
||||
backgroundType,
|
||||
// backgroundColor, // removed
|
||||
backgroundImage,
|
||||
backgroundOpacity,
|
||||
uiLanguage,
|
||||
t,
|
||||
resetSettings
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user