mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-06-16 13:34:04 +08:00
dc865fbbbf
When ProviderIcon is used without a color prop, it now automatically fetches the defaultColor from icon metadata. This fixes the issue where Gemini app icon turns black when selected in AppSwitcher, because the component was inheriting the parent's text-foreground color.
101 lines
2.6 KiB
TypeScript
101 lines
2.6 KiB
TypeScript
import React, { useMemo } from "react";
|
||
import { getIcon, hasIcon, getIconMetadata } from "@/icons/extracted";
|
||
import { cn } from "@/lib/utils";
|
||
|
||
interface ProviderIconProps {
|
||
icon?: string; // 图标名称
|
||
name: string; // 供应商名称(用于 fallback)
|
||
color?: string; // 自定义颜色 (Deprecated, kept for compatibility but ignored for SVG)
|
||
size?: number | string; // 尺寸
|
||
className?: string;
|
||
showFallback?: boolean; // 是否显示 fallback
|
||
}
|
||
|
||
export const ProviderIcon: React.FC<ProviderIconProps> = ({
|
||
icon,
|
||
name,
|
||
color,
|
||
size = 32,
|
||
className,
|
||
showFallback = true,
|
||
}) => {
|
||
// 获取图标 SVG
|
||
const iconSvg = useMemo(() => {
|
||
if (icon && hasIcon(icon)) {
|
||
return getIcon(icon);
|
||
}
|
||
return "";
|
||
}, [icon]);
|
||
|
||
// 计算尺寸样式
|
||
const sizeStyle = useMemo(() => {
|
||
const sizeValue = typeof size === "number" ? `${size}px` : size;
|
||
return {
|
||
width: sizeValue,
|
||
height: sizeValue,
|
||
// 内嵌 SVG 使用 1em 作为尺寸基准,这里同步 fontSize 让图标实际跟随 size 放大
|
||
fontSize: sizeValue,
|
||
lineHeight: 1,
|
||
};
|
||
}, [size]);
|
||
|
||
// 获取有效颜色:优先使用传入的 color,否则从元数据获取 defaultColor
|
||
const effectiveColor = useMemo(() => {
|
||
if (color) return color;
|
||
if (icon) {
|
||
const metadata = getIconMetadata(icon);
|
||
// 只有当 defaultColor 不是 currentColor 时才使用
|
||
if (metadata?.defaultColor && metadata.defaultColor !== "currentColor") {
|
||
return metadata.defaultColor;
|
||
}
|
||
}
|
||
return undefined;
|
||
}, [color, icon]);
|
||
|
||
// 如果有图标,显示图标
|
||
if (iconSvg) {
|
||
return (
|
||
<span
|
||
className={cn(
|
||
"inline-flex items-center justify-center flex-shrink-0",
|
||
className,
|
||
)}
|
||
style={{ ...sizeStyle, color: effectiveColor }}
|
||
dangerouslySetInnerHTML={{ __html: iconSvg }}
|
||
/>
|
||
);
|
||
}
|
||
|
||
// Fallback:显示首字母
|
||
if (showFallback) {
|
||
const initials = name
|
||
.split(" ")
|
||
.map((word) => word[0])
|
||
.join("")
|
||
.toUpperCase()
|
||
.slice(0, 2);
|
||
const fallbackFontSize =
|
||
typeof size === "number" ? `${Math.max(size * 0.5, 12)}px` : "0.5em";
|
||
return (
|
||
<span
|
||
className={cn(
|
||
"inline-flex items-center justify-center flex-shrink-0 rounded-lg",
|
||
"bg-muted text-muted-foreground font-semibold",
|
||
className,
|
||
)}
|
||
style={sizeStyle}
|
||
>
|
||
<span
|
||
style={{
|
||
fontSize: fallbackFontSize,
|
||
}}
|
||
>
|
||
{initials}
|
||
</span>
|
||
</span>
|
||
);
|
||
}
|
||
|
||
return null;
|
||
};
|