From ea850bc9b952bbe1b34d4c2ee8c1416178cc7bf2 Mon Sep 17 00:00:00 2001 From: THIS ONE IS A LITTLE BIT TRICKY KRUB Date: Mon, 18 Nov 2024 15:30:02 +0700 Subject: [PATCH] feat: enhance mobile menu and search bar with improved animations and accessibility features --- src/components/navigationBar/mobileMenu.tsx | 127 +++++++++++--------- src/components/navigationBar/serchBar.tsx | 96 ++++++++++++--- 2 files changed, 154 insertions(+), 69 deletions(-) diff --git a/src/components/navigationBar/mobileMenu.tsx b/src/components/navigationBar/mobileMenu.tsx index e88bf71..30a03e9 100644 --- a/src/components/navigationBar/mobileMenu.tsx +++ b/src/components/navigationBar/mobileMenu.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { Menu, X } from "lucide-react"; import { Button } from "../ui/button"; -import { motion } from "framer-motion"; +import { AnimatePresence, motion } from "framer-motion"; import { NavigationMenu, NavigationMenuContent, @@ -24,60 +24,79 @@ export function MobileMenu() { - {isVisible && ( - - setIsVisible(false)} /> - - - - Businesses - - {businessComponents.map((component) => ( - - {component.description} - - ))} - - - - Projects - -
    - {projectComponents.map((component) => ( - - {component.description} - - ))} -
-
-
- - Dataroom - -
    - {dataroomComponents.map((component) => ( - - {component.description} - - ))} -
-
-
+ + {isVisible && ( + +
+
+
+ - - - - - - - - )} + + + + Businesses + +
    + {businessComponents.map((component) => ( + + {component.description} + + ))} +
+
+
+ + + Projects + +
    + {projectComponents.map((component) => ( + + {component.description} + + ))} +
+
+
+ + + Dataroom + +
    + {dataroomComponents.map((component) => ( + + {component.description} + + ))} +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+ )} +
); } diff --git a/src/components/navigationBar/serchBar.tsx b/src/components/navigationBar/serchBar.tsx index 026e52b..00dd390 100644 --- a/src/components/navigationBar/serchBar.tsx +++ b/src/components/navigationBar/serchBar.tsx @@ -2,34 +2,100 @@ import * as React from "react"; import { useRouter } from "next/navigation"; -import { Search } from "lucide-react"; +import { Search, X } from "lucide-react"; import { cn } from "@/lib/utils"; +import { useEffect, useRef } from "react"; export function SearchBar() { const [searchActive, setSearchActive] = React.useState(false); + const [query, setQuery] = React.useState(""); const router = useRouter(); + const inputRef = useRef(null); + const containerRef = useRef(null); const handleKeyDown = async (e: React.KeyboardEvent) => { if (e.key === "Enter") { - const query = (e.target as HTMLInputElement).value.trim(); - if (query) { - router.push(`/find?query=${encodeURIComponent(query)}`); + const trimmedQuery = query.trim(); + if (trimmedQuery) { + router.push(`/find?query=${encodeURIComponent(trimmedQuery)}`); + setSearchActive(false); + setQuery(""); } + } else if (e.key === "Escape") { + setSearchActive(false); + setQuery(""); } }; + // Handle clicks outside of search bar + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (containerRef.current && !containerRef.current.contains(event.target as Node)) { + setSearchActive(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + // Focus input when search becomes active + useEffect(() => { + if (searchActive && inputRef.current) { + inputRef.current.focus(); + } + }, [searchActive]); + return ( -
- setSearchActive(!searchActive)} className="cursor-pointer" /> - +
+ {/* Mobile overlay header when search is active */} + {searchActive && ( +
+ { + setSearchActive(false); + setQuery(""); + }} + /> +
+ )} + +
+ setSearchActive(!searchActive)} + className={cn( + "w-5 h-5 cursor-pointer transition-colors", + searchActive ? "text-blue-500" : "text-slate-600 dark:text-slate-400", + "md:hover:text-blue-500" + )} + /> + + setQuery(e.target.value)} + placeholder="Enter business name..." + className={cn( + "ml-2 rounded-md transition-all duration-300 ease-in-out outline-none", + "placeholder:text-slate-400 dark:placeholder:text-slate-500", + "bg-transparent md:bg-slate-100 md:dark:bg-slate-800", + "md:px-3 md:py-1.5", + searchActive + ? "w-full opacity-100 border-b md:border md:w-48 lg:w-64 md:border-slate-200 md:dark:border-slate-700" + : "w-0 opacity-0 border-transparent" + )} + onKeyDown={handleKeyDown} + /> +
); }