65 lines
1.6 KiB
TypeScript
65 lines
1.6 KiB
TypeScript
import type { LucideIcon } from 'lucide-react'
|
|
import { cn } from '../../lib/cn.ts'
|
|
|
|
export interface TabItem {
|
|
id: string
|
|
label: string
|
|
count?: number
|
|
icon?: LucideIcon
|
|
}
|
|
|
|
export function Tabs({
|
|
tabs,
|
|
value,
|
|
onChange,
|
|
className,
|
|
}: {
|
|
tabs: TabItem[]
|
|
value: string
|
|
onChange: (id: string) => void
|
|
className?: string
|
|
}) {
|
|
return (
|
|
<div
|
|
role="tablist"
|
|
className={cn(
|
|
'inline-flex max-w-full items-center gap-1 overflow-x-auto rounded-lg border border-line bg-surface-2 p-1',
|
|
className,
|
|
)}
|
|
>
|
|
{tabs.map((tab) => {
|
|
const active = tab.id === value
|
|
const Icon = tab.icon
|
|
return (
|
|
<button
|
|
key={tab.id}
|
|
type="button"
|
|
role="tab"
|
|
aria-selected={active}
|
|
onClick={() => onChange(tab.id)}
|
|
className={cn(
|
|
'inline-flex shrink-0 items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors',
|
|
active
|
|
? 'bg-surface-3 text-fg'
|
|
: 'text-fg-muted hover:bg-surface-3/60 hover:text-fg',
|
|
)}
|
|
>
|
|
{Icon && <Icon size={14} strokeWidth={2} aria-hidden="true" />}
|
|
{tab.label}
|
|
{tab.count !== undefined && (
|
|
<span
|
|
className={cn(
|
|
'tabular rounded px-1 py-px text-[10px]',
|
|
active ? 'bg-accent-soft text-accent' : 'bg-surface-3 text-fg-subtle',
|
|
)}
|
|
>
|
|
{tab.count}
|
|
</span>
|
|
)}
|
|
</button>
|
|
)
|
|
})}
|
|
</div>
|
|
)
|
|
}
|