Files
IdP/apps/frontend/components/family/hover-upload-avatar.tsx
2026-06-25 23:48:57 +03:00

63 lines
1.7 KiB
TypeScript

'use client';
import { Camera, Loader2 } from 'lucide-react';
import { useId } from 'react';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { cn } from '@/lib/utils';
interface HoverUploadAvatarProps {
name: string;
imageUrl?: string | null;
uploading?: boolean;
onFileSelect: (file: File) => void;
className?: string;
fallbackClassName?: string;
}
export function HoverUploadAvatar({
name,
imageUrl,
uploading = false,
onFileSelect,
className,
fallbackClassName
}: HoverUploadAvatarProps) {
const inputId = useId();
return (
<label
htmlFor={inputId}
className={cn(
'group/avatar relative block cursor-pointer overflow-hidden rounded-full transition',
uploading && 'pointer-events-none',
className
)}
>
<Avatar className="h-full w-full">
{imageUrl ? <AvatarImage src={imageUrl} alt={name} /> : null}
<AvatarFallback className={fallbackClassName}>{name.slice(0, 2).toUpperCase()}</AvatarFallback>
</Avatar>
<span
className={cn(
'absolute inset-0 flex items-center justify-center bg-black/45 text-white opacity-0 transition-opacity duration-200 group-hover/avatar:opacity-100',
uploading && 'opacity-100'
)}
>
{uploading ? <Loader2 className="h-5 w-5 animate-spin" /> : <Camera className="h-5 w-5" />}
</span>
<input
id={inputId}
type="file"
accept="image/*"
className="sr-only"
disabled={uploading}
onChange={(event) => {
const file = event.target.files?.[0];
if (file) onFileSelect(file);
event.target.value = '';
}}
/>
</label>
);
}