Аватары заглушки

This commit is contained in:
Халимов Рустам
2026-04-02 15:26:05 +03:00
parent a42007df2d
commit 757142eda7
10 changed files with 100 additions and 80 deletions

View File

@@ -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>
) : (

View File

@@ -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>
) : (

View File

@@ -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>

View File

@@ -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 && (

View File

@@ -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>