mirror of
https://gitbruv.vercel.app/api/git/bruv/gitbruv.git
synced 2025-12-20 23:24:09 +01:00
add tabs
This commit is contained in:
parent
c768b15bd7
commit
1a8b4c881f
6 changed files with 247 additions and 69 deletions
|
|
@ -11,69 +11,67 @@ type Repository = {
|
|||
visibility: "public" | "private";
|
||||
updatedAt: Date;
|
||||
starCount?: number;
|
||||
owner?: {
|
||||
username: string;
|
||||
name: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
export function RepoList({
|
||||
repos,
|
||||
username,
|
||||
}: {
|
||||
repos: Repository[];
|
||||
username: string;
|
||||
}) {
|
||||
export function RepoList({ repos, username }: { repos: Repository[]; username?: string }) {
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
{repos.map((repo) => (
|
||||
<Link
|
||||
key={repo.id}
|
||||
href={`/${username}/${repo.name}`}
|
||||
className="block p-5 rounded-xl border border-border bg-card hover:border-accent/50 transition-all duration-200 group"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center gap-3 mb-1.5">
|
||||
<span className="font-semibold text-accent group-hover:underline text-lg">
|
||||
{repo.name}
|
||||
</span>
|
||||
<span
|
||||
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border ${
|
||||
repo.visibility === "private"
|
||||
? "border-yellow-500/30 text-yellow-500 bg-yellow-500/10"
|
||||
: "border-border text-muted-foreground bg-secondary"
|
||||
}`}
|
||||
>
|
||||
{repo.visibility === "private" ? (
|
||||
<>
|
||||
<Lock className="h-3 w-3" />
|
||||
Private
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Globe className="h-3 w-3" />
|
||||
Public
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{repo.description && (
|
||||
<p className="text-sm text-muted-foreground line-clamp-2 mt-2">
|
||||
{repo.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col items-end gap-1 shrink-0 pt-1">
|
||||
{typeof repo.starCount === "number" && repo.starCount > 0 && (
|
||||
<div className="flex items-center gap-1 text-muted-foreground">
|
||||
<Star className="h-3.5 w-3.5" />
|
||||
<span className="text-xs">{repo.starCount}</span>
|
||||
{repos.map((repo) => {
|
||||
const ownerUsername = repo.owner?.username || username || "";
|
||||
const showOwner = repo.owner && repo.owner.username !== username;
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={repo.id}
|
||||
href={`/${ownerUsername}/${repo.name}`}
|
||||
className="block p-5 rounded-xl border border-border bg-card hover:border-accent/50 transition-all duration-200 group"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center gap-3 mb-1.5">
|
||||
<span className="font-semibold text-accent group-hover:underline text-lg">
|
||||
{showOwner && <span className="text-muted-foreground font-normal">{repo.owner?.username}/</span>}
|
||||
{repo.name}
|
||||
</span>
|
||||
<span
|
||||
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border ${
|
||||
repo.visibility === "private"
|
||||
? "border-yellow-500/30 text-yellow-500 bg-yellow-500/10"
|
||||
: "border-border text-muted-foreground bg-secondary"
|
||||
}`}
|
||||
>
|
||||
{repo.visibility === "private" ? (
|
||||
<>
|
||||
<Lock className="h-3 w-3" />
|
||||
Private
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Globe className="h-3 w-3" />
|
||||
Public
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{formatDistanceToNow(new Date(repo.updatedAt), { addSuffix: true })}
|
||||
</p>
|
||||
{repo.description && <p className="text-sm text-muted-foreground line-clamp-2 mt-2">{repo.description}</p>}
|
||||
</div>
|
||||
<div className="flex flex-col items-end gap-1 shrink-0 pt-1">
|
||||
{typeof repo.starCount === "number" && repo.starCount > 0 && (
|
||||
<div className="flex items-center gap-1 text-muted-foreground">
|
||||
<Star className="h-3.5 w-3.5" />
|
||||
<span className="text-xs">{repo.starCount}</span>
|
||||
</div>
|
||||
)}
|
||||
<p className="text-xs text-muted-foreground">{formatDistanceToNow(new Date(repo.updatedAt), { addSuffix: true })}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
66
components/ui/tabs.tsx
Normal file
66
components/ui/tabs.tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Tabs({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
||||
return (
|
||||
<TabsPrimitive.Root
|
||||
data-slot="tabs"
|
||||
className={cn("flex flex-col gap-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsList({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.List>) {
|
||||
return (
|
||||
<TabsPrimitive.List
|
||||
data-slot="tabs-list"
|
||||
className={cn(
|
||||
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsTrigger({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
||||
return (
|
||||
<TabsPrimitive.Trigger
|
||||
data-slot="tabs-trigger"
|
||||
className={cn(
|
||||
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsContent({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
||||
return (
|
||||
<TabsPrimitive.Content
|
||||
data-slot="tabs-content"
|
||||
className={cn("flex-1 outline-none", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent }
|
||||
Loading…
Add table
Add a link
Reference in a new issue