feat: UI 组件适配 PathEntry — 复选框列、禁用行灰显删除线

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 13:56:52 +08:00
parent e646a84291
commit d6e535aa98
3 changed files with 89 additions and 40 deletions
+45 -19
View File
@@ -1,6 +1,7 @@
import { useMemo } from 'react';
import { useAppStore } from '@/store/app-store';
import { useTranslation } from 'react-i18next';
import type { PathEntry } from '@/core/path-entry';
export function MergePreview() {
const sysPaths = useAppStore((s) => s.sysPaths);
@@ -9,13 +10,27 @@ export function MergePreview() {
const { t } = useTranslation();
const allPaths = useMemo(() => {
const result: { path: string; source: string; index: number }[] = [];
sysPaths.forEach((p, i) => result.push({ path: p, source: t('merge.system'), index: i }));
userPaths.forEach((p, i) => result.push({ path: p, source: t('merge.user'), index: i }));
const seen = new Set<string>();
const merged: (PathEntry & { source: string; displayIndex: number })[] = [];
if (!searchQuery) return result;
for (const entry of sysPaths) {
const lower = entry.path.toLowerCase();
if (!seen.has(lower)) {
seen.add(lower);
merged.push({ ...entry, source: t('merge.system'), displayIndex: merged.length });
}
}
for (const entry of userPaths) {
const lower = entry.path.toLowerCase();
if (!seen.has(lower)) {
seen.add(lower);
merged.push({ ...entry, source: t('merge.user'), displayIndex: merged.length });
}
}
if (!searchQuery) return merged;
const q = searchQuery.toLowerCase();
return result.filter((r) => r.path.toLowerCase().includes(q));
return merged.filter((r) => r.path.toLowerCase().includes(q));
}, [sysPaths, userPaths, searchQuery, t]);
return (
@@ -32,20 +47,31 @@ export function MergePreview() {
</tr>
</thead>
<tbody>
{allPaths.map(({ path, source, index }, rowIdx) => (
<tr
key={`${source}-${index}`}
style={{
backgroundColor:
rowIdx % 2 === 0 ? 'var(--app-list-bg)' : 'var(--app-list-alt)',
color: 'var(--app-fg)',
}}
>
<td className="px-2 py-0.5 text-xs opacity-50">{rowIdx + 1}</td>
<td className="px-2 py-0.5 text-sm">{path}</td>
<td className="px-2 py-0.5 text-xs opacity-60">{source}</td>
</tr>
))}
{allPaths.map(({ path, enabled, source, displayIndex }, rowIdx) => {
const textColor = enabled ? 'var(--app-fg)' : '#6b7280';
const textDecoration = enabled ? 'none' : 'line-through';
const opacity = enabled ? 1 : 0.6;
return (
<tr
key={`${source}-${displayIndex}`}
style={{
backgroundColor:
rowIdx % 2 === 0 ? 'var(--app-list-bg)' : 'var(--app-list-alt)',
color: 'var(--app-fg)',
}}
>
<td className="px-2 py-0.5 text-xs opacity-50">{rowIdx + 1}</td>
<td
className="px-2 py-0.5 text-sm"
style={{ color: textColor, textDecoration, opacity }}
>
{path}
</td>
<td className="px-2 py-0.5 text-xs opacity-60">{source}</td>
</tr>
);
})}
</tbody>
</table>
</div>