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 flex min-h-[160px] cursor-pointer flex-col rounded-xl border-2 border-solid border-transparent bg-white shadow-sm transition-all duration-200 ease-in-out hover:shadow-lg', active && '!border-primary-400')} onClick={onSelect}>
  36. <div className='flex h-[66px] shrink-0 grow-0 items-center gap-3 px-[14px] pb-3 pt-[14px]'>
  37. <div className='relative shrink-0'>
  38. {typeof collection.icon === 'string' && (
  39. <div className='h-10 w-10 rounded-md bg-cover bg-center bg-no-repeat' 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='w-0 grow py-[1px]'>
  50. <div className='flex items-center text-sm font-semibold leading-5 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] font-medium leading-[18px] text-gray-500'>
  54. <div className='truncate'>{t('tools.author')}&nbsp;{collection.author}</div>
  55. </div>
  56. </div>
  57. </div>
  58. <div
  59. className={cn(
  60. 'mb-2 max-h-[72px] grow px-[14px] 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='mt-1 flex h-[42px] shrink-0 items-center pb-[6px] pl-[14px] pr-[6px] pt-1'>
  70. <div className='relative flex w-full items-center gap-1 rounded-md py-[7px] text-gray-500' title={labelContent}>
  71. <Tag01 className='h-3 w-3 shrink-0' />
  72. <div className='grow truncate text-start text-xs font-normal leading-[18px]'>{labelContent}</div>
  73. </div>
  74. </div>
  75. )}
  76. </div>
  77. )
  78. }
  79. export default ProviderCard