fixed burger menu mobile
This commit is contained in:
parent
009ea87198
commit
486451381c
26
src/App.tsx
26
src/App.tsx
@ -2,7 +2,7 @@ import { Toaster } from "@/components/ui/toaster";
|
||||
import { Toaster as Sonner } from "@/components/ui/sonner";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import Index from "./pages/Index";
|
||||
import NotFound from "./pages/NotFound";
|
||||
import ProjectPage from "./pages/ProjectPage";
|
||||
@ -13,6 +13,21 @@ const queryClient = new QueryClient();
|
||||
|
||||
const IndexWrapper = () => <Index />;
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <IndexWrapper />,
|
||||
},
|
||||
{
|
||||
path: "/project/:projectId",
|
||||
element: <ProjectPage />,
|
||||
},
|
||||
{
|
||||
path: "*",
|
||||
element: <NotFound />,
|
||||
},
|
||||
]);
|
||||
|
||||
const App = () => (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TooltipProvider>
|
||||
@ -20,14 +35,7 @@ const App = () => (
|
||||
<ParticlesBackground />
|
||||
<Toaster />
|
||||
<Sonner />
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<IndexWrapper />} />
|
||||
<Route path="/project/:projectId" element={<ProjectPage />} />
|
||||
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
|
||||
<Route path="*" element={<NotFound />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
<RouterProvider router={router} />
|
||||
</ThemeProvider>
|
||||
</TooltipProvider>
|
||||
</QueryClientProvider>
|
||||
|
||||
@ -1,26 +1,53 @@
|
||||
import { Moon, Sun } from "lucide-react";
|
||||
import { Moon, Sun, Menu, X } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useTheme } from "@/contexts/ThemeContext";
|
||||
import { useLanguage } from "@/contexts/LanguageContext";
|
||||
import { motion } from "framer-motion";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
|
||||
export const Header = () => {
|
||||
const { theme, toggleTheme } = useTheme();
|
||||
const { language, setLanguage, t } = useLanguage();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
const mobileMenuRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Check if we're on a project page
|
||||
const isProjectPage = location.pathname.startsWith('/project/');
|
||||
|
||||
// Close mobile menu when clicking outside
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (mobileMenuRef.current && !mobileMenuRef.current.contains(event.target as Node)) {
|
||||
setMobileMenuOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (mobileMenuOpen) {
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, [mobileMenuOpen]);
|
||||
|
||||
const handleNavigation = (section: string) => {
|
||||
// Close mobile menu immediately
|
||||
setMobileMenuOpen(false);
|
||||
|
||||
// Then scroll to section (happens independently)
|
||||
if (isProjectPage) {
|
||||
// If on project page, navigate to home with section anchor
|
||||
navigate(`/#${section}`);
|
||||
} else {
|
||||
// If on home page, scroll to section
|
||||
scrollToSection(section);
|
||||
// Use setTimeout to ensure scroll happens after menu animation starts
|
||||
setTimeout(() => {
|
||||
scrollToSection(section);
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
@ -50,6 +77,7 @@ export const Header = () => {
|
||||
initial={{ y: -100 }}
|
||||
animate={{ y: 0 }}
|
||||
className="fixed top-0 left-0 right-0 z-50 border-b border-border/40 bg-background/80 backdrop-blur-lg"
|
||||
ref={mobileMenuRef}
|
||||
>
|
||||
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
|
||||
<motion.button
|
||||
@ -63,6 +91,7 @@ export const Header = () => {
|
||||
AP
|
||||
</motion.button>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<nav className="hidden md:flex items-center gap-8">
|
||||
{["home", "projects", "skills", "contact"].map((item, i) => (
|
||||
<motion.button
|
||||
@ -107,8 +136,58 @@ export const Header = () => {
|
||||
)}
|
||||
</Button>
|
||||
</motion.div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 0.5 }}
|
||||
className="md:hidden"
|
||||
>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
{mobileMenuOpen ? (
|
||||
<X className="h-5 w-5" />
|
||||
) : (
|
||||
<Menu className="h-5 w-5" />
|
||||
)}
|
||||
</Button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Navigation */}
|
||||
<AnimatePresence>
|
||||
{mobileMenuOpen && (
|
||||
<motion.nav
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: "auto" }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="md:hidden border-t border-border/40 bg-background/95 backdrop-blur-lg overflow-hidden"
|
||||
>
|
||||
<div className="container mx-auto px-4 py-4 flex flex-col gap-4">
|
||||
{["home", "projects", "skills", "contact"].map((item, i) => (
|
||||
<motion.button
|
||||
key={item}
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: -20 }}
|
||||
transition={{ delay: 0.1 * i }}
|
||||
onClick={() => handleNavigation(item)}
|
||||
className="text-left text-base font-medium text-muted-foreground hover:text-foreground transition-colors py-2"
|
||||
>
|
||||
{t(`nav.${item}`)}
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
</motion.nav>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</motion.header>
|
||||
);
|
||||
};
|
||||
|
||||
@ -16,7 +16,7 @@ export const ParticlesBackground = () => {
|
||||
}, []);
|
||||
|
||||
const particlesLoaded = async (container) => {
|
||||
console.log(container);
|
||||
// console.log(container);
|
||||
};
|
||||
|
||||
const options = useMemo(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user