feat: partner badge in marketplace (#14258)

This commit is contained in:
Wu Tianwei
2025-02-25 12:09:37 +08:00
committed by GitHub
parent 28add22f20
commit 42b13bd312
31 changed files with 2288 additions and 31 deletions

View File

@@ -0,0 +1,37 @@
import React, { type FC } from 'react'
import cn from '@/utils/classnames'
import Tooltip from '@/app/components/base/tooltip'
import { Theme } from '@/types/app'
type IconWithTooltipProps = {
className?: string
popupContent?: string
theme: Theme
BadgeIconLight: React.ElementType
BadgeIconDark: React.ElementType
}
const IconWithTooltip: FC<IconWithTooltipProps> = ({
className,
theme,
popupContent,
BadgeIconLight,
BadgeIconDark,
}) => {
const isDark = theme === Theme.dark
const iconClassName = cn('w-5 h-5', className)
const Icon = isDark ? BadgeIconDark : BadgeIconLight
return (
<Tooltip
popupClassName='p-1.5 border-[0.5px] border-[0.5px] border-components-panel-border bg-components-tooltip-bg text-text-secondary system-xs-medium'
popupContent={popupContent}
>
<div className='flex items-center justify-center shrink-0'>
<Icon className={iconClassName} />
</div>
</Tooltip>
)
}
export default React.memo(IconWithTooltip)

View File

@@ -0,0 +1,29 @@
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import IconWithTooltip from './icon-with-tooltip'
import PartnerDark from '@/app/components/base/icons/src/public/plugins/PartnerDark'
import PartnerLight from '@/app/components/base/icons/src/public/plugins/PartnerLight'
import useTheme from '@/hooks/use-theme'
type PartnerProps = {
className?: string
}
const Partner: FC<PartnerProps> = ({
className,
}) => {
const { t } = useTranslation()
const { theme } = useTheme()
return (
<IconWithTooltip
className={className}
theme={theme}
BadgeIconLight={PartnerLight}
BadgeIconDark={PartnerDark}
popupContent={t('plugin.marketplace.partnerTip')}
/>
)
}
export default Partner

View File

@@ -0,0 +1,29 @@
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import IconWithTooltip from './icon-with-tooltip'
import VerifiedDark from '@/app/components/base/icons/src/public/plugins/VerifiedDark'
import VerifiedLight from '@/app/components/base/icons/src/public/plugins/VerifiedLight'
import useTheme from '@/hooks/use-theme'
type VerifiedProps = {
className?: string
}
const Verified: FC<VerifiedProps> = ({
className,
}) => {
const { t } = useTranslation()
const { theme } = useTheme()
return (
<IconWithTooltip
className={className}
theme={theme}
BadgeIconLight={VerifiedLight}
BadgeIconDark={VerifiedDark}
popupContent={t('plugin.marketplace.verifiedTip')}
/>
)
}
export default Verified

View File

@@ -1,6 +1,5 @@
'use client'
import React from 'react'
import { RiVerifiedBadgeLine } from '@remixicon/react'
import type { Plugin } from '../types'
import Icon from '../card/base/card-icon'
import CornerMark from './base/corner-mark'
@@ -14,6 +13,8 @@ import { getLanguage } from '@/i18n/language'
import { useSingleCategories } from '../hooks'
import { renderI18nObject } from '@/hooks/use-i18n'
import { useMixedTranslation } from '@/app/components/plugins/marketplace/hooks'
import Partner from '../base/badges/partner'
import Verified from '../base/badges/verified'
export type Props = {
className?: string
@@ -46,11 +47,12 @@ const Card = ({
const locale = localeFromProps ? getLanguage(localeFromProps) : defaultLocale
const { t } = useMixedTranslation(localeFromProps)
const { categoriesMap } = useSingleCategories(t)
const { category, type, name, org, label, brief, icon, verified } = payload
const { category, type, name, org, label, brief, icon, verified, badges = [] } = payload
const isBundle = !['plugin', 'model', 'tool', 'extension', 'agent-strategy'].includes(type)
const cornerMark = isBundle ? categoriesMap.bundle?.label : categoriesMap[category]?.label
const getLocalizedText = (obj: Record<string, string> | undefined) =>
obj ? renderI18nObject(obj, locale) : ''
const isPartner = badges.includes('partner')
const wrapClassName = cn('relative p-4 pb-3 border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg hover-bg-components-panel-on-panel-item-bg rounded-xl shadow-xs', className)
if (isLoading) {
@@ -71,7 +73,8 @@ const Card = ({
<div className="ml-3 w-0 grow">
<div className="flex items-center h-5">
<Title title={getLocalizedText(label)} />
{verified && <RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" />}
{isPartner && <Partner className='w-4 h-4 ml-0.5' />}
{verified && <Verified className='w-4 h-4 ml-0.5' />}
{titleLeft} {/* This can be version badge */}
</div>
<OrgInfo

View File

@@ -38,7 +38,7 @@ export const pluginManifestInMarketToPluginProps = (pluginManifest: PluginManife
label: pluginManifest.label,
brief: pluginManifest.brief,
icon: pluginManifest.icon,
verified: pluginManifest.verified,
verified: true,
introduction: pluginManifest.introduction,
repository: '',
install_count: 0,
@@ -46,6 +46,7 @@ export const pluginManifestInMarketToPluginProps = (pluginManifest: PluginManife
settings: [],
},
tags: [],
badges: pluginManifest.badges,
}
}

View File

@@ -87,6 +87,7 @@ export type PluginManifestInMarket = {
introduction: string
verified: boolean
install_count: number
badges: string[]
}
export type PluginDetail = {
@@ -137,6 +138,7 @@ export type Plugin = {
settings: CredentialFormSchemaBase[]
}
tags: { name: string }[]
badges: string[]
}
export enum PermissionType {