Починка импорта, плеер для аудио
This commit is contained in:
@@ -212,7 +212,7 @@ export default function UserProfile({ userId, onClose, onMessage, isSelf: isSelf
|
||||
exit={{ opacity: 0, scale: 0.98, y: 15 }}
|
||||
transition={{ type: 'spring', damping: 25, stiffness: 300 }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="relative w-full max-w-[560px] h-[85vh] bg-[#0a0a0a] rounded-[3rem] border border-white/10 shadow-2xl overflow-hidden flex flex-col backdrop-blur-3xl"
|
||||
className="relative w-full max-w-[850px] h-[85vh] bg-[#0a0a0a] rounded-[3rem] border border-white/10 shadow-2xl overflow-hidden flex flex-col backdrop-blur-3xl"
|
||||
>
|
||||
<div className="flex items-center justify-between px-8 py-5 border-b border-white/5 bg-white/[0.01]">
|
||||
<span className="text-sm font-black uppercase tracking-[0.3em] text-white/50">{t('userProfileUpper')}</span>
|
||||
@@ -268,18 +268,18 @@ export default function UserProfile({ userId, onClose, onMessage, isSelf: isSelf
|
||||
|
||||
{/* Tabs Nav */}
|
||||
{availableTabs.length > 0 && (
|
||||
<div className="bg-white/[0.03] p-1.5 rounded-2xl flex items-center mb-8 border border-white/5 shadow-inner">
|
||||
<div className="bg-white/[0.03] p-2 rounded-2xl flex items-center mb-8 border border-white/5 shadow-inner gap-2">
|
||||
{availableTabs.map((t) => (
|
||||
<button
|
||||
key={t.id}
|
||||
onClick={() => setActiveTab(t.id)}
|
||||
className={`relative flex-1 flex items-center justify-center gap-2.5 py-4 rounded-2xl transition-all duration-300 ${activeTab === t.id ? 'text-primary bg-white/[0.08]' : 'text-white/20 hover:text-white/60'}`}
|
||||
className={`relative flex-1 flex items-center justify-center gap-3 py-4 rounded-2xl transition-all duration-300 ${activeTab === t.id ? 'text-primary bg-white/[0.08] shadow-[0_0_20px_rgba(168,85,247,0.15)]' : 'text-white/20 hover:text-white/60'}`}
|
||||
>
|
||||
<t.icon size={18} className="relative z-10" />
|
||||
<div className="relative z-10 flex items-center gap-2">
|
||||
<span className="text-[11px] font-black uppercase tracking-widest leading-none">{t.label}</span>
|
||||
<t.icon size={20} className="relative z-10" />
|
||||
<div className="relative z-10 flex items-center gap-2.5">
|
||||
<span className="text-[12px] font-black uppercase tracking-widest leading-none">{t.label}</span>
|
||||
{counts[t.id] > 0 && (
|
||||
<span className="flex items-center justify-center min-w-[22px] h-[20px] px-1.5 rounded-lg bg-[#1e1e1e] border border-white/10 text-primary text-[10px] font-black shadow-md">
|
||||
<span className="flex items-center justify-center min-w-[24px] h-[22px] px-2 rounded-lg bg-[#1e1e1e] border border-white/10 text-primary text-[11px] font-black shadow-md">
|
||||
{counts[t.id]}
|
||||
</span>
|
||||
)}
|
||||
@@ -301,14 +301,17 @@ export default function UserProfile({ userId, onClose, onMessage, isSelf: isSelf
|
||||
|
||||
{(activeTab === 'media' || activeTab === 'gif') ? (
|
||||
tabData.flatMap((item) => (item.media || []).map((m: any) => {
|
||||
const mediaType = m.type?.toLowerCase() || 'image';
|
||||
const isGif = (mediaType === 'image' && (m.url.toLowerCase().endsWith('.gif') || m.url.toLowerCase().endsWith('.mp4'))) || m.url.toLowerCase().indexOf('klipy') !== -1;
|
||||
const mType = m.type?.toLowerCase() || 'image';
|
||||
const mFilename = m.filename?.toLowerCase() || '';
|
||||
const isGif = mType === 'gif' || (mType === 'image' && (mFilename.endsWith('.gif') || mFilename.endsWith('.mp4'))) || mFilename.includes('gif') || mFilename.includes('animation') || m.url?.toLowerCase().includes('klipy');
|
||||
|
||||
if (activeTab === 'media' && isGif) return null;
|
||||
const isVideo = mediaType === 'video' || m.url.toLowerCase().endsWith('.mp4');
|
||||
if (activeTab === 'gif' && !isGif) return null;
|
||||
|
||||
const isVideo = mType === 'video' || m.url?.toLowerCase().endsWith('.mp4');
|
||||
|
||||
return (
|
||||
<div key={`${item.messageId}-${m.id}`} className="relative aspect-square group/item">
|
||||
<div key={`${item.id}-${m.id}`} className="relative aspect-square group/item">
|
||||
<button
|
||||
onClick={() => {
|
||||
const gIdx = galleryItems.findIndex(g => g.id === m.id);
|
||||
@@ -319,7 +322,7 @@ export default function UserProfile({ userId, onClose, onMessage, isSelf: isSelf
|
||||
{isVideo ? (
|
||||
<div className="w-full h-full relative">
|
||||
<video src={resolveUrl(m.url)} className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700" />
|
||||
{!isGif && (
|
||||
{(activeTab === 'media') && (
|
||||
<div className="absolute inset-0 bg-black/20 flex items-center justify-center">
|
||||
<div className="w-10 h-10 rounded-full bg-black/50 backdrop-blur-sm border border-white/20 flex items-center justify-center text-white">
|
||||
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
|
||||
@@ -333,8 +336,7 @@ export default function UserProfile({ userId, onClose, onMessage, isSelf: isSelf
|
||||
{activeTab === 'gif' && <div className="absolute bottom-2 right-2 px-1.5 py-0.5 rounded-md bg-black/80 text-[8px] font-black text-white uppercase tracking-tighter">GIF</div>}
|
||||
</button>
|
||||
|
||||
{/* Jump to Message Button */}
|
||||
<div className="absolute top-3 right-3 opacity-0 group-hover/item:opacity-100 transition-opacity z-20 flex gap-1.5">
|
||||
<div className="absolute top-3 right-3 opacity-0 group-hover/item:opacity-100 transition-opacity z-20">
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); onGoToMessage?.(item.id, item.createdAt); }}
|
||||
className="p-2.5 rounded-2xl bg-primary/95 text-white shadow-xl backdrop-blur-md hover:scale-110 active:scale-95 transition-all"
|
||||
@@ -350,7 +352,16 @@ export default function UserProfile({ userId, onClose, onMessage, isSelf: isSelf
|
||||
tabData.map((item, idx) => {
|
||||
const mediaItem = item.media?.[0];
|
||||
const linkUrl = item.links && item.links.length > 0 ? item.links[0] : (mediaItem?.url || '');
|
||||
if (activeTab === 'files' && !mediaItem) return null;
|
||||
|
||||
const mType = mediaItem?.type?.toLowerCase() || 'file';
|
||||
const mFilename = mediaItem?.filename?.toLowerCase() || '';
|
||||
const isGif = mType === 'gif' || (mType === 'image' && (mFilename.endsWith('.mp4') || mFilename.endsWith('.gif'))) || mFilename.includes('gif') || mFilename.includes('animation') || (mediaItem?.url?.toLowerCase().includes('klipy'));
|
||||
|
||||
if (activeTab === 'files') {
|
||||
if (!mediaItem) return null;
|
||||
if (mType === 'image' || mType === 'video' || isGif) return null;
|
||||
}
|
||||
|
||||
if (activeTab === 'links' && (!item.links || item.links.length === 0)) return null;
|
||||
|
||||
return (
|
||||
@@ -359,8 +370,12 @@ export default function UserProfile({ userId, onClose, onMessage, isSelf: isSelf
|
||||
{activeTab === 'files' ? <FileText size={24} /> : <LinkIcon size={24} />}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-sm font-black text-white truncate mb-1">{mediaItem?.filename || item.content}</div>
|
||||
<div className="text-xs text-white/40 font-bold uppercase tracking-widest">{mediaItem?.size ? formatSize(mediaItem.size) : (linkUrl?.length > 40 ? linkUrl.slice(0, 40) + '...' : linkUrl)}</div>
|
||||
<div className="text-sm font-black text-white truncate mb-1">
|
||||
{activeTab === 'links' ? (item.content || linkUrl) : (mediaItem?.filename || item.content || 'File')}
|
||||
</div>
|
||||
<div className="text-xs text-white/40 font-bold uppercase tracking-widest">
|
||||
{activeTab === 'files' ? formatSize(mediaItem?.size) : (linkUrl?.length > 50 ? linkUrl.slice(0, 50) + '...' : linkUrl)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -376,14 +391,14 @@ export default function UserProfile({ userId, onClose, onMessage, isSelf: isSelf
|
||||
<Download size={20} />
|
||||
</button>
|
||||
) : (
|
||||
<button onClick={() => window.open(resolveUrl(linkUrl), '_blank')} className="p-3 rounded-2xl bg-white/5 hover:bg-primary/20 hover:text-primary transition-all">
|
||||
<button onClick={() => window.open(linkUrl.startsWith('http') ? linkUrl : 'https://' + linkUrl, '_blank')} className="p-3 rounded-2xl bg-white/5 hover:bg-primary/20 hover:text-primary transition-all">
|
||||
<ExternalLink size={20} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}).filter(Boolean)
|
||||
)}
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user