Tabs.tsx raw
1 import { cn } from '@/lib/utils'
2 import { useTranslation } from 'react-i18next'
3 import { useRef, useEffect, useState } from 'react'
4
5 export type TTabValue = 'replies' | 'quotes' | 'reactions' | 'reposts' | 'zaps'
6 const TABS = [
7 { value: 'replies', label: 'Replies' },
8 { value: 'zaps', label: 'Zaps' },
9 { value: 'reposts', label: 'Reposts' },
10 { value: 'reactions', label: 'Reactions' },
11 { value: 'quotes', label: 'Quotes' }
12 ] as { value: TTabValue; label: string }[]
13
14 export function Tabs({
15 selectedTab,
16 onTabChange
17 }: {
18 selectedTab: TTabValue
19 onTabChange: (tab: TTabValue) => void
20 }) {
21 const { t } = useTranslation()
22 const tabRefs = useRef<(HTMLDivElement | null)[]>([])
23 const [indicatorStyle, setIndicatorStyle] = useState({ width: 0, left: 0 })
24
25 useEffect(() => {
26 setTimeout(() => {
27 const activeIndex = TABS.findIndex((tab) => tab.value === selectedTab)
28 if (activeIndex >= 0 && tabRefs.current[activeIndex]) {
29 const activeTab = tabRefs.current[activeIndex]
30 const { offsetWidth, offsetLeft } = activeTab
31 const padding = 32 // 16px padding on each side
32 setIndicatorStyle({
33 width: offsetWidth - padding,
34 left: offsetLeft + padding / 2
35 })
36 }
37 }, 20) // ensure tabs are rendered before calculating
38 }, [selectedTab])
39
40 return (
41 <div className="w-fit">
42 <div className="flex relative">
43 {TABS.map((tab, index) => (
44 <div
45 key={tab.value}
46 ref={(el) => (tabRefs.current[index] = el)}
47 className={cn(
48 `text-center px-4 py-2 font-semibold clickable cursor-pointer rounded-lg`,
49 selectedTab === tab.value ? '' : 'text-muted-foreground'
50 )}
51 onClick={() => onTabChange(tab.value)}
52 >
53 {t(tab.label)}
54 </div>
55 ))}
56 <div
57 className="absolute bottom-0 h-1 bg-primary rounded-full transition-all duration-500"
58 style={{
59 width: `${indicatorStyle.width}px`,
60 left: `${indicatorStyle.left}px`
61 }}
62 />
63 </div>
64 </div>
65 )
66 }
67