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
@@ -14,14 +14,14 @@ export default function DiffNavigator({ total, currentIndex, onPrev, onNext }: D
if (total === 0) {
return (
<div className="flex items-center justify-center gap-3 p-2.5 rounded-lg bg-blue-50 border border-blue-200">
<span className="text-sm font-bold text-gray-500">{t('jsonDiff:noDiffs')}</span>
<div className="flex items-center justify-center gap-3 p-2.5 rounded-lg bg-primary/10 border border-primary/30">
<span className="text-sm font-bold text-muted-foreground">{t('jsonDiff:noDiffs')}</span>
</div>
);
}
return (
<div className="flex items-center justify-center gap-3 p-2.5 rounded-lg bg-blue-50 border border-blue-200">
<div className="flex items-center justify-center gap-3 p-2.5 rounded-lg bg-primary/10 border border-primary/30">
<button
type="button"
aria-label={t('jsonDiff:previousDiff')}
+3 -3
View File
@@ -27,14 +27,14 @@ export default function DiffResult({ result, viewMode, activePath }: DiffResultP
}
return (
<div className="p-3 rounded-lg bg-white border border-gray-200 font-mono text-sm overflow-x-auto min-h-[200px] max-h-[480px] overflow-y-auto">
<div className="p-3 rounded-lg bg-background border border-border font-mono text-sm overflow-x-auto min-h-[200px] max-h-[480px] overflow-y-auto">
<UnifiedView node={result.root} depth={0} activePath={activePath} />
</div>
);
}
const SectionLabel = ({ text }: { text: string }) => (
<span className="block mb-1.5 text-[11px] font-extrabold tracking-wider text-gray-500 uppercase">
<span className="block mb-1.5 text-[11px] font-extrabold tracking-wider text-muted-foreground uppercase">
{text}
</span>
);
@@ -61,7 +61,7 @@ const colorForType = (type: DiffType): string => {
if (type === 'added') return 'text-green-600';
if (type === 'removed') return 'text-red-600';
if (type === 'modified') return 'text-amber-600';
return 'text-gray-900';
return 'text-foreground';
};
const bgForType = (type: DiffType): string | undefined => {
+9 -7
View File
@@ -120,17 +120,17 @@ export default function JsonConvertSection({
{/* 转换结果 */}
{result && result.output ? (
<div className="relative rounded-lg bg-white border border-gray-200 overflow-hidden">
<div className="relative rounded-lg bg-background border border-border overflow-hidden">
{/* 结果头部 */}
<div className="flex justify-between items-center px-4 py-2 border-b border-gray-200 bg-gray-50">
<div className="flex justify-between items-center px-4 py-2 border-b border-border bg-muted">
<div className="flex gap-4 items-center">
<span className="text-[11px] font-extrabold text-gray-500">
<span className="text-[11px] font-extrabold text-muted-foreground">
{t(`jsonFormat:${pk}OutputLabel`)}
</span>
<span className="text-[10px] text-gray-400">
<span className="text-[10px] text-muted-foreground">
{t('jsonFormat:originalSize')}: {formatByteSize(result.originalBytes)}
</span>
<span className="text-[10px] text-gray-400">
<span className="text-[10px] text-muted-foreground">
{t('jsonFormat:formattedSize')}: {formatByteSize(result.outputBytes)}
</span>
</div>
@@ -143,8 +143,10 @@ export default function JsonConvertSection({
</div>
</div>
) : (
<div className="p-4 rounded-lg bg-gray-50 border border-dashed border-gray-300 text-center">
<p className="text-sm font-semibold text-gray-500">{t(`jsonFormat:${pk}EmptyHint`)}</p>
<div className="p-4 rounded-lg bg-muted border border-dashed border-input text-center">
<p className="text-sm font-semibold text-muted-foreground">
{t(`jsonFormat:${pk}EmptyHint`)}
</p>
</div>
)}
</div>
+1 -1
View File
@@ -17,7 +17,7 @@ export default function JsonDiffInput({
}: JsonDiffInputProps) {
return (
<div className="flex-1 min-w-0">
<span className="block mb-1.5 text-[11px] font-extrabold tracking-wider text-gray-500 uppercase">
<span className="block mb-1.5 text-[11px] font-extrabold tracking-wider text-muted-foreground uppercase">
{label}
</span>
<TextInputArea
+11 -11
View File
@@ -73,7 +73,7 @@ export default function JsonFormatSection() {
<div className="flex flex-col sm:flex-row gap-3 justify-between items-stretch sm:items-center">
<div className="flex gap-3 items-center">
{/* 缩进选择 */}
<span className="text-[11px] font-extrabold text-gray-500">
<span className="text-[11px] font-extrabold text-muted-foreground">
{t('jsonFormat:indentSize')}
</span>
<SwitchButtonGroup
@@ -90,7 +90,7 @@ export default function JsonFormatSection() {
type="checkbox"
checked={sortKeys}
onChange={(e) => setSortKeys(e.target.checked)}
className="h-4 w-4 rounded border-gray-300 text-blue-500 focus:ring-blue-500"
className="h-4 w-4 rounded border-input text-blue-500 focus:ring-primary"
/>
<span className="text-xs font-bold">{t('jsonFormat:sortKeys')}</span>
</label>
@@ -119,8 +119,8 @@ export default function JsonFormatSection() {
onChange={(e) => setInput(e.target.value)}
rows={6}
className={`w-full rounded-lg border ${
error ? 'border-red-300' : 'border-gray-200'
} p-3 font-mono text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 resize-y`}
error ? 'border-red-300' : 'border-border'
} p-3 font-mono text-sm focus:outline-none focus:ring-2 focus:ring-primary resize-y`}
/>
{error && (
<p className="mx-3 mt-1 text-xs font-semibold text-red-500">
@@ -131,17 +131,17 @@ export default function JsonFormatSection() {
{/* 格式化结果 */}
{result && result.formatted ? (
<div className="relative rounded-lg bg-white border border-gray-200 overflow-hidden">
<div className="relative rounded-lg bg-background border border-border overflow-hidden">
{/* 结果头部 */}
<div className="flex justify-between items-center px-4 py-2 border-b border-gray-200 bg-gray-50">
<div className="flex justify-between items-center px-4 py-2 border-b border-border bg-muted">
<div className="flex gap-4 items-center">
<span className="text-[11px] font-extrabold text-gray-500">
<span className="text-[11px] font-extrabold text-muted-foreground">
{t('jsonFormat:outputLabel')}
</span>
<span className="text-[10px] text-gray-400">
<span className="text-[10px] text-muted-foreground">
{t('jsonFormat:originalSize')}: {formatByteSize(result.originalBytes)}
</span>
<span className="text-[10px] text-gray-400">
<span className="text-[10px] text-muted-foreground">
{t('jsonFormat:formattedSize')}: {formatByteSize(result.formattedBytes)}
</span>
</div>
@@ -154,8 +154,8 @@ export default function JsonFormatSection() {
</div>
</div>
) : (
<div className="p-4 rounded-lg bg-gray-50 border border-dashed border-gray-300 text-center">
<p className="text-sm font-semibold text-gray-500">{t('jsonFormat:emptyHint')}</p>
<div className="p-4 rounded-lg bg-muted border border-dashed border-input text-center">
<p className="text-sm font-semibold text-muted-foreground">{t('jsonFormat:emptyHint')}</p>
</div>
)}
</div>
+10 -10
View File
@@ -121,17 +121,17 @@ const NodeRow = ({
onClick={() => setOverride(expanded ? 'closed' : 'open')}
className={`cursor-pointer pr-1 py-0.5 ${bg ?? ''} ${
isActive ? 'ring-2 ring-blue-500 rounded' : ''
} flex items-center gap-1 whitespace-nowrap hover:${bg ? 'bg-opacity-80' : 'bg-gray-50'}`}
} flex items-center gap-1 whitespace-nowrap hover:${bg ? 'bg-opacity-80' : 'bg-muted'}`}
style={{ paddingLeft: `${depth * 1.5}rem` }}
>
<span className="w-3 text-gray-500 text-[11px]">{expanded ? '▾' : '▸'}</span>
<span className="w-3 text-muted-foreground text-[11px]">{expanded ? '▾' : '▸'}</span>
{!isRoot && (
<span className="text-gray-900 font-bold">{isArrayKeyDisplay(node.key)}:</span>
<span className="text-foreground font-bold">{isArrayKeyDisplay(node.key)}:</span>
)}
<span className="text-gray-500">{open}</span>
{!expanded && <span className="text-gray-400 italic">{summarize(value)}</span>}
<span className="text-muted-foreground">{open}</span>
{!expanded && <span className="text-muted-foreground italic">{summarize(value)}</span>}
{!expanded && (
<span className="text-gray-500">
<span className="text-muted-foreground">
{close}
{isLastChild ? '' : ','}
</span>
@@ -154,7 +154,7 @@ const NodeRow = ({
)}
{expanded && (
<div
className="text-gray-500 whitespace-nowrap"
className="text-muted-foreground whitespace-nowrap"
style={{ paddingLeft: `${depth * 1.5 + 1.0625}rem` }}
>
{close}
@@ -175,8 +175,8 @@ const NodeRow = ({
style={{ paddingLeft: `${depth * 1.5}rem` }}
>
<span className="w-3" />
{!isRoot && <span className="text-gray-900 font-bold">{isArrayKeyDisplay(node.key)}:</span>}
<span className={valueColor ?? 'text-gray-900'}>
{!isRoot && <span className="text-foreground font-bold">{isArrayKeyDisplay(node.key)}:</span>}
<span className={valueColor ?? 'text-foreground'}>
{formatPrimitive(value)}
{isLastChild ? '' : ','}
</span>
@@ -206,7 +206,7 @@ export default function JsonTree({
}: JsonTreeProps) {
const sideKey = useMemo(() => side, [side]);
return (
<div className="p-3 rounded-lg bg-white border border-gray-200 font-mono text-sm overflow-x-auto min-h-[200px] max-h-[480px] overflow-y-auto">
<div className="p-3 rounded-lg bg-background border border-border font-mono text-sm overflow-x-auto min-h-[200px] max-h-[480px] overflow-y-auto">
<NodeRow
node={node}
side={sideKey}
+4 -2
View File
@@ -219,8 +219,10 @@ export default function Index() {
<DiffResult result={diffResult} viewMode={viewMode} activePath={activePath} />
</>
) : (
<div className="p-4 rounded-lg bg-gray-50 border border-dashed border-gray-300 text-center">
<p className="text-sm font-semibold text-gray-500">{t('jsonDiff:emptyHint')}</p>
<div className="p-4 rounded-lg bg-muted border border-dashed border-input text-center">
<p className="text-sm font-semibold text-muted-foreground">
{t('jsonDiff:emptyHint')}
</p>
</div>
)}
</>