refactor(nav): unify navigation links with Button asChild pattern

This commit is contained in:
zetaloop
2026-02-25 14:31:28 +08:00
parent 7a55f35b76
commit 84dffd6764
4 changed files with 25 additions and 27 deletions
+7 -8
View File
@@ -3,6 +3,7 @@
import { Bell, CreditCard, Settings, ShieldCheck } from "lucide-react" import { Bell, CreditCard, Settings, ShieldCheck } from "lucide-react"
import Link from "next/link" import Link from "next/link"
import { usePathname } from "next/navigation" import { usePathname } from "next/navigation"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
const links = [ const links = [
@@ -23,19 +24,17 @@ export function AccountSidebar() {
const Icon = link.icon const Icon = link.icon
const isActive = pathname === link.href const isActive = pathname === link.href
return ( return (
<Link <Button
key={link.href} key={link.href}
href={link.href} variant={isActive ? "secondary" : "ghost"}
className={cn( className={cn("w-full justify-start", !isActive && "text-muted-foreground")}
"flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors", asChild
isActive
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:text-foreground hover:bg-accent/50",
)}
> >
<Link href={link.href}>
<Icon className="h-4 w-4" /> <Icon className="h-4 w-4" />
{link.label} {link.label}
</Link> </Link>
</Button>
) )
})} })}
</nav> </nav>
+7 -8
View File
@@ -13,6 +13,7 @@ import {
} from "lucide-react" } from "lucide-react"
import Link from "next/link" import Link from "next/link"
import { usePathname } from "next/navigation" import { usePathname } from "next/navigation"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
import { useAuthStore } from "@/store/auth" import { useAuthStore } from "@/store/auth"
@@ -49,19 +50,17 @@ export function DashboardSidebar() {
const Icon = link.icon const Icon = link.icon
const isActive = pathname === link.href const isActive = pathname === link.href
return ( return (
<Link <Button
key={link.href} key={link.href}
href={link.href} variant={isActive ? "secondary" : "ghost"}
className={cn( className={cn("w-full justify-start", !isActive && "text-muted-foreground")}
"flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors", asChild
isActive
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:text-foreground hover:bg-accent/50",
)}
> >
<Link href={link.href}>
<Icon className="h-4 w-4" /> <Icon className="h-4 w-4" />
{link.label} {link.label}
</Link> </Link>
</Button>
) )
})} })}
</nav> </nav>
+1 -1
View File
@@ -308,7 +308,7 @@ export function Header() {
{isAuthenticated && ( {isAuthenticated && (
<div className="border-t pt-4"> <div className="border-t pt-4">
<p className="px-3 text-xs text-muted-foreground mb-2"></p> <p className="px-3 text-xs text-muted-foreground mb-2"></p>
<div className="flex gap-1 px-3"> <div className="flex gap-2 px-3">
{availableRoles.map(([role, label]) => ( {availableRoles.map(([role, label]) => (
<Button <Button
key={role} key={role}
+4 -4
View File
@@ -5,7 +5,7 @@ import type * as React from "react"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all duration-200 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-all duration-200 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{ {
variants: { variants: {
variant: { variant: {
@@ -21,10 +21,10 @@ const buttonVariants = cva(
size: { size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3", default: "h-9 px-4 py-2 has-[>svg]:px-3",
xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3", xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", sm: "h-8 gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4", lg: "h-10 px-6 has-[>svg]:px-4",
icon: "size-9", icon: "size-9",
"icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3", "icon-xs": "size-6 rounded-sm [&_svg:not([class*='size-'])]:size-3",
"icon-sm": "size-8", "icon-sm": "size-8",
"icon-lg": "size-10", "icon-lg": "size-10",
}, },