160 lines · 5.9 KB
import { Popover } from "@cloudflare/kumo/components/popover";
import { Tabs } from "@cloudflare/kumo/components/tabs";
import { compactInputClass } from "~/ui/Field";
import { useNavigate } from "@tanstack/react-router";
import { useEffect, useId, useRef, useState } from "react";
import { fuzzyFilter } from "~/lib/fuzzy";
import { cn } from "~/utils/cn";

const MAX_RESULTS = 60;
const SHORT_SHA = 12;

type Kind = "branches" | "tags";

type Props = {
  owner: string;
  repo: string;
  current: string;
  branches: string[];
  tags: string[];
  path: string;
  mode: "tree" | "blob" | "commits" | "blame";
};

/**
 * Branch and tag picker: a styled trigger that opens a fuzzy-filterable list, with a branches/tags
 * toggle so hundreds of tags never crowd the branch list. Keyboard: type to filter, arrows, Enter, Escape.
 */
export function RefSwitcher({ owner, repo, current, branches, tags, path, mode }: Props) {
  const navigate = useNavigate();
  const [open, setOpen] = useState(false);
  const [kind, setKind] = useState<Kind>(tags.includes(current) && !branches.includes(current) ? "tags" : "branches");
  const [query, setQuery] = useState("");
  const [active, setActive] = useState(0);
  const inputRef = useRef<HTMLInputElement>(null);
  const listId = useId();

  const refs = kind === "branches" ? branches : tags;
  const results = fuzzyFilter(query, refs, MAX_RESULTS).map((match) => match.path);
  const known = branches.includes(current) || tags.includes(current);