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";
10
11export const Route = createFileRoute("/")({
12 component: RouteComponent,
13 loader: async ({ context: { preloadQuery } }) => {
14 const repositoriesRef = preloadQuery<RepositoriesQuery>(RepositoriesDocument);
15 return { repositoriesRef: await preloadQuery.toPromise(repositoriesRef) };
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 replace: true,
39 });
40 }
41 }, [data, navigate]);
42
43 return (
44 <div className="mx-auto max-w-lg py-12">
45 <div className="mb-8 flex items-center gap-3">
46 <GitFork className="text-muted-foreground size-6" />
47 <h1 className="text-xl font-semibold">Repositories</h1>
48 </div>
49
50 {error && (
51 <div className="border-destructive/30 bg-destructive/10 text-destructive flex items-center gap-2 rounded-md border px-4 py-3 text-sm">
52 <AlertCircle className="size-4 shrink-0" />
53 Failed to load repositories: {error.message}
54 </div>
55 )}
56
57 <div className="divide-border border-border divide-y rounded-md border">
58 {data?.repositories.nodes.map((repo) => (
59 <Link
60 key={repoSlug(repo.name)}
61 to="/$repo"
62 params={{ repo: repoSlug(repo.name) }}
63 className="hover:bg-muted/50 flex items-center gap-3 px-4 py-4 transition-colors"
64 >
65 <FolderOpen className="text-muted-foreground size-5 shrink-0" />
66 <p className="text-foreground font-medium">{repoLabel(repo.name)}</p>
67 </Link>
68 ))}
69
70 {data?.repositories.totalCount === 0 && (
71 <p className="text-muted-foreground px-4 py-8 text-center text-sm">
72 No repositories found.
73 </p>
74 )}
75 </div>
76 </div>
77 );
78}