feat: better diff. integration

This commit is contained in:
2026-02-16 12:03:22 +01:00
parent 9d71aa63fb
commit c5c3a55a5c
14 changed files with 336 additions and 33 deletions

View File

@@ -14,14 +14,9 @@
color: var(--vscode-sideBar-foreground);
}
.git-diff-patch {
margin: 0;
padding: 12px;
overflow: auto;
white-space: pre;
font-family: var(--vscode-editor-font-family);
font-size: 12px;
line-height: 1.5;
.git-diff-editor-wrap {
flex: 1;
min-height: 0;
}
.git-diff-message,

View File

@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
import { DiffEditor } from '@monaco-editor/react';
import { useAppStore } from '../../store';
import './GitDiffView.css';
@@ -6,11 +7,40 @@ interface GitDiffViewProps {
filePath: string;
}
function detectLanguage(filePath: string): string {
const extension = filePath.split('.').pop()?.toLowerCase();
switch (extension) {
case 'md':
case 'markdown':
return 'markdown';
case 'ts':
return 'typescript';
case 'tsx':
return 'typescript';
case 'js':
return 'javascript';
case 'jsx':
return 'javascript';
case 'json':
return 'json';
case 'css':
return 'css';
case 'html':
return 'html';
case 'yml':
case 'yaml':
return 'yaml';
default:
return 'plaintext';
}
}
export const GitDiffView: React.FC<GitDiffViewProps> = ({ filePath }) => {
const { activeProject } = useAppStore();
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [patch, setPatch] = useState('');
const [original, setOriginal] = useState('');
const [modified, setModified] = useState('');
useEffect(() => {
const loadDiff = async () => {
@@ -32,8 +62,9 @@ export const GitDiffView: React.FC<GitDiffViewProps> = ({ filePath }) => {
return;
}
const diff = await window.electronAPI.git.getDiff(projectPath, filePath);
setPatch(diff.patch || '');
const diff = await window.electronAPI.git.getDiffContent(projectPath, filePath);
setOriginal(diff.original || '');
setModified(diff.modified || '');
} catch {
setError('Failed to load diff.');
} finally {
@@ -65,7 +96,27 @@ export const GitDiffView: React.FC<GitDiffViewProps> = ({ filePath }) => {
return (
<div className="git-diff-view">
<div className="git-diff-header">Diff: {filePath}</div>
{patch ? <pre className="git-diff-patch">{patch}</pre> : <div className="git-diff-message">No diff available.</div>}
<div className="git-diff-editor-wrap">
<DiffEditor
original={original}
modified={modified}
language={detectLanguage(filePath)}
theme="vs-dark"
height="100%"
options={{
readOnly: true,
renderSideBySide: false,
minimap: { enabled: false },
lineNumbers: 'on',
scrollBeyondLastLine: false,
renderOverviewRuler: true,
originalEditable: false,
diffCodeLens: false,
wordWrap: 'off',
ignoreTrimWhitespace: false,
}}
/>
</div>
</div>
);
};

View File

@@ -42,15 +42,6 @@
padding-top: 8px;
}
.git-sidebar-section-header {
padding: 0 12px 8px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
color: var(--vscode-sideBar-foreground);
letter-spacing: 0.3px;
}
.git-sidebar-empty-state {
padding: 0 12px 8px;
color: var(--vscode-descriptionForeground);
@@ -96,6 +87,34 @@
color: var(--vscode-descriptionForeground);
}
.git-sidebar-history-list {
display: flex;
flex-direction: column;
gap: 6px;
padding: 0 12px 8px;
}
.git-sidebar-history-item {
padding: 6px 8px;
border-radius: 4px;
background: var(--vscode-input-background);
}
.git-sidebar-history-subject {
font-size: 12px;
color: var(--vscode-sideBar-foreground);
margin-bottom: 2px;
word-break: break-word;
}
.git-sidebar-history-meta {
display: flex;
gap: 8px;
flex-wrap: wrap;
font-size: 10px;
color: var(--vscode-descriptionForeground);
}
.git-sidebar-main {
min-height: 0;
}

View File

@@ -1,7 +1,8 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useAppStore } from '../../store';
import type { GitInitProgress } from '../../../main/shared/electronApi';
import type { GitInitProgress, GitHistoryEntry } from '../../../main/shared/electronApi';
import './GitSidebar.css';
import '../Sidebar/Sidebar.css';
export const GitSidebar: React.FC = () => {
const { activeProject, openTab } = useAppStore();
@@ -13,6 +14,8 @@ export const GitSidebar: React.FC = () => {
const [isRepo, setIsRepo] = useState(false);
const [currentBranch, setCurrentBranch] = useState<string | null>(null);
const [statusFiles, setStatusFiles] = useState<Array<{ path: string; status: string }>>([]);
const [historyLoading, setHistoryLoading] = useState(false);
const [historyEntries, setHistoryEntries] = useState<GitHistoryEntry[]>([]);
const [initProgress, setInitProgress] = useState<GitInitProgress | null>(null);
const [initTranscript, setInitTranscript] = useState<GitInitProgress[]>([]);
const [isTranscriptExpanded, setIsTranscriptExpanded] = useState(false);
@@ -70,19 +73,27 @@ export const GitSidebar: React.FC = () => {
if (repoState.isRepo) {
setStatusLoading(true);
setHistoryLoading(true);
try {
const status = await window.electronAPI.git.getStatus(resolvedProjectPath);
const [status, history] = await Promise.all([
window.electronAPI.git.getStatus(resolvedProjectPath),
window.electronAPI.git.getHistory(resolvedProjectPath, 20),
]);
setStatusFiles(status.files);
setHistoryEntries(history);
} finally {
setStatusLoading(false);
setHistoryLoading(false);
}
} else {
setStatusFiles([]);
setHistoryEntries([]);
}
} catch {
setError('Unable to load repository status.');
setIsRepo(false);
setStatusFiles([]);
setHistoryEntries([]);
} finally {
setLoading(false);
}
@@ -176,7 +187,7 @@ export const GitSidebar: React.FC = () => {
<div className="git-sidebar-header">SOURCE CONTROL</div>
<div className="git-sidebar-content">
<div className="git-sidebar-section">
<div className="git-sidebar-section-header">OPEN CHANGES</div>
<div className="sidebar-section-title">Open Changes ({statusFiles.length})</div>
{statusLoading ? (
<div className="git-sidebar-empty-state">Loading changes...</div>
) : statusFiles.length === 0 ? (
@@ -201,10 +212,26 @@ export const GitSidebar: React.FC = () => {
</div>
<div className="git-sidebar-section git-sidebar-history">
<div className="git-sidebar-section-header">VERSION HISTORY</div>
<div className="git-sidebar-empty-state">
{currentBranch ? `Branch: ${currentBranch}` : 'No branch information'}
</div>
<div className="sidebar-section-title">Version History ({historyEntries.length})</div>
{historyLoading ? (
<div className="git-sidebar-empty-state">Loading history...</div>
) : historyEntries.length === 0 ? (
<div className="git-sidebar-empty-state">No commits yet</div>
) : (
<div className="git-sidebar-history-list" role="list" aria-label="Version History">
{historyEntries.map((entry) => (
<div key={entry.hash} className="git-sidebar-history-item">
<div className="git-sidebar-history-subject">{entry.subject}</div>
<div className="git-sidebar-history-meta">
<span>{entry.shortHash}</span>
<span>{entry.author}</span>
<span>{new Date(entry.date).toLocaleDateString()}</span>
</div>
</div>
))}
</div>
)}
{currentBranch && <div className="git-sidebar-empty-state">Branch: {currentBranch}</div>}
</div>
{transcriptSection}
</div>