git-statistics 0.1.0

Collect commits from Git repository and present statistics in a comfortable way.
Documentation
import './App.css';
import Chart from './Chart.tsx';
import {useMemo} from 'react';
import {type Commit} from './types.ts';
import {pickRepo} from './open_repo.ts';
import {useHotkeys} from 'react-hotkeys-hook';
import {SortBy, useSettingsStore} from './SettingsState.ts';
import {useShallow} from 'zustand/react/shallow';
import SideBar from './components/SideBar.tsx';
import StatusBar from './components/StatusBar.tsx';

function App() {
	const {commits, countLimitation, countLimitationEnabled,repo, ...settings} = useSettingsStore(useShallow(state => ({
		commits: state.commits,
		repo: state.repo,
		sortBy: state.sortBy,
		countLimitationEnabled: state.countLimitationEnabled,
		countLimitation: state.countLimitation,
	})));

	useHotkeys('mod+o', pickRepo);

	const groupedData = useMemo(() => {
		const grouped = new Map<string, Commit>();
		for (const item of commits) {
			const stat = grouped.get(item.author);
			if (stat) {
				stat.commits += 1;
				stat.insertions += item.insertions;
				stat.deletions += item.deletions;
				stat.files_changed += item.files_changed;
			} else {
				grouped.set(item.author, {...item, commits: 1});
			}
		}

		const groupedArray = Array.from(grouped.values());
		groupedArray.sort((a, b) => {
			switch (settings.sortBy) {
				case SortBy.Commits:
					return b.commits - a.commits;
				case SortBy.Insertions:
					return b.insertions - a.insertions;
				case SortBy.Deletions:
					return b.deletions - a.deletions;
				case SortBy.FilesChanged:
					return b.files_changed - a.files_changed;
				case SortBy.LinesChanged:
					return (b.insertions + b.deletions) - (a.insertions + a.deletions);
			}

			return 0;
		});
		return groupedArray;
	}, [commits, settings.sortBy]);

	const sortedData = useMemo(() => {
		if (countLimitationEnabled) {
			if (countLimitation) {
				return groupedData.slice(0, countLimitation);
			}
		}

		return undefined;
	}, [countLimitation, countLimitationEnabled, groupedData]);

	if (!repo) {
		return (
			<div className='flex flex-col justify-center items-center w-full h-full gap-2'>
				<h1 className='text-4xl'>Welcome to <b>Git Statistic</b></h1>
				<p className='mb-2'>Please open a repository first.</p>
				<button className='btn btn-wide btn-primary' onClick={pickRepo}>Open Repository...</button>
			</div>
		);
	}

	return (
		<div className='flex flex-col w-full h-full'>
			{/* Top */}
			<div className='w-screen flex flex-1 overflow-hidden'>
				<div className='bg-base-200 w-72 h-full'>
					<SideBar/>
				</div>

				<div className='flex-1 h-full'>
					{/* Page content here */}
					<Chart data={sortedData ?? groupedData}/>
				</div>
			</div>
			<StatusBar/>
		</div>
	);
}

export default App;