From 14c2da4d29448816b7e01ac0ac683faa762ac83c Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Sat, 9 May 2026 23:57:24 +0800 Subject: [PATCH] feat(extensions): fallback lucide icon when extension icon is missing Render a tinted lucide icon (Puzzle / Server / Sparkles) on the extension card when the icon URL is empty or the image fails to load. Picked icons distinct from EventListener (AudioWaveform) and KnowledgeEngine (Book) to avoid visual collision with plugin component badges. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ExtensionCardComponent.tsx | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/web/src/app/home/plugins/components/plugin-installed/ExtensionCardComponent.tsx b/web/src/app/home/plugins/components/plugin-installed/ExtensionCardComponent.tsx index 61c19ff7..8ddf4f34 100644 --- a/web/src/app/home/plugins/components/plugin-installed/ExtensionCardComponent.tsx +++ b/web/src/app/home/plugins/components/plugin-installed/ExtensionCardComponent.tsx @@ -2,7 +2,16 @@ import { ExtensionCardVO, ExtensionType } from './ExtensionCardVO'; import { useState } from 'react'; import { Badge } from '@/components/ui/badge'; import { useTranslation } from 'react-i18next'; -import { BugIcon, ExternalLink, Ellipsis, Trash, ArrowUp } from 'lucide-react'; +import { + BugIcon, + ExternalLink, + Ellipsis, + Trash, + ArrowUp, + Server, + Sparkles, + Puzzle, +} from 'lucide-react'; import { getCloudServiceClientSync, systemInfo } from '@/app/infra/http'; import { httpClient } from '@/app/infra/http/HttpClient'; import { Button } from '@/components/ui/button'; @@ -30,6 +39,17 @@ export default function ExtensionCardComponent({ }: ExtensionCardComponentProps) { const { t } = useTranslation(); const [dropdownOpen, setDropdownOpen] = useState(false); + const [iconFailed, setIconFailed] = useState(false); + + const FallbackIcon = + cardVO.type === 'mcp' + ? Server + : cardVO.type === 'skill' + ? Sparkles + : Puzzle; + const iconSrc = + cardVO.iconURL || httpClient.getPluginIconURL(cardVO.author, cardVO.name); + const showFallback = iconFailed || !iconSrc; const getTypeBadgeColor = (type: ExtensionType) => { switch (type) { @@ -202,14 +222,18 @@ export default function ExtensionCardComponent({ onClick={() => onCardClick()} >
- extension icon + {showFallback ? ( +
+ +
+ ) : ( + extension icon setIconFailed(true)} + /> + )}