Аватары заглушки
This commit is contained in:
@@ -148,7 +148,7 @@ function ChatListItem({ chat, isActive }: ChatListItemProps) {
|
||||
{/* Аватар */}
|
||||
<div className="relative flex-shrink-0">
|
||||
{isFavorites ? (
|
||||
<div className="w-12 h-12 rounded-full bg-gradient-to-br from-primary to-primary-container flex items-center justify-center shadow-lg shadow-primary/10 border-2 border-outline-variant/10">
|
||||
<div className="w-12 h-12 rounded-2xl bg-gradient-to-br from-primary to-primary-container flex items-center justify-center shadow-lg shadow-primary/10 border-2 border-outline-variant/10">
|
||||
<span className="material-symbols-outlined text-on-primary-container text-[24px]">bookmark</span>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -427,7 +427,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
|
||||
initial={{ scale: 0.8, opacity: 0 }}
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1] }}
|
||||
className="w-24 h-24 mb-6 rounded-full bg-[#1c1c1c] flex items-center justify-center shadow-[0_0_80px_rgba(48,150,229,0.15)] border border-white/5"
|
||||
className="w-24 h-24 mb-6 rounded-[2rem] bg-[#1c1c1c] flex items-center justify-center shadow-[0_0_80px_rgba(48,150,229,0.15)] border border-white/5"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[#3096e5] text-5xl select-none" style={{ fontVariationSettings: "'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 48" }}>
|
||||
forum
|
||||
@@ -613,7 +613,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
|
||||
>
|
||||
<div className="relative flex-shrink-0 transform transition-all duration-500 group-hover:scale-105 active:scale-95">
|
||||
{isFavorites ? (
|
||||
<div className="w-11 h-11 rounded-full bg-gradient-to-br from-primary to-primary-container flex items-center justify-center shadow-lg shadow-primary/10 border-2 border-outline-variant/10">
|
||||
<div className="w-11 h-11 rounded-2xl bg-gradient-to-br from-primary to-primary-container flex items-center justify-center shadow-lg shadow-primary/10 border-2 border-outline-variant/10">
|
||||
<span className="material-symbols-outlined text-on-primary-container text-[20px]">bookmark</span>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -24,7 +24,7 @@ import { useAuthStore } from '../../../auth/application/authStore';
|
||||
import { useChatStore } from '../../application/chatStore';
|
||||
import { getSocket } from '../../../../core/infrastructure/socket';
|
||||
import { useLang } from '../../../../core/infrastructure/i18n';
|
||||
import { extractWaveform, getMediaUrl, generateAvatarColor } from '../../../../core/utils/utils';
|
||||
import { extractWaveform, getMediaUrl, generateAvatarColor, getInitials } from '../../../../core/utils/utils';
|
||||
import type { Message, MediaItem, Reaction, ChatMember } from '../../../../core/domain/types';
|
||||
import ImageLightbox from '../../../../core/presentation/components/ui/ImageLightbox';
|
||||
import LinkPreview from './LinkPreview';
|
||||
@@ -313,7 +313,7 @@ function MessageBubble({
|
||||
if (reactionGroups[r.emoji].avatars.length < 3) {
|
||||
reactionGroups[r.emoji].avatars.push({
|
||||
url: r.user?.avatar,
|
||||
initials: displayName[0].toUpperCase(),
|
||||
initials: getInitials(displayName),
|
||||
colorClass: 'from-primary/80 to-primary-container'
|
||||
});
|
||||
}
|
||||
@@ -398,10 +398,10 @@ function MessageBubble({
|
||||
{showAvatar ? (
|
||||
<button onClick={() => onViewProfile?.(message.senderId)}>
|
||||
{senderAvatar ? (
|
||||
<img src={senderAvatar} alt="" className="w-8 h-8 rounded-full object-cover" />
|
||||
<img src={senderAvatar} alt="" className="w-8 h-8 rounded-lg object-cover" />
|
||||
) : (
|
||||
<div className="w-8 h-8 rounded-full bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary text-xs font-black shadow-inner">
|
||||
{senderName[0]?.toUpperCase() || '?'}
|
||||
<div className="w-8 h-8 rounded-lg bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary text-xs font-black shadow-inner">
|
||||
{getInitials(senderName)}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
@@ -845,10 +845,10 @@ function MessageBubble({
|
||||
{showAvatar ? (
|
||||
<button onClick={() => onViewProfile?.(message.senderId)}>
|
||||
{senderAvatar ? (
|
||||
<img src={senderAvatar} alt="" className="w-8 h-8 rounded-full object-cover" />
|
||||
<img src={senderAvatar} alt="" className="w-8 h-8 rounded-lg object-cover" />
|
||||
) : (
|
||||
<div className="w-8 h-8 rounded-full bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary text-xs font-black shadow-inner">
|
||||
{senderName[0]?.toUpperCase() || '?'}
|
||||
<div className="w-8 h-8 rounded-lg bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary text-[10px] font-black shadow-inner">
|
||||
{getInitials(senderName)}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
|
||||
@@ -9,6 +9,8 @@ import { useAuthStore } from '../../../auth/application/authStore';
|
||||
import { useLang } from '../../../../core/infrastructure/i18n';
|
||||
import type { UserPresence, FriendWithId } from '../../../../core/domain/types';
|
||||
|
||||
import { getInitials } from '../../../../core/utils/utils';
|
||||
|
||||
interface NewChatModalProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
@@ -55,6 +57,18 @@ export default function NewChatModal({ onClose }: NewChatModalProps) {
|
||||
const handleSelectUser = async (selectedUser: UserPresence) => {
|
||||
if (mode === 'personal') {
|
||||
try {
|
||||
// Check if personal chat with this user already exists
|
||||
const existingChat = useChatStore.getState().chats.find(
|
||||
(c) => c.type === 'personal' && c.members.some((m) => m.user.id === selectedUser.id)
|
||||
);
|
||||
|
||||
if (existingChat) {
|
||||
setActiveChat(existingChat.id);
|
||||
loadMessages(existingChat.id);
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
|
||||
const chat = await ChatApi.createPersonalChat(selectedUser.id);
|
||||
addChat(chat);
|
||||
import('../../../../core/infrastructure/socket').then(({ getSocket }) => getSocket()?.emit('join_chat', chat.id));
|
||||
@@ -170,10 +184,10 @@ export default function NewChatModal({ onClose }: NewChatModalProps) {
|
||||
className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-knot-500/20 border border-knot-500/30"
|
||||
>
|
||||
{u.avatar ? (
|
||||
<img src={u.avatar} alt="" className="w-5 h-5 rounded-full object-cover" />
|
||||
<img src={u.avatar} alt="" className="w-5 h-5 rounded-lg object-cover" />
|
||||
) : (
|
||||
<div className="w-5 h-5 rounded-full bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary text-[9px] font-black shadow-inner">
|
||||
{(u.displayName || u.userName || u.username || '?')[0]?.toUpperCase()}
|
||||
<div className="w-5 h-5 rounded-lg bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary text-[9px] font-black shadow-inner">
|
||||
{getInitials(u.displayName || u.userName || u.username || '?')}
|
||||
</div>
|
||||
)}
|
||||
<span className="text-xs text-white">{u.displayName || u.userName || u.username || ''}</span>
|
||||
@@ -279,7 +293,7 @@ export default function NewChatModal({ onClose }: NewChatModalProps) {
|
||||
<img src={u.avatar} alt="" className="w-11 h-11 rounded-2xl object-cover" />
|
||||
) : (
|
||||
<div className="w-11 h-11 rounded-2xl bg-linear-to-br from-primary to-primary-container flex items-center justify-center text-on-primary font-black text-sm shadow-inner">
|
||||
{(u.displayName || u.userName || u.username || '?')[0]?.toUpperCase() || '?'}
|
||||
{getInitials(u.displayName || u.userName || u.username || '?')}
|
||||
</div>
|
||||
)}
|
||||
{u.isOnline && (
|
||||
@@ -331,7 +345,7 @@ export default function NewChatModal({ onClose }: NewChatModalProps) {
|
||||
<img src={u.avatar} alt="" className="w-11 h-11 rounded-2xl object-cover" />
|
||||
) : (
|
||||
<div className="w-11 h-11 rounded-2xl bg-linear-to-br from-primary to-primary-container flex items-center justify-center text-on-primary font-black text-sm shadow-inner">
|
||||
{(u.displayName || u.userName || u.username || '?')[0]?.toUpperCase() || '?'}
|
||||
{getInitials(u.displayName || u.userName || u.username || '?')}
|
||||
</div>
|
||||
)}
|
||||
{u.isOnline && (
|
||||
|
||||
@@ -15,6 +15,7 @@ import { httpClient } from '../../../../core/infrastructure/httpClient';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import ImageLightbox from '../../../../core/presentation/components/ui/ImageLightbox';
|
||||
import type { FriendWithId, FriendRequest } from '../../../../core/domain/types';
|
||||
import { getInitials } from '../../../../core/utils/utils';
|
||||
|
||||
interface UserProfileProps {
|
||||
userId: string;
|
||||
@@ -225,12 +226,12 @@ export default function UserProfile({ userId, onClose, onMessage, isSelf: isSelf
|
||||
{/* Profile Card */}
|
||||
<div className="flex flex-col items-center mb-10">
|
||||
<div className="relative mb-8 group">
|
||||
<div className="absolute -inset-4 bg-primary/20 blur-3xl rounded-full opacity-40 group-hover:opacity-60 transition-opacity" />
|
||||
<div className="absolute -inset-4 bg-primary/20 blur-3xl rounded-[3rem] opacity-40 group-hover:opacity-60 transition-opacity" />
|
||||
<div className="relative w-40 h-40 rounded-[3rem] bg-zinc-900 border-2 border-white/10 overflow-hidden shadow-2xl">
|
||||
{user.avatar ? (
|
||||
<img src={resolveUrl(user.avatar)} className="w-full h-full object-cover" alt="" />
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center bg-gradient-to-br from-primary/30 to-primary-container/10 text-5xl font-black text-primary">{user.displayName?.[0] || 'U'}</div>
|
||||
<div className="w-full h-full flex items-center justify-center bg-gradient-to-br from-primary/30 to-primary-container/10 text-5xl font-black text-primary">{getInitials(user.displayName)}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user