Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 17x 136x 102x 3x 102x 102x 102x | import type { LucideIcon } from 'lucide-react'
import { cn } from '../../lib/utils'
export interface TabConfig<T extends string> {
id: T
label: string
icon: LucideIcon
visible: boolean
variant?: 'default' | 'destructive'
}
interface SettingsTabNavProps<T extends string> {
tabs: TabConfig<T>[]
activeTab: T
onTabChange: (tab: T) => void
}
export default function SettingsTabNav<T extends string>({
tabs,
activeTab,
onTabChange,
}: SettingsTabNavProps<T>) {
return (
<div className="border-b border-border px-4">
<div className="mx-auto max-w-4xl">
<div className="flex gap-4 overflow-x-auto">
{tabs.filter((tab) => tab.visible).map((tab) => (
<TabButton
key={tab.id}
tab={tab}
isActive={activeTab === tab.id}
onClick={() => onTabChange(tab.id)}
/>
))}
</div>
</div>
</div>
)
}
interface TabButtonProps<T extends string> {
tab: TabConfig<T>
isActive: boolean
onClick: () => void
}
function TabButton<T extends string>({ tab, isActive, onClick }: TabButtonProps<T>) {
const Icon = tab.icon
const isDestructive = tab.variant === 'destructive'
return (
<button
onClick={onClick}
className={cn(
'border-b-2 py-3 text-sm font-medium transition-colors whitespace-nowrap',
isActive
? isDestructive
? 'border-destructive text-destructive'
: 'border-primary text-primary'
: isDestructive
? 'border-transparent text-muted-foreground hover:text-destructive'
: 'border-transparent text-muted-foreground hover:text-foreground'
)}
>
<span className="flex items-center gap-2">
<Icon className="h-4 w-4" />
{tab.label}
</span>
</button>
)
}
|