import { useState, useEffect } from 'react' import { ThemeProvider } from '@/hooks/useTheme' import { useStorage } from '@/hooks/useStorage' import { Logo } from '@/components/Logo' import { HistoryManager } from '@/components/HistoryManager' import type { UserSettings, Language, SearchHistory } from '@/types' import { DEFAULT_SETTINGS } from '@/types' import { TranslationProvider, useTranslation, translate } from '@/i18n' // 设置页面组件 function App() { const [settings, setSettings] = useState(null) const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [message, setMessage] = useState<{ type: 'success' | 'error'; key: string; params?: Record } | null>(null) const [history, setHistory] = useState([]) const [activeTab, setActiveTab] = useState<'settings' | 'history'>('settings') // 从存储中加载设置和历史记录 const { data: storedSettings, save: saveSettings } = useStorage('user_settings', DEFAULT_SETTINGS) const { data: storedHistory } = useStorage('search_history') useEffect(() => { setSettings(storedSettings || DEFAULT_SETTINGS) setLoading(false) }, [storedSettings]) useEffect(() => { if (storedHistory) { setHistory(storedHistory) } }, [storedHistory]) const language = settings?.language ?? 'zh-CN' // 清除历史记录 const handleClearHistory = () => { if (confirm(translate(language, 'options.confirm.clearHistory'))) { setHistory([]) chrome.storage.local.remove('search_history') } } // 保存设置 const handleSaveSettings = async () => { if (!settings) return setSaving(true) setMessage(null) try { // 检查是否需要清理历史记录 const currentHistoryData = await chrome.storage.local.get('search_history') const currentHistory: SearchHistory[] = currentHistoryData.search_history || [] const willDelete = currentHistory.length - settings.historyLimit // 如果当前记录超过新限制,需要用户确认 if (willDelete > 0) { const confirmed = confirm( translate(language, 'options.confirm.trimHistory', { current: currentHistory.length.toString(), limit: settings.historyLimit.toString(), willDelete: willDelete.toString() }) ) if (!confirmed) { // 用户取消,不保存设置 setSaving(false) setMessage({ type: 'error', key: 'options.messages.saveCancelled' }) setTimeout(() => setMessage(null), 3000) return } // 用户确认,立即清理超出的记录(保留最新的N条) const trimmedHistory = currentHistory.slice(0, settings.historyLimit) await chrome.storage.local.set({ search_history: trimmedHistory }) // 更新本地状态 setHistory(trimmedHistory) } // 保存设置 const success = await saveSettings(settings) if (success) { if (willDelete > 0) { setMessage({ type: 'success', key: 'options.messages.saveSuccessWithTrim', params: { removed: willDelete.toString() } }) } else { setMessage({ type: 'success', key: 'options.messages.saveSuccess' }) } } else { setMessage({ type: 'error', key: 'options.messages.saveFailure' }) } } catch (error) { console.error('保存设置失败:', error) setMessage({ type: 'error', key: 'options.messages.saveFailure' }) } finally { setSaving(false) } // 3秒后清除消息 setTimeout(() => setMessage(null), 3000) } // 重置设置 const handleResetSettings = async () => { if (confirm(translate(language, 'options.confirm.reset'))) { const defaultSettings = { ...DEFAULT_SETTINGS } setSettings(defaultSettings) // 自动保存重置后的设置 setSaving(true) setMessage(null) try { const success = await saveSettings(defaultSettings) if (success) { setMessage({ type: 'success', key: 'options.messages.resetSuccess' }) } else { setMessage({ type: 'error', key: 'options.messages.resetFailure' }) } } catch (error) { setMessage({ type: 'error', key: 'options.messages.resetFailure' }) } finally { setSaving(false) } // 3秒后清除消息 setTimeout(() => setMessage(null), 3000) } } const handleExportData = () => { chrome.storage.local.get(null, (data) => { const exportData = { version: '1.0.0', timestamp: Date.now(), data: data } const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `ssp-backup-${new Date().toISOString().split('T')[0]}.json` document.body.appendChild(a) a.click() document.body.removeChild(a) URL.revokeObjectURL(url) }) } const handleImportData = () => { const input = document.createElement('input') input.type = 'file' input.accept = '.json' input.onchange = (e) => { const file = (e.target as HTMLInputElement).files?.[0] if (!file) return const reader = new FileReader() reader.onload = (event) => { try { const importData = JSON.parse(event.target?.result as string) // 验证数据格式 if (!importData.version || !importData.data) { throw new Error(translate(language, 'options.alert.importInvalid')) } // 导入数据 chrome.storage.local.clear(() => { chrome.storage.local.set(importData.data, () => { alert(translate(language, 'options.alert.importSuccess')) window.location.reload() }) }) } catch (error) { const errorMessage = error instanceof Error ? error.message : translate(language, 'options.alert.unknownError') alert(translate(language, 'options.alert.importFailure', { error: errorMessage })) } } reader.readAsText(file) } input.click() } const handleClearAllData = () => { if (confirm(translate(language, 'options.confirm.clearAll'))) { if (confirm(translate(language, 'options.confirm.clearAllSecond'))) { chrome.storage.local.clear(() => { alert(translate(language, 'options.alert.clearSuccess')) window.location.reload() }) } } } const updateSettings = (updater: (prev: UserSettings) => UserSettings) => { setSettings((prev) => (prev ? updater(prev) : prev)) } return ( ) } export default App interface OptionsContentProps { loading: boolean settings: UserSettings | null updateSettings: (updater: (prev: UserSettings) => UserSettings) => void message: { type: 'success' | 'error'; key: string; params?: Record } | null saving: boolean history: SearchHistory[] activeTab: 'settings' | 'history' onTabChange: (tab: 'settings' | 'history') => void onReset: () => void onSave: () => void onExport: () => void onImport: () => void onClearAll: () => void onClearHistory: () => void } function OptionsContent({ loading, settings, updateSettings, message, saving, history, activeTab, onTabChange, onReset, onSave, onExport, onImport, onClearAll, onClearHistory }: OptionsContentProps) { const { t } = useTranslation() if (loading) { return (
) } if (!settings) { return (
{t('options.status.loadError')}
) } return (
{/* 头部 */}

{t('options.header.title')}

{t('options.header.subtitle')}

{/* Tab 切换 */}
{/* 消息提示 */} {message && (
{t(message.key, message.params)}
)} {/* Tab 内容 */} {activeTab === 'history' ? (

{t('options.sections.historyManagement')}

) : ( <> {/* 原有的设置内容 */} {/* 基本设置 */}

{t('options.sections.basic')}

{/* 默认搜索引擎 */}
{/* 界面语言 */}
{/* 主题设置 */}
{/* 功能设置 */}

{t('options.sections.features')}

{/* 启用搜索历史 */}

{t('options.fields.enableHistory.description')}

updateSettings((prev) => ({ ...prev, enableHistory: e.target.checked })) } className="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded" />
{/* 自动在新标签页打开 */}

{t('options.fields.autoOpen.description')}

updateSettings((prev) => ({ ...prev, autoOpenInNewTab: e.target.checked })) } className="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded" />
{/* 历史记录限制 */}
{ const parsed = parseInt(e.target.value) updateSettings((prev) => ({ ...prev, historyLimit: Number.isNaN(parsed) ? prev.historyLimit : parsed })) }} className="input" />

{t('options.fields.historyLimit.description')}

{/* 数据管理 */}

{t('options.sections.data')}

{/* 操作按钮 */}
{/* 关于信息 - 仅在设置页面显示 */} {activeTab === 'settings' && ( )} )}
) }