Files
cats/client/src/components/Navbar.tsx
heagbokat ae01ebdeea feat: clean navbar icons, floating theme bubble, auto theme on first visit
- Navbar: remove theme switcher, clean nav icons (no text labels),
  active state is accent dot underline + icon color — no pill bg
- useTheme: drop 'system' from stored type; first visit = auto
  by system preference, stays unset until user explicitly clicks
- ThemeBubble: fixed bottom-right pill with Sun/Moon icon + label,
  hover lift, click toggles light ↔ dark and persists to localStorage
- App.tsx: render ThemeBubble inside ThemeProvider

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 00:51:42 +03:00

87 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Link, useLocation } from 'react-router-dom';
import { useAuth } from '@/hooks/useAuth';
import UserAvatar from '@/components/UserAvatar';
import { Home, PlusSquare, Shield } from 'lucide-react';
export default function Navbar() {
const { user } = useAuth();
const location = useLocation();
if (!user) return null;
const isFeed = location.pathname === '/feed' || location.pathname === '/';
const isUpload = location.pathname === '/upload';
const isProfile = location.pathname.startsWith('/profile');
return (
<nav className="sticky top-0 z-50 nav-glass border-b border-[var(--border-light)]">
<div className="nav-accent-bar" />
<div className="mx-auto flex h-[58px] max-w-[900px] items-center justify-between px-5">
{/* Логотип */}
<Link to="/feed" className="wordmark flex items-center gap-2 group select-none">
<span className="text-xl">🐾</span>
<span className="group-hover:text-[var(--accent)] transition-colors duration-200">
Котограм<span className="wordmark-dot" />
</span>
</Link>
{/* Навигация */}
<div className="flex items-center gap-1">
<NavIcon to="/feed" active={isFeed} icon={Home} label="Лента" />
<NavIcon to="/upload" active={isUpload} icon={PlusSquare} label="Добавить" />
{/* Аватар */}
<Link
to="/profile"
title="Профиль"
className={[
'relative ml-1 flex items-center rounded-full transition-all duration-200',
isProfile
? 'ring-[2.5px] ring-[var(--accent)] ring-offset-2 ring-offset-[var(--bg)]'
: 'opacity-75 hover:opacity-100',
].join(' ')}
>
<UserAvatar
avatarUrl={user.avatar_url}
username={user.username}
className="h-8 w-8"
fallbackClassName="text-[11px] avatar-colored bg-[var(--accent)]"
/>
{user.is_admin && (
<span className="absolute -top-0.5 -right-0.5 h-3.5 w-3.5 rounded-full bg-[var(--accent)] flex items-center justify-center ring-2 ring-[var(--bg)]">
<Shield className="h-2 w-2 text-white" strokeWidth={3} />
</span>
)}
</Link>
</div>
</div>
</nav>
);
}
function NavIcon({
to, active, icon: Icon, label,
}: {
to: string; active: boolean; icon: React.ComponentType<any>; label: string;
}) {
return (
<Link
to={to}
title={label}
className={[
'relative flex items-center justify-center h-9 w-9 rounded-xl',
'transition-all duration-200',
active
? 'text-[var(--accent)] bg-[var(--accent-soft)]'
: 'text-[var(--fg-tertiary)] hover:text-[var(--fg)] hover:bg-[var(--border-light)]',
].join(' ')}
>
<Icon className="h-5 w-5" strokeWidth={active ? 2.2 : 1.7} />
{active && (
<span className="absolute -bottom-[11px] left-1/2 -translate-x-1/2 h-[2.5px] w-4 rounded-full bg-[var(--accent)]" />
)}
</Link>
);
}