Анимации, профиль, медиа
This commit is contained in:
@@ -17,11 +17,25 @@ export class AppApi {
|
||||
});
|
||||
}
|
||||
|
||||
static async getTrendingGifs() {
|
||||
return httpClient.request<any>('/klipy/trending');
|
||||
static async getTrendingGifs(page: number = 1) {
|
||||
return httpClient.request<any>(`/klipy/trending?page=${page}`);
|
||||
}
|
||||
|
||||
static async searchKlipyGifs(query: string) {
|
||||
return httpClient.request<any>(`/klipy/search?q=${encodeURIComponent(query)}`);
|
||||
static async searchKlipyGifs(query: string, page: number = 1) {
|
||||
return httpClient.request<any>(`/klipy/search?q=${encodeURIComponent(query)}&page=${page}`);
|
||||
}
|
||||
|
||||
static async getRecentGifs(page: number = 1) {
|
||||
return httpClient.request<any>(`/klipy/recent?page=${page}`);
|
||||
}
|
||||
|
||||
static async getGifCategories(countryCode: string = 'RU') {
|
||||
return httpClient.request<any>(`/klipy/categories?countryCode=${countryCode}`);
|
||||
}
|
||||
|
||||
static async markGifShared(gifId: string, query: string = '') {
|
||||
return httpClient.request<void>(`/klipy/${gifId}/share?q=${encodeURIComponent(query)}`, {
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ function AvatarInner({ src, name, size = 'md', className = '', online }: AvatarP
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
className={`${sizeClass} rounded-full bg-gradient-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary font-bold tracking-tighter`}
|
||||
className={`${sizeClass} rounded-full ${gradientClass} flex items-center justify-center text-on-primary font-black tracking-tighter shadow-inner`}
|
||||
>
|
||||
{initials}
|
||||
</div>
|
||||
|
||||
@@ -46,7 +46,7 @@ export default function ImageLightbox({ url, images, initialIndex = 0, onClose }
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="fixed inset-0 z-[9999] bg-black flex items-center justify-center"
|
||||
className="fixed inset-0 z-[20000] bg-black flex items-center justify-center"
|
||||
onClick={onClose}
|
||||
>
|
||||
{/* Top bar */}
|
||||
|
||||
@@ -165,9 +165,9 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
|
||||
{/* ── Premium header with avatar ── */}
|
||||
<div className="relative overflow-hidden flex-shrink-0">
|
||||
{/* Animated gradient backdrop */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-knot-500/40 via-purple-600/25 to-transparent pointer-events-none" />
|
||||
<div className="absolute -top-20 -right-20 w-56 h-56 bg-knot-500/15 rounded-full blur-[80px] pointer-events-none" />
|
||||
<div className="absolute -bottom-10 -left-10 w-40 h-40 bg-purple-600/10 rounded-full blur-[60px] pointer-events-none" />
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/30 via-primary-container/20 to-transparent pointer-events-none" />
|
||||
<div className="absolute -top-20 -right-20 w-56 h-56 bg-primary/10 rounded-full blur-[80px] pointer-events-none" />
|
||||
<div className="absolute -bottom-10 -left-10 w-40 h-40 bg-primary-container/10 rounded-full blur-[60px] pointer-events-none" />
|
||||
|
||||
<div className="relative p-6 pb-5">
|
||||
<div className="flex items-start justify-between mb-5">
|
||||
@@ -178,9 +178,8 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
|
||||
{user?.avatar ? (
|
||||
<img src={user.avatar} alt="" className="w-[72px] h-[72px] rounded-full object-cover ring-[3px] ring-surface" />
|
||||
) : (
|
||||
<div className="w-[72px] h-[72px] rounded-full bg-gradient-to-br from-surface to-surface-secondary flex items-center justify-center ring-[3px] ring-surface relative overflow-hidden">
|
||||
<div className="absolute inset-0 bg-gradient-to-tr from-accent/20 to-purple-500/20" />
|
||||
<span className="relative z-10 text-2xl font-bold text-transparent bg-clip-text bg-gradient-to-br from-white to-zinc-400 drop-shadow-md">{initials}</span>
|
||||
<div className="w-[72px] h-[72px] rounded-full bg-linear-to-br from-primary/80 to-primary flex items-center justify-center ring-[3px] ring-surface relative overflow-hidden">
|
||||
<span className="relative z-10 text-2xl font-black text-on-primary drop-shadow-md">{initials}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -223,7 +222,7 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
|
||||
{item.subtitle && <p className="text-[11px] text-zinc-500 mt-0.5">{item.subtitle}</p>}
|
||||
</div>
|
||||
{'badge' in item && item.badge ? (
|
||||
<span className="bg-gradient-to-r from-knot-500 to-purple-600 text-white text-[11px] font-bold min-w-[22px] h-[22px] px-1.5 rounded-full flex items-center justify-center flex-shrink-0 shadow-[0_0_12px_rgba(168,85,247,0.4)]">
|
||||
<span className="bg-linear-to-r from-primary to-primary-container text-on-primary text-[11px] font-black min-w-[22px] h-[22px] px-1.5 rounded-full flex items-center justify-center flex-shrink-0 shadow-[0_0_12px_rgba(var(--color-primary),0.4)]">
|
||||
{item.badge}
|
||||
</span>
|
||||
) : (
|
||||
@@ -521,7 +520,7 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
|
||||
{u.avatar ? (
|
||||
<img src={u.avatar} alt="" className="w-10 h-10 rounded-full object-cover" />
|
||||
) : (
|
||||
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-knot-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm">
|
||||
<div className="w-10 h-10 rounded-full bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary font-black text-sm">
|
||||
{(u.displayName || u.username || '?')[0].toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
@@ -556,7 +555,7 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
|
||||
{req.user.avatar ? (
|
||||
<img src={req.user.avatar} alt="" className="w-10 h-10 rounded-full object-cover" />
|
||||
) : (
|
||||
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-knot-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm">
|
||||
<div className="w-10 h-10 rounded-full bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary font-black text-sm">
|
||||
{(req.user.displayName || req.user.username || '?')[0].toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
@@ -601,7 +600,7 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
|
||||
{friend.avatar ? (
|
||||
<img src={friend.avatar} alt="" className="w-10 h-10 rounded-full object-cover" />
|
||||
) : (
|
||||
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-knot-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm">
|
||||
<div className="w-10 h-10 rounded-full bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary font-black text-sm">
|
||||
{(friend.displayName || friend.username || '?')[0].toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -71,14 +71,14 @@ export function getInitials(name: string): string {
|
||||
|
||||
export function generateAvatarColor(name: string): string {
|
||||
const colors = [
|
||||
'from-violet-500 to-purple-600',
|
||||
'from-blue-500 to-indigo-600',
|
||||
'from-emerald-500 to-teal-600',
|
||||
'from-rose-500 to-pink-600',
|
||||
'from-amber-500 to-orange-600',
|
||||
'from-cyan-500 to-blue-600',
|
||||
'from-fuchsia-500 to-purple-600',
|
||||
'from-lime-500 to-green-600',
|
||||
'bg-linear-to-br from-blue-400 to-blue-600',
|
||||
'bg-linear-to-br from-sky-400 to-sky-600',
|
||||
'bg-linear-to-br from-cyan-400 to-blue-600',
|
||||
'bg-linear-to-br from-blue-500 to-indigo-600',
|
||||
'bg-linear-to-br from-emerald-400 to-blue-600',
|
||||
'bg-linear-to-br from-blue-600 to-primary-container',
|
||||
'bg-linear-to-br from-primary to-primary-container',
|
||||
'bg-linear-to-br from-blue-400 to-cyan-500',
|
||||
];
|
||||
|
||||
let hash = 0;
|
||||
|
||||
Reference in New Issue
Block a user