583047895f
- Navbar: z-[999] - Mobile menu container/panel: z-[1000]/z-[1001] - Cart drawer: z-[980]/z-[990] - LanguageSwitcher dropdown/backdrop: z-[1010]/z-[1020] - Updated comments - Mobile menu (incl. when clicking language inside it) now reliably stacks above the mobile banner video and other content.
287 lines
14 KiB
TypeScript
287 lines
14 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import Link from "next/link";
|
|
import { useCart } from "./CartContext";
|
|
import { ShoppingBag, ArrowRight, Home, UtensilsCrossed, MapPin, Star, Phone, X } from "lucide-react";
|
|
import LanguageSwitcher from "./LanguageSwitcher";
|
|
import { useLanguage } from "@/lib/language-context";
|
|
import { getTranslation } from "@/lib/translations";
|
|
import { motion, AnimatePresence } from "framer-motion";
|
|
import { usePathname } from "next/navigation";
|
|
|
|
/**
|
|
* =============================================================================
|
|
* GLOBAL NAVIGATION BAR — Shahi Kitchen (Luxury Edition)
|
|
* =============================================================================
|
|
*/
|
|
|
|
interface NavbarProps {
|
|
variant?: "default" | "menu";
|
|
}
|
|
|
|
export default function Navbar({ variant = "default" }: NavbarProps) {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [scrolled, setScrolled] = useState(false);
|
|
const { totalItems, openCart } = useCart();
|
|
const { language } = useLanguage();
|
|
const t = getTranslation(language);
|
|
const pathname = usePathname();
|
|
|
|
// Scroll effect - only for subtle visual polish, NOT height (height must stay consistent)
|
|
useEffect(() => {
|
|
const handleScroll = () => setScrolled(window.scrollY > 20);
|
|
window.addEventListener("scroll", handleScroll);
|
|
return () => window.removeEventListener("scroll", handleScroll);
|
|
}, []);
|
|
|
|
const navLinks = [
|
|
{ href: "/", label: t.nav.home },
|
|
{ href: "/menu", label: t.nav.menu },
|
|
{ href: "/locations", label: t.nav.locations },
|
|
{ href: "/#experience", label: t.nav.experience },
|
|
{ href: "/#contact", label: t.nav.contact },
|
|
];
|
|
|
|
// Determine active link (supports hash links)
|
|
const isActive = (href: string) => {
|
|
if (href === "/") return pathname === "/";
|
|
if (href.includes("#")) return false; // hash links handled separately
|
|
return pathname === href;
|
|
};
|
|
|
|
const closeMenu = () => setIsOpen(false);
|
|
|
|
return (
|
|
<nav
|
|
className="fixed top-0 left-0 right-0 z-[999] h-[64px] border-b border-[#c99a2e]/20 bg-[#fbf7ef] shadow-sm backdrop-blur-xl"
|
|
>
|
|
<div className="max-w-7xl mx-auto px-6 flex items-center justify-between h-full">
|
|
{/* Top subtle gold line for extra frame separation */}
|
|
<div className="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-[#c99a2e]/20 to-transparent" />
|
|
{/* Premium Animated Logo */}
|
|
<Link href="/" className="group flex items-center gap-3">
|
|
<div className="relative">
|
|
<motion.span
|
|
whileHover={{ scale: 1.08, rotate: 2 }}
|
|
transition={{ type: "spring", stiffness: 300, damping: 15 }}
|
|
className="grid h-12 w-12 place-items-center overflow-hidden rounded-2xl border border-[#c99a2e]/30 bg-white shadow-xl shadow-[#0f5a4a]/10 p-1 transition-all duration-300 group-hover:border-[#c99a2e]/70 group-hover:shadow-[#c99a2e]/25"
|
|
>
|
|
<img
|
|
src="/images/logo/logo1.png"
|
|
alt="Shahi Kitchen Logo"
|
|
className="h-10 w-10 object-contain transition-all duration-500"
|
|
/>
|
|
</motion.span>
|
|
<div className="absolute inset-0 rounded-2xl bg-[#c99a2e]/0 group-hover:bg-[#c99a2e]/15 blur-2xl transition-all duration-500 pointer-events-none" />
|
|
</div>
|
|
<span className="hidden leading-none sm:block">
|
|
<span className="block font-serif text-[21px] tracking-[-0.5px] text-[#101724] transition-colors group-hover:text-[#0f5a4a]">Shahi Kitchen</span>
|
|
<span className="text-[10px] font-semibold uppercase tracking-[0.32em] text-[#8a6a25]">Royal Taste • Gothenburg</span>
|
|
</span>
|
|
</Link>
|
|
|
|
{/* Desktop Navigation - Premium Mesmerizing Design */}
|
|
<div className="hidden md:block">
|
|
<div className="flex items-center rounded-full border border-[#c99a2e]/20 bg-white/60 px-2 py-1.5 backdrop-blur-3xl shadow-sm">
|
|
<div className="relative flex items-center gap-1 text-sm font-medium text-[#101724]">
|
|
{navLinks.map((link, index) => {
|
|
const active = isActive(link.href);
|
|
return (
|
|
<Link
|
|
key={index}
|
|
href={link.href}
|
|
className="relative px-5 py-2 rounded-full transition-colors hover:text-[#0f5a4a] z-10"
|
|
>
|
|
<span className="relative z-10">{link.label}</span>
|
|
|
|
{/* Sliding Active Indicator - Very Premium */}
|
|
{active && (
|
|
<motion.div
|
|
layoutId="activeNavPill"
|
|
className="absolute inset-0 rounded-full bg-gradient-to-r from-[#c99a2e] to-[#d4a73d] shadow-md"
|
|
transition={{ type: "spring", stiffness: 380, damping: 30 }}
|
|
/>
|
|
)}
|
|
|
|
{/* Mesmerizing Gold Underline on Hover */}
|
|
<motion.span
|
|
className="absolute bottom-1 left-1/2 h-[1.5px] w-0 bg-gradient-to-r from-[#c99a2e] to-[#f4d47f] rounded-full"
|
|
whileHover={{ width: "60%", x: "-30%" }}
|
|
transition={{ type: "spring", stiffness: 300, damping: 20 }}
|
|
/>
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Desktop Actions — Stunning Mesmerizing Buttons */}
|
|
<div className="hidden md:flex items-center gap-3">
|
|
<LanguageSwitcher />
|
|
|
|
{/* Cart Button - Elegant dark with gold accent */}
|
|
<button
|
|
onClick={openCart}
|
|
className="group flex items-center gap-2.5 rounded-full border border-[#c99a2e]/30 bg-white/70 px-5 py-2.5 text-sm font-semibold text-[#101724] backdrop-blur-xl transition-all hover:border-[#c99a2e] hover:bg-white hover:shadow-lg active:scale-[0.985]"
|
|
>
|
|
<ShoppingBag className="h-4 w-4 transition-transform group-hover:scale-110" />
|
|
{t.cart}
|
|
{totalItems > 0 && (
|
|
<span className="ml-0.5 rounded-full bg-[#c99a2e] px-2 py-px text-[10px] font-black text-white">{totalItems}</span>
|
|
)}
|
|
</button>
|
|
|
|
{/* Reserve Table - The star of the nav, with mesmerizing gold gradient + shine */}
|
|
<Link
|
|
href="/#contact"
|
|
className="relative overflow-hidden rounded-full bg-gradient-to-r from-[#c99a2e] via-[#d4a73d] to-[#c99a2e] px-7 py-2.5 text-sm font-bold text-[#241806] shadow-lg shadow-[#c99a2e]/25 transition-all hover:scale-[1.02] active:scale-[0.985] bg-[length:200%_100%] hover:bg-right"
|
|
>
|
|
<span className="relative z-10 flex items-center gap-2 tracking-[0.3px]">
|
|
{t.reserve}
|
|
<ArrowRight className="h-4 w-4" />
|
|
</span>
|
|
{/* Subtle shine sweep on hover */}
|
|
<span className="absolute inset-0 bg-gradient-to-r from-transparent via-white/40 to-transparent opacity-0 group-hover:animate-[shimmer_1.2s_ease] group-hover:opacity-100" />
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Mobile Hamburger + Cart (compact, high touch target) */}
|
|
<div className="md:hidden flex items-center gap-2">
|
|
{/* MOBILE CART ICON (always visible) */}
|
|
<button
|
|
onClick={openCart}
|
|
className="relative flex items-center justify-center w-10 h-10 rounded-full hover:bg-[#F5F1E9] active:bg-[#EDE6D9] transition-colors"
|
|
aria-label="Open cart"
|
|
>
|
|
<ShoppingBag className="h-5 w-5 text-[#101724]" />
|
|
{totalItems > 0 && (
|
|
<span className="absolute -top-1 -right-1 bg-[#B38B4D] text-white text-[10px] font-bold min-w-[18px] h-[18px] rounded-full flex items-center justify-center px-1 tabular-nums">
|
|
{totalItems}
|
|
</span>
|
|
)}
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="text-[#B38B4D] p-2 -mr-1 active:text-[#8C6B3A] transition-colors"
|
|
aria-label="Toggle menu"
|
|
aria-expanded={isOpen}
|
|
>
|
|
<div className="space-y-1.5">
|
|
<span className={`block h-px w-6 bg-current transition-all duration-200 ${isOpen ? "rotate-45 translate-y-1.5" : ""}`} />
|
|
<span className={`block h-px w-6 bg-current transition-all duration-200 ${isOpen ? "opacity-0" : ""}`} />
|
|
<span className={`block h-px w-6 bg-current transition-all duration-200 ${isOpen ? "-rotate-45 -translate-y-1.5" : ""}`} />
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Modern Mobile Menu Drawer (slide-in, animated, high-contrast, touch-friendly) - high z to always appear in front of hero banner video etc. */}
|
|
<AnimatePresence>
|
|
{isOpen && (
|
|
<div className="md:hidden fixed inset-0 z-[1000]">
|
|
{/* Backdrop */}
|
|
<motion.div
|
|
className="absolute inset-0 bg-[#101724]/70 backdrop-blur-md"
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
transition={{ duration: 0.15 }}
|
|
onClick={closeMenu}
|
|
/>
|
|
|
|
{/* Sliding Panel - modern, full-bleed on small phones, elegant on larger */}
|
|
<motion.div
|
|
className="absolute right-0 top-0 bottom-0 w-[82%] max-w-[340px] bg-[#fbf7ef] shadow-2xl border-l border-[#c99a2e]/10 flex flex-col overflow-y-auto z-[1001]"
|
|
initial={{ x: '100%' }}
|
|
animate={{ x: 0 }}
|
|
exit={{ x: '100%' }}
|
|
transition={{ type: 'spring', stiffness: 320, damping: 32 }}
|
|
>
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between p-6 border-b border-[#EDE6D9]">
|
|
<div className="flex items-center gap-3">
|
|
<img
|
|
src="/images/logo/logo1.png"
|
|
alt="Shahi Kitchen"
|
|
className="h-10 w-10 rounded-xl object-contain"
|
|
/>
|
|
<div>
|
|
<div className="font-serif text-[19px] leading-none text-[#101724]">Shahi Kitchen</div>
|
|
<div className="text-[10px] uppercase tracking-[1.5px] text-[#8a6a25] -mt-0.5">Gothenburg</div>
|
|
</div>
|
|
</div>
|
|
<button
|
|
onClick={closeMenu}
|
|
className="w-10 h-10 flex items-center justify-center rounded-full bg-white/70 active:bg-[#EDE6D9] text-[#101724] transition-colors"
|
|
aria-label="Close menu"
|
|
>
|
|
<X className="h-5 w-5" />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Primary Nav Links - modern list with icons + active state for visibility */}
|
|
<div className="px-3 py-4">
|
|
{navLinks.map((link) => {
|
|
const active = isActive(link.href);
|
|
const Icon =
|
|
link.href === '/' ? Home :
|
|
link.href === '/menu' ? UtensilsCrossed :
|
|
link.href === '/locations' ? MapPin :
|
|
link.href.includes('experience') ? Star : Phone;
|
|
|
|
return (
|
|
<Link
|
|
key={link.href}
|
|
href={link.href}
|
|
onClick={closeMenu}
|
|
className={`flex items-center gap-4 px-4 py-3.5 mx-1 my-0.5 rounded-2xl text-[17px] font-medium transition-all active:scale-[0.985] ${
|
|
active
|
|
? 'bg-[#101724] text-white shadow-sm'
|
|
: 'text-[#101724] hover:bg-white active:bg-[#EDE6D9]'
|
|
}`}
|
|
>
|
|
<Icon className={`h-5 w-5 flex-shrink-0 ${active ? 'text-[#c99a2e]' : 'text-[#B38B4D]'}`} />
|
|
<span>{link.label}</span>
|
|
{active && (
|
|
<span className="ml-auto text-xs tracking-widest opacity-70">CURRENT</span>
|
|
)}
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* Secondary actions + Language */}
|
|
<div className="mt-auto px-5 pb-8 pt-4 border-t border-[#EDE6D9] bg-white/40 space-y-3">
|
|
<div className="px-1">
|
|
<div className="text-[10px] uppercase tracking-[2px] text-[#8a6a25] mb-1.5 px-1">LANGUAGE</div>
|
|
<LanguageSwitcher />
|
|
</div>
|
|
|
|
<Link
|
|
href="/#contact"
|
|
onClick={closeMenu}
|
|
className="block w-full rounded-2xl bg-gradient-to-r from-[#c99a2e] via-[#d4a73d] to-[#c99a2e] py-4 text-center text-[15px] font-bold text-[#241806] shadow active:scale-[0.985] transition-transform"
|
|
>
|
|
{t.reserve}
|
|
</Link>
|
|
|
|
<button
|
|
onClick={() => { openCart(); closeMenu(); }}
|
|
className="block w-full rounded-2xl border-2 border-[#c99a2e]/40 bg-white py-4 text-[15px] font-semibold text-[#101724] active:bg-[#F5F1E9] active:border-[#c99a2e] transition-all"
|
|
>
|
|
{t.cart} {totalItems > 0 && `(${totalItems})`}
|
|
</button>
|
|
|
|
<p className="text-center text-[11px] text-[#8A8478] pt-1">Tap to open WhatsApp for orders & bookings</p>
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
)}
|
|
</AnimatePresence>
|
|
</nav>
|
|
);
|
|
}
|