import { createFileRoute, Link, useNavigate } from "@tanstack/react-router"; import { z } from "zod"; import { exploreRepos } from "~/fns/repos"; import { searchAccounts } from "~/fns/account"; import { searchCode } from "~/fns/code"; import { CodeSearchResults } from "~/components/CodeSearchResults"; import { RepoList } from "~/components/RepoList"; import { SearchForm } from "~/components/SearchForm"; import { Badge } from "~/ui/Badge"; import { Avatar } from "~/ui/Avatar"; import { EmptyState } from "~/ui/EmptyState"; import { PageContainer } from "~/ui/PageContainer"; import { Panel } from "~/ui/Panel"; import { Heading } from "~/ui/Heading"; import { buttonClass } from "~/ui/Button"; import { TextLink } from "~/ui/TextLink"; import { useViewer } from "~/hooks/use-viewer"; import { CodeSearchPager } from "~/components/CodeSearchPager"; import { CODE_MAX_PAGES, CODE_PAGE_SIZE } from "~/lib/code-search"; const MAX_OWNER_CHOICES = 6; type CodePage = Awaited>; export const Route = createFileRoute("/search")({ validateSearch: z.object({ q: z.string().optional(), type: z.enum(["code"]).optional().catch(undefined), owner: z.string().max(100).optional(), page: z.coerce.number().int().min(1).max(CODE_MAX_PAGES).optional().catch(undefined), }), loaderDeps: ({ search }) => ({ q: search.q?.trim() ?? "", type: search.type, owner: search.owner?.trim() || undefined, page: search.page ?? 1, }), loader: async ({ deps }) => { if (!deps.q) return { q: "", kind: "overview" as const, repos: [], accounts: [] }; if (deps.type === "code" && deps.owner) { const code = await searchCode({ data: { q: deps.q, owner: deps.owner, page: deps.page } }); return { q: deps.q, kind: "code" as const, owner: deps.owner, code }; } const [repos, accounts] = await Promise.all([ exploreRepos({ data: { q: deps.q, page: 1 } }), searchAccounts({ data: { q: deps.q } }), ]); return { q: deps.q, kind: "overview" as const, repos: repos.repos, accounts }; }, component: SearchPage, }); function SearchStart() { return (

Search gitfor

Find repositories, people and organizations. Search issues, pull requests and code from inside a repository, or a person's or organization's code from here. Results only include what you have access to.

); } /** Every code result for a query, a page at a time. */ function CodeOnlyResults({ q, owner, code }: { q: string; owner: string; code: CodePage }) { const navigate = useNavigate({ from: Route.fullPath }); return (
Code in {owner} matching “{q}” All result types
{code.reposSearched} repositor{code.reposSearched === 1 ? "y" : "ies"} searched {code.reposTruncated ? " (the most recently pushed)" : ""} } > { void navigate({ search: { q, type: "code", owner, page } }); window.scrollTo({ top: 0 }); }} />
); } /** * There is no instance-wide code index (each repository keeps its own), so code search is offered per owner: * the owners of matching repositories, plus the viewer's own account. */ function CodeScopes({ q, owners }: { q: string; owners: string[] }) { return (

Code is searched inside a repository or across one owner's repositories.

{owners.length > 0 && (
    {owners.map((owner) => (
  • Search code in {owner}
  • ))}
)}
); } function SearchPage() { const data = Route.useLoaderData(); const viewer = useViewer(); const { q } = data; if (!q) return ; if (data.kind === "code") return ; const { repos, accounts } = data; const total = repos.length + accounts.length; const owners = [ ...new Set([ ...(viewer ? [viewer.name] : []), ...accounts.map((account) => account.name), ...repos.map((repo) => repo.owner), ]), ].slice(0, MAX_OWNER_CHOICES); if (total === 0) { return ( Browse repositories } > Try fewer or different words, or check the spelling. Private repositories only show up when you have access. ); } return ( {total} result{total === 1 ? "" : "s"} for “{q}” {accounts.length === 0 ? ( ) : (
    {accounts.map((account) => (
  • {account.name} {account.display_name && ( {account.display_name} )} {account.kind === "org" && Organization}
  • ))}
)}
); }