fix: 修复暗黑模式样式兼容性

- 在 tailwind.config.js 中启用 darkMode: 'class' 并扩展语义化颜色变量
- 将全项目硬编码颜色(bg-white、text-gray-*、border-gray-* 等)替换为语义化类名
- 修复 popup/index.html 硬编码浅色背景色
- 同步更新相关单元测试中的类名断言
This commit is contained in:
雨霖铃
2026-05-22 16:04:50 +08:00
parent 5b9a0f59d3
commit de7da9f1db
42 changed files with 274 additions and 261 deletions
+3 -3
View File
@@ -8,8 +8,8 @@ interface AutoRefreshToggleProps {
export default function AutoRefreshToggle({ autoRefresh, onChange }: AutoRefreshToggleProps) {
const { t } = useLazyTranslation('storageCleaner');
return (
<div className="mb-3 p-4 rounded-lg bg-white border border-gray-200 flex justify-between items-center shadow-sm transition-all hover:shadow-md">
<span className="text-sm font-bold text-gray-700 px-3">
<div className="mb-3 p-4 rounded-lg bg-background border border-border flex justify-between items-center shadow-sm transition-all hover:shadow-md">
<span className="text-sm font-bold text-foreground px-3">
{t('storageCleaner:autoRefresh')}
</span>
<label className="relative inline-flex items-center cursor-pointer">
@@ -19,7 +19,7 @@ export default function AutoRefreshToggle({ autoRefresh, onChange }: AutoRefresh
onChange={(e) => onChange(e.target.checked)}
className="sr-only peer"
/>
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-amber-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-amber-500" />
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-amber-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-background after:border-input after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-amber-500" />
</label>
</div>
);
+1 -1
View File
@@ -27,7 +27,7 @@ export default function CleaningResult({ result }: CleaningResultProps) {
)}
<span
className={`text-sm font-semibold leading-relaxed ${
isSuccess ? 'text-green-700' : 'text-red-700'
isSuccess ? 'text-green-600' : 'text-red-700'
}`}
>
{isSuccess
+1 -1
View File
@@ -13,7 +13,7 @@ export default function ErrorDisplay({ error }: ErrorDisplayProps) {
<div className="flex flex-col items-center justify-center rounded-lg p-6 shadow-lg border border-red-200 bg-red-50">
<AlertCircle className="h-9 w-9 text-red-500 mb-3" />
<p className="text-sm font-bold leading-relaxed mb-4 text-red-600">{error}</p>
<p className="text-xs font-medium leading-relaxed text-gray-500">
<p className="text-xs font-medium leading-relaxed text-muted-foreground">
{t('storageCleaner:errorStandardOnly')}
</p>
</div>
+5 -5
View File
@@ -22,23 +22,23 @@ export default function OptionItem({
className={`flex justify-between items-center py-2 px-3 rounded-lg transition-all duration-200 ${
checked
? 'bg-amber-50 border border-amber-200'
: 'bg-transparent border border-transparent hover:bg-gray-50 hover:shadow-sm'
: 'bg-transparent border border-transparent hover:bg-muted hover:shadow-sm'
}`}
>
<div className="flex-1 min-w-0 mr-3">
<span
className={`block text-xs leading-tight truncate transition-colors ${
checked ? 'text-amber-700 font-bold' : 'text-gray-900 font-bold'
checked ? 'text-amber-700 font-bold' : 'text-foreground font-bold'
}`}
>
{t(labelKey)}
</span>
{size !== undefined && size > 0 ? (
<span className="block text-[10px] font-semibold text-gray-500 mt-0.5 opacity-80">
<span className="block text-[10px] font-semibold text-muted-foreground mt-0.5 opacity-80">
{isCount ? `${size} ${t('storageCleaner:countUnit')}` : formatSize(size)}
</span>
) : (
<span className="block text-[10px] font-medium text-gray-400 mt-0.5 italic">
<span className="block text-[10px] font-medium text-muted-foreground mt-0.5 italic">
{t('storageCleaner:noData')}
</span>
)}
@@ -47,7 +47,7 @@ export default function OptionItem({
type="checkbox"
checked={checked}
onChange={onChange}
className="h-4 w-4 rounded border-gray-300 text-amber-500 focus:ring-amber-500"
className="h-4 w-4 rounded border-input text-amber-500 focus:ring-amber-500"
/>
</div>
);
+6 -4
View File
@@ -31,7 +31,7 @@ export default function StorageOptionsGrid({
];
return (
<div className="mb-3 border rounded-lg bg-white shadow-sm overflow-hidden transition-all hover:shadow-md">
<div className="mb-3 border rounded-lg bg-background shadow-sm overflow-hidden transition-all hover:shadow-md">
<div className="p-3">
<div className="grid grid-cols-2 gap-3">
{optionKeys.map(({ key, isCount }) => (
@@ -48,13 +48,15 @@ export default function StorageOptionsGrid({
</div>
</div>
<div className="border-t" />
<div className="flex justify-between items-center px-5 py-2 transition-colors hover:bg-gray-50 rounded-b-lg">
<span className="text-xs font-bold text-gray-500">{t('storageCleaner:selectAll')}</span>
<div className="flex justify-between items-center px-5 py-2 transition-colors hover:bg-muted rounded-b-lg">
<span className="text-xs font-bold text-muted-foreground">
{t('storageCleaner:selectAll')}
</span>
<input
type="checkbox"
checked={allSelected}
onChange={(e) => onSelectAll(e.target.checked)}
className="h-4 w-4 rounded border-gray-300 text-amber-500 focus:ring-amber-500"
className="h-4 w-4 rounded border-input text-amber-500 focus:ring-amber-500"
/>
</div>
</div>