- 사용자 온라인 상태 표시 (온라인/자리비움/오프라인) 디스코드 스타일 - 채팅방별 알림 ON/OFF 토글 (Bell 아이콘, localStorage 저장) - 파일 업로드 실시간 소켓 브로드캐스트 및 한글 파일명 깨짐 수정 - FAB 읽지않음 배지 버그 수정 (메신저 닫혀있을 때 markAsRead 차단) - 타이핑 도트 애니메이션, 날짜 오늘/어제 표시 - 입력창 bordered box, DM 편집 버튼 숨김 - 메신저 설정 버튼 제거, 새 대화 시작하기 Empty state CTA - useMessengerSocket 소켓 중복 생성 방지 (MessengerModal로 이동) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> [RAPID-micro] 추적 파일 정리 및 메신저 소소한 변경 - .omc/state/ 파일 git 추적 제거 (.gitignore 이미 설정됨) - db/checkpoints/ gitignore 추가 - globals.css: 메신저 메시지 시간 폰트 스타일 추가 - useMessenger.ts: fileMimeType 필드 및 API_BASE_URL import 추가 Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
60 lines
1.5 KiB
TypeScript
60 lines
1.5 KiB
TypeScript
"use client";
|
|
|
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export type UserStatus = "online" | "away" | "offline";
|
|
|
|
interface UserAvatarProps {
|
|
photo?: string | null;
|
|
name: string;
|
|
size?: "sm" | "md" | "lg";
|
|
status?: UserStatus;
|
|
/** @deprecated use status instead */
|
|
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.5 w-2.5",
|
|
md: "h-3 w-3",
|
|
lg: "h-3.5 w-3.5",
|
|
};
|
|
|
|
const statusColorMap: Record<UserStatus, string> = {
|
|
online: "bg-green-500",
|
|
away: "bg-yellow-400",
|
|
offline: "bg-gray-500",
|
|
};
|
|
|
|
export function UserAvatar({ photo, name, size = "md", status, online }: UserAvatarProps) {
|
|
// Resolve effective status (support legacy `online` prop)
|
|
const effectiveStatus: UserStatus | undefined =
|
|
status ?? (online === true ? "online" : online === false ? "offline" : undefined);
|
|
|
|
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>
|
|
{effectiveStatus !== undefined && (
|
|
<span
|
|
className={cn(
|
|
"absolute bottom-0 right-0 rounded-full border-2 border-background",
|
|
dotSizeMap[size],
|
|
statusColorMap[effectiveStatus]
|
|
)}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|