mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-02 10:35:37 +08:00
feat(plugins): add SVG icon support with authenticated inline rendering
This commit is contained in:
6
examples/plugins/hello-world/icon.svg
Normal file
6
examples/plugins/hello-world/icon.svg
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<line x1="18" y1="20" x2="18" y2="10"/>
|
||||||
|
<line x1="12" y1="20" x2="12" y2="4"/>
|
||||||
|
<line x1="6" y1="20" x2="6" y2="14"/>
|
||||||
|
<line x1="2" y1="20" x2="22" y2="20"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 353 B |
39
src/components/plugins/PluginIcon.tsx
Normal file
39
src/components/plugins/PluginIcon.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
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 }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user