/** * @license * Copyright 2025 Qwen Team * SPDX-License-Identifier: Apache-2.0 * * Diff display component for showing file changes */ import type React from 'react'; import { useState, useMemo } from 'react'; import { FileLink } from '../../shared/FileLink.js'; import { calculateDiffStats, formatDiffStatsDetailed, } from '../../../utils/diffStats.js'; import './DiffDisplay.css'; /** * Props for DiffDisplay */ interface DiffDisplayProps { path?: string; oldText?: string | null; newText?: string; onOpenDiff?: () => void; /** 默认显示模式:'compact' | 'full' */ defaultMode?: 'compact' | 'full'; } /** * Display diff with compact stats or full before/after sections * Supports toggling between compact and full view modes */ export const DiffDisplay: React.FC = ({ path, oldText, newText, onOpenDiff, defaultMode = 'compact', }) => { // 视图模式状态:紧凑或完整 const [viewMode, setViewMode] = useState<'compact' | 'full'>(defaultMode); // 计算 diff 统计信息(仅在文本变化时重新计算) const stats = useMemo( () => calculateDiffStats(oldText, newText), [oldText, newText], ); // 渲染紧凑视图 const renderCompactView = () => (
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onOpenDiff?.(); } }} >
{path && (
)}
{stats.added > 0 && ( +{stats.added} )} {stats.removed > 0 && ( -{stats.removed} )} {stats.changed > 0 && ( ~{stats.changed} )} {stats.total === 0 && ( No changes )}
); // 渲染完整视图 const renderFullView = () => (
{path && }
{onOpenDiff && ( )}
{formatDiffStatsDetailed(stats)}
{oldText !== undefined && (
Before:
            
{oldText || '(empty)'}
)} {newText !== undefined && (
After:
            
{newText}
)}
); return (
{viewMode === 'compact' ? renderCompactView() : renderFullView()}
); };