Quellcode durchsuchen

menu+首页产品跳转链接调整

zhangzf vor 1 Woche
Ursprung
Commit
560fafb36c

+ 1 - 1
src/app/(public)/_components/HomeBestSellers.tsx

@@ -38,7 +38,7 @@ const HomeBestSellers = ({ bestSellerSection }: jinGangSectionProps) => {
             </div>
 
             <Link
-              href="/wiggins-ready-go-250-density-popping-curly-hd-lace-front-wigs-medium-length-human-hair-wigs.html"
+              href={`/${product.urlKey}.html`}
               className="truncate text-sm leading-ly-22 font-normal text-gray-800"
             >
               {product.name}

+ 1 - 1
src/app/(public)/_components/HomeNewArrival.tsx

@@ -34,7 +34,7 @@ const HomeNewArrival = ({ newArrivalSection }: newArrivalSectionProps) => {
             </div>
 
             <Link
-              href="/wiggins-ready-go-250-density-popping-curly-hd-lace-front-wigs-medium-length-human-hair-wigs.html"
+              href={`/${product.urlKey}.html`}
               className="truncate text-sm leading-ly-22 font-normal text-gray-800"
             >
               {product.name}

+ 3 - 2
src/app/(public)/_components/MiddleImageSwiper.tsx

@@ -3,6 +3,7 @@ import { Swiper, SwiperSlide } from "swiper/react";
 // import {  Pagination  } from "swiper/modules";
 import { OpenAddToCartModalButton } from "@/components/common/AddToCartModal/OpenAddToCartModalButton";
 import type {HomeProduct,HomeSectionImage} from "@/types/home/type"
+import Link from "next/link";
 interface zeroWearProps {
   zeroWear: HomeProduct[];
   zeroWearImage:HomeSectionImage[]
@@ -173,9 +174,9 @@ const MiddleImageSwiper = ({ zeroWear,zeroWearImage }: zeroWearProps) => {
                   />
 
                   <div className="p-2 flex flex-col gap-2">
-                    <p className="text-sm text-gray-800 truncate">
+                    <Link   href={`/${item.urlKey}.html`} className="text-sm text-gray-800 truncate">
                       {item.name}
-                    </p>
+                    </Link>
                     {/* 价格 + 购物车图标 */}
                     <div className="flex items-center justify-between">
                       <div className="flex items-center gap-1">

+ 4 - 1
src/app/(public)/_components/RecommendedProducts.tsx

@@ -1,6 +1,7 @@
 "use client";
 import { useState, useEffect, useCallback } from "react";
 import Image from "next/image";
+import Link from "next/link";
 import { OpenAddToCartModalButton } from "@/components/common/AddToCartModal/OpenAddToCartModalButton";
 import type {HomeProduct,HomeSection} from "@/types/home/type"
 // interface recommendedProps {
@@ -141,7 +142,9 @@ export default function RecommendedProducts({ recommendedSection }: newArrivalSe
             </div>
 
             {/* 标题 */}
-            <p className="text-sm text-gray-800 truncate">{item.name}</p>
+            <Link   href={`/${item.urlKey}.html`} className="text-sm text-gray-800 truncate">
+              {item.name}
+            </Link>
 
             {/* 星级 + 评论数 */}
             <div className="flex items-center gap-1">

+ 3 - 3
src/app/(public)/_components/Trending.tsx

@@ -3,7 +3,7 @@ import { Swiper, SwiperSlide } from "swiper/react";
 import type { Swiper as SwiperType } from "swiper/types";
 // import { Navigation } from "swiper/modules";
 import Image from "next/image";
-// import Link from "next/link";
+import Link from "next/link";
 import { OpenAddToCartModalButton } from "@/components/common/AddToCartModal/OpenAddToCartModalButton";
 import type { HomeProduct,HomeSection } from "@/types/home/type";
 interface newArrivalSectionProps{
@@ -164,9 +164,9 @@ const Trending = ({ trendingSection }: newArrivalSectionProps) => {
 
                 {/* 底部文字价格区域 */}
                 <div className="p-3 flex flex-col rounded-xl mt-3 bg-[#f0f8f5] gap-3">
-                  <p className="text-base text-gray-900 truncate">
+                  <Link   href={`/${item.urlKey}.html`} className="text-sm text-gray-800 truncate">
                     {item.name}
-                  </p>
+                  </Link>
                   {/* 价格 + 购物车图标 */}
                   <div className="flex items-center justify-between">
                     <div className="flex items-center gap-1">

+ 485 - 0
src/components/layout/navbar/DesktopNavigation.tsx

@@ -0,0 +1,485 @@
+"use client";
+
+import { useState } from "react";
+import Image from "next/image";
+import Link from "next/link";
+import type { TreefrontMenu } from "@/types/theme/menus";
+interface MenuEdge {
+  node: MenuItem;
+}
+
+interface MenuChildren {
+  edges: MenuEdge[];
+}
+
+export interface MenuItem {
+  _id: number;
+  name: string;
+  slug: string;
+  url: string;
+
+  showIcon?: boolean;
+
+  image?: string;
+  wapImage?: string;
+
+  banner?: string;
+  wapBanner?: string;
+
+  sortOrder: number;
+  status: boolean;
+
+  children?: MenuChildren;
+}
+
+interface DesktopNavigationProps {
+  menus:TreefrontMenu[];
+}
+
+const getMenuUrl = (url?: string) => {
+  if (!url) return "#";
+
+  if (
+    url.startsWith("/") ||
+    url.startsWith("http://") ||
+    url.startsWith("https://")
+  ) {
+    return url;
+  }
+
+  return `/${url}`;
+};
+
+const getChildren = (menu?: MenuItem) => {
+  if (!menu?.children?.edges) {
+    return [];
+  }
+
+  return menu.children.edges
+    .map((edge) => edge.node)
+    .filter((item) => item.status)
+    .sort((a, b) => a.sortOrder - b.sortOrder);
+};
+// 设置特殊分类ID
+const SPECIAL_IMAGE_MENU_IDS = new Set([999]);
+export default function DesktopNavigation({
+  menus,
+}: DesktopNavigationProps) {
+  const [activeMenu, setActiveMenu] =
+    useState<MenuItem | null>(null);
+
+  const topMenus = menus
+    .filter((item) => item.status)
+    .sort((a, b) => a.sortOrder - b.sortOrder);
+
+  const secondLevelMenus = getChildren(
+    activeMenu ?? undefined,
+  );
+  const banner =
+    activeMenu?.banner ||
+    activeMenu?.wapBanner ||
+    "";
+  // 是否是特殊图片菜单
+  const isSpecialImageMenu =
+    activeMenu !== null &&
+    SPECIAL_IMAGE_MENU_IDS.has(activeMenu._id);
+  
+  // 特殊结构:
+  // 一级 -> 唯一二级 -> 多个三级
+  const specialSecondMenu =
+    isSpecialImageMenu
+      ? secondLevelMenus[0]
+      : undefined;
+  
+  const specialThirdLevelMenus =
+  specialSecondMenu
+    ? getChildren(specialSecondMenu)
+    : [];
+
+
+ const hasMegaMenu =
+  activeMenu !== null &&
+  (
+    isSpecialImageMenu
+      ? specialThirdLevelMenus.length > 0
+      : Boolean(banner) ||
+        secondLevelMenus.length > 0
+  );
+
+  return (
+    <div
+      className="relative z-50 w-full bg-white"
+      onMouseLeave={() => {
+        setActiveMenu(null);
+      }}
+    >
+      {/* =========================
+          一级导航
+      ========================= */}
+      <div className="border-b border-[#EEEEEE]">
+        <nav
+          className="
+            mx-auto
+            flex
+            h-[50px]
+            max-w-[1440px]
+            items-stretch
+            justify-between
+          "
+        >
+          {/* Home */}
+          <Link
+            href="/"
+            onMouseEnter={() => {
+              setActiveMenu(null);
+            }}
+            className={`
+              relative
+              flex
+              items-center
+              px-2
+              text-[16px]
+              font-medium
+              transition-colors
+              ${
+                activeMenu === null
+                  ? "text-[#036141]"
+                  : "text-[#111111] hover:text-[#036141]"
+              }
+            `}
+          >
+            Home
+
+            {activeMenu === null && (
+              <span
+                className="
+                  absolute
+                  bottom-0
+                  left-0
+                  h-[3px]
+                  w-full
+                  bg-[#036141]
+                "
+              />
+            )}
+          </Link>
+
+          {/* 接口一级菜单 */}
+          {topMenus.map((menu) => {
+            const isActive =
+              activeMenu?._id === menu._id;
+
+            return (
+              <Link
+                key={menu._id}
+                href={getMenuUrl(menu.url)}
+                onMouseEnter={() => {
+                  setActiveMenu(menu);
+                }}
+                className={`
+                  relative
+                  flex
+                  items-center
+                  px-2
+                  text-[16px]
+                  font-medium
+                  transition-colors
+                  ${
+                    isActive
+                      ? "text-[#036141]"
+                      : "text-[#111111] hover:text-[#036141]"
+                  }
+                `}
+              >
+                {menu.name}
+
+                {isActive && (
+                  <span
+                    className="
+                      absolute
+                      bottom-0
+                      left-0
+                      h-[3px]
+                      w-full
+                      bg-[#036141]
+                    "
+                  />
+                )}
+              </Link>
+            );
+          })}
+        </nav>
+      </div>
+
+      {/* =========================
+        Mega Menu
+      ========================= */}
+      {hasMegaMenu && activeMenu && (
+        <div
+          className="
+            absolute
+            left-0
+            top-full
+            w-full
+            border-b
+            border-[#EEEEEE]
+            bg-white
+            shadow-[0_8px_20px_rgba(0,0,0,0.04)]
+          "
+        >
+          {/* ======================================
+              特殊一级分类:
+              一级 -> 唯一二级 -> 多个三级图片
+          ======================================= */}
+          {isSpecialImageMenu ? (
+            <div
+              className="
+                mx-auto
+                flex
+                w-full
+                justify-center
+                px-10
+                py-5
+              "
+            >
+              <div
+                className="
+                  flex
+                  flex-wrap
+                  justify-center
+                  gap-x-10
+                  gap-y-8
+                "
+              >
+                {specialThirdLevelMenus.map(
+                  (thirdMenu) => {
+                    const content = (
+                      <>
+                        {/* 三级分类图片 */}
+                        <div
+                          className="
+                            relative
+                            aspect-[3/4]
+                            w-full
+                            overflow-hidden
+                          "
+                        >
+                          { thirdMenu.image && (
+                            <Image
+                              src={thirdMenu.image}
+                              alt={thirdMenu.name}
+                              fill
+                              sizes="192px"
+                              className="object-cover"
+                            />
+                          )}
+                        </div>
+      
+                        {/* 三级分类名称 */}
+                        <div
+                          className="
+                            mt-3
+                            text-center
+                            text-[16px]
+                            font-medium
+                            leading-[24px]
+                            text-[#111111]
+                          "
+                        >
+                          {thirdMenu.name}
+                        </div>
+                      </>
+                    );
+      
+                    return thirdMenu.url ? (
+                      <Link
+                        key={thirdMenu._id}
+                        href={getMenuUrl(
+                          thirdMenu.url,
+                        )}
+                        className="
+                          block
+                          w-[192px]
+                          shrink-0
+                          transition-opacity
+                          hover:opacity-80
+                        "
+                      >
+                        {content}
+                      </Link>
+                    ) : (
+                      <div
+                        key={thirdMenu._id}
+                        className="
+                          w-[192px]
+                          shrink-0
+                        "
+                      >
+                        {content}
+                      </div>
+                    );
+                  },
+                )}
+              </div>
+            </div>
+          ) : (
+            /* ======================================
+                普通 Mega Menu
+            ======================================= */
+            <div
+              className="
+                mx-auto
+                flex
+                max-w-[1220px]
+                gap-8
+                px-6
+                py-6
+              "
+            >
+              {/* 左侧 Banner */}
+              {banner && (
+                <Link
+                  href={getMenuUrl(
+                    activeMenu.url,
+                  )}
+                  className="
+                    relative
+                    block
+                    aspect-[3/4]
+                    w-[330px]
+                    shrink-0
+                    overflow-hidden
+                  "
+                >
+                  <Image
+                    src={banner}
+                    alt={activeMenu.name}
+                    fill
+                    sizes="330px"
+                    className="object-cover"
+                  />
+                </Link>
+              )}
+      
+              {/* 二级 / 三级文字菜单 */}
+              {secondLevelMenus.length > 0 && (
+                <div
+                  className="
+                    grid
+                    min-w-0
+                    flex-1
+                    grid-cols-3
+                    items-start
+                    gap-x-16
+                    gap-y-8
+                    pt-2
+                  "
+                >
+                  {secondLevelMenus.map(
+                    (secondMenu) => {
+                      const thirdLevelMenus =
+                        getChildren(
+                          secondMenu,
+                        );
+      
+                      return (
+                        <div
+                          key={secondMenu._id}
+                          className="min-w-0"
+                        >
+                          {/* 二级标题 */}
+                          {secondMenu.url ? (
+                            <Link
+                              href={getMenuUrl(
+                                secondMenu.url,
+                              )}
+                              className="
+                                inline-block
+                                text-[15px]
+                                font-semibold
+                                text-[#111111]
+                                transition-colors
+                                hover:text-[#036141]
+                              "
+                            >
+                              {secondMenu.name}
+                            </Link>
+                          ) : (
+                            <div
+                              className="
+                                text-[15px]
+                                font-semibold
+                                text-[#111111]
+                              "
+                            >
+                              {secondMenu.name}
+                            </div>
+                          )}
+      
+                          {/* 三级菜单 */}
+                          {thirdLevelMenus.length >
+                            0 && (
+                            <div
+                              className="
+                                mt-5
+                                flex
+                                flex-col
+                                gap-[18px]
+                              "
+                            >
+                              {thirdLevelMenus.map(
+                                (thirdMenu) =>
+                                  thirdMenu.url ? (
+                                    <Link
+                                      key={
+                                        thirdMenu._id
+                                      }
+                                      href={getMenuUrl(
+                                        thirdMenu.url,
+                                      )}
+                                      className="
+                                        block
+                                        text-[14px]
+                                        leading-[20px]
+                                        text-[#222222]
+                                        transition-colors
+                                        hover:text-[#036141]
+                                      "
+                                    >
+                                      {
+                                        thirdMenu.name
+                                      }
+                                    </Link>
+                                  ) : (
+                                    <div
+                                      key={
+                                        thirdMenu._id
+                                      }
+                                      className="
+                                        text-[14px]
+                                        leading-[20px]
+                                        text-[#222222]
+                                      "
+                                    >
+                                      {
+                                        thirdMenu.name
+                                      }
+                                    </div>
+                                  ),
+                              )}
+                            </div>
+                          )}
+                        </div>
+                      );
+                    },
+                  )}
+                </div>
+              )}
+            </div>
+          )}
+        </div>
+      )}
+
+    </div>
+  );
+}

+ 7 - 6
src/components/layout/navbar/index.tsx

@@ -1,11 +1,11 @@
 import Link from "next/link";
 import { Suspense } from "react";
 import LogoIcon from "@components/common/icons/LogoIcon";
-import MobileMenuTrigger from "./MobileMenuTrigger";
+// import MobileMenuTrigger from "./MobileMenuTrigger";
 import { NavbarActions } from "./NavbarActions";
-import { NavigationSkeleton } from "./NavigationSkeleton";
+// import { NavigationSkeleton } from "./NavigationSkeleton";
 import { NavbarErrorBoundary } from "@/components/error/ErrorBoundary";
-
+import  DesktopNavigation from "./DesktopNavigation";
 import { 
   GET_TREEFRONT_MENUS } from "@/graphql";
 import { serverGraphqlFetch } from "@utils/bagisto/index";
@@ -36,9 +36,9 @@ export default async function Navbar() {
             {/* 1. THE STATIC SHELL (Visible Instantly) */}
             <div className="flex items-center max-w-fit gap-5 xl:gap-6">
               {/* 2. STATIC HOLE: Categories (Suspended) */}
-              <Suspense fallback={<NavigationSkeleton />}>
+              {/* <Suspense fallback={<NavigationSkeleton />}>
                 <MobileMenuTrigger isGuest={isGuest} menuData={menudatas} />
-              </Suspense>
+              </Suspense> */}
               <div className="flex-1 justify-center flex">
                 {/* <Suspense fallback={<SearchSkeleton />}>
                   <Search search={false} />
@@ -54,11 +54,12 @@ export default async function Navbar() {
               <LogoIcon />
             </Link>
 
-
+                  
             <NavbarActions isGuest={isGuest} />
                   
           </div>
         </nav>
+        <DesktopNavigation  menus={menudatas}/>
       </header>
     </NavbarErrorBoundary>
   );

+ 1 - 0
src/types/home/type.ts

@@ -19,6 +19,7 @@ export type HomeProduct = {
   is_featured: boolean;
   short_description: string;
   videoUrl?: string;
+  urlKey?:string;
 };
 export type HomeSection = {
   id: number;