diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css index 0c05fdee0a..cdc27e9a3a 100644 --- a/apps/web/app/globals.css +++ b/apps/web/app/globals.css @@ -92,6 +92,10 @@ --scrollbar-thumb-hover: oklch(0.66 0 0); --scrollbar-track: var(--background); --sidebar-ring: oklch(0.708 0 0); + + /* Git diff colors - centralized for easy maintenance */ + --git-addition: 16 185 129; /* emerald-500 */ + --git-deletion: 244 63 94; /* rose-500 */ } .dark { @@ -129,6 +133,10 @@ --scrollbar-thumb-hover: oklch(0.62 0 0 / 0.8); --scrollbar-track: var(--background); --sidebar-ring: oklch(0.556 0 0); + + /* Git diff colors - same as light mode for consistency */ + --git-addition: 16 185 129; /* emerald-500 */ + --git-deletion: 244 63 94; /* rose-500 */ } @layer base { diff --git a/apps/web/components/diff/diff-viewer.tsx b/apps/web/components/diff/diff-viewer.tsx index 194e2fd864..db41f43409 100644 --- a/apps/web/components/diff/diff-viewer.tsx +++ b/apps/web/components/diff/diff-viewer.tsx @@ -430,6 +430,22 @@ export const DiffViewer = memo(function DiffViewer({ disableFileHeader: !showHeader, lineDiffType: 'word', overflow: wordWrap ? 'wrap' : 'scroll', + unsafeCSS: ` + * { + background: transparent !important; + } + + /* Reduce icon size */ + [data-change-icon] { + width: 12px !important; + height: 12px !important; + } + + /* Adjust header padding */ + [data-diffs-header] { + padding-inline: 12px !important; + } + `, }), [globalViewMode, resolvedTheme, enableComments, showHeader, handleLineSelectionEnd, wordWrap] ); @@ -476,6 +492,11 @@ export const DiffViewer = memo(function DiffViewer({ renderAnnotation={renderAnnotation} renderHeaderMetadata={showHeader ? renderHeaderMetadata : undefined} renderHoverUtility={renderHoverUtility} + style={{ + '--diffs-addition-color-override': 'rgb(var(--git-addition))', + '--diffs-deletion-color-override': 'rgb(var(--git-deletion))', + '--diffs-font-size': '12px', + } as React.CSSProperties} className={cn( 'rounded-md border border-border/50', compact && 'text-xs' diff --git a/apps/web/components/task/file-status-icon.tsx b/apps/web/components/task/file-status-icon.tsx new file mode 100644 index 0000000000..7aee63ce94 --- /dev/null +++ b/apps/web/components/task/file-status-icon.tsx @@ -0,0 +1,44 @@ +'use client'; + +import { IconPlus, IconCircleFilled, IconMinus } from '@tabler/icons-react'; +import type { FileInfo } from '@/lib/state/store'; + +type FileStatusIconProps = { + status: FileInfo['status']; +}; + +export function FileStatusIcon({ status }: FileStatusIconProps) { + switch (status) { + case 'added': + case 'untracked': + return ( +
+ +
+ ); + case 'modified': + return ( +
+ +
+ ); + case 'deleted': + return ( +
+ +
+ ); + case 'renamed': + return ( +
+ +
+ ); + default: + return ( +
+ +
+ ); + } +} diff --git a/apps/web/components/task/task-changes-panel.tsx b/apps/web/components/task/task-changes-panel.tsx index b0868c0979..7fb9ddb4bb 100644 --- a/apps/web/components/task/task-changes-panel.tsx +++ b/apps/web/components/task/task-changes-panel.tsx @@ -24,6 +24,7 @@ import { useGitOperations } from '@/hooks/use-git-operations'; import { FileDiffViewer } from '@/components/diff'; import type { FileInfo } from '@/lib/state/slices'; import type { SelectedDiff } from './task-layout'; +import { FileStatusIcon } from './file-status-icon'; type TaskChangesPanelProps = { selectedDiff: SelectedDiff | null; @@ -88,15 +89,18 @@ const TaskChangesPanel = memo(function TaskChangesPanel({ if (!cumulativeDiff?.files || Object.keys(cumulativeDiff.files).length === 0) { return []; } + // Create a Set of uncommitted file paths for efficient lookup + const uncommittedPaths = new Set(uncommittedFiles.map(f => f.path)); + return Object.entries(cumulativeDiff.files) - .filter(([, file]) => file.diff) // Only include files with diffs + .filter(([path, file]) => file.diff && !uncommittedPaths.has(path)) // Exclude uncommitted files .map(([path, file]) => ({ path, diff: file.diff!, additions: file.additions ?? 0, deletions: file.deletions ?? 0, })); - }, [cumulativeDiff]); + }, [cumulativeDiff, uncommittedFiles]); const selectedFile = selectedDiffPath && gitStatus?.files ? gitStatus.files[selectedDiffPath] : null; // Prioritize current git status for uncommitted files, use provided content only for historical diffs @@ -253,9 +257,12 @@ const TaskChangesPanel = memo(function TaskChangesPanel({ return (
- - {file.path} - +
+ + + {file.path} + +
+{file.additions} {' / '} diff --git a/apps/web/components/task/task-files-panel.tsx b/apps/web/components/task/task-files-panel.tsx index 0d4d23b1f8..1fe4c87b77 100644 --- a/apps/web/components/task/task-files-panel.tsx +++ b/apps/web/components/task/task-files-panel.tsx @@ -5,7 +5,6 @@ import { IconArrowBackUp, IconExternalLink, IconPlus, - IconCircleFilled, IconMinus, IconCheck, IconChevronRight, @@ -47,6 +46,7 @@ import { hasUserSelectedFilesPanelTab, setUserSelectedFilesPanelTab, } from '@/lib/local-storage'; +import { FileStatusIcon } from './file-status-icon'; type TaskFilesPanelProps = { onSelectDiff: (path: string, content?: string) => void; @@ -56,42 +56,6 @@ type TaskFilesPanelProps = { -const StatusIcon = ({ status }: { status: FileInfo['status'] }) => { - switch (status) { - case 'added': - case 'untracked': - return ( -
- -
- ); - case 'modified': - return ( -
- -
- ); - case 'deleted': - return ( -
- -
- ); - case 'renamed': - return ( -
- -
- ); - default: - return ( -
- -
- ); - } -}; - const splitPath = (path: string) => { const lastSlash = path.lastIndexOf('/'); if (lastSlash === -1) return { folder: '', file: path }; @@ -398,7 +362,7 @@ const TaskFilesPanel = memo(function TaskFilesPanel({ onSelectDiff, onOpenFile,
- +
); @@ -458,7 +422,7 @@ const TaskFilesPanel = memo(function TaskFilesPanel({ onSelectDiff, onOpenFile, className="flex items-center gap-2 text-xs rounded px-1 py-0.5 hover:bg-muted/50 cursor-pointer" onClick={() => onSelectDiff(path, file.diff)} > - + {folder}/ {fileName} diff --git a/apps/web/components/task/task-top-bar.tsx b/apps/web/components/task/task-top-bar.tsx index 656b4bd769..98942638a4 100644 --- a/apps/web/components/task/task-top-bar.tsx +++ b/apps/web/components/task/task-top-bar.tsx @@ -46,9 +46,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@kandev/ui/tooltip'; import { Popover, PopoverContent, PopoverTrigger } from '@kandev/ui/popover'; import { Checkbox } from '@kandev/ui/checkbox'; import { Label } from '@kandev/ui/label'; -import { CommitStatBadge, LineStat } from '@/components/diff-stat'; +import { CommitStatBadge } from '@/components/diff-stat'; import { useSessionGitStatus } from '@/hooks/domains/session/use-session-git-status'; -import { useSessionCommits } from '@/hooks/domains/session/use-session-commits'; import { useGitOperations } from '@/hooks/use-git-operations'; import type { FileInfo } from '@/lib/state/slices'; import { formatUserHomePath } from '@/lib/utils'; @@ -105,7 +104,6 @@ const TaskTopBar = memo(function TaskTopBar({ const router = useRouter(); const { toast } = useToast(); const gitStatus = useSessionGitStatus(activeSessionId ?? null); - const { commits } = useSessionCommits(activeSessionId ?? null); const { pull, push, rebase, merge, commit, createPR, isLoading: isGitLoading } = useGitOperations(activeSessionId ?? null); const { open: openFolder, isLoading: isOpenFolderLoading } = useOpenSessionFolder(activeSessionId); @@ -128,14 +126,6 @@ const TaskTopBar = memo(function TaskTopBar({ } } - // Calculate cumulative additions and deletions from commits. - const commitAdditions = commits.reduce((sum, c) => sum + c.insertions, 0); - const commitDeletions = commits.reduce((sum, c) => sum + c.deletions, 0); - - // Combined total (uncommitted + commits) - const totalAdditions = uncommittedAdditions + commitAdditions; - const totalDeletions = uncommittedDeletions + commitDeletions; - const handleGitOperation = useCallback(async ( operation: () => Promise<{ success: boolean; output: string; error?: string; conflict_files?: string[] }>, operationName: string @@ -391,20 +381,6 @@ const TaskTopBar = memo(function TaskTopBar({ )} - {/* Git Status: Total Lines Changed (uncommitted + commits) */} - {(totalAdditions > 0 || totalDeletions > 0) && ( - - - - - - - - Total changes{commits.length > 0 ? ` (${commits.length} commit${commits.length !== 1 ? 's' : ''}${uncommittedAdditions > 0 || uncommittedDeletions > 0 ? ' + uncommitted' : ''})` : ''} - - - )} -
{DEBUG_UI && onToggleDebugOverlay && (