Files
FunConnect/client/ui/src/components/FriendCard.tsx

122 lines
3.6 KiB
TypeScript

import { Avatar } from './Avatar';
import { cn } from '../lib/utils';
import { Friend, FriendRequest } from '../stores/friendStore';
interface FriendCardProps {
friend: Friend;
onRemove?: () => void;
onInvite?: () => void;
className?: string;
}
export function FriendCard({ friend, onRemove, onInvite, className }: FriendCardProps) {
return (
<div
className={cn(
'flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-bg-tertiary transition-colors group',
className
)}
>
<Avatar
seed={friend.avatar_seed}
name={friend.username}
size="md"
showOnline
isOnline={friend.is_online}
/>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-text-primary truncate">{friend.username}</p>
<p className="text-xs text-text-muted">{friend.is_online ? '在线' : '离线'}</p>
</div>
<div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
{onInvite && friend.is_online && (
<button
onClick={onInvite}
className="p-1.5 rounded text-text-muted hover:text-accent-green hover:bg-accent-green/10 transition-colors"
title="邀请加入房间"
>
<svg
className="w-4 h-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
<circle cx="8.5" cy="7" r="4" />
<line x1="20" y1="8" x2="20" y2="14" />
<line x1="23" y1="11" x2="17" y2="11" />
</svg>
</button>
)}
{onRemove && (
<button
onClick={onRemove}
className="p-1.5 rounded text-text-muted hover:text-accent-red hover:bg-accent-red/10 transition-colors"
title="删除好友"
>
<svg
className="w-4 h-4"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<polyline points="3 6 5 6 21 6" />
<path d="M19 6l-1 14H6L5 6" />
<path d="M10 11v6M14 11v6" />
<path d="M9 6V4h6v2" />
</svg>
</button>
)}
</div>
</div>
);
}
interface FriendRequestCardProps {
request: FriendRequest;
onAccept: () => void;
onReject?: () => void;
className?: string;
}
export function FriendRequestCard({
request,
onAccept,
onReject,
className,
}: FriendRequestCardProps) {
return (
<div
className={cn(
'flex items-center gap-3 px-3 py-2.5 rounded-lg bg-bg-tertiary',
className
)}
>
<Avatar seed={request.avatar_seed} name={request.username} size="md" />
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-text-primary truncate">{request.username}</p>
<p className="text-xs text-text-muted"></p>
</div>
<div className="flex items-center gap-2">
{onReject && (
<button
onClick={onReject}
className="btn-ghost py-1 px-2 text-xs"
>
</button>
)}
<button onClick={onAccept} className="btn-primary py-1 px-3 text-xs">
</button>
</div>
</div>
);
}