This commit is contained in:
Your Name committed 2026-07-19 07:42:34 -04:00
1 parent 173c583787
commit b415fb2eb4
2 files changed
+43 -21

No files matched your search

+11 -11
View File
@@ -27,6 +27,7 @@ export default function Navbar({ topOffsetClassName = 'top-0', isTransparent = f
const [searchQuery, setSearchQuery] = useState('') const [searchQuery, setSearchQuery] = useState('')
const [scrolled, setScrolled] = useState(false) const [scrolled, setScrolled] = useState(false)
const [hasAnnouncement, setHasAnnouncement] = useState(false) const [hasAnnouncement, setHasAnnouncement] = useState(false)
const [isClientReady, setIsClientReady] = useState(false)
const [settings, setSettings] = useState<StoreSettings | null>(null) const [settings, setSettings] = useState<StoreSettings | null>(null)
const navigate = useNavigate() const navigate = useNavigate()
@@ -55,6 +56,7 @@ export default function Navbar({ topOffsetClassName = 'top-0', isTransparent = f
} }
useEffect(() => { useEffect(() => {
setIsClientReady(true)
fetchMegaMenu() fetchMegaMenu()
const checkAnnouncement = () => { const checkAnnouncement = () => {
@@ -173,7 +175,7 @@ export default function Navbar({ topOffsetClassName = 'top-0', isTransparent = f
</div> </div>
{/* Center: Desktop mega menu */} {/* Center: Desktop mega menu */}
{isDesktop && ( {isClientReady && isDesktop && (
<div className="flex-1 flex justify-center"> <div className="flex-1 flex justify-center">
<DesktopMegaMenu items={megaMenu} /> <DesktopMegaMenu items={megaMenu} />
</div> </div>
@@ -219,7 +221,7 @@ export default function Navbar({ topOffsetClassName = 'top-0', isTransparent = f
)} )}
</button> </button>
{isDesktop && ( {isClientReady && isDesktop && (
<> <>
<div className="relative group flex items-center"> <div className="relative group flex items-center">
<button className="px-3 py-2 rounded-full text-[10px] font-bold transition-all text-pop-black border border-pop-black/20 hover:bg-pop-black/5 bg-pop-bg flex items-center gap-1.5 uppercase tracking-wider"> <button className="px-3 py-2 rounded-full text-[10px] font-bold transition-all text-pop-black border border-pop-black/20 hover:bg-pop-black/5 bg-pop-bg flex items-center gap-1.5 uppercase tracking-wider">
@@ -286,7 +288,7 @@ export default function Navbar({ topOffsetClassName = 'top-0', isTransparent = f
</> </>
)} )}
{!isDesktop && ( {isClientReady && !isDesktop && (
<button <button
onClick={() => setMobileOpen(prev => !prev)} onClick={() => setMobileOpen(prev => !prev)}
className="p-1.5 rounded-full text-pop-black/80 hover:bg-pop-black/5 transition-all" className="p-1.5 rounded-full text-pop-black/80 hover:bg-pop-black/5 transition-all"
@@ -299,7 +301,7 @@ export default function Navbar({ topOffsetClassName = 'top-0', isTransparent = f
</div> </div>
</nav> </nav>
{!isDesktop && ( {isClientReady && !isDesktop && mobileOpen && (
<MobileDrawer <MobileDrawer
isOpen={mobileOpen} isOpen={mobileOpen}
onClose={() => setMobileOpen(false)} onClose={() => setMobileOpen(false)}
@@ -345,16 +347,13 @@ export default function Navbar({ topOffsetClassName = 'top-0', isTransparent = f
</div> </div>
)} )}
{langSheetOpen && (
<div className="fixed inset-0 z-[110] md:hidden transition-all duration-300">
<div <div
className={`fixed inset-0 z-[110] md:hidden transition-all duration-300 ${langSheetOpen ? 'visible' : 'invisible'}`} className="absolute inset-0 bg-pop-black/40 backdrop-blur-sm transition-opacity duration-300"
>
<div
className={`absolute inset-0 bg-pop-black/40 backdrop-blur-sm transition-opacity duration-300 ${langSheetOpen ? 'opacity-100' : 'opacity-0'}`}
onClick={() => setLangSheetOpen(false)} onClick={() => setLangSheetOpen(false)}
/> />
<div <div className="absolute bottom-0 left-0 right-0 bg-pop-bg rounded-t-3xl transition-transform duration-300 shadow-2xl pb-safe">
className={`absolute bottom-0 left-0 right-0 bg-pop-bg rounded-t-3xl transition-transform duration-300 shadow-2xl pb-safe ${langSheetOpen ? 'translate-y-0' : 'translate-y-full'}`}
>
<div className="flex justify-center pt-3 pb-1"> <div className="flex justify-center pt-3 pb-1">
<div className="w-12 h-1.5 bg-pop-black/20 rounded-full" /> <div className="w-12 h-1.5 bg-pop-black/20 rounded-full" />
</div> </div>
@@ -386,6 +385,7 @@ export default function Navbar({ topOffsetClassName = 'top-0', isTransparent = f
</div> </div>
</div> </div>
</div> </div>
)}
</> </>
) )
} }
+32 -10
View File
@@ -47,6 +47,8 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
const [langSheetOpen, setLangSheetOpen] = useState(false) const [langSheetOpen, setLangSheetOpen] = useState(false)
const [searchQuery, setSearchQuery] = useState('') const [searchQuery, setSearchQuery] = useState('')
const [scrolled, setScrolled] = useState(false) const [scrolled, setScrolled] = useState(false)
const [isClientReady, setIsClientReady] = useState(false)
const [canRenderDesktopMenu, setCanRenderDesktopMenu] = useState(false)
// Seed from server-fetched initialMenu — no client flash // Seed from server-fetched initialMenu — no client flash
const [megaMenu] = useState<MegaMenuPayload[]>(initialMenu) const [megaMenu] = useState<MegaMenuPayload[]>(initialMenu)
const navRef = useRef<HTMLElement>(null) const navRef = useRef<HTMLElement>(null)
@@ -153,6 +155,18 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
const isHome = getPathWithoutLocale(pathname) === '/' const isHome = getPathWithoutLocale(pathname) === '/'
const isTransparent = isHome && !scrolled && !mobileOpen && !searchOpen && !langSheetOpen const isTransparent = isHome && !scrolled && !mobileOpen && !searchOpen && !langSheetOpen
useEffect(() => {
setIsClientReady(true)
const mediaQuery = window.matchMedia('(min-width: 768px)')
const updateDesktopMenu = () => setCanRenderDesktopMenu(mediaQuery.matches)
updateDesktopMenu()
mediaQuery.addEventListener('change', updateDesktopMenu)
return () => mediaQuery.removeEventListener('change', updateDesktopMenu)
}, [])
return ( return (
<> <>
<nav <nav
@@ -182,7 +196,9 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
</div> </div>
<div className="flex flex-1 justify-center"> <div className="flex flex-1 justify-center">
{canRenderDesktopMenu && (
<DesktopMegaMenu items={menuItems} lang={lang} currentPath={pathname} /> <DesktopMegaMenu items={menuItems} lang={lang} currentPath={pathname} />
)}
</div> </div>
<div className="flex shrink-0 items-center gap-1.5 md:gap-2"> <div className="flex shrink-0 items-center gap-1.5 md:gap-2">
@@ -227,7 +243,9 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
)} )}
</button> </button>
<div className="group relative hidden items-center md:flex"> {canRenderDesktopMenu && (
<>
<div className="group relative flex items-center">
<button className="ui-nav-chip"> <button className="ui-nav-chip">
<Globe className="h-3.5 w-3.5" strokeWidth={1.5} /> <Globe className="h-3.5 w-3.5" strokeWidth={1.5} />
{activeLanguage.short} {activeLanguage.short}
@@ -253,7 +271,7 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
</div> </div>
</div> </div>
<div className="relative hidden items-center md:flex"> <div className="relative flex items-center">
{customer ? ( {customer ? (
<Link href="/profile" className="ml-1"> <Link href="/profile" className="ml-1">
{customer.pictureUrl ? ( {customer.pictureUrl ? (
@@ -280,18 +298,23 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
</button> </button>
)} )}
</div> </div>
</>
)}
{isClientReady && !canRenderDesktopMenu && (
<button <button
onClick={() => setMobileOpen((prev) => !prev)} onClick={() => setMobileOpen((prev) => !prev)}
className={`${iconButtonClass} md:hidden`} className={iconButtonClass}
aria-label={mobileOpen ? 'Close menu' : 'Open menu'} aria-label={mobileOpen ? 'Close menu' : 'Open menu'}
> >
{mobileOpen ? <X className="h-5 w-5" /> : <MenuIcon className="h-5 w-5" />} {mobileOpen ? <X className="h-5 w-5" /> : <MenuIcon className="h-5 w-5" />}
</button> </button>
)}
</div> </div>
</div> </div>
</nav> </nav>
{isClientReady && mobileOpen && (
<MobileDrawer <MobileDrawer
isOpen={mobileOpen} isOpen={mobileOpen}
items={menuItems} items={menuItems}
@@ -302,6 +325,7 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
onLogin={loginWithLine} onLogin={loginWithLine}
onLogout={logout} onLogout={logout}
/> />
)}
{searchOpen && ( {searchOpen && (
<div <div
@@ -356,16 +380,13 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
</div> </div>
)} )}
<div className={`fixed inset-0 z-[110] transition-all duration-300 md:hidden ${langSheetOpen ? 'visible' : 'invisible'}`}> {langSheetOpen && (
<div className="fixed inset-0 z-[110] transition-all duration-300 md:hidden">
<div <div
className={`absolute inset-0 bg-text-main/40 backdrop-blur-sm transition-opacity duration-300 ${langSheetOpen ? 'opacity-100' : 'opacity-0'}`} className="absolute inset-0 bg-text-main/40 backdrop-blur-sm transition-opacity duration-300"
onClick={() => setLangSheetOpen(false)} onClick={() => setLangSheetOpen(false)}
/> />
<div <div className="absolute bottom-0 left-0 right-0 rounded-t-3xl bg-surface-card shadow-2xl transition-transform duration-300">
className={`absolute bottom-0 left-0 right-0 rounded-t-3xl bg-surface-card shadow-2xl transition-transform duration-300 ${
langSheetOpen ? 'translate-y-0' : 'translate-y-full'
}`}
>
<div className="flex justify-center pb-1 pt-3"> <div className="flex justify-center pb-1 pt-3">
<div className="h-1.5 w-12 rounded-full bg-text-main/15" /> <div className="h-1.5 w-12 rounded-full bg-text-main/15" />
</div> </div>
@@ -399,6 +420,7 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
</div> </div>
</div> </div>
</div> </div>
)}
</> </>
) )
} }