index.tsx 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  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(
  25. 'relative pb-2.5 system-xl-semibold',
  26. !isActive && 'cursor-pointer',
  27. className,
  28. )}
  29. onClick={() => !isActive && onClick(option.value)}
  30. >
  31. <div className={cn(isActive ? 'text-text-primary' : 'text-text-tertiary')}>{option.text}</div>
  32. {isActive && (
  33. <div className='absolute bottom-0 left-0 right-0 h-0.5 bg-util-colors-blue-blue-500'></div>
  34. )}
  35. </div>
  36. )
  37. }
  38. type Props = {
  39. className?: string
  40. value: string
  41. onChange: (v: string) => void
  42. options: Option[]
  43. noBorderBottom?: boolean
  44. itemClassName?: string
  45. }
  46. const TabSlider: FC<Props> = ({
  47. className,
  48. value,
  49. onChange,
  50. options,
  51. noBorderBottom,
  52. itemClassName,
  53. }) => {
  54. return (
  55. <div className={cn(className, !noBorderBottom && 'border-b border-divider-subtle', 'flex space-x-6')}>
  56. {options.map(option => (
  57. <Item
  58. isActive={option.value === value}
  59. option={option}
  60. onClick={onChange}
  61. key={option.value}
  62. className={itemClassName}
  63. />
  64. ))}
  65. </div>
  66. )
  67. }
  68. export default React.memo(TabSlider)