Files
config-vault/components/AppIcon.tsx
T
2026-08-26 14:21:53 +03:00

81 lines
2.4 KiB
TypeScript

import React from 'react'
import { cn } from '@/lib/utils'
interface AppIconProps {
name: string
iconUrl?: string | null
className?: string
size?: 'sm' | 'md' | 'lg' | 'xl'
}
export function AppIcon({ name, iconUrl, className, size = 'md' }: AppIconProps) {
const sizeClasses = {
sm: 'w-7 h-7 text-xs rounded-lg',
md: 'w-10 h-10 text-base rounded-xl',
lg: 'w-12 h-12 text-lg rounded-2xl',
xl: 'w-16 h-16 text-2xl rounded-3xl',
}[size]
// If iconUrl is an image (starts with http, / or data:image)
const isImage = iconUrl && (
iconUrl.startsWith('http://') ||
iconUrl.startsWith('https://') ||
iconUrl.startsWith('/') ||
iconUrl.startsWith('data:image/')
)
// Gradient generator from app name
const initial = name ? name.charAt(0).toUpperCase() : 'A'
const gradients = [
'from-emerald-500 to-teal-700',
'from-cyan-500 to-blue-700',
'from-indigo-500 to-purple-700',
'from-amber-500 to-orange-700',
'from-rose-500 to-pink-700',
'from-violet-500 to-fuchsia-700',
]
const gradientIndex = (name.charCodeAt(0) || 0) % gradients.length
const bgGradient = gradients[gradientIndex]
if (isImage) {
return (
<div className={cn('relative overflow-hidden bg-slate-900 border border-slate-800 shadow-md flex items-center justify-center flex-shrink-0', sizeClasses, className)}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={iconUrl}
alt={name}
className="w-full h-full object-cover"
onError={(e) => {
// fallback if image fails to load
e.currentTarget.style.display = 'none'
}}
/>
</div>
)
}
// If iconUrl is an emoji or custom text
if (iconUrl && iconUrl.trim()) {
return (
<div className={cn(
'bg-slate-900 border border-slate-800/80 shadow-md flex items-center justify-center flex-shrink-0 select-none',
sizeClasses,
className
)}>
<span className="leading-none">{iconUrl}</span>
</div>
)
}
// Fallback initial with background gradient
return (
<div className={cn(
`bg-gradient-to-br ${bgGradient} p-[1px] shadow-lg flex items-center justify-center text-white font-extrabold flex-shrink-0 select-none`,
sizeClasses,
className
)}>
<span className="drop-shadow-sm">{initial}</span>
</div>
)
}