// Sticky top navigation bar. Adapts based on whether we're on the repo picker // page (root) or inside a specific repo: // - Root: shows logo only, no Code/Issues links // - Repo: shows Code + Issues nav links scoped to the current repo slug // // In external mode, shows a "Sign in" button when logged out and a sign-out // action when logged in. import { Link, useParams, useRouterState } from "@tanstack/react-router"; import { Bug, Plus, Sun, Moon, LogIn, LogOut } from "lucide-react"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { ButtonLink } from "@/components/ui/button-link"; import { useAuth } from "@/lib/auth"; import { useTheme } from "@/lib/theme"; import { cn } from "@/lib/utils"; // SignOutButton sends a POST to /auth/logout and reloads the page. // A full reload is the simplest way to reset all Apollo cache + React state. function handleSignOut() { void fetch("/auth/logout", { method: "POST", credentials: "include" }).finally(() => window.location.assign("/"), ); } function SignOutButton() { return ( ); } export function Header() { const { user, mode, loginProviders } = useAuth(); const { theme, toggle } = useTheme(); // Detect if we're inside a /$repo route and grab the slug. const params = useParams({ strict: false }); const repo = params.repo ?? null; // Don't show repo nav on the /auth/* pages. const effectiveRepo = repo === "auth" ? null : repo; return (
{/* Logo always goes to the repo picker root */} git-bug {/* Repo-scoped nav links — only shown when inside a repo */} {effectiveRepo && }
{mode === "readonly" && Read only} {/* External mode: show sign-in buttons when logged out */} {mode === "external" && !user && loginProviders.map((p) => ( ))} {user && effectiveRepo && ( <> New issue {user.displayName.slice(0, 2).toUpperCase()} )} {/* Sign out only shown in external mode when logged in */} {mode === "external" && user && }
); } const navLinkBase = "rounded-md px-3 py-1.5 text-sm font-medium transition-colors"; const navLinkActive = "bg-accent text-accent-foreground"; const navLinkInactive = "text-muted-foreground hover:bg-accent hover:text-accent-foreground"; function RepoNav({ repo }: { repo: string }) { // Determine which section is active from the matched route IDs. // The _code layout match means we're in the code browser; _issues means issues. const matchedIds = useRouterState({ select: (s) => s.matches.map((m) => m.routeId), }); const isCodeActive = matchedIds.some((id) => id.includes("/_code")); const isIssuesActive = matchedIds.some((id) => id.includes("/_issues")); return ( ); } function providerLabel(name: string): string { const labels: Record = { github: "GitHub", gitlab: "GitLab", gitea: "Gitea" }; return labels[name] ?? name; }