126 lines
4.4 KiB
TypeScript
126 lines
4.4 KiB
TypeScript
'use client'
|
|
|
|
import Button from './Button'
|
|
import Image from 'next/image'
|
|
|
|
type MiniCardProps = {
|
|
title: string
|
|
avatar: string
|
|
steamId: string
|
|
selected?: boolean
|
|
onSelect?: (steamId: string) => void
|
|
onKick?: (steamId: string) => void
|
|
isLeader?: boolean
|
|
draggable?: boolean
|
|
currentUserSteamId: string
|
|
teamLeaderSteamId: string
|
|
location?: string
|
|
dragListeners?: any
|
|
hoverEffect?: boolean
|
|
onPromote?: (steamId: string) => void
|
|
hideActions?: boolean
|
|
hideOverlay?: boolean
|
|
}
|
|
|
|
export default function MiniCard({
|
|
title,
|
|
avatar,
|
|
steamId,
|
|
selected,
|
|
onSelect,
|
|
onKick,
|
|
isLeader = false,
|
|
draggable,
|
|
currentUserSteamId,
|
|
teamLeaderSteamId,
|
|
location,
|
|
dragListeners,
|
|
hoverEffect = false,
|
|
onPromote,
|
|
hideActions = false,
|
|
hideOverlay = false,
|
|
}: MiniCardProps) {
|
|
const isSelectable = typeof onSelect === 'function'
|
|
const canKick = currentUserSteamId === teamLeaderSteamId && steamId !== teamLeaderSteamId
|
|
|
|
const cardClasses = `
|
|
relative flex flex-col items-center p-4 border rounded-lg transition
|
|
max-h-[154px] w-full overflow-hidden
|
|
bg-white dark:bg-neutral-800 border shadow-2xs rounded-xl
|
|
${selected ? 'ring-1 ring-blue-500 border-blue-500 dark:ring-blue-400' : 'border-gray-200 dark:border-neutral-700'}
|
|
${hoverEffect ? 'hover:cursor-grab hover:scale-105' : ''}
|
|
${isSelectable ? 'hover:border-blue-400 dark:hover:border-blue-400 cursor-pointer' : ''}
|
|
`
|
|
|
|
const avatarWrapper = 'relative w-16 h-16 mb-2'
|
|
|
|
const handleCardClick = () => {
|
|
if (isSelectable) onSelect?.(steamId)
|
|
}
|
|
|
|
const handleKickClick = (e: React.MouseEvent) => {
|
|
onKick?.(steamId)
|
|
}
|
|
|
|
const handlePromoteClick = (e: React.MouseEvent) => {
|
|
onPromote?.(steamId)
|
|
}
|
|
|
|
const stopDrag = (e: React.PointerEvent | React.MouseEvent) => {
|
|
e.stopPropagation()
|
|
}
|
|
|
|
return (
|
|
<div className={`${cardClasses} group`} onClick={handleCardClick} {...dragListeners}>
|
|
{canKick && !hideActions && !hideOverlay && (
|
|
<div className={`absolute inset-0 bg-white dark:bg-black bg-opacity-50 flex flex-col items-center justify-center gap-2 transition-opacity z-10 ${
|
|
hideOverlay ? 'opacity-0 pointer-events-none' : 'opacity-0 group-hover:opacity-100'
|
|
}`}>
|
|
<span className="text-gray-800 dark:text-neutral-200 font-semibold text-sm mb-1 truncate px-2 max-w-[90%] text-center">{title}</span>
|
|
<div className="pointer-events-auto" onPointerDown={stopDrag}>
|
|
<Button title="Kicken" color="red" variant="solid" size="sm" onClick={handleKickClick} />
|
|
</div>
|
|
{typeof onPromote === 'function' && (
|
|
<div className="pointer-events-auto" onPointerDown={stopDrag}>
|
|
<Button title="Leader" color="blue" variant="solid" size="sm" onClick={handlePromoteClick} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex flex-col items-center z-0">
|
|
<div className={avatarWrapper}>
|
|
<div className="relative w-16 h-16 mb-2">
|
|
<Image
|
|
src={avatar}
|
|
alt={title}
|
|
fill
|
|
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
quality={75}
|
|
className="rounded-full object-cover"
|
|
draggable={false}
|
|
/>
|
|
{isLeader && (
|
|
<div className="absolute -top-1 -right-1 bg-yellow-400 rounded-full p-0.5 shadow ring-2 ring-white dark:ring-neutral-800" draggable={false}>
|
|
<svg className="w-3.5 h-3.5 text-white" fill="currentColor" viewBox="0 0 20 20">
|
|
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.286 3.965a1 1 0 00.95.69h4.172c.969 0 1.371 1.24.588 1.81l-3.375 2.455a1 1 0 00-.364 1.118l1.287 3.966c.3.92-.755 1.688-1.54 1.118l-3.375-2.455a1 1 0 00-1.175 0l-3.375 2.455c-.784.57-1.838-.197-1.539-1.118l1.286-3.966a1 1 0 00-.364-1.118L2.05 9.392c-.783-.57-.38-1.81.588-1.81h4.172a1 1 0 00.95-.69l1.286-3.965z" />
|
|
</svg>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<span className="text-sm text-gray-800 dark:text-neutral-200 text-center mt-1 truncate max-w-[100px] w-full block">
|
|
{title}
|
|
</span>
|
|
|
|
{location ? (
|
|
<span className={`fi fi-${location.toLowerCase()} text-xl mt-1`} title={location} />
|
|
) : (
|
|
<span className="text-xl mt-1" title="Weltweit">🌐</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|