1// Repository picker page (/). Auto-redirects when there is exactly one repo.
2// Shows a list when multiple repos are registered.
3
4import { useReadQuery } from "@apollo/client/react";
5import { createFileRoute, Link, useNavigate } from "@tanstack/react-router";
6import { GitFork, FolderOpen, AlertCircle } from "lucide-react";
7import { useEffect } from "react";
8
9import { type RepositoriesQuery, RepositoriesDocument } from "@/__generated__/graphql";
10import { preloadQuery } from "@/lib/apollo";
11
12export const Route = createFileRoute("/")({
13 component: RouteComponent,
14 loader: () => ({
15 repositoriesRef: preloadQuery<RepositoriesQuery>(RepositoriesDocument),
16 }),
17});
18
19function repoSlug(name: string | null | undefined): string {
20 return name ?? "_";
21}
22
23function repoLabel(name: string | null | undefined): string {
24 return name ?? "default";
25}
26
27function RouteComponent() {
28 const { repositoriesRef } = Route.useLoaderData();
29 const { data, error } = useReadQuery(repositoriesRef);
30 const navigate = useNavigate();
31
32 // Auto-redirect when there is exactly one repo — no need to pick.
33 useEffect(() => {
34 if (data?.repositories.nodes.length === 1) {
35 void navigate({
36 to: "/$repo",
37 params: { repo: repoSlug(data.repositories.nodes[0].name) },
38 search: { ref: "", path: "", type: "tree" as const },
39 replace: true,
40 });
41 }
42 }, [data, navigate]);
43
44 return (
45 <div className="mx-auto max-w-lg py-12">
46 <div className="mb-8 flex items-center gap-3">
47 <GitFork className="text-muted-foreground size-6" />
48 <h1 className="text-xl font-semibold">Repositories</h1>
49 </div>
50
51 {error && (
52 <div className="border-destructive/30 bg-destructive/10 text-destructive flex items-center gap-2 rounded-md border px-4 py-3 text-sm">
53 <AlertCircle className="size-4 shrink-0" />
54 Failed to load repositories: {error.message}
55 </div>
56 )}
57
58 <div className="divide-border border-border divide-y rounded-md border">
59 {data?.repositories.nodes.map((repo) => (
60 <Link
61 key={repoSlug(repo.name)}
62 to="/$repo"
63 params={{ repo: repoSlug(repo.name) }}
64 search={{ ref: "", path: "", type: "tree" as const }}
65 className="hover:bg-muted/50 flex items-center gap-3 px-4 py-4 transition-colors"
66 >
67 <FolderOpen className="text-muted-foreground size-5 shrink-0" />
68 <p className="text-foreground font-medium">{repoLabel(repo.name)}</p>
69 </Link>
70 ))}
71
72 {data?.repositories.totalCount === 0 && (
73 <p className="text-muted-foreground px-4 py-8 text-center text-sm">
74 No repositories found.
75 </p>
76 )}
77 </div>
78 </div>
79 );
80}