mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
feat: responsive desktop nav — icon-only on lg, icon+text on xl
Remove horizontal scroll from desktop top nav bar. Items now show icons only at 1024-1279px with native tooltips, and icons+labels at 1280px+. All 9 items fit on screen in any language without scrolling.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useLocation, Link } from 'react-router';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -269,31 +269,6 @@ export function AppShell({ children }: AppShellProps) {
|
||||
haptic.impact('light');
|
||||
};
|
||||
|
||||
// Desktop nav scroll fade indicators
|
||||
const navRef = useRef<HTMLElement>(null);
|
||||
const [navCanScrollLeft, setNavCanScrollLeft] = useState(false);
|
||||
const [navCanScrollRight, setNavCanScrollRight] = useState(false);
|
||||
|
||||
const updateNavScroll = useCallback(() => {
|
||||
const el = navRef.current;
|
||||
if (!el) return;
|
||||
setNavCanScrollLeft(el.scrollLeft > 2);
|
||||
setNavCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 2);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const el = navRef.current;
|
||||
if (!el) return;
|
||||
updateNavScroll();
|
||||
el.addEventListener('scroll', updateNavScroll, { passive: true });
|
||||
const ro = new ResizeObserver(updateNavScroll);
|
||||
ro.observe(el);
|
||||
return () => {
|
||||
el.removeEventListener('scroll', updateNavScroll);
|
||||
ro.disconnect();
|
||||
};
|
||||
}, [updateNavScroll]);
|
||||
|
||||
// Calculate header height based on fullscreen mode (only on mobile Telegram)
|
||||
// On iOS: contentSafeAreaInset.top includes status bar + dynamic island + Telegram header
|
||||
// On Android: safeAreaInset.top only includes status bar, need to add Telegram header height (~48px)
|
||||
@@ -342,89 +317,76 @@ export function AppShell({ children }: AppShellProps) {
|
||||
</Link>
|
||||
|
||||
{/* Center Navigation */}
|
||||
<div className="relative min-w-0">
|
||||
{/* Left fade */}
|
||||
<div
|
||||
className={cn(
|
||||
'pointer-events-none absolute bottom-0 left-0 top-0 z-10 w-6 bg-gradient-to-r from-dark-950/95 to-transparent transition-opacity duration-200',
|
||||
navCanScrollLeft ? 'opacity-100' : 'opacity-0',
|
||||
)}
|
||||
/>
|
||||
{/* Right fade */}
|
||||
<div
|
||||
className={cn(
|
||||
'pointer-events-none absolute bottom-0 right-0 top-0 z-10 w-6 bg-gradient-to-l from-dark-950/95 to-transparent transition-opacity duration-200',
|
||||
navCanScrollRight ? 'opacity-100' : 'opacity-0',
|
||||
)}
|
||||
/>
|
||||
<nav ref={navRef} className="scrollbar-hide flex items-center gap-1 overflow-x-auto">
|
||||
<nav className="flex min-w-0 items-center gap-0.5">
|
||||
{desktopNavItems.map((item) => (
|
||||
<Link
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
onClick={handleNavClick}
|
||||
title={item.label}
|
||||
className={cn(
|
||||
'flex shrink-0 items-center gap-2 whitespace-nowrap rounded-lg px-3 py-2 text-sm font-medium transition-colors',
|
||||
'flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs font-medium transition-colors',
|
||||
isActive(item.path)
|
||||
? 'bg-dark-800 text-dark-50'
|
||||
: 'text-dark-400 hover:bg-dark-800/50 hover:text-dark-200',
|
||||
)}
|
||||
>
|
||||
<item.icon className="h-4 w-4" />
|
||||
<span>{item.label}</span>
|
||||
<item.icon className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="hidden xl:inline">{item.label}</span>
|
||||
</Link>
|
||||
))}
|
||||
{referralEnabled && (
|
||||
<Link
|
||||
to="/referral"
|
||||
onClick={handleNavClick}
|
||||
title={t('nav.referral')}
|
||||
className={cn(
|
||||
'flex shrink-0 items-center gap-2 whitespace-nowrap rounded-lg px-3 py-2 text-sm font-medium transition-colors',
|
||||
'flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs font-medium transition-colors',
|
||||
isActive('/referral')
|
||||
? 'bg-dark-800 text-dark-50'
|
||||
: 'text-dark-400 hover:bg-dark-800/50 hover:text-dark-200',
|
||||
)}
|
||||
>
|
||||
<UsersIcon className="h-4 w-4" />
|
||||
<span>{t('nav.referral')}</span>
|
||||
<UsersIcon className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="hidden xl:inline">{t('nav.referral')}</span>
|
||||
</Link>
|
||||
)}
|
||||
{giftEnabled && (
|
||||
<Link
|
||||
to="/gift"
|
||||
onClick={handleNavClick}
|
||||
title={t('nav.gift')}
|
||||
className={cn(
|
||||
'flex shrink-0 items-center gap-2 whitespace-nowrap rounded-lg px-3 py-2 text-sm font-medium transition-colors',
|
||||
'flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs font-medium transition-colors',
|
||||
isActive('/gift')
|
||||
? 'bg-dark-800 text-dark-50'
|
||||
: 'text-dark-400 hover:bg-dark-800/50 hover:text-dark-200',
|
||||
)}
|
||||
>
|
||||
<GiftIcon className="h-4 w-4" />
|
||||
<span>{t('nav.gift')}</span>
|
||||
<GiftIcon className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="hidden xl:inline">{t('nav.gift')}</span>
|
||||
</Link>
|
||||
)}
|
||||
{isAdmin && (
|
||||
<>
|
||||
{/* Separator before admin */}
|
||||
<div className="mx-2 h-5 w-px shrink-0 bg-dark-700" />
|
||||
<div className="mx-1 h-4 w-px shrink-0 bg-dark-700" />
|
||||
<Link
|
||||
to="/admin"
|
||||
onClick={handleNavClick}
|
||||
title={t('admin.nav.title')}
|
||||
className={cn(
|
||||
'flex shrink-0 items-center gap-2 whitespace-nowrap rounded-lg px-3 py-2 text-sm font-medium transition-colors',
|
||||
'flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs font-medium transition-colors',
|
||||
location.pathname.startsWith('/admin')
|
||||
? 'bg-warning-500/10 text-warning-400'
|
||||
: 'text-warning-500/70 hover:bg-warning-500/10 hover:text-warning-400',
|
||||
)}
|
||||
>
|
||||
<ShieldIcon className="h-4 w-4" />
|
||||
<span>{t('admin.nav.title')}</span>
|
||||
<ShieldIcon className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="hidden xl:inline">{t('admin.nav.title')}</span>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{/* Right side actions */}
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
|
||||
Reference in New Issue
Block a user