File
Blob: src/client/pages/OwnerPage.tsx
| 1 | import { Folder, Lock } from "lucide-react"; |
| 2 | |
| 3 | import { EmptyState } from "@/client/components/EmptyState"; |
| 4 | import { PageHeader } from "@/client/components/ui/page-header"; |
| 5 | |
| 6 | export type OwnerPageRepo = { |
| 7 | slug: string; |
| 8 | visibility: "public" | "private"; |
| 9 | }; |
| 10 | |
| 11 | export type OwnerPageProps = { |
| 12 | owner: string; |
| 13 | repos: OwnerPageRepo[]; |
| 14 | }; |
| 15 | |
| 16 | export function OwnerPage({ owner, repos }: OwnerPageProps) { |
| 17 | return ( |
| 18 | <div> |
| 19 | <PageHeader> |
| 20 | <div> |
| 21 | <span className="mb-1 inline-block text-xs font-semibold uppercase tracking-wider text-accent-500 dark:text-accent-400"> |
| 22 | Owner |
| 23 | </span> |
| 24 | <div className="font-display text-2xl font-bold tracking-tight">{owner}</div> |
| 25 | </div> |
| 26 | <div></div> |
| 27 | </PageHeader> |
| 28 | <h2>Repositories</h2> |
| 29 | <div className="mt-6 grid gap-6 md:grid-cols-2"> |
| 30 | {repos.length ? ( |
| 31 | repos.map((repo, i) => { |
| 32 | const isPrivate = repo.visibility === "private"; |
| 33 | const Icon = isPrivate ? Lock : Folder; |
| 34 | return ( |
| 35 | <a |
| 36 | key={repo.slug} |
| 37 | href={`/${owner}/${repo.slug}`} |
| 38 | className="group block animate-slide-up opacity-0 rounded-2xl border border-zinc-300 dark:border-zinc-800/60 bg-white shadow-sm dark:bg-zinc-900/50 dark:shadow-none p-5 hover:-translate-y-0.5 transition-transform cursor-pointer hover:border-zinc-400 dark:hover:border-zinc-700/60 hover:shadow-md" |
| 39 | style={{ animationDelay: `${Math.min(i, 7) * 60}ms` }} |
| 40 | > |
| 41 | <div className="flex items-center gap-3"> |
| 42 | <span |
| 43 | className={`inline-grid h-9 w-9 shrink-0 place-items-center rounded-xl bg-zinc-100 transition-colors group-hover:bg-accent-50 dark:bg-zinc-800 dark:group-hover:bg-accent-900/20 ${ |
| 44 | isPrivate |
| 45 | ? "text-amber-700 group-hover:text-amber-700 dark:text-amber-400 dark:group-hover:text-amber-400" |
| 46 | : "text-zinc-500 group-hover:text-accent-500 dark:text-zinc-400 dark:group-hover:text-accent-400" |
| 47 | }`} |
| 48 | aria-label={isPrivate ? "Private repository" : undefined} |
| 49 | > |
| 50 | <Icon className="h-[1.1rem] w-[1.1rem]" aria-hidden="true" /> |
| 51 | </span> |
| 52 | <div className="text-lg font-medium"> |
| 53 | <span className="text-zinc-500 dark:text-zinc-400">{owner}</span> |
| 54 | <span className="mx-1 text-zinc-300 dark:text-zinc-600">/</span> |
| 55 | <span className="transition-colors group-hover:text-accent-500 dark:group-hover:text-accent-400"> |
| 56 | {repo.slug} |
| 57 | </span> |
| 58 | </div> |
| 59 | </div> |
| 60 | </a> |
| 61 | ); |
| 62 | }) |
| 63 | ) : ( |
| 64 | <div className="col-span-full"> |
| 65 | <EmptyState |
| 66 | icon={ |
| 67 | <Folder className="h-7 w-7 text-zinc-500 dark:text-zinc-400" aria-hidden="true" /> |
| 68 | } |
| 69 | title="No repositories yet" |
| 70 | detail="Push a repository to get started." |
| 71 | large |
| 72 | /> |
| 73 | </div> |
| 74 | )} |
| 75 | </div> |
| 76 | </div> |
| 77 | ); |
| 78 | } |