UI: complete redesign — warm atelier style, Manrope font, burnt orange accent, shadow-based cards
This commit is contained in:
@@ -6,7 +6,7 @@ import CatModal from '@/components/CatModal';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
|
||||
import { ArrowLeft, Plus, LogOut, Shield } from 'lucide-react';
|
||||
import { ArrowLeft, Plus, LogOut, Shield, Heart, Image, Trophy } from 'lucide-react';
|
||||
|
||||
export default function ProfilePage() {
|
||||
const { id: paramId } = useParams<{ id?: string }>();
|
||||
@@ -27,16 +27,16 @@ export default function ProfilePage() {
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="mx-auto max-w-[660px] px-4 py-8">
|
||||
<div className="mx-auto max-w-[540px] px-5 py-8">
|
||||
<div className="flex items-center gap-5 mb-10">
|
||||
<Skeleton className="h-20 w-20 rounded-full" />
|
||||
<div className="space-y-2.5 flex-1">
|
||||
<Skeleton className="h-6 w-36 rounded-full" />
|
||||
<Skeleton className="h-6 w-32 rounded-full" />
|
||||
<Skeleton className="h-4 w-48 rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{Array.from({ length: 6 }).map((_, i) => (<Skeleton key={i} className="aspect-square rounded-xl" />))}
|
||||
<div className="grid grid-cols-3 gap-1.5">
|
||||
{Array.from({ length: 6 }).map((_, i) => <Skeleton key={i} className="aspect-square rounded-xl" />)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -44,10 +44,12 @@ export default function ProfilePage() {
|
||||
|
||||
if (!profileUser && !isMe) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center py-24 animate-rise">
|
||||
<div className="mb-4 flex h-14 w-14 items-center justify-center rounded-xl bg-[var(--secondary)]"><span className="text-xl">🔍</span></div>
|
||||
<div className="flex flex-col items-center justify-center py-24 animate-fade-up">
|
||||
<div className="mb-4 h-14 w-14 rounded-2xl flex items-center justify-center bg-[var(--border-light)]">
|
||||
<Image className="h-7 w-7 text-[var(--fg-tertiary)]" strokeWidth={1.5} />
|
||||
</div>
|
||||
<p className="text-base font-semibold mb-1">Пользователь не найден</p>
|
||||
<Button variant="outline" onClick={() => navigate('/feed')} className="rounded-lg text-xs mt-2">Вернуться в ленту</Button>
|
||||
<Button variant="outline" onClick={() => navigate('/feed')} className="rounded-xl text-xs mt-2 h-9 px-4">В ленту</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -57,47 +59,61 @@ export default function ProfilePage() {
|
||||
const totalLikes = cats.reduce((sum, c) => sum + c.likes_count, 0);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-[660px] px-4 py-6 animate-rise">
|
||||
<div className="mx-auto max-w-[540px] px-5 py-6 animate-fade-up">
|
||||
{!isMe && (
|
||||
<button onClick={() => navigate(-1)} className="mb-4 flex items-center gap-1.5 text-xs text-[var(--fg-secondary)] hover:text-[var(--fg)] transition-colors">
|
||||
<ArrowLeft className="h-4 w-4 stroke-[1.5]" /> Назад
|
||||
<button onClick={() => navigate(-1)} className="mb-5 flex items-center gap-1.5 text-xs text-[var(--fg-tertiary)] hover:text-[var(--fg)] transition-colors">
|
||||
<ArrowLeft className="h-4 w-4" strokeWidth={1.5} /> Назад
|
||||
</button>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-6 mb-8">
|
||||
<Avatar className="h-20 w-20 shrink-0">
|
||||
<AvatarFallback className="text-2xl font-bold avatar" style={{ borderRadius: '50%' }}>
|
||||
<div className="flex items-center gap-5 mb-8">
|
||||
<Avatar className="h-[72px] w-[72px] shrink-0">
|
||||
<AvatarFallback className="text-2xl font-800 avatar-colored bg-[var(--accent)]">
|
||||
{initials}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<h1 className="text-xl font-bold truncate">@{profileUser?.username}</h1>
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<h1 className="text-lg font-800 truncate">@{profileUser?.username}</h1>
|
||||
<div className="flex items-center gap-1 ml-auto">
|
||||
{isMe && me?.is_admin && (
|
||||
<Link to="/admin" className="btn-icon h-8 w-8 text-[var(--primary)] hover:bg-[var(--primary-light)]" title="Админ-панель">
|
||||
<Link to="/admin" className="btn-ghost h-8 w-8 text-[var(--accent)]" title="Админ-панель">
|
||||
<Shield className="h-4 w-4" strokeWidth={1.5} />
|
||||
</Link>
|
||||
)}
|
||||
{isMe && (
|
||||
<button onClick={logout} className="btn-icon h-8 w-8 text-[var(--fg-secondary)] hover:text-[var(--danger)] hover:bg-[var(--danger-light)]" title="Выйти">
|
||||
<button onClick={logout} className="btn-ghost h-8 w-8 text-[var(--fg-tertiary)] hover:text-red-500" title="Выйти">
|
||||
<LogOut className="h-4 w-4" strokeWidth={1.5} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-6">
|
||||
<div><span className="font-bold">{cats.length}</span><span className="text-xs text-[var(--fg-secondary)] ml-1">фото</span></div>
|
||||
<div><span className="font-bold">{totalLikes}</span><span className="text-xs text-[var(--fg-secondary)] ml-1">❤️</span></div>
|
||||
<div><span className="font-bold">🏆{profileUser?.points ?? 0}</span></div>
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="text-center">
|
||||
<div className="stat-value text-base">{cats.length}</div>
|
||||
<div className="text-[10px] text-[var(--fg-tertiary)] uppercase tracking-wider">фото</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="stat-value text-base flex items-center justify-center gap-0.5">
|
||||
<Heart className="h-3.5 w-3.5 text-[var(--fg-tertiary)]" strokeWidth={1.5} />
|
||||
{totalLikes}
|
||||
</div>
|
||||
<div className="text-[10px] text-[var(--fg-tertiary)] uppercase tracking-wider">лайков</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="stat-value text-base flex items-center justify-center gap-0.5">
|
||||
<Trophy className="h-3.5 w-3.5 text-[var(--fg-tertiary)]" strokeWidth={1.5} />
|
||||
{profileUser?.points ?? 0}
|
||||
</div>
|
||||
<div className="text-[10px] text-[var(--fg-tertiary)] uppercase tracking-wider">баллов</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isMe && (
|
||||
<div className="mt-3">
|
||||
<Link to="/upload">
|
||||
<Button size="sm" className="rounded-lg text-xs h-8 gap-1.5"
|
||||
style={{ background: 'linear-gradient(135deg, #2563eb, #7c3aed)' }}>
|
||||
<Button size="sm" className="rounded-xl text-xs h-8 gap-1.5 bg-[var(--accent)] hover:bg-[var(--accent-hover)] text-white px-4">
|
||||
<Plus className="h-3.5 w-3.5" strokeWidth={2} /> Новая публикация
|
||||
</Button>
|
||||
</Link>
|
||||
@@ -107,24 +123,29 @@ export default function ProfilePage() {
|
||||
</div>
|
||||
|
||||
{cats.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center py-16 text-center animate-rise">
|
||||
<div className="mb-4 flex h-14 w-14 items-center justify-center rounded-xl bg-[var(--secondary)]"><span className="text-xl">📸</span></div>
|
||||
<p className="text-sm font-medium mb-1">Пока нет котов</p>
|
||||
<p className="text-xs text-[var(--fg-secondary)] mb-5">{isMe ? 'Поделитесь первым фото' : 'У пользователя пока нет котов'}</p>
|
||||
<div className="flex flex-col items-center justify-center py-16 text-center animate-fade-up">
|
||||
<div className="mb-4 h-14 w-14 rounded-2xl flex items-center justify-center bg-[var(--border-light)]">
|
||||
<Image className="h-7 w-7 text-[var(--fg-tertiary)]" strokeWidth={1.5} />
|
||||
</div>
|
||||
<p className="text-sm font-semibold mb-1">Пока нет котов</p>
|
||||
<p className="text-xs text-[var(--fg-tertiary)] mb-5">{isMe ? 'Поделитесь первым фото' : 'У пользователя пока нет котов'}</p>
|
||||
{isMe && (
|
||||
<Link to="/upload"><Button size="sm" className="rounded-lg text-xs"
|
||||
style={{ background: 'linear-gradient(135deg, #2563eb, #7c3aed)' }}>Загрузить кота</Button></Link>
|
||||
<Link to="/upload">
|
||||
<Button size="sm" className="rounded-xl text-xs bg-[var(--accent)] hover:bg-[var(--accent-hover)] text-white">Загрузить кота</Button>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-3 gap-1.5">
|
||||
{cats.map((cat) => (
|
||||
{cats.map(cat => (
|
||||
<button key={cat.id} onClick={() => setModalCatId(cat.id)}
|
||||
className="group relative aspect-square overflow-hidden bg-[var(--secondary)] rounded-xl">
|
||||
className="group relative aspect-square overflow-hidden bg-[var(--bg)] rounded-xl">
|
||||
<img src={cat.image_url} alt={cat.caption || 'Фото кота'}
|
||||
className="h-full w-full object-cover transition-all duration-300 group-hover:scale-105" loading="lazy" />
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/30 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity flex items-end p-2.5">
|
||||
<span className="text-white text-xs font-semibold drop-shadow">❤️ {cat.likes_count}</span>
|
||||
className="h-full w-full object-cover transition-transform duration-300 group-hover:scale-105" loading="lazy" />
|
||||
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/20 transition-colors flex items-center justify-center">
|
||||
<span className="text-white text-xs font-semibold opacity-0 group-hover:opacity-100 transition-opacity flex items-center gap-1 drop-shadow-lg">
|
||||
<Heart className="h-3.5 w-3.5 fill-white" strokeWidth={0} /> {cat.likes_count}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user