({ plugin }: { plugin: PluginCardData })
| 33 | } |
| 34 | |
| 35 | export function PluginCard({ plugin }: { plugin: PluginCardData }) { |
| 36 | return ( |
| 37 | <Link href={plugin.href}> |
| 38 | <Card className="h-[156px] overflow-hidden border-border bg-transparent transition-colors hover:border-input hover:bg-transparent"> |
| 39 | <CardContent className="flex flex-col gap-3 p-4 h-full"> |
| 40 | <div className="flex items-center gap-3"> |
| 41 | {isValidImageUrl(plugin.logo) ? ( |
| 42 | <Avatar className="size-9 rounded-[4px] flex-shrink-0 border border-border bg-muted"> |
| 43 | <AvatarImage |
| 44 | src={plugin.logo} |
| 45 | alt={plugin.name} |
| 46 | className={cn( |
| 47 | "object-cover", |
| 48 | isSvgLogo(plugin.logo) && "invert", |
| 49 | )} |
| 50 | /> |
| 51 | <AvatarFallback className="rounded-[4px] bg-muted text-xs text-foreground"> |
| 52 | {plugin.name.charAt(0).toUpperCase()} |
| 53 | </AvatarFallback> |
| 54 | </Avatar> |
| 55 | ) : ( |
| 56 | <PluginIconFallback size={36} /> |
| 57 | )} |
| 58 | <h3 className="flex min-w-0 items-center gap-1.5 truncate text-sm font-medium tracking-[0.005em] text-foreground"> |
| 59 | <span className="truncate">{plugin.name}</span> |
| 60 | {plugin.verified && <VerifiedBadge size="sm" />} |
| 61 | {plugin.unpublished && ( |
| 62 | <span className="shrink-0 rounded border border-border px-1.5 py-0.5 text-[10px] font-mono uppercase text-muted-foreground"> |
| 63 | Unpublished |
| 64 | </span> |
| 65 | )} |
| 66 | </h3> |
| 67 | </div> |
| 68 | |
| 69 | <p className="flex-1 line-clamp-2 text-[13px] leading-5 text-muted-foreground"> |
| 70 | {plugin.description} |
| 71 | </p> |
| 72 | |
| 73 | <div className="mt-auto flex items-center gap-2"> |
| 74 | {plugin.type === "mcp" || plugin.type === "both" ? ( |
| 75 | <span className="rounded-[4px] border border-border bg-muted px-1.5 py-0.5 text-[10px] font-mono text-muted-foreground"> |
| 76 | MCP |
| 77 | </span> |
| 78 | ) : null} |
| 79 | {(plugin.type === "rules" || plugin.type === "both") && |
| 80 | plugin.rulesCount ? ( |
| 81 | <span className="rounded-[4px] border border-border bg-muted px-1.5 py-0.5 text-[10px] font-mono text-muted-foreground"> |
| 82 | {plugin.rulesCount} {plugin.rulesCount === 1 ? "rule" : "rules"} |
| 83 | </span> |
| 84 | ) : null} |
| 85 | {plugin.installCount ? ( |
| 86 | <span className="ml-auto rounded-[4px] border border-border bg-muted px-1.5 py-0.5 text-[10px] font-mono text-muted-foreground"> |
| 87 | {formatCount(plugin.installCount)}{" "} |
| 88 | {plugin.installCount === 1 ? "install" : "installs"} |
| 89 | </span> |
| 90 | ) : null} |
| 91 | </div> |
| 92 | </CardContent> |
nothing calls this directly
no test coverage detected