diff --git a/client/src/components/CatCard.tsx b/client/src/components/CatCard.tsx index ed5b3c2..a02114b 100644 --- a/client/src/components/CatCard.tsx +++ b/client/src/components/CatCard.tsx @@ -22,7 +22,6 @@ export default function CatCard({ cat, onOpen }: CatCardProps) { const toggleLike = async () => { if (isOwner || !user) return; - if (liked) { setLiked(false); setLikeCount((c) => c - 1); @@ -47,13 +46,12 @@ export default function CatCard({ cat, onOpen }: CatCardProps) { return (
- {/* Header */} -
-
onOpen(cat.id)} - > - +
onOpen(cat.id)} + > +
+ {cat.username.charAt(0).toUpperCase()} @@ -62,28 +60,23 @@ export default function CatCard({ cat, onOpen }: CatCardProps) {

@{cat.username}

- +
- {/* Image */} -
onOpen(cat.id)} - > +
onOpen(cat.id)}> {cat.caption
- {/* Caption */} {cat.caption && ( -
onOpen(cat.id)}> +
onOpen(cat.id)}>

@{cat.username} {cat.caption} @@ -91,7 +84,6 @@ export default function CatCard({ cat, onOpen }: CatCardProps) {

)} - {/* Actions */}
- + 🏆 {cat.user_points} - баллов
diff --git a/client/src/components/CatModal.tsx b/client/src/components/CatModal.tsx index 4824774..cf8ac07 100644 --- a/client/src/components/CatModal.tsx +++ b/client/src/components/CatModal.tsx @@ -26,10 +26,12 @@ export default function CatModal({ catId, onClose }: CatModalProps) { useEffect(() => { if (likeData) setLiked(likeData.liked); }, [likeData]); useEffect(() => { if (data?.cat) setLikeCount(data.cat.likes_count); }, [data]); + useEffect(() => { document.body.style.overflow = 'hidden'; return () => { document.body.style.overflow = ''; }; }, []); useEffect(() => { - document.body.style.overflow = 'hidden'; - return () => { document.body.style.overflow = ''; }; - }, []); + const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; + window.addEventListener('keydown', handler); + return () => window.removeEventListener('keydown', handler); + }, [onClose]); const cat = data?.cat; const isOwner = cat && user && cat.user_id === user.id; @@ -37,17 +39,14 @@ export default function CatModal({ catId, onClose }: CatModalProps) { const toggleLike = async () => { if (isOwner || !user || !cat) return; if (liked) { - setLiked(false); - setLikeCount((c) => c - 1); + setLiked(false); setLikeCount((c) => c - 1); try { const res = await unlikeMutation.mutateAsync(); - if (res.ownerPoints !== undefined && cat.user_id === user.id) - updateUser({ ...user, points: res.ownerPoints }); + if (res.ownerPoints !== undefined && cat.user_id === user.id) updateUser({ ...user, points: res.ownerPoints }); refetchLike(); } catch { setLiked(true); setLikeCount((c) => c + 1); } } else { - setLiked(true); - setLikeCount((c) => c + 1); + setLiked(true); setLikeCount((c) => c + 1); toast('Нравится ❤️'); try { await likeMutation.mutateAsync(); refetchLike(); } catch { setLiked(false); setLikeCount((c) => c - 1); } @@ -63,19 +62,12 @@ export default function CatModal({ catId, onClose }: CatModalProps) { } catch { toast('Ошибка удаления', 'error'); } }; - // Close on Escape - useEffect(() => { - const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; - window.addEventListener('keydown', handler); - return () => window.removeEventListener('keydown', handler); - }, [onClose]); - if (isLoading || !cat) { return (
- Загрузка... + Загрузка...
); @@ -86,51 +78,37 @@ export default function CatModal({ catId, onClose }: CatModalProps) { }); return ( -
+
e.stopPropagation()} > - {/* Header */}
- - {cat.username.charAt(0).toUpperCase()} - + {cat.username.charAt(0).toUpperCase()}
@{cat.username} -

{dateStr}

+

{dateStr}

{isOwner && ( - )} -
- {/* Image */}
{!imageLoaded && (
-
+
)}
- {/* Info */}
- - {cat.username.charAt(0).toUpperCase()} - + {cat.username.charAt(0).toUpperCase()}

@@ -158,31 +133,26 @@ export default function CatModal({ catId, onClose }: CatModalProps) {

- {/* Actions */}
-
- -
- + + 🏆 {cat.user_points} - баллов + баллов
diff --git a/client/src/components/FeedSidebar.tsx b/client/src/components/FeedSidebar.tsx index df1d0ac..c0d619e 100644 --- a/client/src/components/FeedSidebar.tsx +++ b/client/src/components/FeedSidebar.tsx @@ -4,6 +4,19 @@ import { Avatar, AvatarFallback } from '@/components/ui/avatar'; import { Link } from 'react-router-dom'; import { Trophy, Sparkles } from 'lucide-react'; +function MedalBadge({ rank }: { rank: number }) { + const colors = [ + 'bg-amber-100 text-amber-600 shadow-[0_0_0_1px_rgba(217,119,6,0.15)]', + 'bg-gray-100 text-gray-500 shadow-[0_0_0_1px_rgba(107,114,128,0.15)]', + 'bg-orange-100 text-orange-600 shadow-[0_0_0_1px_rgba(234,88,12,0.15)]', + ]; + return ( + + {rank + 1} + + ); +} + export default function FeedSidebar() { const { user } = useAuth(); const { data } = useCats(1); @@ -21,82 +34,46 @@ export default function FeedSidebar() { .slice(0, 5); return ( -
- {/* Current user */} +
{user && ( - - + + {user.username.charAt(0).toUpperCase()}
-

- {user.username} -

-

- 🏆 {user.points} баллов -

+

{user.username}

+

🏆 {user.points} баллов

)} - {/* Top users */}
-

- Лидеры -

+

Лидеры

{topUsers.length === 0 ? ( -

- Пока нет пользователей -

+

Пока нет пользователей

) : ( -
+
{topUsers.map(([id, u], i) => ( - - - {i + 1} - + + - - {u.username.charAt(0).toUpperCase()} - + {u.username.charAt(0).toUpperCase()} - - {u.username} - - - {u.points} - + {u.username} + {u.points} ))}
)}
- {/* Info */} -
+
Catstagram · Сообщество котоводов diff --git a/client/src/components/Navbar.tsx b/client/src/components/Navbar.tsx index 81a1c97..c07bedb 100644 --- a/client/src/components/Navbar.tsx +++ b/client/src/components/Navbar.tsx @@ -1,7 +1,6 @@ import { Link, useLocation } from 'react-router-dom'; import { useAuth } from '@/hooks/useAuth'; import { Avatar, AvatarFallback } from '@/components/ui/avatar'; -import { House, Plus } from 'lucide-react'; export default function Navbar() { const { user } = useAuth(); @@ -9,44 +8,19 @@ export default function Navbar() { if (!user) return null; - const navItems = [ - { to: '/feed', label: 'Лента', icon: House }, - { to: '/upload', label: 'Добавить', icon: Plus }, - ]; - return ( -