mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-03-07 15:07:38 +00:00
refactor(DiffViewer): rename different diff viewers and place them in different components
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
function DiffViewer({ diff, fileName, isMobile, wrapText }) {
|
||||
if (!diff) {
|
||||
return (
|
||||
<div className="p-4 text-center text-muted-foreground text-sm">
|
||||
No diff available
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const renderDiffLine = (line, index) => {
|
||||
const isAddition = line.startsWith('+') && !line.startsWith('+++');
|
||||
const isDeletion = line.startsWith('-') && !line.startsWith('---');
|
||||
const isHeader = line.startsWith('@@');
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={`font-mono text-xs px-3 py-0.5 ${
|
||||
isMobile && wrapText ? 'whitespace-pre-wrap break-all' : 'whitespace-pre overflow-x-auto'
|
||||
} ${
|
||||
isAddition ? 'bg-green-50 dark:bg-green-950/50 text-green-700 dark:text-green-300' :
|
||||
isDeletion ? 'bg-red-50 dark:bg-red-950/50 text-red-700 dark:text-red-300' :
|
||||
isHeader ? 'bg-primary/5 text-primary' :
|
||||
'text-muted-foreground/70'
|
||||
}`}
|
||||
>
|
||||
{line}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="diff-viewer">
|
||||
{diff.split('\n').map((line, index) => renderDiffLine(line, index))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DiffViewer;
|
||||
@@ -17,7 +17,7 @@ tools/
|
||||
│ ├── CollapsibleDisplay.tsx # Expandable tool display (uses children pattern)
|
||||
│ ├── CollapsibleSection.tsx # <details>/<summary> wrapper
|
||||
│ ├── ContentRenderers/
|
||||
│ │ ├── DiffViewer.tsx # File diff viewer (memoized)
|
||||
│ │ ├── ToolDiffViewer.tsx # File diff viewer (memoized)
|
||||
│ │ ├── MarkdownContent.tsx # Markdown renderer
|
||||
│ │ ├── FileListContent.tsx # Comma-separated clickable file list
|
||||
│ │ ├── TodoListContent.tsx # Todo items with status badges
|
||||
@@ -82,7 +82,7 @@ Wraps `CollapsibleSection` (`<details>`/`<summary>`) with a `border-l-2` accent
|
||||
rawContent="..." // Raw JSON string
|
||||
toolCategory="edit" // Drives border color
|
||||
>
|
||||
<DiffViewer {...} /> // Content as children
|
||||
<ToolDiffViewer {...} /> // Content as children
|
||||
</CollapsibleDisplay>
|
||||
```
|
||||
|
||||
@@ -217,7 +217,7 @@ interface ToolDisplayConfig {
|
||||
|
||||
- **ToolRenderer** is wrapped with `React.memo` — skips re-render when props haven't changed
|
||||
- **parsedData** is memoized with `useMemo` — JSON parsing only runs when input changes
|
||||
- **DiffViewer** memoizes `createDiff()` — expensive diff computation cached
|
||||
- **ToolDiffViewer** memoizes `createDiff()` — expensive diff computation cached
|
||||
- **MessageComponent** caches `localStorage` reads and timestamp formatting via `useMemo`
|
||||
- Tool results route through `ToolRenderer` (no duplicate rendering paths)
|
||||
- `CollapsibleDisplay` uses children pattern (no wasteful contentProps indirection)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { memo, useMemo, useCallback } from 'react';
|
||||
import { getToolConfig } from './configs/toolConfigs';
|
||||
import { OneLineDisplay, CollapsibleDisplay, DiffViewer, MarkdownContent, FileListContent, TodoListContent, TaskListContent, TextContent, QuestionAnswerContent, SubagentContainer } from './components';
|
||||
import { OneLineDisplay, CollapsibleDisplay, ToolDiffViewer, MarkdownContent, FileListContent, TodoListContent, TaskListContent, TextContent, QuestionAnswerContent, SubagentContainer } from './components';
|
||||
import type { Project } from '../../../types/app';
|
||||
import type { SubagentChildTool } from '../types/types';
|
||||
|
||||
@@ -142,7 +142,7 @@ export const ToolRenderer: React.FC<ToolRendererProps> = memo(({
|
||||
case 'diff':
|
||||
if (createDiff) {
|
||||
contentComponent = (
|
||||
<DiffViewer
|
||||
<ToolDiffViewer
|
||||
{...contentProps}
|
||||
createDiff={createDiff}
|
||||
onFileClick={() => onFileOpen?.(contentProps.filePath)}
|
||||
|
||||
@@ -6,7 +6,7 @@ type DiffLine = {
|
||||
lineNum: number;
|
||||
};
|
||||
|
||||
interface DiffViewerProps {
|
||||
interface ToolDiffViewerProps {
|
||||
oldContent: string;
|
||||
newContent: string;
|
||||
filePath: string;
|
||||
@@ -19,7 +19,7 @@ interface DiffViewerProps {
|
||||
/**
|
||||
* Compact diff viewer — VS Code-style
|
||||
*/
|
||||
export const DiffViewer: React.FC<DiffViewerProps> = ({
|
||||
export const ToolDiffViewer: React.FC<ToolDiffViewerProps> = ({
|
||||
oldContent,
|
||||
newContent,
|
||||
filePath,
|
||||
@@ -1,5 +1,5 @@
|
||||
export { CollapsibleSection } from './CollapsibleSection';
|
||||
export { DiffViewer } from './DiffViewer';
|
||||
export { ToolDiffViewer } from './ToolDiffViewer';
|
||||
export { OneLineDisplay } from './OneLineDisplay';
|
||||
export { CollapsibleDisplay } from './CollapsibleDisplay';
|
||||
export { SubagentContainer } from './SubagentContainer';
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
import { ChevronRight, Trash2 } from 'lucide-react';
|
||||
import DiffViewer from '../../../DiffViewer.jsx';
|
||||
import type { FileStatusCode } from '../../types/types';
|
||||
import { getStatusBadgeClass, getStatusLabel } from '../../utils/gitPanelUtils';
|
||||
|
||||
type DiffViewerProps = {
|
||||
diff: string;
|
||||
fileName: string;
|
||||
isMobile: boolean;
|
||||
wrapText: boolean;
|
||||
};
|
||||
|
||||
const DiffViewerComponent = DiffViewer as unknown as (props: DiffViewerProps) => JSX.Element;
|
||||
import GitDiffViewer from '../shared/DiffViewer';
|
||||
|
||||
type FileChangeItemProps = {
|
||||
filePath: string;
|
||||
@@ -104,9 +95,8 @@ export default function FileChangeItem({
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`bg-muted/50 transition-all duration-400 ease-in-out overflow-hidden ${
|
||||
isExpanded && diff ? 'max-h-[600px] opacity-100 translate-y-0' : 'max-h-0 opacity-0 -translate-y-1'
|
||||
}`}
|
||||
className={`bg-muted/50 transition-all duration-400 ease-in-out overflow-hidden ${isExpanded && diff ? 'max-h-[600px] opacity-100 translate-y-0' : 'max-h-0 opacity-0 -translate-y-1'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between p-2 border-b border-border">
|
||||
<span className="flex items-center gap-2">
|
||||
@@ -130,7 +120,7 @@ export default function FileChangeItem({
|
||||
</div>
|
||||
|
||||
<div className="max-h-96 overflow-y-auto">
|
||||
{diff && <DiffViewerComponent diff={diff} fileName={filePath} isMobile={isMobile} wrapText={wrapText} />}
|
||||
{diff && <GitDiffViewer diff={diff} isMobile={isMobile} wrapText={wrapText} />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
import { ChevronDown, ChevronRight } from 'lucide-react';
|
||||
import DiffViewer from '../../../DiffViewer.jsx';
|
||||
|
||||
import type { GitCommitSummary } from '../../types/types';
|
||||
import GitDiffViewer from '../shared/DiffViewer';
|
||||
|
||||
type DiffViewerProps = {
|
||||
diff: string;
|
||||
fileName: string;
|
||||
isMobile: boolean;
|
||||
wrapText: boolean;
|
||||
};
|
||||
|
||||
const DiffViewerComponent = DiffViewer as unknown as (props: DiffViewerProps) => JSX.Element;
|
||||
|
||||
type CommitHistoryItemProps = {
|
||||
commit: GitCommitSummary;
|
||||
@@ -62,7 +55,7 @@ export default function CommitHistoryItem({
|
||||
<div className="text-sm font-mono text-muted-foreground mb-2">
|
||||
{commit.stats}
|
||||
</div>
|
||||
<DiffViewerComponent diff={diff} fileName="commit" isMobile={isMobile} wrapText={wrapText} />
|
||||
<GitDiffViewer diff={diff} isMobile={isMobile} wrapText={wrapText} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
41
src/components/git-panel/view/shared/DiffViewer.tsx
Normal file
41
src/components/git-panel/view/shared/DiffViewer.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
type GitDiffViewerProps = {
|
||||
diff: string | null;
|
||||
isMobile: boolean;
|
||||
wrapText: boolean;
|
||||
};
|
||||
|
||||
export default function GitDiffViewer({ diff, isMobile, wrapText }: GitDiffViewerProps) {
|
||||
if (!diff) {
|
||||
return (
|
||||
<div className="p-4 text-center text-muted-foreground text-sm">
|
||||
No diff available
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const renderDiffLine = (line: string, index: number) => {
|
||||
const isAddition = line.startsWith('+') && !line.startsWith('+++');
|
||||
const isDeletion = line.startsWith('-') && !line.startsWith('---');
|
||||
const isHeader = line.startsWith('@@');
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={`font-mono text-xs px-3 py-0.5 ${isMobile && wrapText ? 'whitespace-pre-wrap break-all' : 'whitespace-pre overflow-x-auto'
|
||||
} ${isAddition ? 'bg-green-50 dark:bg-green-950/50 text-green-700 dark:text-green-300' :
|
||||
isDeletion ? 'bg-red-50 dark:bg-red-950/50 text-red-700 dark:text-red-300' :
|
||||
isHeader ? 'bg-primary/5 text-primary' :
|
||||
'text-muted-foreground/70'
|
||||
}`}
|
||||
>
|
||||
{line}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="diff-viewer">
|
||||
{diff.split('\n').map((line, index) => renderDiffLine(line, index))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user