Vectrum
Sign In
49 lines · 2.3 KB · TypeScript
import Link from "next/link";
import { Card } from "@unlocalhosted/metalui";
import type { ForkParent, RepoRecord } from "@/lib/repos";
import { timeAgo } from "@/lib/format";
import { ClockIcon, LockIcon, RepoIcon } from "./icons";
import { ForkedFrom, ForkLabel } from "./forks";
import { CardDescription, CardTitle } from "./metal";
import { RepoAvatar, VisibilityLabel } from "./ui";

export type RepoListItem = RepoRecord & { updatedAt: number; empty: boolean; parent: ForkParent | null };

/** Repositories as MetalUI cards: the title is the card's one link, so the whole plate goes to the repository. */
export function RepoList({ repos, showOwner = true }: { repos: RepoListItem[]; showOwner?: boolean }) {
  return (
    <ul className="grid gap-4 sm:grid-cols-2">
      {repos.map((r) => (
        <li key={r.id} className="flex">
          <Card className="w-full grid-rows-[auto_1fr_auto]">
            <div className="flex items-start gap-3">
              <RepoAvatar repo={r} size={40} />
              <div className="min-w-0 flex-1">
                <CardTitle render={<Link href={`/${r.owner}/${r.name}`} />} className="truncate">
                  {showOwner && <span className="font-normal text-ink3">{r.owner} / </span>}
                  {r.name}
                </CardTitle>
                <div className="mt-1.5 flex flex-wrap items-center gap-1.5">
                  <VisibilityLabel visibility={r.visibility} />
                  {r.forkOf && <ForkLabel />}
                </div>
                {r.forkOf && <ForkedFrom parent={r.parent} className="mt-1.5 max-w-full" />}
              </div>
            </div>
            <CardDescription className={`mt-1.5 line-clamp-2 ${r.description ? "" : "text-ink3 italic"}`}>
              {r.description || "No description"}
            </CardDescription>
            <p className="rule-t mt-2 flex items-center gap-1.5 pt-2.5 type-readout text-ink3">
              <ClockIcon width={12} height={12} />
              {r.empty ? "Empty repository" : `Updated ${timeAgo(r.updatedAt)}`}
            </p>
          </Card>
        </li>
      ))}
    </ul>
  );
}

export function RepoIconFor({ visibility }: { visibility: "public" | "private" }) {
  return visibility === "private" ? <LockIcon className="text-ink3" /> : <RepoIcon className="text-ink3" />;
}