import { useState } from "react"; import { useNavigate } from "react-router-dom"; import type { ProjectCard } from "@/shared/types"; import { formatRelativeTime, formatStars, totalFindings } from "../shared/lib/format"; import { SeverityBar } from "./SeverityBar"; function OwnerAvatar({ owner, compact = false }: { owner: string; compact?: boolean }) { const [failed, setFailed] = useState(false); const sizeClass = compact ? "h-7 w-7" : "h-8 w-8"; if (failed) { return (
{owner.slice(0, 1).toUpperCase()}
); } return ( setFailed(true)} /> ); } export function ProjectRow({ project, compact = false }: { project: ProjectCard; compact?: boolean }) { const nav = useNavigate(); const state = project.latest_scan?.state; const scanning = state === "scanning" || state === "dispatching"; const waiting = state !== "completed" && !scanning; const soFar = project.latest_scan?.findings_so_far ?? 0; const findings = totalFindings(project.severity_counts); return (
nav(`/p/${project.owner_login}/${project.name}`)} onKeyDown={(e) => { if (e.key === "Enter") nav(`/p/${project.owner_login}/${project.name}`); }} className={`group block cursor-pointer overflow-hidden border-b border-line px-1 transition-colors hover:bg-surface-sunken/60 focus-ring rounded-sm ${ compact ? "h-[104px] py-3" : "py-4" }`} >
{project.full_name}
{project.description && (

{project.description}

)}
{project.language && ( {project.language} )} · ★ {formatStars(project.stars)} {project.latest_scan?.finished_at && ( <> · scanned {formatRelativeTime(project.latest_scan.finished_at)} )} {!waiting && findings > 0 && ( <> · {findings} findings )}
{scanning ? ( {soFar > 0 ? `Scanning · ${soFar} findings so far` : "Scanning…"} ) : waiting ? ( In scan queue ) : compact && findings === 0 ? ( No findings ) : ( )}
); }