index.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import {
  2. useEffect,
  3. useRef,
  4. } from 'react'
  5. import {
  6. RiArrowRightUpLine,
  7. RiArrowUpDoubleLine,
  8. } from '@remixicon/react'
  9. import { useTranslation } from 'react-i18next'
  10. import { useMarketplace } from './hooks'
  11. import List from '@/app/components/plugins/marketplace/list'
  12. import Loading from '@/app/components/base/loading'
  13. import { getLocaleOnClient } from '@/i18n'
  14. import { MARKETPLACE_URL_PREFIX } from '@/config'
  15. type MarketplaceProps = {
  16. searchPluginText: string
  17. filterPluginTags: string[]
  18. onMarketplaceScroll: () => void
  19. }
  20. const Marketplace = ({
  21. searchPluginText,
  22. filterPluginTags,
  23. onMarketplaceScroll,
  24. }: MarketplaceProps) => {
  25. const locale = getLocaleOnClient()
  26. const { t } = useTranslation()
  27. const {
  28. isLoading,
  29. marketplaceCollections,
  30. marketplaceCollectionPluginsMap,
  31. plugins,
  32. handleScroll,
  33. page,
  34. } = useMarketplace(searchPluginText, filterPluginTags)
  35. const containerRef = useRef<HTMLDivElement>(null)
  36. useEffect(() => {
  37. const container = containerRef.current
  38. if (container)
  39. container.addEventListener('scroll', handleScroll)
  40. return () => {
  41. if (container)
  42. container.removeEventListener('scroll', handleScroll)
  43. }
  44. }, [handleScroll])
  45. return (
  46. <div
  47. ref={containerRef}
  48. className='grow flex flex-col shrink-0 sticky bottom-[-442px] h-[530px] overflow-y-auto px-12 py-2 pt-0 bg-background-default-subtle'
  49. >
  50. <RiArrowUpDoubleLine
  51. className='absolute top-2 left-1/2 -translate-x-1/2 w-4 h-4 text-text-quaternary cursor-pointer'
  52. onClick={() => onMarketplaceScroll()}
  53. />
  54. <div className='sticky top-0 pt-5 pb-3 bg-background-default-subtle z-10'>
  55. <div className='title-2xl-semi-bold bg-gradient-to-r from-[rgba(11,165,236,0.95)] to-[rgba(21,90,239,0.95)] bg-clip-text text-transparent'>
  56. {t('plugin.marketplace.moreFrom')}
  57. </div>
  58. <div className='flex items-center text-center body-md-regular text-text-tertiary'>
  59. {t('plugin.marketplace.discover')}
  60. <span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
  61. {t('plugin.category.models')}
  62. </span>
  63. ,
  64. <span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
  65. {t('plugin.category.tools')}
  66. </span>
  67. ,
  68. <span className="relative ml-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
  69. {t('plugin.category.agents')}
  70. </span>
  71. ,
  72. <span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
  73. {t('plugin.category.extensions')}
  74. </span>
  75. {t('plugin.marketplace.and')}
  76. <span className="relative ml-1 mr-1 body-md-medium text-text-secondary after:content-[''] after:absolute after:left-0 after:bottom-[1.5px] after:w-full after:h-2 after:bg-text-text-selected">
  77. {t('plugin.category.bundles')}
  78. </span>
  79. {t('common.operation.in')}
  80. <a
  81. href={`${MARKETPLACE_URL_PREFIX}?language=${locale}&q=${searchPluginText}&tags=${filterPluginTags.join(',')}`}
  82. className='flex items-center ml-1 system-sm-medium text-text-accent'
  83. target='_blank'
  84. >
  85. {t('plugin.marketplace.difyMarketplace')}
  86. <RiArrowRightUpLine className='w-4 h-4' />
  87. </a>
  88. </div>
  89. </div>
  90. {
  91. isLoading && page === 1 && (
  92. <div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
  93. <Loading />
  94. </div>
  95. )
  96. }
  97. {
  98. (!isLoading || page > 1) && (
  99. <List
  100. marketplaceCollections={marketplaceCollections || []}
  101. marketplaceCollectionPluginsMap={marketplaceCollectionPluginsMap || {}}
  102. plugins={plugins}
  103. showInstallButton
  104. locale={locale}
  105. />
  106. )
  107. }
  108. </div>
  109. )
  110. }
  111. export default Marketplace