项目文件夹

文件
wehub-resource-sync 2114b14ee0
Sync main into demo / sync (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:26 +08:00

77 行
2.0 KiB
TypeScript

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
import React, { useEffect, useState } from 'react';
import { useTheme } from '../ThemeContext';
import type { AppManifest } from '../types/manifest';
export const AppIcon: React.FC<{
manifest: AppManifest;
size: number;
radius?: number;
showShadow?: boolean;
}> = ({ manifest, size, radius = 12, showShadow = true }) => {
const { themeService, version } = useTheme();
const themedIcon = themeService.getAppIcon(manifest.packageName);
const iconSource = manifest.icon;
const [broken, setBroken] = useState(false);
useEffect(() => {
setBroken(false);
}, [themedIcon, version, manifest.packageName, manifest.id]);
if (themedIcon && !broken) {
return (
<img
key={`${manifest.packageName || manifest.id}_${version}`}
src={themedIcon}
width={size}
height={size}
className="object-cover"
style={{ borderRadius: radius, flexShrink: 0 }}
alt={manifest.displayName}
decoding="async"
draggable={false}
onError={() => setBroken(true)}
/>
);
}
const iconSize = Math.round(size * 0.55);
// manifest.icon 为图片 URLPNG/WebP)时直接渲染 img
if (typeof iconSource === 'string') {
return (
<img
src={iconSource}
width={size}
height={size}
className="object-cover"
style={{ borderRadius: radius, flexShrink: 0 }}
alt={manifest.displayName}
draggable={false}
/>
);
}
// manifest.icon 为 React 组件(lucide / 自定义 SVG
const Icon = iconSource;
return (
<div
className={`${showShadow ? 'shadow-sm' : ''} flex items-center justify-center`}
style={{
width: size,
height: size,
borderRadius: radius,
flexShrink: 0,
overflow: 'hidden',
background: manifest.iconBackground,
color: manifest.iconForeground ?? 'currentColor',
}}
aria-hidden="true"
>
{Icon ? (
<Icon size={iconSize} color={manifest.iconForeground ?? 'currentColor'} />
) : null}
</div>
);
};