- DB: messenger_rooms/participants/messages/reactions/files 테이블 생성 - Backend: REST API 9개 엔드포인트 + Socket.IO 실시간 핸들러 - Frontend: Gmail 스타일 FAB + 모달, 채팅방 목록, 채팅 패널 - 기능: DM/그룹/채널, 파일 첨부, 이모지 리액션, 멘션, 스레드 - 알림: 토스트 on/off 토글, FAB 읽지 않은 배지 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
46 lines
1.1 KiB
TypeScript
46 lines
1.1 KiB
TypeScript
"use client";
|
|
|
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface UserAvatarProps {
|
|
photo?: string | null;
|
|
name: string;
|
|
size?: "sm" | "md" | "lg";
|
|
online?: boolean;
|
|
}
|
|
|
|
const sizeMap = {
|
|
sm: "h-7 w-7 text-xs",
|
|
md: "h-9 w-9 text-sm",
|
|
lg: "h-11 w-11 text-base",
|
|
};
|
|
|
|
const dotSizeMap = {
|
|
sm: "h-2 w-2",
|
|
md: "h-2.5 w-2.5",
|
|
lg: "h-3 w-3",
|
|
};
|
|
|
|
export function UserAvatar({ photo, name, size = "md", online }: UserAvatarProps) {
|
|
return (
|
|
<div className="relative inline-block shrink-0">
|
|
<Avatar className={cn(sizeMap[size])}>
|
|
{photo && <AvatarImage src={photo} alt={name} />}
|
|
<AvatarFallback className="bg-muted text-muted-foreground">
|
|
{name.charAt(0).toUpperCase()}
|
|
</AvatarFallback>
|
|
</Avatar>
|
|
{online !== undefined && (
|
|
<span
|
|
className={cn(
|
|
"absolute bottom-0 right-0 rounded-full border-2 border-background",
|
|
dotSizeMap[size],
|
|
online ? "bg-green-500" : "bg-gray-300"
|
|
)}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|