Vectrum
Sign In
50 lines · 2.1 KB · TypeScript
"use client";

import Link from "next/link";
import { useState } from "react";
import { Field } from "@unlocalhosted/metalui";
import { LockIcon, SearchIcon } from "./icons";
import { RepoAvatar } from "./ui";

type Item = { owner: string; name: string; visibility: "public" | "private"; imageVersion: number | null };

/** The viewer's repositories: a compact search well that filters as you type, then rows that lift on hover. */
export function RepoFilterList({ repos }: { repos: Item[] }) {
  const [query, setQuery] = useState("");
  const filtered = repos.filter((r) => `${r.owner}/${r.name}`.toLowerCase().includes(query.toLowerCase()));
  return (
    <div>
      <Field size="compact" className="mb-2">
        <Field.Icon>
          <SearchIcon />
        </Field.Icon>
        <Field.Input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Filter…" aria-label="Find a repository" />
      </Field>
      <ul className="-mx-2 flex flex-col gap-0.5">
        {filtered.map((r) => (
          <li key={`${r.owner}/${r.name}`}>
            <Link
              href={`/${r.owner}/${r.name}`}
              className="flex items-center gap-2.5 rounded-row px-2 py-1.5 type-ui transition-row outline-none hover:recipe-row-list-hover focus-visible:recipe-row-list-hover focus-visible:focus-ring-flush"
            >
              <RepoAvatar repo={r} size={22} />
              <span className="min-w-0 flex-1 truncate">
                <span className="text-ink3">{r.owner}/</span>
                <span className="font-medium text-ink">{r.name}</span>
              </span>
              {r.visibility === "private" && (
                <span className="shrink-0 text-ink3" title="Private">
                  <LockIcon width={13} height={13} />
                  <span className="sr-only">Private</span>
                </span>
              )}
            </Link>
          </li>
        ))}
        {filtered.length === 0 && (
          <li className="px-2 py-1.5 type-body text-ink3">{repos.length ? "No matching repositories." : "No repositories yet."}</li>
        )}
      </ul>
    </div>
  );
}