Vectrum
Sign In
48 lines · 2.3 KB · TypeScript
"use client";

import { useRouter } from "next/navigation";
import { Select } from "@unlocalhosted/metalui";
import { BranchIcon, RepoIcon } from "@/components/icons";

type Side = { baseRepo: string; base: string; headRepo: string; head: string | null };

/**
 * The two sides of a comparison: where the changes go (base) and where they come from (head). With
 * forks around, each side also names its repository ("owner/name"), and the page belongs to the base's.
 */
export function CompareSelect({ branches, headBranches, repos, current }: { branches: string[]; headBranches: string[]; repos: string[]; current: Side }) {
  const router = useRouter();
  const options = (names: string[]) => names.map((b) => ({ value: b, label: b, lead: <BranchIcon /> }));
  const repoOptions = repos.map((r) => ({ value: r, label: r, lead: <RepoIcon /> }));
  const go = (next: Side) => {
    const query = new URLSearchParams({
      ...(next.base ? { base: next.base } : {}),
      ...(next.headRepo !== next.baseRepo ? { head_repo: next.headRepo } : {}),
      ...(next.head ? { head: next.head } : {}),
    });
    router.push(`/${next.baseRepo}/compare?${query}`);
  };
  const forks = repos.length > 1;
  return (
    <div className="flex flex-wrap items-center gap-2 type-ui text-ink2">
      <span className="type-label engraved">base</span>
      {forks && (
        <Select aria-label="Base repository" options={repoOptions} value={current.baseRepo} className="max-w-60" onValueChange={(v) => go({ ...current, baseRepo: v, base: "" })} />
      )}
      <Select aria-label="Base branch" options={options(branches)} value={current.base} className="max-w-60" onValueChange={(v) => go({ ...current, base: v })} />
      <span aria-hidden>←</span>
      <span className="type-label engraved">compare</span>
      {forks && (
        <Select aria-label="Repository with the changes" options={repoOptions} value={current.headRepo} className="max-w-60" onValueChange={(v) => go({ ...current, headRepo: v, head: null })} />
      )}
      <Select
        aria-label="Branch with the changes"
        options={options(headBranches)}
        value={current.head}
        placeholder="Choose a branch"
        className="max-w-60"
        onValueChange={(v) => go({ ...current, head: v })}
      />
    </div>
  );
}