refactor: 统一中文文案并简化组件结构,提升代码可读性
移除 chrome.i18n 后,将各功能页面、布局与工具模块的 UI 文案改为内联中文; 删除冗余注释与过度抽象(如 ToolCard、StatCard),精简 props 与状态管理; 同步优化 JsonTools、StorageCleaner、Timestamp、TestDataGenerator、Dashboard、 Base64Converter、RightClickRestorer、TextStatistics、TopBar、RouterProvider、 ThemeModeProvider 及生成器库与 utils 工具文件。
This commit is contained in:
@@ -5,7 +5,6 @@ import Index from '../index';
|
||||
import { clearStorage, getCookieSize, getCurrentTab } from '@/utils/storageCleaner';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
// Mock the chrome APIs
|
||||
vi.mock('@/utils/chromeStorage', () => ({
|
||||
storageUtil: {
|
||||
get: vi.fn().mockResolvedValue(null),
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/**
|
||||
* 自动刷新开关行
|
||||
*
|
||||
* 用于 StorageCleaner 页面的操作区域内(非独立卡片),
|
||||
* 控制清理后是否自动刷新页面。左侧为标签文本,右侧为 shadcn/ui Switch 开关。
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <AutoRefreshToggle
|
||||
* reloadAfterClean={reloadAfterClean}
|
||||
* onChange={(checked) => setReloadAfterClean(checked)}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
@@ -22,20 +7,10 @@ export interface AutoRefreshToggleProps extends Omit<
|
||||
React.HTMLAttributes<HTMLDivElement>,
|
||||
'onChange'
|
||||
> {
|
||||
/** 开关的当前状态(受控) */
|
||||
reloadAfterClean: boolean;
|
||||
/** 状态变化时的回调函数 */
|
||||
onChange: (checked: boolean) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动刷新开关
|
||||
*
|
||||
* @param reloadAfterClean - 当前开关状态
|
||||
* @param onChange - 状态变化回调,接收新的布尔值
|
||||
* @param className - 额外的 CSS 类名,用于覆盖或扩展样式
|
||||
* @param props - 透传给外层 div 的其他 HTML 属性
|
||||
*/
|
||||
export default function AutoRefreshToggle({
|
||||
reloadAfterClean,
|
||||
onChange,
|
||||
@@ -54,7 +29,7 @@ export default function AutoRefreshToggle({
|
||||
htmlFor="auto-refresh-switch"
|
||||
className="text-xs font-bold text-muted-foreground/90 cursor-pointer select-none tracking-wide uppercase"
|
||||
>
|
||||
{'清理后自动刷新页面'}
|
||||
清理后自动刷新页面
|
||||
</Label>
|
||||
|
||||
<Switch id="auto-refresh-switch" checked={reloadAfterClean} onCheckedChange={onChange} />
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function ErrorDisplay({ error, className, ...props }: ErrorDispla
|
||||
</p>
|
||||
|
||||
<p className="text-xs font-medium leading-relaxed text-muted-foreground/90 px-2">
|
||||
{'存储清理功能仅适用于标准网页'}
|
||||
存储清理功能仅适用于标准网页
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,11 +2,11 @@ import React from 'react';
|
||||
import { formatBytes } from '@/utils/format';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { StorageSizeInfo } from '../useStorageCleaner';
|
||||
import { OPTION_LABELS } from '../constants';
|
||||
import { CLEAN_OPTION_KEYS, OPTION_LABELS } from '../constants';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
|
||||
interface OptionItemProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
labelKey: string;
|
||||
labelKey: (typeof CLEAN_OPTION_KEYS)[number];
|
||||
checked: boolean;
|
||||
sizeInfo?: StorageSizeInfo;
|
||||
onChange: () => void;
|
||||
@@ -22,8 +22,7 @@ export default function OptionItem({
|
||||
}: OptionItemProps) {
|
||||
const sizeValue = sizeInfo?.value;
|
||||
const isCount = sizeInfo?.displayType === 'count';
|
||||
const label =
|
||||
labelKey in OPTION_LABELS ? OPTION_LABELS[labelKey as keyof typeof OPTION_LABELS] : labelKey;
|
||||
const label = OPTION_LABELS[labelKey];
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -58,7 +57,7 @@ export default function OptionItem({
|
||||
</span>
|
||||
) : (
|
||||
<span className="block text-[10px] font-medium text-muted-foreground/50 mt-0.5 italic">
|
||||
{'无数据'}
|
||||
无数据
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { AlertTriangle } from 'lucide-react';
|
||||
import type { StorageCleanerOptions } from '@/types/storage';
|
||||
import { OPTION_LABELS } from '../constants';
|
||||
import { OPTION_LABELS, CLEAN_OPTION_KEYS } from '../constants';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export interface StorageCleanerConfirmProps {
|
||||
@@ -26,11 +26,9 @@ export function StorageCleanerConfirm({
|
||||
onConfirm,
|
||||
options,
|
||||
}: StorageCleanerConfirmProps) {
|
||||
const selectedOptions = Object.entries(options)
|
||||
.filter(([_, value]) => value)
|
||||
.map(([key]) =>
|
||||
key in OPTION_LABELS ? OPTION_LABELS[key as keyof typeof OPTION_LABELS] : key,
|
||||
);
|
||||
const selectedOptions = CLEAN_OPTION_KEYS.filter((key) => options[key]).map(
|
||||
(key) => OPTION_LABELS[key],
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
|
||||
@@ -42,14 +40,14 @@ export function StorageCleanerConfirm({
|
||||
{/* 头部标题区域 */}
|
||||
<DialogHeader className="pt-1">
|
||||
<DialogTitle className="text-center text-lg font-bold tracking-tight text-foreground">
|
||||
{'确认清理数据?'}
|
||||
确认清理数据?
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
{/* 内容主体:限制最大宽度,防止内部元素在大分辨率下被横向拉得太松散 */}
|
||||
<div className="text-center py-4 flex flex-col items-center w-full max-w-[280px] mx-auto">
|
||||
<DialogDescription className="mb-4 text-xs font-medium text-muted-foreground/90 leading-relaxed">
|
||||
{'您将永久删除当前页面的以下选定存储项。'}
|
||||
您将永久删除当前页面的以下选定存储项。
|
||||
</DialogDescription>
|
||||
|
||||
{/* 待清理项目徽章群 */}
|
||||
@@ -69,7 +67,7 @@ export function StorageCleanerConfirm({
|
||||
<div className="inline-flex items-center justify-center gap-1.5 px-3.5 py-2 rounded-lg bg-destructive/5 border border-dashed border-destructive/20 w-full max-w-[240px]">
|
||||
<AlertTriangle className="h-3.5 w-3.5 text-destructive shrink-0" />
|
||||
<span className="text-[11px] font-bold text-destructive leading-none tracking-tight">
|
||||
{'此操作不可撤销'}
|
||||
此操作不可撤销
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,7 +79,7 @@ export function StorageCleanerConfirm({
|
||||
onClick={onConfirm}
|
||||
className="w-full text-xs font-bold shadow-sm h-9"
|
||||
>
|
||||
{'确认清理'}
|
||||
确认清理
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -89,7 +87,7 @@ export function StorageCleanerConfirm({
|
||||
onClick={onClose}
|
||||
className="w-full text-xs font-semibold shadow-sm h-9 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
{'取消'}
|
||||
取消
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
@@ -51,7 +51,7 @@ export default function StorageOptionsGrid({
|
||||
className="border-t border-border flex justify-between items-center pl-3.5 pr-7 py-2.5 bg-muted/20 hover:bg-muted/40 cursor-pointer select-none transition-colors"
|
||||
>
|
||||
<Label className="text-xs font-bold text-muted-foreground/90 cursor-pointer tracking-wide uppercase">
|
||||
{'全选所有项'}
|
||||
全选所有项
|
||||
</Label>
|
||||
|
||||
<Checkbox
|
||||
|
||||
@@ -34,7 +34,7 @@ export default function Index() {
|
||||
<div className="flex flex-col items-center justify-center py-12 min-h-[280px] w-full">
|
||||
<Loader2 className="h-6 w-6 text-muted-foreground/80" />
|
||||
<span className="text-xs text-muted-foreground mt-2 font-medium tracking-wide">
|
||||
{'正在读取数据...'}
|
||||
正在读取数据...
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
@@ -73,7 +73,7 @@ export default function Index() {
|
||||
{loading ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
{'正在清理...'}
|
||||
正在清理...
|
||||
</>
|
||||
) : (
|
||||
'立即清理'
|
||||
|
||||
@@ -117,7 +117,6 @@ export function useStorageCleaner(): UseStorageCleanerReturn {
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 核心数据拉取链条
|
||||
const loadInfo = useCallback(async () => {
|
||||
const currentRequestId = ++requestIdRef.current;
|
||||
setIsRefreshingSizes(true);
|
||||
@@ -189,7 +188,6 @@ export function useStorageCleaner(): UseStorageCleanerReturn {
|
||||
}, 300);
|
||||
}, []);
|
||||
|
||||
// 监听浏览器标签行为
|
||||
useEffect(() => {
|
||||
loadInfoRef.current().catch(console.error);
|
||||
|
||||
@@ -216,15 +214,12 @@ export function useStorageCleaner(): UseStorageCleanerReturn {
|
||||
|
||||
if (storageTimerRef.current) clearTimeout(storageTimerRef.current);
|
||||
storageTimerRef.current = setTimeout(async () => {
|
||||
try {
|
||||
await storageUtil.set('storageCleaner/preferences', {
|
||||
await storageUtil
|
||||
.set('storageCleaner/preferences', {
|
||||
reloadAfterClean,
|
||||
selectedTypes: options,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Failed to save storage cleaner preferences:', err);
|
||||
toast.warning('偏好保存失败,本次设置可能不会保留');
|
||||
}
|
||||
})
|
||||
.catch(console.error);
|
||||
}, 500);
|
||||
}, [options, reloadAfterClean, isInitializing]);
|
||||
|
||||
@@ -251,7 +246,7 @@ export function useStorageCleaner(): UseStorageCleanerReturn {
|
||||
if (loadingRef.current) return;
|
||||
|
||||
const tab = await getCurrentTab();
|
||||
if (!tab || tab.id === undefined || !tab.url) {
|
||||
if (!tab || !tab.id || !tab.url) {
|
||||
toast.warning('无法获取当前标签页');
|
||||
return;
|
||||
}
|
||||
@@ -286,7 +281,6 @@ export function useStorageCleaner(): UseStorageCleanerReturn {
|
||||
toast.error(`清理失败: ${String(err)}`);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setShowConfirm(false);
|
||||
}
|
||||
}, [options, reloadAfterClean, loadInfo]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user