0b6cc1acae
- Set 'sv' as default in LanguageProvider + layout (users can switch to 'en') - Completely revamped mobile drawer menu: slide animation (framer-motion), icons, active states with high-contrast text, large touch targets, better tap feedback - Horizontal snap-scrolling category filters on mobile (homepage + /menu) for thumb-friendly UX - Added active:scale / touch-manipulation + press states across cards, buttons, filters for better mobile tap visibility/feedback - Updated translations for menu page, locations, footer, experience (Swedish-first) - Made locations + footer language-aware - Trimmed banner_mobile.mp4 (raw + re-optimized) from 6s to 4s for faster load on mobile - Reordered languages so Svenska appears first in switcher - .gitignore already protects developer_instructions.txt (previous commit)
287 lines
13 KiB
TypeScript
287 lines
13 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-[60] 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) */}
|
|
<AnimatePresence>
|
|
{isOpen && (
|
|
<div className="md:hidden fixed inset-0 z-[65]">
|
|
{/* 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"
|
|
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>
|
|
);
|
|
}
|