diff --git a/src/components/IconPicker.tsx b/src/components/IconPicker.tsx index 360ac419851..db8a310f367 100644 --- a/src/components/IconPicker.tsx +++ b/src/components/IconPicker.tsx @@ -241,30 +241,28 @@ export const IconPicker: React.FC = ({ {t("iconPicker.myIcons")}
- - - + + + {t("iconPicker.upload")} + + = ({
))} - {library.length === 0 && !currentUnsaved && ( -

- {t("iconPicker.myIconsEmpty")} -

- )} +

+ {library.length === 0 && !currentUnsaved + ? `${t("iconPicker.myIconsEmpty")} ` + : ""} + {t("iconPicker.uploadHint")} +

diff --git a/src/components/ProviderIcon.tsx b/src/components/ProviderIcon.tsx index 60ba3b2ca4c..faa2858a7cb 100644 --- a/src/components/ProviderIcon.tsx +++ b/src/components/ProviderIcon.tsx @@ -5,6 +5,9 @@ import { getIconMetadata, getIconUrl, isUrlIcon, + isDarkInk, + adaptSvgToTheme, + isTileIcon, } from "@/icons/extracted"; import { cn } from "@/lib/utils"; import { isCustomIcon } from "@/utils/customIcon"; @@ -29,11 +32,14 @@ export const ProviderIcon: React.FC = ({ fallbackClassName, }) => { // 获取内联 SVG 字符串 - const iconSvg = useMemo(() => { + const { svg: iconSvg, adapted } = useMemo(() => { if (icon && !isCustomIcon(icon) && !isUrlIcon(icon) && hasIcon(icon)) { - return getIcon(icon); + const raw = getIcon(icon); + // tile 图标自带底色,里面的深色是底,不能换成文字色 + const themed = isTileIcon(icon) ? raw : adaptSvgToTheme(raw); + return { svg: themed, adapted: themed !== raw }; } - return ""; + return { svg: "", adapted: false }; }, [icon]); // 获取图标 URL:内置的大图(URL_ICONS 列表中的 SVG / 光栅图片),或用户上传的 PNG。 @@ -62,19 +68,23 @@ export const ProviderIcon: React.FC = ({ }; }, [size]); - // 获取有效颜色:优先使用传入的有效 color,否则从元数据获取 defaultColor + // 获取有效颜色:优先使用传入的有效 color,否则从元数据获取 defaultColor。 + // 近黑色(#000 / #111 这类)的颜色不写死,交给外层文字色, + // 否则深色模式下是黑底上的黑图标。已经把近黑笔画换成 currentColor 的图标 + // 也不能再套品牌色,否则眼睛、嘴这些细节会和脸同色 const effectiveColor = useMemo(() => { + if (adapted) return undefined; + let resolved: string | undefined; if (color && typeof color === "string" && color.trim() !== "") { - return color; - } - if (icon) { + resolved = color; + } else if (icon) { const metadata = getIconMetadata(icon); if (metadata?.defaultColor && metadata.defaultColor !== "currentColor") { - return metadata.defaultColor; + resolved = metadata.defaultColor; } } - return undefined; - }, [color, icon]); + return isDarkInk(resolved) ? undefined : resolved; + }, [color, icon, adapted]); // 内联 SVG 渲染(支持 CSS currentColor 着色) if (iconSvg) { diff --git a/src/components/ProviderIconBox.tsx b/src/components/ProviderIconBox.tsx index 34ba2567650..f30b90f9374 100644 --- a/src/components/ProviderIconBox.tsx +++ b/src/components/ProviderIconBox.tsx @@ -1,5 +1,5 @@ import { ProviderIcon } from "@/components/ProviderIcon"; -import { isTileIcon } from "@/icons/extracted"; +import { isTileIcon, needsLightBacking } from "@/icons/extracted"; import { cn } from "@/lib/utils"; import { isCustomIcon } from "@/utils/customIcon"; @@ -31,6 +31,8 @@ export function ProviderIconBox({ }: ProviderIconBoxProps) { // 用户上传的图标在编码时已经按 tile / 透明 logo 留好了白,统一铺满整框 const tile = isCustomIcon(icon) || isTileIcon(icon); + // 透明底的位图 / 上传图标、适配后仍带近黑笔画的图标:深色下垫浅色衬底,否则看不见 + const lightBacking = isCustomIcon(icon) || needsLightBacking(icon); return (