feat: update AGENTS.md with new components and API details; enhance FileContent.vue with Plyr video support; add VideoPlayer.vue for video playback; improve MilkdownEditor.vue for video file handling; refine TTSPlayer.vue volume controls; optimize settings store for localStorage; implement video upload support in uploadBlock.js; create utility functions for Plyr player management.
This commit is contained in:
+52
-134
@@ -2,165 +2,83 @@ 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', () => {
|
||||
// --- 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
|
||||
// --- 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)
|
||||
|
||||
// 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 backgroundOpacity = ref(0.2) // 0.05 - 0.50
|
||||
const ttsInstruct = ref('')
|
||||
|
||||
// --- Getters ---
|
||||
// --- Computed getters (derived from reactive state) ---
|
||||
const uiLanguage = computed(() => {
|
||||
if (language.value !== 'auto') {
|
||||
return language.value
|
||||
}
|
||||
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'
|
||||
return ['zh', 'en', 'ja', 'ko', 'de', 'fr'].includes(sysLang) ? sysLang : 'en'
|
||||
})
|
||||
|
||||
const detectedTimezone = computed(() => {
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'
|
||||
})
|
||||
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 || '')
|
||||
|
||||
// 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
|
||||
// --- localStorage persistence ---
|
||||
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
|
||||
}
|
||||
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 */ }
|
||||
}
|
||||
|
||||
// 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,
|
||||
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,
|
||||
}
|
||||
localStorage.setItem('llm-in-text-settings', JSON.stringify(data))
|
||||
} catch {
|
||||
// Failed to save settings
|
||||
}
|
||||
}))
|
||||
} catch { /* silently fail */ }
|
||||
}
|
||||
|
||||
// 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()
|
||||
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()
|
||||
}
|
||||
)
|
||||
// Watch all reactive refs and auto-save on change
|
||||
watch([theme, modelThinking, debounceMs, proThinking, privacyMode, language, currency
|
||||
, backgroundType, backgroundImage, backgroundOpacity, ttsInstruct], saveSettings)
|
||||
|
||||
// Initialize
|
||||
loadSettings()
|
||||
loadSettings() // Initialize from localStorage
|
||||
|
||||
return {
|
||||
theme,
|
||||
modelThinking,
|
||||
debounceMs,
|
||||
proThinking,
|
||||
privacyMode,
|
||||
language,
|
||||
currency,
|
||||
backgroundType,
|
||||
backgroundImage,
|
||||
backgroundOpacity,
|
||||
ttsInstruct,
|
||||
detectedTimezone,
|
||||
uiLanguage,
|
||||
t,
|
||||
initialMarkdown,
|
||||
resetSettings
|
||||
}
|
||||
return { theme, modelThinking, debounceMs, proThinking, privacyMode, language
|
||||
, currency, backgroundType, backgroundImage, backgroundOpacity, ttsInstruct
|
||||
, detectedTimezone, uiLanguage, t, initialMarkdown, resetSettings }
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user