You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.tsx 4.4KB

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