mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-03-12 17:37:24 +00:00
40 lines
1.1 KiB
TypeScript
40 lines
1.1 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { authenticatedFetch } from '../../utils/api';
|
|
|
|
type Props = {
|
|
pluginName: string;
|
|
iconFile: string;
|
|
className?: string;
|
|
};
|
|
|
|
// Module-level cache so repeated renders don't re-fetch
|
|
const svgCache = new Map<string, string>();
|
|
|
|
export default function PluginIcon({ pluginName, iconFile, className }: Props) {
|
|
const url = `/api/plugins/${encodeURIComponent(pluginName)}/assets/${encodeURIComponent(iconFile)}`;
|
|
const [svg, setSvg] = useState<string | null>(svgCache.get(url) ?? null);
|
|
|
|
useEffect(() => {
|
|
if (svgCache.has(url)) return;
|
|
authenticatedFetch(url)
|
|
.then((r) => r.text())
|
|
.then((text) => {
|
|
if (text.trimStart().startsWith('<svg')) {
|
|
svgCache.set(url, text);
|
|
setSvg(text);
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
}, [url]);
|
|
|
|
if (!svg) return <span className={className} />;
|
|
|
|
return (
|
|
<span
|
|
className={className}
|
|
// SVG is fetched from the user's own installed plugin — same trust level as the plugin code itself
|
|
dangerouslySetInnerHTML={{ __html: svg }}
|
|
/>
|
|
);
|
|
}
|