Skip to content
File

Blob: src/client/components/RepoNav.tsx

typescript83 lines
1import { Settings } from "lucide-react";
2import { IslandHost } from "@/client/server/IslandHost";
3import { RefPickerIsland } from "@/client/islands/ref-picker";
4import { PageHeader } from "@/client/components/ui/page-header";
5 
6function decodeRef(refEnc: string): string {
7 try {
8 return decodeURIComponent(refEnc);
9 } catch {
10 return refEnc;
11 }
12}
13 
14type RepoNavProps = {
15 owner: string;
16 repo: string;
17 refEnc?: string;
18 currentTab?: "browse" | "commits" | "admin";
19 showRefDropdown?: boolean;
20};
21 
22const tabBase =
23 "inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800/40 hover:text-zinc-900 dark:hover:text-zinc-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-500/50";
24 
25const tabActive =
26 "inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium bg-accent-100/50 dark:bg-accent-900/20 text-accent-700 dark:text-accent-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-500/50";
27 
28export function RepoNav({ owner, repo, refEnc, currentTab, showRefDropdown = true }: RepoNavProps) {
29 const decodedRef = refEnc ? decodeRef(refEnc) : "";
30 
31 return (
32 <PageHeader>
33 <div className="font-semibold text-lg">
34 <a href={`/${owner}`} className="hover:text-accent-600 dark:hover:text-accent-400">
35 {owner}
36 </a>
37 <span className="mx-1 text-zinc-500 dark:text-zinc-400">/</span>
38 <a href={`/${owner}/${repo}`} className="hover:text-accent-600 dark:hover:text-accent-400">
39 {repo}
40 </a>
41 </div>
42 {refEnc ? (
43 <div className="flex items-center gap-3">
44 <nav className="flex items-center gap-3" aria-label="Repository navigation">
45 {showRefDropdown ? (
46 <IslandHost
47 name="ref-picker"
48 props={{ owner, repo, currentRef: decodedRef }}
49 className="relative"
50 >
51 <RefPickerIsland owner={owner} repo={repo} currentRef={decodedRef} />
52 </IslandHost>
53 ) : null}
54 <div className="inline-flex items-center gap-1 rounded-xl border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 p-1">
55 <a
56 href={`/${owner}/${repo}/tree?ref=${refEnc}`}
57 className={currentTab === "browse" ? tabActive : tabBase}
58 >
59 Browse
60 </a>
61 <a
62 href={`/${owner}/${repo}/commits?ref=${refEnc}`}
63 className={currentTab === "commits" ? tabActive : tabBase}
64 >
65 Commits
66 </a>
67 <a
68 href={`/${owner}/${repo}/admin`}
69 className={currentTab === "admin" ? tabActive : tabBase}
70 >
71 <Settings className="h-4 w-4" aria-hidden="true" />
72 <span>Admin</span>
73 </a>
74 </div>
75 </nav>
76 </div>
77 ) : (
78 <div></div>
79 )}
80 </PageHeader>
81 );
82}