UNPKG

reviewit

Version:

A lightweight command-line tool that spins up a local web server to display Git commit diffs in a GitHub-like Files changed view

93 lines (92 loc) 4.33 kB
import React, { useState, useEffect } from 'react'; import { Box, Text, useApp, useInput } from 'ink'; import { loadGitDiff } from '../server/git-diff-tui.js'; import FileList from './components/FileList.js'; import DiffViewer from './components/DiffViewer.js'; import SideBySideDiffViewer from './components/SideBySideDiffViewer.js'; import StatusBar from './components/StatusBar.js'; const App = ({ targetCommitish, baseCommitish, mode }) => { const [files, setFiles] = useState([]); const [selectedFileIndex, setSelectedFileIndex] = useState(0); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [viewMode, setViewMode] = useState(mode === 'inline' ? 'inline' : 'side-by-side'); const { exit } = useApp(); const loadDiff = async () => { setLoading(true); setError(null); try { const fileDiffs = await loadGitDiff(targetCommitish, baseCommitish); setFiles(fileDiffs); setLoading(false); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); setLoading(false); } }; useEffect(() => { loadDiff(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [targetCommitish, baseCommitish]); useInput((input, key) => { if (input === 'q' || (key.ctrl && input === 'c')) { exit(); } // Reload on 'r' key if (input === 'r') { loadDiff(); return; } if (viewMode === 'list') { if (key.upArrow || input === 'k') { setSelectedFileIndex((prev) => Math.max(0, prev - 1)); } if (key.downArrow || input === 'j') { setSelectedFileIndex((prev) => Math.min(files.length - 1, prev + 1)); } if (key.return || input === ' ') { setViewMode('side-by-side'); } if (input === 'd') { setViewMode('inline'); } } else { if (key.escape || input === 'b') { setViewMode('list'); } } }, { isActive: true }); if (loading) { return React.createElement(Text, null, "Loading diff for ", targetCommitish, "..."); } if (error) { return React.createElement(Text, { color: "red" }, "Error: ", error); } if (files.length === 0) { return (React.createElement(Box, { flexDirection: "column" }, React.createElement(StatusBar, { commitish: targetCommitish, totalFiles: 0, currentMode: "list" }), React.createElement(Box, { marginTop: 1 }, React.createElement(Text, { color: "yellow" }, "No changes found for ", targetCommitish)), React.createElement(Box, { marginTop: 1 }, React.createElement(Text, { dimColor: true }, "Press 'q' to quit")))); } return (React.createElement(Box, { flexDirection: "column", height: process.stdout.rows }, React.createElement(StatusBar, { commitish: targetCommitish, totalFiles: files.length, currentMode: viewMode }), React.createElement(Box, { flexGrow: 1, flexDirection: "column" }, viewMode === 'list' ? (React.createElement(FileList, { files: files, selectedIndex: selectedFileIndex })) : viewMode === 'side-by-side' ? (React.createElement(SideBySideDiffViewer, { files: files, initialFileIndex: selectedFileIndex, onBack: () => setViewMode('list') })) : (React.createElement(DiffViewer, { files: files, initialFileIndex: selectedFileIndex, onBack: () => setViewMode('list') }))), React.createElement(Box, { borderStyle: "single", paddingX: 1 }, React.createElement(Text, { dimColor: true }, viewMode === 'list' ? '↑/↓ or j/k: navigate | Enter/Space: side-by-side | d: inline diff | r: reload | q: quit' : viewMode === 'side-by-side' ? 'Tab: next file | Shift+Tab: prev | ↑/↓ or j/k: scroll | ESC/b: list | r: reload | q: quit' : 'Tab: next | Shift+Tab: prev | ↑/↓ or j/k: scroll | ESC/b: list | r: reload | q: quit')))); }; export default App;