feat: v1.34.0 — Mobile UI Early Preview, Russian 2, macOS network fix

Co-authored-by: kilyabin <kilyabin@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Psychotoxical
2026-04-06 12:46:13 +02:00
parent 29203803de
commit 50ac1b8284
30 changed files with 3141 additions and 123 deletions
+55
View File
@@ -0,0 +1,55 @@
import { useState } from 'react';
import { NavLink } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Disc3, Search, Music4, AudioLines } from 'lucide-react';
import { usePlayerStore } from '../store/playerStore';
import MobileSearchOverlay from './MobileSearchOverlay';
const NAV_ITEMS = [
{ to: '/', end: true, icon: Disc3, labelKey: 'sidebar.mainstage' },
{ to: '/albums', end: false, icon: Music4, labelKey: 'sidebar.allAlbums' },
{ to: '/now-playing', end: false, icon: AudioLines, labelKey: 'sidebar.nowPlaying' },
] as const;
export default function BottomNav() {
const { t } = useTranslation();
const isPlaying = usePlayerStore(s => s.isPlaying);
const currentTrack = usePlayerStore(s => s.currentTrack);
const [searchOpen, setSearchOpen] = useState(false);
return (
<>
<nav className="bottom-nav" aria-label="Mobile navigation">
{NAV_ITEMS.map(({ to, end, icon: Icon, labelKey }) => (
<NavLink
key={to}
to={to}
end={end}
className={({ isActive }) => `bottom-nav-item${isActive ? ' active' : ''}`}
>
<span className="bottom-nav-icon-wrap">
<Icon size={22} />
{to === '/now-playing' && isPlaying && currentTrack && (
<span className="bottom-nav-np-dot" />
)}
</span>
<span className="bottom-nav-label">{t(labelKey)}</span>
</NavLink>
))}
<button
className="bottom-nav-item"
onClick={() => setSearchOpen(true)}
aria-label={t('search.title')}
>
<span className="bottom-nav-icon-wrap">
<Search size={22} />
</span>
<span className="bottom-nav-label">{t('search.title')}</span>
</button>
</nav>
{searchOpen && <MobileSearchOverlay onClose={() => setSearchOpen(false)} />}
</>
);
}