({ extension }: { extension: {
productId: string
displayName: string
description: string
type: string
author: { name: string }
tags: string[]
} })
| 15 | import { Button } from "@/components/ui/button" |
| 16 | |
| 17 | function ExtensionCard({ extension }: { extension: { |
| 18 | productId: string |
| 19 | displayName: string |
| 20 | description: string |
| 21 | type: string |
| 22 | author: { name: string } |
| 23 | tags: string[] |
| 24 | } }) { |
| 25 | const typeInfo = EXTENSION_TYPES[extension.type as ExtensionType] |
| 26 | |
| 27 | return ( |
| 28 | <Link |
| 29 | href={`/plugin/${extension.productId}`} |
| 30 | className="group flex flex-col gap-4 rounded border border-[var(--color-border-weak)] bg-[var(--color-bg-weak)] p-5 transition-colors hover:border-[var(--color-border)] hover:bg-[var(--color-bg-weak-hover)]" |
| 31 | > |
| 32 | <div className="flex items-start justify-between"> |
| 33 | <div className="flex flex-col gap-1"> |
| 34 | <span className="font-medium text-[var(--color-text-strong)]"> |
| 35 | {extension.displayName} |
| 36 | </span> |
| 37 | <span className="text-xs text-[var(--color-text-weak)]"> |
| 38 | Submitted by {extension.author.name} |
| 39 | </span> |
| 40 | </div> |
| 41 | <Badge variant="secondary">{typeInfo?.label || extension.type}</Badge> |
| 42 | </div> |
| 43 | <p className="text-sm leading-relaxed text-[var(--color-text)] line-clamp-2"> |
| 44 | {extension.description} |
| 45 | </p> |
| 46 | {extension.tags.length > 0 && ( |
| 47 | <div className="flex flex-wrap gap-1"> |
| 48 | {extension.tags.slice(0, 3).map((tag, i) => ( |
| 49 | <span key={i} className="text-xs text-[var(--color-text-weak)]"> |
| 50 | #{tag} |
| 51 | </span> |
| 52 | ))} |
| 53 | </div> |
| 54 | )} |
| 55 | </Link> |
| 56 | ) |
| 57 | } |
| 58 | |
| 59 | function SearchContent() { |
| 60 | const router = useRouter() |
nothing calls this directly
no outgoing calls
no test coverage detected