feat(ui): 演化历史条目增加可展开差异视图 + 文件变更标签

点击展开显示 soul/instructions/profile 变更内容,不再截断原因文本。
This commit is contained in:
iven
2026-04-11 12:58:25 +08:00
parent b3f7328778
commit f5c6abf03f

View File

@@ -275,30 +275,81 @@ function HistoryItem({
onRestore: () => void; onRestore: () => void;
isRestoring: boolean; isRestoring: boolean;
}) { }) {
const [expanded, setExpanded] = useState(false);
const timeAgo = getTimeAgo(snapshot.timestamp); const timeAgo = getTimeAgo(snapshot.timestamp);
// Determine which files changed
const fileEntries: Array<{ key: string; label: string; color: string; content: string }> = [];
if (snapshot.files?.soul) {
fileEntries.push({ key: 'soul', label: 'Soul', color: 'text-purple-600 dark:text-purple-400', content: snapshot.files.soul });
}
if (snapshot.files?.instructions) {
fileEntries.push({ key: 'instructions', label: 'Instructions', color: 'text-blue-600 dark:text-blue-400', content: snapshot.files.instructions });
}
if (snapshot.files?.user_profile) {
fileEntries.push({ key: 'user_profile', label: 'Profile', color: 'text-emerald-600 dark:text-emerald-400', content: snapshot.files.user_profile });
}
return ( return (
<div className="flex items-start gap-3 p-3 rounded-lg bg-gray-50 dark:bg-gray-800/50 border border-gray-100 dark:border-gray-700"> <div className="rounded-lg bg-gray-50 dark:bg-gray-800/50 border border-gray-100 dark:border-gray-700">
<div className="w-8 h-8 rounded-lg bg-gray-200 dark:bg-gray-700 flex items-center justify-center flex-shrink-0"> <div
<History className="w-4 h-4 text-gray-500 dark:text-gray-400" /> className="flex items-start gap-3 p-3 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800/70"
</div> onClick={() => setExpanded(!expanded)}
<div className="flex-1 min-w-0"> >
<div className="flex items-center justify-between gap-2"> <div className="w-8 h-8 rounded-lg bg-gray-200 dark:bg-gray-700 flex items-center justify-center flex-shrink-0">
<span className="text-xs text-gray-500 dark:text-gray-400">{timeAgo}</span> <History className="w-4 h-4 text-gray-500 dark:text-gray-400" />
<Button </div>
variant="ghost" <div className="flex-1 min-w-0">
size="sm" <div className="flex items-center justify-between gap-2">
onClick={onRestore} <span className="text-xs text-gray-500 dark:text-gray-400">{timeAgo}</span>
disabled={isRestoring} <div className="flex items-center gap-2">
className="text-xs text-gray-500 hover:text-orange-600" {fileEntries.length > 0 && (
> <span className="text-xs text-gray-400">
{fileEntries.length}
</Button> </span>
)}
<Button
variant="ghost"
size="sm"
onClick={(e) => { e.stopPropagation(); onRestore(); }}
disabled={isRestoring}
className="text-xs text-gray-500 hover:text-orange-600"
>
</Button>
</div>
</div>
<p className="text-sm text-gray-700 dark:text-gray-300 mt-1">
{snapshot.reason || '自动快照'}
</p>
{fileEntries.length > 0 && (
<div className="flex gap-1 mt-1.5">
{fileEntries.map(({ key, label, color }) => (
<span
key={key}
className={`text-[10px] px-1.5 py-0.5 rounded bg-gray-200 dark:bg-gray-700 ${color}`}
>
{label}
</span>
))}
</div>
)}
</div> </div>
<p className="text-sm text-gray-700 dark:text-gray-300 mt-1 truncate">
{snapshot.reason || '自动快照'}
</p>
</div> </div>
{expanded && fileEntries.length > 0 && (
<div className="px-3 pb-3 pt-1 border-t border-gray-200 dark:border-gray-700 space-y-2">
{fileEntries.map(({ key, label, color, content }) => (
<div key={key}>
<div className={`text-xs font-medium ${color} mb-1`}>{label}</div>
<pre className="text-xs text-gray-600 dark:text-gray-400 whitespace-pre-wrap max-h-32 overflow-y-auto bg-white dark:bg-gray-900 p-2 rounded">
{content.slice(0, 500)}
{content.length > 500 ? '...' : ''}
</pre>
</div>
))}
</div>
)}
</div> </div>
); );
} }