card.tsx 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. 'use client'
  2. import { useMemo } from 'react'
  3. import { useContext } from 'use-context-selector'
  4. import { useTranslation } from 'react-i18next'
  5. import type { Collection } from '../types'
  6. import cn from '@/utils/classnames'
  7. import AppIcon from '@/app/components/base/app-icon'
  8. import { Tag01 } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
  9. import I18n from '@/context/i18n'
  10. import { getLanguage } from '@/i18n/language'
  11. import { useStore as useLabelStore } from '@/app/components/tools/labels/store'
  12. type Props = {
  13. active: boolean
  14. collection: Collection
  15. onSelect: () => void
  16. }
  17. const ProviderCard = ({
  18. active,
  19. collection,
  20. onSelect,
  21. }: Props) => {
  22. const { t } = useTranslation()
  23. const { locale } = useContext(I18n)
  24. const language = getLanguage(locale)
  25. const labelList = useLabelStore(s => s.labelList)
  26. const labelContent = useMemo(() => {
  27. if (!collection.labels)
  28. return ''
  29. return collection.labels.map((name) => {
  30. const label = labelList.find(item => item.name === name)
  31. return label?.label[language]
  32. }).filter(Boolean).join(', ')
  33. }, [collection.labels, labelList, language])
  34. return (
  35. <div className={cn('group col-span-1 bg-white border-2 border-solid border-transparent rounded-xl shadow-sm min-h-[160px] flex flex-col transition-all duration-200 ease-in-out cursor-pointer hover:shadow-lg', active && '!border-primary-400')} onClick={onSelect}>
  36. <div className='flex pt-[14px] px-[14px] pb-3 h-[66px] items-center gap-3 grow-0 shrink-0'>
  37. <div className='relative shrink-0'>
  38. {typeof collection.icon === 'string' && (
  39. <div className='w-10 h-10 bg-center bg-cover bg-no-repeat rounded-md' style={{ backgroundImage: `url(${collection.icon})` }} />
  40. )}
  41. {typeof collection.icon !== 'string' && (
  42. <AppIcon
  43. size='large'
  44. icon={collection.icon.content}
  45. background={collection.icon.background}
  46. />
  47. )}
  48. </div>
  49. <div className='grow w-0 py-[1px]'>
  50. <div className='flex items-center text-sm leading-5 font-semibold text-gray-800'>
  51. <div className='truncate' title={collection.label[language]}>{collection.label[language]}</div>
  52. </div>
  53. <div className='flex items-center text-[10px] leading-[18px] text-gray-500 font-medium'>
  54. <div className='truncate'>{t('tools.author')}&nbsp;{collection.author}</div>
  55. </div>
  56. </div>
  57. </div>
  58. <div
  59. className={cn(
  60. 'grow mb-2 px-[14px] max-h-[72px] text-xs leading-normal text-gray-500',
  61. collection.labels?.length ? 'line-clamp-2' : 'line-clamp-4',
  62. collection.labels?.length > 0 && 'group-hover:line-clamp-2 group-hover:max-h-[36px]',
  63. )}
  64. title={collection.description[language]}
  65. >
  66. {collection.description[language]}
  67. </div>
  68. {collection.labels?.length > 0 && (
  69. <div className='flex items-center shrink-0 mt-1 pt-1 pl-[14px] pr-[6px] pb-[6px] h-[42px]'>
  70. <div className='relative w-full flex items-center gap-1 py-[7px] rounded-md text-gray-500' title={labelContent}>
  71. <Tag01 className='shrink-0 w-3 h-3' />
  72. <div className='grow text-xs text-start leading-[18px] font-normal truncate'>{labelContent}</div>
  73. </div>
  74. </div>
  75. )}
  76. </div>
  77. )
  78. }
  79. export default ProviderCard