64 lines · 2.5 KB
import { LanguageDot } from "~/components/LanguageBar";
import { TopicList } from "~/components/TopicList";
import { Avatar } from "~/ui/Avatar";
import { Badge } from "~/ui/Badge";
import { EmptyState } from "~/ui/EmptyState";
import { RelativeTime } from "~/ui/RelativeTime";
import type { RepoSummary } from "~/lib/types";
import { TextLink } from "~/ui/TextLink";

type Props = { repos: RepoSummary[]; empty?: string; showOwnerAvatar?: boolean };

export function RepoList({ repos, empty = "No repositories yet.", showOwnerAvatar = true }: Props) {
  if (repos.length === 0) return <EmptyState title={empty} icon="repo" />;
  return (
    <ul className="divide-y divide-kumo-hairline">
      {repos.map((repo, index) => (
        <li
          key={repo.id}
          className="animate-rise px-4 py-4"
          style={{ animationDelay: `${Math.min(index, 12) * 25}ms` }}
        >
          <div className="flex flex-wrap items-center gap-2">
            {showOwnerAvatar && <Avatar name={repo.owner} size="sm" />}
            <TextLink
              to="/$owner/$repo"
              params={{ owner: repo.owner, repo: repo.name }}
              mono
              className="text-base font-medium"
            >
              <span className="text-kumo-subtle">{repo.owner}/</span>
              {repo.name}
            </TextLink>
            {repo.visibility === "private" && <Badge>Private</Badge>}
            {repo.isArchived && <Badge tone="warning">Archived</Badge>}
            {repo.status !== "ready" && <Badge tone="warning">{repo.status}</Badge>}
          </div>
          {repo.forkOf && (
            <p className="mt-0.5 text-xs text-kumo-subtle">
              forked from {repo.forkOf.owner}/{repo.forkOf.name}
            </p>