Prechádzať zdrojové kódy

搜索弹窗和搜索结果页调整

zhangzf 2 týždňov pred
rodič
commit
0cb73ec22d

+ 2 - 2
src/app/(public)/search/page.tsx

@@ -9,7 +9,7 @@ import {
 } from "@/graphql";
 import Recommend from "@/app/(public)/product/_components/youmaylike/Recommend";
 import { generateMetadataForPage, buildProductFilters } from "@/utils/helper";
-import SortOrder from "@/components/theme/filters/SortOrder";
+import SearchSortOrder from "@/components/theme/filters/SearchSortOrder";
 import { SortByFields } from "@/utils/constants";
 // import MobileFilter from "@/components/theme/filters/MobileFilter";
 // import FilterList from "@/components/theme/filters/FilterList";
@@ -163,7 +163,7 @@ export default async function SearchPage({
         <div className="flex items-center justify-between gap-4 pt-0 pb-6 mx-auto w-full max-w-[1200px]  xss:px-7.5">
           {/* <MobileFilter filterAttributes={filterAttributes} /> */}
           <div>{totalCount||0} items</div>
-          <SortOrder sortOrders={SortByFields} title="Sort by" />
+          <SearchSortOrder sortOrders={SortByFields} title="Sort by" />
         </div>
       ) : null}
       {!isArray(products) && (

+ 112 - 0
src/components/theme/filters/SearchSortOrder.tsx

@@ -0,0 +1,112 @@
+"use client";
+import { type FC, useRef, useEffect, useCallback } from "react";
+import { useDisclosure } from "@heroui/use-disclosure";
+import { SORT, type SortOrderTypes } from "@/utils/constants";
+import { createUrl } from "@/utils/helper";
+import { usePathname, useRouter, useSearchParams } from "next/navigation";
+
+const ChevronDownIcon = ({ className = "" }: { className?: string }) => (
+  <svg
+    xmlns="http://www.w3.org/2000/svg"
+    width="20"
+    height="20"
+    viewBox="0 0 24 24"
+    fill="none"
+    stroke="currentColor"
+    strokeWidth="2"
+    strokeLinecap="round"
+    strokeLinejoin="round"
+    className={className}
+  >
+    <path d="m6 9 6 6 6-6" />
+  </svg>
+);
+
+interface SearchSortOrderProps {
+  sortOrders: SortOrderTypes[];
+  title: string;
+}
+const SearchSortOrder: FC<SearchSortOrderProps> = ({ sortOrders, title }) => {
+  const searchParams = useSearchParams();
+  const pathname = usePathname();
+  const router = useRouter();
+
+  // 从url拿sort参数
+  const sortValue = searchParams.get(SORT) || sortOrders[0]?.value;
+
+  const { isOpen, onOpen, onClose } = useDisclosure();
+  const toggleDropdown = useCallback(() => {
+    if (isOpen) {
+      onClose();
+    } else {
+      onOpen();
+    }
+  }, [isOpen, onOpen, onClose]);
+
+  const containerRef = useRef<HTMLDivElement>(null);
+  // 找到当前激活项
+  const activeOrder = sortOrders.find((item) => item.value === sortValue);
+  const displayLabel = activeOrder?.title || sortOrders[0]?.title;
+
+  // ✅ 新逻辑:修改URL query,替换原来onChange回调
+  const handleSortChange = (value: string) => {
+    const newParams = new URLSearchParams(searchParams.toString());
+    if (value) newParams.set(SORT, value);
+    const newUrl = createUrl(pathname, newParams);
+    router.replace(newUrl);
+    onClose(); // 选中关闭下拉
+  };
+
+  // 点击空白关闭
+  useEffect(() => {
+    const handleClickOutside = (event: MouseEvent) => {
+      if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
+        if (isOpen) onClose();
+      }
+    };
+    document.addEventListener("mousedown", handleClickOutside);
+    return () => document.removeEventListener("mousedown", handleClickOutside);
+  }, [isOpen, onClose]);
+
+  return (
+    <div className="flex flex-wrap mb-6 justify-end">
+      <div ref={containerRef} className="relative inline-block">
+        <button
+          type="button"
+          onClick={toggleDropdown}
+          className="inline-flex items-center justify-between w-full gap-1.5 text-base font-outfit tracking-wide bg-neutral-100 dark:bg-neutral-800 px-4 py-2 rounded-lg"
+        >
+          <span>{displayLabel}</span>
+          <ChevronDownIcon
+            className={`transition-transform duration-300 ease ${
+              isOpen ? "rotate-180" : "rotate-0"
+            }`}
+          />
+        </button>
+        {isOpen && (
+          <div className="absolute top-full left-0 mt-1 w-full bg-white dark:bg-neutral-800 rounded-lg shadow-lg z-30 ">
+            <div className="flex flex-col">
+              {sortOrders.map((order) => {
+                const isActive = sortValue === order.value;
+                return (
+                  <button
+                    key={order.value}
+                    onClick={() => handleSortChange(order.value)}
+                    className={`w-full  px-4 py-3 text-base transition-colors text-center ${
+                      isActive
+                        ? "bg-neutral-100 dark:bg-neutral-700 font-semibold"
+                        : "hover:bg-neutral-50 dark:hover:bg-neutral-700/50"
+                    }`}
+                  >
+                    {order.title}
+                  </button>
+                );
+              })}
+            </div>
+          </div>
+        )}
+      </div>
+    </div>
+  );
+};
+export default SearchSortOrder;