index.tsx 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React from 'react'
  4. import cn from '@/utils/classnames'
  5. type Option = {
  6. value: string
  7. text: string | JSX.Element
  8. }
  9. type ItemProps = {
  10. className?: string
  11. isActive: boolean
  12. onClick: (v: string) => void
  13. option: Option
  14. }
  15. const Item: FC<ItemProps> = ({
  16. className,
  17. isActive,
  18. onClick,
  19. option,
  20. }) => {
  21. return (
  22. <div
  23. key={option.value}
  24. className={cn(className, !isActive && 'cursor-pointer', 'relative pb-2.5 leading-6 text-base font-semibold')}
  25. onClick={() => !isActive && onClick(option.value)}
  26. >
  27. <div className={cn(isActive ? 'text-gray-900' : 'text-gray-600')}>{option.text}</div>
  28. {isActive && (
  29. <div className='absolute bottom-0 left-0 right-0 h-0.5 bg-[#155EEF]'></div>
  30. )}
  31. </div>
  32. )
  33. }
  34. type Props = {
  35. className?: string
  36. value: string
  37. onChange: (v: string) => void
  38. options: Option[]
  39. noBorderBottom?: boolean
  40. itemClassName?: string
  41. }
  42. const TabSlider: FC<Props> = ({
  43. className,
  44. value,
  45. onChange,
  46. options,
  47. noBorderBottom,
  48. itemClassName,
  49. }) => {
  50. return (
  51. <div className={cn(className, !noBorderBottom && 'border-b border-[#EAECF0]', 'flex space-x-6')}>
  52. {options.map(option => (
  53. <Item
  54. isActive={option.value === value}
  55. option={option}
  56. onClick={onChange}
  57. key={option.value}
  58. className={itemClassName}
  59. />
  60. ))}
  61. </div>
  62. )
  63. }
  64. export default React.memo(TabSlider)