import type { ReactNode } from "react"; import { useTranslation } from "react-i18next"; import { useLocale, useLocalizePath } from "~/i18n"; import { AuthorAvatar } from "./author-link"; import { InstallCount } from "./install-count"; import { pluginCardScreenshot } from "./thumbnails"; import { pluginHref } from "./links"; import { PluginTile } from "./plugin-tile"; import { firstMediaImage, getAuthor, getCategory, type Plugin, pluginListing } from "./registry"; export const PLUGIN_GRID_CLASS = "grid gap-x-4 gap-y-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"; /** First allowed image, or the plugin tile on a quiet backdrop when there is none. */ function PluginShot({ plugin }: { plugin: Plugin }) { const url = firstMediaImage(plugin); return (
{url ? ( ) : (
)}
); } /** * Gallery card, in three rows under the screenshot: tile and name, description, then author and * `children`, such as when the plugin was added or its install count. */ export function PluginCard({ plugin, children }: { plugin: Plugin; children?: ReactNode }) { const author = getAuthor(plugin); const listing = pluginListing(plugin, useLocale()); const localize = useLocalizePath(); return ( // Grid items size to their content by default; min-w-0 keeps the card in its column.

{listing.name}

{listing.description}

{author.name} {children !== undefined && ( <> ยท {children} )}

); } /** Ranked row for the directory's Most installed list. */ export function PluginRankRow({ plugin, rank, installs, }: { plugin: Plugin; rank: number; installs: number; }) { const { t } = useTranslation(); const listing = pluginListing(plugin, useLocale()); const localize = useLocalizePath(); const category = getCategory(plugin.categories[0]); return ( {rank}

{listing.name}

{category && t(`plugins.categories.${category}.label`)}

); }