first commit
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user