website/components/Navbar.tsx

214 lines
8.6 KiB
TypeScript
Raw Permalink Normal View History

2025-11-06 12:02:10 +00:00
'use client';
import { motion, AnimatePresence } from "framer-motion";
2025-11-06 12:02:10 +00:00
import { Button } from "@/components/ui/button";
import { Heart, Menu, X } from "lucide-react";
2025-11-06 12:02:10 +00:00
import { ThemeToggle } from "@/components/ThemeToggle";
import { useEffect, useState } from "react";
import { LoginDialog } from "@/components/LoginDialog";
import { useRouter } from "next/navigation";
import Link from "next/link";
import { useAppTheme } from "@/components/ThemeProvider";
2025-11-06 12:02:10 +00:00
export function Navbar() {
const { theme } = useAppTheme();
const isDark = theme === "dark";
const [loginDialogOpen, setLoginDialogOpen] = useState(false);
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const router = useRouter();
2025-11-06 12:02:10 +00:00
const scrollToSection = (id: string) => {
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({ behavior: "smooth" });
setMobileMenuOpen(false); // Close mobile menu after navigation
2025-11-06 12:02:10 +00:00
}
};
const handleLoginSuccess = () => {
// Redirect to user dashboard after successful login
router.push("/user/dashboard");
setMobileMenuOpen(false);
};
// Close mobile menu when clicking outside
useEffect(() => {
if (mobileMenuOpen) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = 'unset';
}
return () => {
document.body.style.overflow = 'unset';
};
}, [mobileMenuOpen]);
2025-11-06 12:02:10 +00:00
return (
<motion.nav
initial={{ y: -100 }}
animate={{ y: 0 }}
transition={{ duration: 0.5 }}
className="fixed top-0 left-0 right-0 z-50 border-b border-border/50"
style={{
backgroundColor: isDark ? '#1a1e26' : '#ffffff'
}}
>
<div className="container mx-auto px-3 sm:px-4">
<div className="flex items-center justify-between h-14 sm:h-16">
<motion.div
className="flex items-center gap-1.5 sm:gap-2"
2025-11-06 12:02:10 +00:00
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
<Link href="/" className="flex items-center gap-1.5 sm:gap-2">
<div className="bg-gradient-to-r from-rose-500 to-pink-600 p-1.5 sm:p-2 rounded-lg sm:rounded-xl">
<Heart className="h-4 w-4 sm:h-5 sm:w-5 text-white fill-white" />
</div>
<span className="font-bold text-sm sm:text-base md:text-lg bg-gradient-to-r from-rose-600 via-pink-600 to-orange-600 bg-clip-text text-transparent">
<span className="hidden xs:inline sm:hidden">Attune Heart</span>
<span className="hidden sm:inline">Attune Heart Therapy</span>
<span className="xs:hidden">AHT</span>
</span>
</Link>
</motion.div>
2025-11-06 12:02:10 +00:00
{/* Desktop Navigation */}
<div className="hidden lg:flex items-center gap-4 xl:gap-6">
2025-11-06 12:02:10 +00:00
<button
onClick={() => scrollToSection("about")}
className={`text-sm font-medium transition-colors cursor-pointer px-3 py-2 rounded-lg ${isDark ? 'text-gray-300 hover:text-white hover:bg-gray-800' : 'text-gray-700 hover:text-primary hover:bg-gray-100'}`}
2025-11-06 12:02:10 +00:00
>
About
</button>
<button
onClick={() => scrollToSection("services")}
className={`text-sm font-medium transition-colors cursor-pointer px-3 py-2 rounded-lg ${isDark ? 'text-gray-300 hover:text-white hover:bg-gray-800' : 'text-gray-700 hover:text-primary hover:bg-gray-100'}`}
2025-11-06 12:02:10 +00:00
>
Services
</button>
<button
onClick={() => scrollToSection("contact")}
className={`text-sm font-medium transition-colors cursor-pointer px-3 py-2 rounded-lg ${isDark ? 'text-gray-300 hover:text-white hover:bg-gray-800' : 'text-gray-700 hover:text-primary hover:bg-gray-100'}`}
2025-11-06 12:02:10 +00:00
>
Contact
</button>
</div>
{/* Desktop Actions */}
<div className="hidden lg:flex items-center gap-2">
<Button
size="sm"
variant="outline"
className={`hover:opacity-90 hover:scale-105 transition-all text-xs sm:text-sm ${isDark ? 'border-gray-700 text-gray-300 hover:bg-gray-800' : ''}`}
onClick={() => setLoginDialogOpen(true)}
>
Sign In
2025-11-06 12:02:10 +00:00
</Button>
<ThemeToggle />
<Button size="sm" className="hover:opacity-90 hover:scale-105 transition-all text-xs sm:text-sm" asChild>
<a href="/book-now">Book Now</a>
2025-11-06 12:02:10 +00:00
</Button>
</div>
{/* Mobile Actions */}
<div className="flex lg:hidden items-center gap-1.5 sm:gap-2">
<ThemeToggle />
<Button
variant="ghost"
size="icon"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
className="hover:bg-gray-100 dark:hover:bg-gray-800 h-9 w-9 sm:h-10 sm:w-10"
aria-label="Toggle menu"
>
{mobileMenuOpen ? (
<X className="h-5 w-5 sm:h-6 sm:w-6" />
) : (
<Menu className="h-5 w-5 sm:h-6 sm:w-6" />
)}
</Button>
</div>
2025-11-06 12:02:10 +00:00
</div>
</div>
{/* Mobile Menu */}
<AnimatePresence>
{mobileMenuOpen && (
<>
{/* Backdrop */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
className="fixed inset-0 bg-black/50 z-40 lg:hidden"
onClick={() => setMobileMenuOpen(false)}
/>
{/* Mobile Menu Panel */}
<motion.div
initial={{ x: '100%' }}
animate={{ x: 0 }}
exit={{ x: '100%' }}
transition={{ type: 'spring', damping: 25, stiffness: 200 }}
className="fixed top-14 sm:top-16 right-0 bottom-0 w-[280px] sm:w-80 max-w-[85vw] z-50 lg:hidden overflow-y-auto"
style={{
backgroundColor: isDark ? '#1a1e26' : '#ffffff'
}}
>
<div className="flex flex-col p-4 sm:p-6 space-y-3 sm:space-y-4">
{/* Mobile Navigation Links */}
<button
onClick={() => scrollToSection("about")}
className={`text-left text-sm sm:text-base font-medium py-2.5 sm:py-3 px-3 sm:px-4 rounded-lg transition-colors ${isDark ? 'text-gray-300 hover:bg-gray-800' : 'text-gray-700 hover:bg-gray-100'}`}
>
About
</button>
<button
onClick={() => scrollToSection("services")}
className={`text-left text-sm sm:text-base font-medium py-2.5 sm:py-3 px-3 sm:px-4 rounded-lg transition-colors ${isDark ? 'text-gray-300 hover:bg-gray-800' : 'text-gray-700 hover:bg-gray-100'}`}
>
Services
</button>
<button
onClick={() => scrollToSection("contact")}
className={`text-left text-sm sm:text-base font-medium py-2.5 sm:py-3 px-3 sm:px-4 rounded-lg transition-colors ${isDark ? 'text-gray-300 hover:bg-gray-800' : 'text-gray-700 hover:bg-gray-100'}`}
>
Contact
</button>
<div className={`border-t pt-3 sm:pt-4 mt-3 sm:mt-4 space-y-2 sm:space-y-3 ${isDark ? 'border-gray-700' : 'border-gray-200'}`}>
<Button
variant="outline"
className={`w-full justify-start text-sm sm:text-base ${isDark ? 'border-gray-700 text-gray-300 hover:bg-gray-800' : ''}`}
onClick={() => {
setLoginDialogOpen(true);
setMobileMenuOpen(false);
}}
>
Sign In
</Button>
<Button
className="w-full justify-start bg-gradient-to-r from-rose-500 to-pink-600 hover:from-rose-600 hover:to-pink-700 text-white text-sm sm:text-base"
asChild
>
<Link href="/book-now" onClick={() => setMobileMenuOpen(false)}>
Book Now
</Link>
</Button>
</div>
</div>
</motion.div>
</>
)}
</AnimatePresence>
{/* Login Dialog */}
<LoginDialog
open={loginDialogOpen}
onOpenChange={setLoginDialogOpen}
onLoginSuccess={handleLoginSuccess}
/>
2025-11-06 12:02:10 +00:00
</motion.nav>
);
}