mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
feat: add gradient fade indicators to scrollable desktop nav
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { useLocation, Link } from 'react-router';
|
import { useLocation, Link } from 'react-router';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -269,6 +269,31 @@ export function AppShell({ children }: AppShellProps) {
|
|||||||
haptic.impact('light');
|
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)
|
// Calculate header height based on fullscreen mode (only on mobile Telegram)
|
||||||
// On iOS: contentSafeAreaInset.top includes status bar + dynamic island + Telegram header
|
// 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)
|
// On Android: safeAreaInset.top only includes status bar, need to add Telegram header height (~48px)
|
||||||
@@ -317,7 +342,22 @@ export function AppShell({ children }: AppShellProps) {
|
|||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* Center Navigation */}
|
{/* Center Navigation */}
|
||||||
<nav className="scrollbar-hide flex items-center gap-1 overflow-x-auto">
|
<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">
|
||||||
{desktopNavItems.map((item) => (
|
{desktopNavItems.map((item) => (
|
||||||
<Link
|
<Link
|
||||||
key={item.path}
|
key={item.path}
|
||||||
@@ -384,6 +424,7 @@ export function AppShell({ children }: AppShellProps) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Right side actions */}
|
{/* Right side actions */}
|
||||||
<div className="flex items-center justify-end gap-2">
|
<div className="flex items-center justify-end gap-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user