mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-03 11:05:35 +08: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)
|
│ ├── CollapsibleDisplay.tsx # Expandable tool display (uses children pattern)
|
||||||
│ ├── CollapsibleSection.tsx # <details>/<summary> wrapper
|
│ ├── CollapsibleSection.tsx # <details>/<summary> wrapper
|
||||||
│ ├── ContentRenderers/
|
│ ├── ContentRenderers/
|
||||||
│ │ ├── DiffViewer.tsx # File diff viewer (memoized)
|
│ │ ├── ToolDiffViewer.tsx # File diff viewer (memoized)
|
||||||
│ │ ├── MarkdownContent.tsx # Markdown renderer
|
│ │ ├── MarkdownContent.tsx # Markdown renderer
|
||||||
│ │ ├── FileListContent.tsx # Comma-separated clickable file list
|
│ │ ├── FileListContent.tsx # Comma-separated clickable file list
|
||||||
│ │ ├── TodoListContent.tsx # Todo items with status badges
|
│ │ ├── 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
|
rawContent="..." // Raw JSON string
|
||||||
toolCategory="edit" // Drives border color
|
toolCategory="edit" // Drives border color
|
||||||
>
|
>
|
||||||
<DiffViewer {...} /> // Content as children
|
<ToolDiffViewer {...} /> // Content as children
|
||||||
</CollapsibleDisplay>
|
</CollapsibleDisplay>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ interface ToolDisplayConfig {
|
|||||||
|
|
||||||
- **ToolRenderer** is wrapped with `React.memo` — skips re-render when props haven't changed
|
- **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
|
- **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`
|
- **MessageComponent** caches `localStorage` reads and timestamp formatting via `useMemo`
|
||||||
- Tool results route through `ToolRenderer` (no duplicate rendering paths)
|
- Tool results route through `ToolRenderer` (no duplicate rendering paths)
|
||||||
- `CollapsibleDisplay` uses children pattern (no wasteful contentProps indirection)
|
- `CollapsibleDisplay` uses children pattern (no wasteful contentProps indirection)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { memo, useMemo, useCallback } from 'react';
|
import React, { memo, useMemo, useCallback } from 'react';
|
||||||
import { getToolConfig } from './configs/toolConfigs';
|
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 { Project } from '../../../types/app';
|
||||||
import type { SubagentChildTool } from '../types/types';
|
import type { SubagentChildTool } from '../types/types';
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ export const ToolRenderer: React.FC<ToolRendererProps> = memo(({
|
|||||||
case 'diff':
|
case 'diff':
|
||||||
if (createDiff) {
|
if (createDiff) {
|
||||||
contentComponent = (
|
contentComponent = (
|
||||||
<DiffViewer
|
<ToolDiffViewer
|
||||||
{...contentProps}
|
{...contentProps}
|
||||||
createDiff={createDiff}
|
createDiff={createDiff}
|
||||||
onFileClick={() => onFileOpen?.(contentProps.filePath)}
|
onFileClick={() => onFileOpen?.(contentProps.filePath)}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ type DiffLine = {
|
|||||||
lineNum: number;
|
lineNum: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface DiffViewerProps {
|
interface ToolDiffViewerProps {
|
||||||
oldContent: string;
|
oldContent: string;
|
||||||
newContent: string;
|
newContent: string;
|
||||||
filePath: string;
|
filePath: string;
|
||||||
@@ -19,7 +19,7 @@ interface DiffViewerProps {
|
|||||||
/**
|
/**
|
||||||
* Compact diff viewer — VS Code-style
|
* Compact diff viewer — VS Code-style
|
||||||
*/
|
*/
|
||||||
export const DiffViewer: React.FC<DiffViewerProps> = ({
|
export const ToolDiffViewer: React.FC<ToolDiffViewerProps> = ({
|
||||||
oldContent,
|
oldContent,
|
||||||
newContent,
|
newContent,
|
||||||
filePath,
|
filePath,
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
export { CollapsibleSection } from './CollapsibleSection';
|
export { CollapsibleSection } from './CollapsibleSection';
|
||||||
export { DiffViewer } from './DiffViewer';
|
export { ToolDiffViewer } from './ToolDiffViewer';
|
||||||
export { OneLineDisplay } from './OneLineDisplay';
|
export { OneLineDisplay } from './OneLineDisplay';
|
||||||
export { CollapsibleDisplay } from './CollapsibleDisplay';
|
export { CollapsibleDisplay } from './CollapsibleDisplay';
|
||||||
export { SubagentContainer } from './SubagentContainer';
|
export { SubagentContainer } from './SubagentContainer';
|
||||||
|
|||||||
@@ -1,16 +1,7 @@
|
|||||||
import { ChevronRight, Trash2 } from 'lucide-react';
|
import { ChevronRight, Trash2 } from 'lucide-react';
|
||||||
import DiffViewer from '../../../DiffViewer.jsx';
|
|
||||||
import type { FileStatusCode } from '../../types/types';
|
import type { FileStatusCode } from '../../types/types';
|
||||||
import { getStatusBadgeClass, getStatusLabel } from '../../utils/gitPanelUtils';
|
import { getStatusBadgeClass, getStatusLabel } from '../../utils/gitPanelUtils';
|
||||||
|
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 FileChangeItemProps = {
|
type FileChangeItemProps = {
|
||||||
filePath: string;
|
filePath: string;
|
||||||
@@ -104,9 +95,8 @@ export default function FileChangeItem({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`bg-muted/50 transition-all duration-400 ease-in-out overflow-hidden ${
|
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'
|
||||||
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">
|
<div className="flex items-center justify-between p-2 border-b border-border">
|
||||||
<span className="flex items-center gap-2">
|
<span className="flex items-center gap-2">
|
||||||
@@ -130,7 +120,7 @@ export default function FileChangeItem({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="max-h-96 overflow-y-auto">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
import { ChevronDown, ChevronRight } from 'lucide-react';
|
import { ChevronDown, ChevronRight } from 'lucide-react';
|
||||||
import DiffViewer from '../../../DiffViewer.jsx';
|
|
||||||
import type { GitCommitSummary } from '../../types/types';
|
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 = {
|
type CommitHistoryItemProps = {
|
||||||
commit: GitCommitSummary;
|
commit: GitCommitSummary;
|
||||||
@@ -62,7 +55,7 @@ export default function CommitHistoryItem({
|
|||||||
<div className="text-sm font-mono text-muted-foreground mb-2">
|
<div className="text-sm font-mono text-muted-foreground mb-2">
|
||||||
{commit.stats}
|
{commit.stats}
|
||||||
</div>
|
</div>
|
||||||
<DiffViewerComponent diff={diff} fileName="commit" isMobile={isMobile} wrapText={wrapText} />
|
<GitDiffViewer diff={diff} isMobile={isMobile} wrapText={wrapText} />
|
||||||
</div>
|
</div>
|
||||||
</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