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