diff --git a/app/components/Icons.tsx b/app/components/Icons.tsx index 0e6344fa..2d414be1 100644 --- a/app/components/Icons.tsx +++ b/app/components/Icons.tsx @@ -1,3 +1,5 @@ +import clsx from "clsx"; + type IconProps = JSX.IntrinsicElements["svg"]; // Using icons from https://phosphoricons.com/ @@ -61,3 +63,38 @@ export function IconTag(props: IconProps) { ); } + +export function IconCaret(props: IconProps) { + let { className, direction = "right", ...rest } = props; + let rotate; + + switch (direction) { + case "down": + rotate = "rotate-0"; + break; + case "up": + rotate = "rotate-180"; + break; + case "right": + rotate = "-rotate-90"; + break; + case "left": + rotate = "rotate-90"; + break; + default: + rotate = "rotate-0"; + } + return ( + + + + ); +} diff --git a/app/components/predictive-search/usePredictiveSearch.ts b/app/components/predictive-search/usePredictiveSearch.ts index 3e44b615..84d84e72 100644 --- a/app/components/predictive-search/usePredictiveSearch.ts +++ b/app/components/predictive-search/usePredictiveSearch.ts @@ -1,10 +1,6 @@ import { useFetchers } from "@remix-run/react"; -import { useEffect, useRef } from "react"; -import { - NormalizedPredictiveSearch, - NormalizedPredictiveSearchResults, - UseSearchReturn, -} from "./types"; +import { useEffect, useRef, useState } from "react"; +import type { NormalizedPredictiveSearch, NormalizedPredictiveSearchResults, UseSearchReturn } from "./types"; export const NO_PREDICTIVE_SEARCH_RESULTS: NormalizedPredictiveSearchResults = [ { type: "queries", items: [] }, @@ -19,12 +15,18 @@ export function usePredictiveSearch(): UseSearchReturn { const searchTerm = useRef(""); const searchInputRef = useRef(null); const searchFetcher = fetchers.find((fetcher) => fetcher.data?.searchResults); + let [results, setResults] = useState(); + useEffect(() => { + if (searchFetcher) { + setResults(searchFetcher.data?.searchResults); + } + }, [searchFetcher]); - if (searchFetcher?.state === "loading") { - searchTerm.current = (searchFetcher.formData?.get("q") || "") as string; + if (searchFetcher?.state === 'loading') { + searchTerm.current = (searchFetcher.formData?.get('q') || '') as string; } - const search = (searchFetcher?.data?.searchResults || { + const search = (results || { results: NO_PREDICTIVE_SEARCH_RESULTS, totalResults: 0, }) as NormalizedPredictiveSearch; diff --git a/app/modules/Drawer.tsx b/app/modules/Drawer.tsx index 19073ec9..cc9183f1 100644 --- a/app/modules/Drawer.tsx +++ b/app/modules/Drawer.tsx @@ -1,9 +1,10 @@ import { Fragment, useState } from "react"; import { Dialog, Transition } from "@headlessui/react"; -import { Heading, IconCaret, IconClose } from "~/modules"; +import { Heading, IconClose } from "~/modules"; import { cn } from "~/lib/cn"; import clsx from "clsx"; +import { IconCaret } from "~/components/Icons"; /** * Drawer component that opens on user click. @@ -101,7 +102,7 @@ export function Drawer({ data-test="close-cart" > diff --git a/app/modules/menu/DesktopMenu.tsx b/app/modules/menu/DesktopMenu.tsx index e0c47288..d166b68b 100644 --- a/app/modules/menu/DesktopMenu.tsx +++ b/app/modules/menu/DesktopMenu.tsx @@ -6,6 +6,7 @@ import { type MultiMenuProps, type SingleMenuProps, } from "./defines"; +import clsx from "clsx"; const MenuByType = { multi: MultiMenu, @@ -13,6 +14,9 @@ const MenuByType = { single: SingleMenu, }; +const commonAnimatedClass = + "absolute h-0 opacity-0 overflow-hidden bg-white shadow-md transition-all ease-out group-hover:opacity-100 group-hover:border-t duration-500 group-hover:duration-300 group-hover:z-50 "; + export function DesktopMenu() { return (