From 22f8b16839c9a665384492130bf8f2b255ddc86d Mon Sep 17 00:00:00 2001 From: Zain Date: Sat, 8 Nov 2025 15:53:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95):=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0popup=E6=98=BE=E7=A4=BA=E9=99=90=E5=88=B6?= =?UTF-8?q?=E5=92=8C=E8=AE=BE=E7=BD=AE=E9=A1=B5=E7=A1=AE=E8=AE=A4=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加popup页面最多显示50条记录的限制,并在设置页面添加历史记录超出限制时的确认逻辑 当历史记录超过限制时,显示提示信息并引导用户前往设置页面 --- src/components/SearchHistory.tsx | 32 +++++++++++++++++++-- src/i18n/translations.ts | 14 +++++++++ src/options/App.tsx | 49 +++++++++++++++++++++++++++++--- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/src/components/SearchHistory.tsx b/src/components/SearchHistory.tsx index cd3a501..e8644d2 100644 --- a/src/components/SearchHistory.tsx +++ b/src/components/SearchHistory.tsx @@ -63,9 +63,15 @@ export function SearchHistory({ history, onRestore, onClear }: SearchHistoryProp return badges } + // Popup页面显示上限配置 + const POPUP_MAX_DISPLAY = 50 // popup页面最多显示50条记录 + // 计算要显示的记录数 - const displayCount = showAll ? history.length : 10 + const displayCount = showAll + ? Math.min(history.length, POPUP_MAX_DISPLAY) // 展开时最多显示50条 + : 10 // 默认显示10条 const hasMore = history.length > 10 + const reachedLimit = history.length > POPUP_MAX_DISPLAY // 是否超过popup显示上限 return (
@@ -139,7 +145,9 @@ export function SearchHistory({ history, onRestore, onClear }: SearchHistoryProp

{showAll - ? t('searchHistory.showingAll', { count: history.length }) + ? reachedLimit + ? t('searchHistory.showingLimit', { limit: POPUP_MAX_DISPLAY, total: history.length }) + : t('searchHistory.showingAll', { count: displayCount }) : t('searchHistory.showingRecent', { showing: 10, total: history.length }) }

@@ -149,7 +157,9 @@ export function SearchHistory({ history, onRestore, onClear }: SearchHistoryProp > {showAll ? t('searchHistory.collapse') - : t('searchHistory.expandAll', { count: history.length }) + : reachedLimit + ? t('searchHistory.expandLimit', { limit: POPUP_MAX_DISPLAY }) + : t('searchHistory.expandAll', { count: history.length }) } {!showAll && ( @@ -157,6 +167,22 @@ export function SearchHistory({ history, onRestore, onClear }: SearchHistoryProp {t('searchHistory.viewAllHint')}

)} + {/* 当已展开且超过上限时,显示引导到设置页面的提示 */} + {showAll && reachedLimit && ( +
+

+ 💡 {t('searchHistory.viewAllInSettings', { total: history.length })} +

+ +
+ )}
)} diff --git a/src/i18n/translations.ts b/src/i18n/translations.ts index 0eb50a0..dd4a1a6 100644 --- a/src/i18n/translations.ts +++ b/src/i18n/translations.ts @@ -51,9 +51,13 @@ const translations: Record> = { 'searchHistory.unknownTime': '未知时间', 'searchHistory.showingAll': '已展开全部 {count} 条记录', 'searchHistory.showingRecent': '显示最近 {showing} 条,共 {total} 条', + 'searchHistory.showingLimit': '已显示最近 {limit} 条,共 {total} 条记录', 'searchHistory.expandAll': '展开全部 {count} 条记录 ↓', + 'searchHistory.expandLimit': '展开至 {limit} 条记录 ↓', 'searchHistory.collapse': '收起历史记录 ↑', 'searchHistory.viewAllHint': '或前往设置页面查看完整历史记录', + 'searchHistory.viewAllInSettings': '查看全部 {total} 条记录,请前往设置页面', + 'searchHistory.goToSettings': '打开设置页面', 'options.header.title': '搜索语法大师 - 设置', 'options.header.subtitle': '设置和配置', 'options.tabs.settings': '设置', @@ -82,6 +86,8 @@ const translations: Record> = { 'options.actions.save': '保存设置', 'options.actions.saving': '保存中...', 'options.messages.saveSuccess': '设置已保存', + 'options.messages.saveSuccessWithTrim': '设置已保存,已删除超出限制的 {removed} 条历史记录', + 'options.messages.saveCancelled': '已取消保存', 'options.messages.saveFailure': '保存失败', 'options.messages.resetSuccess': '设置已重置为默认值并自动保存', 'options.messages.resetFailure': '重置设置失败', @@ -90,6 +96,7 @@ const translations: Record> = { 'options.confirm.clearAll': '确定要清除所有数据吗?这将删除搜索历史、设置等所有信息,且无法恢复。', 'options.confirm.clearAllSecond': '请再次确认:此操作不可撤销!', 'options.confirm.clearHistory': '确定要清除所有历史记录吗?此操作无法恢复。', + 'options.confirm.trimHistory': '当前有 {current} 条历史记录,新限制为 {limit} 条。\n\n这将立即删除最旧的 {willDelete} 条记录,此操作不可撤销。\n\n是否继续?', 'options.alert.importSuccess': '数据导入成功!页面将重新加载。', 'options.alert.importFailure': '导入失败: {error}', 'options.alert.importInvalid': '无效的备份文件格式', @@ -162,9 +169,13 @@ const translations: Record> = { 'searchHistory.unknownTime': 'Unknown time', 'searchHistory.showingAll': 'Showing all {count} records', 'searchHistory.showingRecent': 'Showing latest {showing} of {total} records', + 'searchHistory.showingLimit': 'Showing latest {limit} of {total} records', 'searchHistory.expandAll': 'Show all {count} records ↓', + 'searchHistory.expandLimit': 'Show up to {limit} records ↓', 'searchHistory.collapse': 'Collapse history ↑', 'searchHistory.viewAllHint': 'Or visit settings page to view complete history', + 'searchHistory.viewAllInSettings': 'To view all {total} records, please visit Settings page', + 'searchHistory.goToSettings': 'Open Settings', 'options.header.title': 'SearchSyntax Pro - Settings', 'options.header.subtitle': 'Settings & configuration', 'options.tabs.settings': 'Settings', @@ -193,6 +204,8 @@ const translations: Record> = { 'options.actions.save': 'Save settings', 'options.actions.saving': 'Saving...', 'options.messages.saveSuccess': 'Settings saved', + 'options.messages.saveSuccessWithTrim': 'Settings saved, removed {removed} history entries exceeding limit', + 'options.messages.saveCancelled': 'Save cancelled', 'options.messages.saveFailure': 'Failed to save settings', 'options.messages.resetSuccess': 'Settings have been reset to defaults and automatically saved', 'options.messages.resetFailure': 'Failed to reset settings', @@ -201,6 +214,7 @@ const translations: Record> = { 'options.confirm.clearAll': 'Are you sure you want to clear all data? This will delete history, settings, and cannot be undone.', 'options.confirm.clearAllSecond': 'Please confirm again: this action cannot be undone!', 'options.confirm.clearHistory': 'Are you sure you want to clear all history? This action cannot be undone.', + 'options.confirm.trimHistory': 'You currently have {current} history entries, but the new limit is {limit}.\n\nThis will immediately delete the oldest {willDelete} entries. This action cannot be undone.\n\nContinue?', 'options.alert.importSuccess': 'Data imported successfully! The page will reload.', 'options.alert.importFailure': 'Import failed: {error}', 'options.alert.importInvalid': 'Invalid backup file format', diff --git a/src/options/App.tsx b/src/options/App.tsx index 62dbe1c..7d15b33 100644 --- a/src/options/App.tsx +++ b/src/options/App.tsx @@ -12,7 +12,7 @@ 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 } | null>(null) + const [message, setMessage] = useState<{ type: 'success' | 'error'; key: string; params?: Record } | null>(null) const [history, setHistory] = useState([]) const [activeTab, setActiveTab] = useState<'settings' | 'history'>('settings') @@ -49,13 +49,54 @@ function App() { 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) { - setMessage({ type: 'success', key: 'options.messages.saveSuccess' }) + 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) @@ -199,7 +240,7 @@ interface OptionsContentProps { loading: boolean settings: UserSettings | null updateSettings: (updater: (prev: UserSettings) => UserSettings) => void - message: { type: 'success' | 'error'; key: string } | null + message: { type: 'success' | 'error'; key: string; params?: Record } | null saving: boolean history: SearchHistory[] activeTab: 'settings' | 'history' @@ -294,7 +335,7 @@ function OptionsContent({ ? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200' : 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200' }`}> - {t(message.key)} + {t(message.key, message.params)} )}