import { Box, Text } from "ink"; import { Spinner } from "@inkjs/ui"; import { UnifiedProjectItem } from "./UnifiedProjectItem.tsx"; import { ColumnHeader, ColumnSeparator } from "./ColumnHeader.tsx"; import { useStore, useFilteredUnifiedRepos } from "../state/store.tsx"; interface ProjectListProps { height?: number; } export function ProjectList({ height = 20 }: ProjectListProps) { const { state } = useStore(); const { cursorIndex, selectedIndices, isLoading, sortBy, sortDirection } = state; const filteredRepos = useFilteredUnifiedRepos(); if (isLoading) { return ( ); } if (filteredRepos.length === 0) { return ( {/* Always show headers */} No repositories found {state.filterText && ( Try a different filter )} {state.viewMode === "github" && !state.githubRepos.length && ( <> {state.githubError ? ( GitHub error: {state.githubError} ) : ( Set GITHUB_TOKEN to see GitHub repos )} )} ); } // Reserve space for header (2 lines: header + separator) const listHeight = height - 2; // Calculate visible range with scroll offset const visibleCount = Math.min(listHeight, filteredRepos.length); let startIndex = Math.max(0, cursorIndex - Math.floor(visibleCount / 2)); // Adjust if we're near the end if (startIndex + visibleCount > filteredRepos.length) { startIndex = Math.max(0, filteredRepos.length - visibleCount); } const visibleRepos = filteredRepos.slice(startIndex, startIndex + visibleCount); return ( {/* Persistent column headers */} {/* Repository list */} {visibleRepos.map((repo, idx) => { const realIndex = startIndex + idx; return ( ); })} {/* Scroll indicator at bottom */} {startIndex + visibleCount < filteredRepos.length && ( ↓ {filteredRepos.length - startIndex - visibleCount} more below )} ); }