File
Blob: src/client/components/RepoNav.tsx
| 1 | import { Settings } from "lucide-react"; |
| 2 | import { IslandHost } from "@/client/server/IslandHost"; |
| 3 | import { RefPickerIsland } from "@/client/islands/ref-picker"; |
| 4 | import { PageHeader } from "@/client/components/ui/page-header"; |
| 5 | |
| 6 | function decodeRef(refEnc: string): string { |
| 7 | try { |
| 8 | return decodeURIComponent(refEnc); |
| 9 | } catch { |
| 10 | return refEnc; |
| 11 | } |
| 12 | } |
| 13 | |
| 14 | type RepoNavProps = { |
| 15 | owner: string; |
| 16 | repo: string; |
| 17 | refEnc?: string; |
| 18 | currentTab?: "browse" | "commits" | "admin"; |
| 19 | showRefDropdown?: boolean; |
| 20 | }; |
| 21 | |
| 22 | const 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 | |
| 25 | const 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 | |
| 28 | export 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 | } |