177 lines
6.0 KiB
TypeScript
177 lines
6.0 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { Menu, X, ChevronDown, Globe } from 'lucide-react';
|
|
import { motion, AnimatePresence } from 'motion/react';
|
|
import { Button } from './ui/button';
|
|
import { ImageWithFallback } from './figma/ImageWithFallback';
|
|
import logoImage from 'figma:asset/e96a0ba8c1e8ee053e3eb462a3b4552a8657e7b6.png';
|
|
|
|
interface SimpleNavbarProps {
|
|
onHomeClick?: () => void;
|
|
onMelbourneClick?: () => void;
|
|
onPassesClick?: () => void;
|
|
onSignInClick?: () => void;
|
|
onAttractionsClick?: () => void;
|
|
currentPage?: string;
|
|
}
|
|
|
|
export function Navbar({
|
|
onHomeClick,
|
|
onMelbourneClick,
|
|
onPassesClick,
|
|
onSignInClick,
|
|
onAttractionsClick,
|
|
currentPage = 'home'
|
|
}: SimpleNavbarProps) {
|
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
|
|
// Handle scroll effect
|
|
useEffect(() => {
|
|
const handleScroll = () => {
|
|
setIsScrolled(window.scrollY > 0);
|
|
};
|
|
|
|
window.addEventListener('scroll', handleScroll);
|
|
return () => window.removeEventListener('scroll', handleScroll);
|
|
}, []);
|
|
|
|
const navItems = [
|
|
{ label: 'Home', action: onHomeClick, active: currentPage === 'home' },
|
|
{ label: 'Melbourne', action: onMelbourneClick, active: currentPage === 'melbourne' },
|
|
{ label: 'Attractions', action: onAttractionsClick, active: currentPage === 'attractions' },
|
|
{ label: 'Passes', action: onPassesClick, active: currentPage === 'passes' }
|
|
];
|
|
|
|
return (
|
|
<motion.nav
|
|
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
|
|
isScrolled
|
|
? 'bg-white/95 backdrop-blur-md shadow-sm border-b border-gray-100'
|
|
: 'bg-transparent'
|
|
}`}
|
|
initial={{ y: -100 }}
|
|
animate={{ y: 0 }}
|
|
transition={{ duration: 0.5 }}
|
|
>
|
|
<div className="container mx-auto px-4">
|
|
<div className="flex items-center justify-between h-16">
|
|
{/* Logo */}
|
|
<motion.div
|
|
className="flex items-center cursor-pointer"
|
|
whileHover={{ scale: 1.02 }}
|
|
whileTap={{ scale: 0.98 }}
|
|
onClick={onHomeClick}
|
|
>
|
|
<ImageWithFallback
|
|
src={logoImage}
|
|
alt="CityCards Logo"
|
|
className="h-8 w-auto"
|
|
/>
|
|
</motion.div>
|
|
|
|
{/* Desktop Navigation */}
|
|
<div className="hidden md:flex items-center space-x-8">
|
|
{navItems.map((item) => (
|
|
<motion.button
|
|
key={item.label}
|
|
onClick={item.action}
|
|
className={`font-poppins relative px-4 py-2 font-medium transition-all duration-200 ${
|
|
item.active
|
|
? 'text-primary'
|
|
: 'text-gray-700 hover:text-gray-900'
|
|
}`}
|
|
whileHover={{ scale: 1.05 }}
|
|
whileTap={{ scale: 0.95 }}
|
|
>
|
|
{item.label}
|
|
{item.active && (
|
|
<motion.div
|
|
className="absolute bottom-0 left-0 right-0 h-0.5 bg-gradient-to-r from-primary to-secondary rounded-full"
|
|
layoutId="activeTab"
|
|
/>
|
|
)}
|
|
</motion.button>
|
|
))}
|
|
</div>
|
|
|
|
{/* Right Section */}
|
|
<div className="hidden md:flex items-center space-x-4">
|
|
<div className="font-poppins flex items-center space-x-2 text-gray-700 hover:text-gray-900 px-3 py-2 font-medium transition-colors duration-200 cursor-pointer rounded-lg hover:bg-gray-50">
|
|
<Globe className="w-4 h-4" />
|
|
<span>ENG</span>
|
|
<ChevronDown className="w-3 h-3" />
|
|
</div>
|
|
|
|
<Button
|
|
onClick={onSignInClick}
|
|
variant="outline"
|
|
className="font-poppins font-medium border-primary text-primary hover:bg-primary hover:text-white"
|
|
>
|
|
Sign In
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Mobile Menu Button */}
|
|
<div className="md:hidden">
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
|
>
|
|
{isMobileMenuOpen ? (
|
|
<X className="h-5 w-5" />
|
|
) : (
|
|
<Menu className="h-5 w-5" />
|
|
)}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile Menu */}
|
|
<AnimatePresence>
|
|
{isMobileMenuOpen && (
|
|
<motion.div
|
|
className="md:hidden"
|
|
initial={{ opacity: 0, height: 0 }}
|
|
animate={{ opacity: 1, height: 'auto' }}
|
|
exit={{ opacity: 0, height: 0 }}
|
|
transition={{ duration: 0.2 }}
|
|
>
|
|
<div className="px-2 pt-2 pb-3 space-y-1 bg-white border-t border-gray-100">
|
|
{navItems.map((item) => (
|
|
<motion.button
|
|
key={item.label}
|
|
onClick={() => {
|
|
item.action?.();
|
|
setIsMobileMenuOpen(false);
|
|
}}
|
|
className={`block w-full text-left px-3 py-2 rounded-md font-medium transition-colors duration-200 ${
|
|
item.active
|
|
? 'text-primary bg-primary/10'
|
|
: 'text-gray-700 hover:text-gray-900 hover:bg-gray-50'
|
|
}`}
|
|
whileHover={{ x: 4 }}
|
|
>
|
|
{item.label}
|
|
</motion.button>
|
|
))}
|
|
|
|
<div className="pt-4 pb-2 border-t border-gray-100">
|
|
<Button
|
|
onClick={() => {
|
|
onSignInClick?.();
|
|
setIsMobileMenuOpen(false);
|
|
}}
|
|
className="w-full"
|
|
>
|
|
Sign In
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</div>
|
|
</motion.nav>
|
|
);
|
|
} |