'use client' import type { Plugin } from '../types' import type { Locale } from '@/i18n-config' import { RiAlertFill } from '@remixicon/react' import * as React from 'react' import { useMixedTranslation } from '@/app/components/plugins/marketplace/hooks' import { useGetLanguage } from '@/context/i18n' import useTheme from '@/hooks/use-theme' import { renderI18nObject, } from '@/i18n-config' import { getLanguage } from '@/i18n-config/language' import { Theme } from '@/types/app' import { cn } from '@/utils/classnames' import Partner from '../base/badges/partner' import Verified from '../base/badges/verified' import Icon from '../card/base/card-icon' import { useCategories } from '../hooks' import CornerMark from './base/corner-mark' import Description from './base/description' import OrgInfo from './base/org-info' import Placeholder from './base/placeholder' import Title from './base/title' export type Props = { className?: string payload: Plugin titleLeft?: React.ReactNode installed?: boolean installFailed?: boolean hideCornerMark?: boolean descriptionLineRows?: number footer?: React.ReactNode isLoading?: boolean loadingFileName?: string locale?: Locale limitedInstall?: boolean } const Card = ({ className, payload, titleLeft, installed, installFailed, hideCornerMark, descriptionLineRows = 2, footer, isLoading = false, loadingFileName, locale: localeFromProps, limitedInstall = false, }: Props) => { const defaultLocale = useGetLanguage() const locale = localeFromProps ? getLanguage(localeFromProps) : defaultLocale const { t } = useMixedTranslation(localeFromProps) const { categoriesMap } = useCategories(t, true) const { category, type, name, org, label, brief, icon, icon_dark, verified, badges = [] } = payload const { theme } = useTheme() const iconSrc = theme === Theme.dark && icon_dark ? icon_dark : icon const getLocalizedText = (obj: Record | undefined) => obj ? renderI18nObject(obj, locale) : '' const isPartner = badges.includes('partner') const wrapClassName = cn('hover-bg-components-panel-on-panel-item-bg relative overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg shadow-xs', className) if (isLoading) { return ( ) } return (
{!hideCornerMark && } {/* Header */}
{isPartner && <Partner className="ml-0.5 h-4 w-4" text={t('marketplace.partnerTip', { ns: 'plugin' })} />} {verified && <Verified className="ml-0.5 h-4 w-4" text={t('marketplace.verifiedTip', { ns: 'plugin' })} />} {titleLeft} {' '} {/* This can be version badge */} </div> <OrgInfo className="mt-0.5" orgName={org} packageName={name} /> </div> </div> <Description className="mt-3" text={getLocalizedText(brief)} descriptionLineRows={descriptionLineRows} /> {footer && <div>{footer}</div>} </div> {limitedInstall && ( <div className="relative flex h-8 items-center gap-x-2 px-3 after:absolute after:bottom-0 after:left-0 after:right-0 after:top-0 after:bg-toast-warning-bg after:opacity-40"> <RiAlertFill className="h-3 w-3 shrink-0 text-text-warning-secondary" /> <p className="system-xs-regular z-10 grow text-text-secondary"> {t('installModal.installWarning', { ns: 'plugin' })} </p> </div> )} </div> ) } export default React.memo(Card)