From f8f220469c86ce403892f82410c89d8f40b01de4 Mon Sep 17 00:00:00 2001 From: HeagBoKaT Date: Fri, 29 May 2026 11:52:04 +0300 Subject: [PATCH] =?UTF-8?q?UI:=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D0=BD=D0=BE=20=D0=BE=D1=84=D0=BE=D1=80=D0=BC=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=E2=80=94=20=D1=82=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?,=20=D0=B0=D0=BD=D0=B8=D0=BC=D0=B0=D1=86=D0=B8=D0=B8,=20=D0=B3?= =?UTF-8?q?=D1=80=D0=B0=D0=B4=D0=B8=D0=B5=D0=BD=D1=82=D1=8B,=20iOS-=D1=81?= =?UTF-8?q?=D1=82=D0=B8=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/CatCard.tsx | 41 ++--- client/src/components/CatModal.tsx | 96 ++++------- client/src/components/FeedSidebar.tsx | 77 +++------ client/src/components/Navbar.tsx | 56 +++--- client/src/components/ProtectedRoute.tsx | 16 +- client/src/components/Toast.tsx | 6 +- client/src/index.css | 207 ++++++++--------------- client/src/pages/CatPage.tsx | 95 +++-------- client/src/pages/FeedPage.tsx | 90 +++------- client/src/pages/LoginPage.tsx | 43 +++-- client/src/pages/ProfilePage.tsx | 147 +++++----------- client/src/pages/RegisterPage.tsx | 91 +++------- client/src/pages/UploadPage.tsx | 124 ++++---------- 13 files changed, 362 insertions(+), 727 deletions(-) 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 ( -