import { useEffect, useState, type ReactNode } from "react"; import { capabilityMonogram } from "../../lib/capabilities"; import { cn } from "../../lib/utils"; /** * A catalog item's logo. Registry vendor logos are served from the public, * immutably-cached `/v1/catalog-assets/*` route (via `client.catalogAssetUrl`), * while the three synthetic first-party rows use web-bundled passive marks. A * missing path or a load error falls back to a calm letter monogram so the grid * never shows broken-image glyphs. Lazy-loaded so 1,000+ tiles don't request * every logo at once. */ export function CapabilityLogo({ src, name, size = "md", className, fallback, }: { src: string | null; name: string; size?: "sm" | "md" | "lg" | undefined; className?: string | undefined; /** Optional reviewed initials for named products; catalog rows derive them from the name. */ fallback?: ReactNode | undefined; }) { const [failed, setFailed] = useState(false); // A new src (e.g. switching the sheet to another item) gets a fresh attempt. useEffect(() => setFailed(false), [src]); const box = size === "lg" ? "size-12 rounded-xl text-base" : size === "sm" ? "size-8 rounded-lg text-2xs" : "size-10 rounded-lg text-sm"; const showImage = src && !failed; return ( {showImage ? ( setFailed(true)} /> ) : ( {fallback ?? capabilityMonogram(name)} )} ); }