2 İşlemeler 35da10311a ... 184b382cae

Yazar SHA1 Mesaj Tarih
  fogwind 184b382cae 样式问题 3 gün önce
  fogwind 24432eb22b 货币切换组件优化;结账页地址板块优化;LyDropDown组件优化 3 gün önce
25 değiştirilmiş dosya ile 521 ekleme ve 976 silme
  1. BIN
      public/image/30days.webp
  2. 77 22
      src/app/(checkout)/checkout/_components/CheckoutAddress/BillingAddressCheckout.tsx
  3. 111 0
      src/app/(checkout)/checkout/_components/CheckoutAddress/MyAddressListTrigger.tsx
  4. 99 20
      src/app/(checkout)/checkout/_components/CheckoutAddress/ShippingAddressCheckout.tsx
  5. 4 3
      src/app/(checkout)/checkout/_components/CheckoutProducts/CheckoutProducts.tsx
  6. 1 1
      src/app/(checkout)/checkout/_components/RewardPointsRedeemMoney/RewardPointsRedeemMoney.tsx
  7. 3 3
      src/app/(checkout)/checkout/cart/_components/CartWrapper.tsx
  8. 18 9
      src/app/(public)/_components/HomeBestSellers.tsx
  9. 19 80
      src/app/(public)/_components/HomeContent.tsx
  10. 17 4
      src/app/(public)/_components/HomeNewArrival.tsx
  11. 19 129
      src/app/(public)/_components/MiddleImageSwiper.tsx
  12. 18 32
      src/app/(public)/_components/RecommendedProducts.tsx
  13. 17 17
      src/app/(public)/_components/TopImageSwiper.tsx
  14. 22 76
      src/app/(public)/_components/Trending.tsx
  15. 2 4
      src/app/(public)/category/[slug]/_components/ProductListing.tsx
  16. 5 5
      src/components/common/AddToCartModal/AddToCartModal.tsx
  17. 1 1
      src/components/common/AddToCartModal/OpenAddToCartModalButton.tsx
  18. 1 2
      src/components/common/AddToCartModal/ProductOptionsInAddToCartModal.tsx
  19. 40 66
      src/components/common/CurrencySwitch/CurrencySwitch.tsx
  20. 0 154
      src/components/home/HomeImageBanner.tsx
  21. 0 289
      src/components/layout/navbar/MobileMenu.tsx
  22. 0 28
      src/components/layout/navbar/MobileMenuTrigger.tsx
  23. 3 10
      src/components/layout/navbar/index.tsx
  24. 43 20
      src/components/theme/ui/LyDropDown.tsx
  25. 1 1
      src/lib/restApiClient.ts

BIN
public/image/30days.webp


Dosya farkı çok büyük olduğundan ihmal edildi
+ 77 - 22
src/app/(checkout)/checkout/_components/CheckoutAddress/BillingAddressCheckout.tsx


Dosya farkı çok büyük olduğundan ihmal edildi
+ 111 - 0
src/app/(checkout)/checkout/_components/CheckoutAddress/MyAddressListTrigger.tsx


Dosya farkı çok büyük olduğundan ihmal edildi
+ 99 - 20
src/app/(checkout)/checkout/_components/CheckoutAddress/ShippingAddressCheckout.tsx


Dosya farkı çok büyük olduğundan ihmal edildi
+ 4 - 3
src/app/(checkout)/checkout/_components/CheckoutProducts/CheckoutProducts.tsx


+ 1 - 1
src/app/(checkout)/checkout/_components/RewardPointsRedeemMoney/RewardPointsRedeemMoney.tsx

@@ -105,7 +105,7 @@ export default function RewardPointsRedeemMoney({
         <>
             {isGuest ?
                 <div className="text-ly-14 p-2.5 bg-ly-middlegray">
-                    Please <button className="underline" onClick={guestUserClick}>LOGIN</button> to use reward points
+                    Please <button className="underline cursor-pointer" onClick={guestUserClick}>LOGIN</button> to use reward points
                 </div>
             :
             <div className="w-full">

Dosya farkı çok büyük olduğundan ihmal edildi
+ 3 - 3
src/app/(checkout)/checkout/cart/_components/CartWrapper.tsx


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

@@ -1,16 +1,18 @@
-// import { Swiper, SwiperSlide } from "swiper/react";
-// import { Navigation, Pagination } from "swiper/modules";
+
 import { OpenAddToCartModalButton } from "@/components/common/AddToCartModal/OpenAddToCartModalButton";
 import type { HomeProduct,HomeSection } from "@/types/home/type";
 import Link from "next/link";
 import Image from "next/image";
+import { useStore } from "@utils/hooks/useConfig";
+import { Price } from "@components/theme/ui/Price";
 interface jinGangSectionProps{
   bestSellerSection:HomeSection |undefined;
 }
-// interface HomeBestSellersProps {
-//   bestSellers: HomeProduct[];
-// }
+
 const HomeBestSellers = ({ bestSellerSection }: jinGangSectionProps) => {
+  const {store} = useStore();
+  const currencyCode = store.currentCurrency;
+
   const bestSellers: HomeProduct[] = bestSellerSection?.products ?? [];
   if (!bestSellers || bestSellers.length === 0) return null;
   // 4. 真实数据按每6个拆分一组,替换原来的模拟拆分逻辑
@@ -66,11 +68,18 @@ const HomeBestSellers = ({ bestSellerSection }: jinGangSectionProps) => {
 
             <div className="flex items-center justify-between">
               <div className="flex items-center gap-1">
-                <span className="font-semibold">${product.min_price}</span>
 
-                <span className="text-xs text-gray-500 line-through">
-                  ${product.price}
-                </span>
+                <Price
+                    className="text-ly-18 font-bold"
+                    amount={product.min_price}
+                    currencyCode={currencyCode}
+                />
+
+                <Price
+                    className="text-ly-18 text-ly-gray line-through"
+                    amount={product.price}
+                    currencyCode={currencyCode}
+                />
               </div>
 
               <OpenAddToCartModalButton

Dosya farkı çok büyük olduğundan ihmal edildi
+ 19 - 80
src/app/(public)/_components/HomeContent.tsx


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

@@ -3,10 +3,15 @@ import { OpenAddToCartModalButton } from "@/components/common/AddToCartModal/Ope
 import Link from "next/link";
 import Image from "next/image";
 import type {HomeProduct,HomeSection} from "@/types/home/type"
+import { useStore } from "@utils/hooks/useConfig";
+import { Price } from "@components/theme/ui/Price";
 interface newArrivalSectionProps{
   newArrivalSection:HomeSection |undefined;
 }
 const HomeNewArrival = ({ newArrivalSection }: newArrivalSectionProps) => {
+    const {store} = useStore();
+    const currencyCode = store.currentCurrency;
+
    const newArrival: HomeProduct[] = newArrivalSection?.products ?? [];
      if (!newArrival || newArrival.length === 0) return null;
         // 4. 真实数据按每6个拆分一组,替换原来的模拟拆分逻辑
@@ -62,11 +67,19 @@ const HomeNewArrival = ({ newArrivalSection }: newArrivalSectionProps) => {
 
             <div className="flex items-center justify-between">
               <div className="flex items-center gap-1">
-                <span className="font-semibold">${product.min_price}</span>
 
-                <span className="text-xs text-gray-500 line-through">
-                  ${product.price}
-                </span>
+                <Price
+                    className="text-ly-18 font-bold"
+                    amount={product.min_price}
+                    currencyCode={currencyCode}
+                />
+
+                <Price
+                    className="text-ly-18 text-ly-gray line-through"
+                    amount={product.price}
+                    currencyCode={currencyCode}
+                />
+           
               </div>
 
               <OpenAddToCartModalButton

+ 19 - 129
src/app/(public)/_components/MiddleImageSwiper.tsx

@@ -1,140 +1,22 @@
 
 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";
 import Image from "next/image";
+import { useStore } from "@utils/hooks/useConfig";
+import { Price } from "@components/theme/ui/Price";
 interface zeroWearProps {
   zeroWear: HomeProduct[];
   zeroWearImage:HomeSectionImage[]
 }
-// const productList = [
-//   {
-//     id: 1,
-//     img: "https://picsum.photos/400/500?random=1",
-//     title: "14-36 In Water Wave Hum...",
-//     price: 143.35,
-//   },
-//   {
-//     id: 2,
-//     img: "https://picsum.photos/400/500?random=2",
-//     title: "14-36 In Water Wave Hum.",
-//     price: 143.35,
-//   },
-//   {
-//     id: 3,
-//     img: "https://picsum.photos/400/500?random=3",
-//     title: "14-36 In Water Wave Hum...",
-//     price: 143.35,
-//   },
-//   {
-//     id: 4,
-//     img: "https://picsum.photos/400/500?random=4",
-//     title: "14-36 In Water Wave Hum.",
-//     price: 143.35,
-//   },
-// ];
+
 
 const MiddleImageSwiper = ({ zeroWear,zeroWearImage }: zeroWearProps) => {
-  // zeroWear=[
-  //                   {
-  //                       "id": 55766,
-  //                       "sku": "STW--4*7BobWig--RTG-10, #4--STW--5*5BobWig--12",
-  //                       "name": "[Pack Deal] 10in Natural Black 7*4 Bob Wig and 12in Chocolate Brown 5*5 Bob Wig",
-  //                       "slug": null,
-  //                       "type": "flexible_variant",
-  //                       "price": '368',
-  //                       "min_price":'368' ,
-  //                       "special_price": null,
-  //                       "image_url": "https://img.asteriahair.com/media/catalog/product/2/_/2_wigs_package_deal_natural_black_bob_wig_and_natural_black_bob_wig_1.jpg",
-  //                       "is_new": false,
-  //                       "is_featured": false,
-  //                       "short_description": "Asteria Hair [Pack Deal] 10in Natural Black Ready To Go 7*4 Lace Bob Wig and 12in Chocolate Brown 5*5 Lace Closure Bob Wig.",
-  //                       "rating": 5,
-  //                       "review_count": 2
-  //                   },
-  //                   {
-  //                       "id": 55811,
-  //                       "sku": "LD--13*4Wig--24,LB--5*7Wig--RTG--20",
-  //                       "name": "[Pack Deal] 2 Long Length Wig 24Inch Loose Deep 13*4 Lace Wig and 20Inch Body Wave Ready To Go Closure Wig",
-  //                       "slug": null,
-  //                       "type": "flexible_variant",
-  //                       "price": "830",
-  //                       "min_price": "830",
-  //                       "special_price": null,
-  //                       "image_url": "https://img.asteriahair.com/media/catalog/product/l/d/ld_body.png",
-  //                       "is_new": false,
-  //                       "is_featured": false,
-  //                       "short_description": "Asteria Hair [Pack Deal] 2 Long Length Wig 24Inch Loose Deep 13*4 Lace Wig and 20Inch Body Wave Ready To Go 5*7 Closure Wig.",
-  //                       "rating": 5,
-  //                       "review_count": 13
-  //                   },
-  //                   {
-  //                       "id": 55651,
-  //                       "sku": "STW--4*7Wig--RTG--16,A025--STW--13*4Bob--RTG--12",
-  //                       "name": "[Pack Deal] 2 Ready To Go Wig 100% Glueless Straight Texture",
-  //                       "slug": null,
-  //                       "type": "flexible_variant",
-  //                       "price": "400",
-  //                       "min_price": "400",
-  //                       "special_price": null,
-  //                       "image_url": "https://img.asteriahair.com/media/catalog/product/b/o/bob_.png",
-  //                       "is_new": false,
-  //                       "is_featured": false,
-  //                       "short_description": "Asteria Hair [Pack Deal] 2 Ready To Go Wig 100% Glueless Straight Texture, straight 7*5 ready to go lace wig 16inch and zigzag style 13*4 ready to go lace bob wig 12inch.",
-  //                       "rating": 5,
-  //                       "review_count": 11
-  //                   },
-  //                   {
-  //                       "id": 55681,
-  //                       "sku": "Curly--HDLaceFrontWig--20--250%,LB--4*7BobWig--RTG-10",
-  //                       "name": "[Pack Deal] 20in 250% Density Curly 13*4 HD Lace Wig and 10Inch 7*4 Ready To Go Body Wave Bob Human Hair Wig",
-  //                       "slug": null,
-  //                       "type": "flexible_variant",
-  //                       "price": "650",
-  //                       "min_price": "650",
-  //                       "special_price": null,
-  //                       "image_url": "https://img.asteriahair.com/media/catalog/product/j/c/jc_rtg_lb_.png",
-  //                       "is_new": false,
-  //                       "is_featured": false,
-  //                       "short_description": "Asteria Hair [Pack Deal] 20in 250% Density Curly 13*4 HD Lace Wig and 10in 7*4 Ready To Go Body Wave Bob Human Hair Lace Wig.",
-  //                       "rating": 5,
-  //                       "review_count": 4
-  //                   },
-  //                   {
-  //                       "id": 55982,
-  //                       "sku": "JC-5*7Wig-24-180%-RTG,NHC-RTG-LB-4*7BOB-12",
-  //                       "name": "[Pack Deal]2 Ready To Go Wigs Curly 5*7 Lace Wig 24 Inch And BOB Body Wave Wig 4*7 Lace Wigs 12 Inch",
-  //                       "slug": null,
-  //                       "type": "flexible_variant",
-  //                       "price": '738',
-  //                       "min_price": '738',
-  //                       "special_price": null,
-  //                       "image_url": "https://img.asteriahair.com/media/catalog/product/1/_/1_6_16.png",
-  //                       "is_new": false,
-  //                       "is_featured": false,
-  //                       "short_description": "This value pack includes two ready-to-wear wigs: a 24-inch curly style with 5*7 lace front and a 12-inch body wave bob with 4*7 lace, both made from human hair for instant perfection and versatile styling.",
-  //                       "rating": 0,
-  //                       "review_count": 0
-  //                   },
-  //                   {
-  //                       "id": 55984,
-  //                       "sku": "NHC-RTG-LB-4*7BOB-12,NHC-RTG-STW-4*7BOB-10",
-  //                       "name": "[Pack Deal]Ready To Go Wigs Bob Straight Wig 4*7 Lace Wigs 10 Inch And BOB Body Wave Wig 4*7 Lace Wigs 12 Inch",
-  //                       "slug": null,
-  //                       "type": "flexible_variant",
-  //                       "price": '398',
-  //                       "min_price": '398',
-  //                       "special_price": null,
-  //                       "image_url": "https://img.asteriahair.com/media/catalog/product/1/_/1_7.png",
-  //                       "is_new": false,
-  //                       "is_featured": false,
-  //                       "short_description": "This value pack includes two ready-to-wear bob wigs: a 10-inch straight style and a 12-inch body wave style, both featuring a 4*7 lace construction and made from human hair, allowing you to effortlessly switch between two fashionable looks.",
-  //                       "rating": 0,
-  //                       "review_count": 0
-  //                   }
-  //               ]
+  
+  const {store} = useStore();
+  const currencyCode = store.currentCurrency;
+
   if (!zeroWear || zeroWear.length === 0) return null;
   const  productList = zeroWear
   const WearImage = zeroWearImage;
@@ -197,10 +79,18 @@ const MiddleImageSwiper = ({ zeroWear,zeroWearImage }: zeroWearProps) => {
                     {/* 价格 + 购物车图标 */}
                     <div className="flex items-center justify-between">
                       <div className="flex items-center gap-1">
-                        <span className="font-semibold">${item.min_price}</span>
-                        <span className="text-xs text-gray-500 line-through">
-                          ${item.price}
-                        </span>
+
+                        <Price
+                            className="text-ly-18 font-bold"
+                            amount={item.min_price}
+                            currencyCode={currencyCode}
+                        />
+
+                        <Price
+                            className="text-ly-18 text-ly-gray line-through"
+                            amount={item.price}
+                            currencyCode={currencyCode}
+                        />
                       </div>
                       {/* 购物车图标 */}
                       <OpenAddToCartModalButton

+ 18 - 32
src/app/(public)/_components/RecommendedProducts.tsx

@@ -4,9 +4,8 @@ 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 {
-//   recommended: HomeProduct[];
-// }
+import { useStore } from "@utils/hooks/useConfig";
+import { Price } from "@components/theme/ui/Price";
 interface newArrivalSectionProps{
   recommendedSection:HomeSection |undefined;
 }
@@ -59,6 +58,10 @@ const mockGetProductApi = async (page: number, pageSize: number) => {
 const PAGE_SIZE = 6;
 
 export default function RecommendedProducts({ recommendedSection }: newArrivalSectionProps) {
+
+  const {store} = useStore();
+  const currencyCode = store.currentCurrency;
+
    const recommended: HomeProduct[] = recommendedSection?.products ?? [];
   // 已渲染的全部商品
   const [productList, _setProductList] = useState<HomeProduct[]>(recommended);
@@ -154,38 +157,21 @@ export default function RecommendedProducts({ recommendedSection }: newArrivalSe
               </span>
             </div>
 
-            {/* 价格 + 购物车按钮 */}
-            {/* <div className="flex items-center justify-between">
-              <div className="flex items-center gap-2">
-                <span className="text-xl font-bold text-black">
-                  ${item.price}
-                </span>
-                <span className="text-sm text-gray-400 line-through">
-                  ${item.originPrice}
-                </span>
-              </div>
-              <button className="w-10 h-10 bg-emerald-600 rounded-lg flex items-center justify-center text-white">
-                <svg
-                  width="18"
-                  height="18"
-                  viewBox="0 0 24 24"
-                  fill="none"
-                  stroke="currentColor"
-                  strokeWidth="2"
-                >
-                  <path d="M6 3h12M3 6h18l-2 11H5L3 6z" />
-                  <circle cx="9" cy="20" r="1" />
-                  <circle cx="15" cy="20" r="1" />
-                </svg>
-              </button>
-            </div> */}
+
             {/* 价格 + 购物车图标 */}
             <div className="flex items-center justify-between">
               <div className="flex items-center gap-1">
-                <span className="font-semibold">${item.min_price}</span>
-                <span className="text-xs text-gray-500 line-through">
-                  ${item.price}
-                </span>
+                <Price
+                    className="text-ly-18 font-bold"
+                    amount={item.min_price}
+                    currencyCode={currencyCode}
+                />
+
+                <Price
+                    className="text-ly-18 text-ly-gray line-through"
+                    amount={item.price}
+                    currencyCode={currencyCode}
+                />
               </div>
               {/* 购物车图标 */}
               <OpenAddToCartModalButton

+ 17 - 17
src/app/(public)/_components/TopImageSwiper.tsx

@@ -1,7 +1,7 @@
-
+import Image from 'next/image';
 import { Swiper, SwiperSlide } from 'swiper/react';
 import Link from 'next/link';
-// import { Navigation, Pagination, Mousewheel, Keyboard } from 'swiper/modules';
+import { Autoplay } from 'swiper/modules';
 // 定义图片类型
 type BannerImageItem = {
   link: string;
@@ -15,35 +15,35 @@ interface TopImageSwiperProps {
 const TopImageSwiper = ({ bannerImages }: TopImageSwiperProps) => {
   // 兜底:没有图片不渲染,防止报错
   if (!bannerImages || bannerImages.length === 0) return null;
-  // ✅ 直接在这里放你的图片数组,想加多少加多少
-  // const images = [
-  //   'https://cdn.asteriahair.com/uploads/202607/01/20260701165056_761989a0fdc11d5e.jpg',
-  //   'https://cdn.asteriahair.com/uploads/202607/01/20260701165110_3fff435adf276b89.jpg',
-  //   'https://cdn.asteriahair.com/uploads/202607/01/20260701165123_c424f6f1d0b29522.jpg',
-  //   'https://cdn.asteriahair.com/uploads/202607/01/20260701165056_761989a0fdc11d5e.jpg',
-  // ];
+
+
 
   return (
     <div className="w-full mx-auto ">
       <Swiper
+        autoplay={{
+          delay: 2500,
+          disableOnInteraction: false,
+        }}
         slidesPerView={1}
         spaceBetween={0}
         loop={true} // 无限轮播
-      
+        modules={[Autoplay]}
         // pagination={{ clickable: true }}
         // mousewheel
         // keyboard={{ enabled: true }}
-        className="h-auto md:h-[80vh]  overflow-hidden"
       >
         {/* ✅ 自动遍历图片数组,一行代码搞定所有图片 */}
         {bannerImages .map((item, index) => (
           <SwiperSlide key={index}>
-            <Link href={item.link}>
-            <img
-                 src={item.image}
-              alt={item.title}
-              className="w-full h-full object-cover"
-            />
+            <Link href={item.link} className="w-full">
+              <Image 
+                  width={1920}
+                  height={680}
+                  src={item.image}
+                  alt={item.title}
+                  className="w-full h-auto object-cover"
+              />
             </Link>
           </SwiperSlide>
         ))}

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

@@ -1,57 +1,24 @@
 import { useState, useRef, useEffect } from "react";
 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 { OpenAddToCartModalButton } from "@/components/common/AddToCartModal/OpenAddToCartModalButton";
 import type { HomeProduct,HomeSection } from "@/types/home/type";
+import { useStore } from "@utils/hooks/useConfig";
+import { Price } from "@components/theme/ui/Price";
 interface newArrivalSectionProps{
   trendingSection:HomeSection |undefined;
 }
-// // 商品数据,每个卡片携带videoUrl视频地址
-// type ProductItem = {
-//   id: number;
-//   img: string;
-//   title: string;
-//   price: number;
-//   videoUrl: string;
-// };
 
-// const productList: ProductItem[] = [
-//   {
-//     id: 1,
-//     img: "/img/hair-video-1.jpg",
-//     title: "14-36 In Water Wave Human Hair HD Inv...",
-//     price: 146.1,
-//     videoUrl: "/video/hair-demo-1.mp4",
-//   },
-//   {
-//     id: 2,
-//     img: "/img/hair-video-2.jpg",
-//     title: "14-36 In Water Wave Human Hair HD Inv...",
-//     price: 146.1,
-//     videoUrl: "/video/hair-demo-2.mp4",
-//   },
-//   {
-//     id: 3,
-//     img: "/img/hair-video-3.jpg",
-//     title: "14-36 In Water Wave Human Hair HD Inv...",
-//     price: 146.1,
-//     videoUrl: "/video/hair-demo-3.mp4",
-//   },
-//   {
-//     id: 4,
-//     img: "/img/hair-video-4.jpg",
-//     title: "14-36 In Water Wave Human Hair HD Inv...",
-//     price: 146.1,
-//     videoUrl: "/video/hair-demo-4.mp4",
-//   },
-// ];
 const SLIDES_PER_VIEW = 6.5;
 const SLIDES_PER_GROUP = 6;
 const SPACE_BETWEEN = 24;
 const Trending = ({ trendingSection }: newArrivalSectionProps) => {
+
+  const {store} = useStore();
+  const currencyCode = store.currentCurrency;
+
    const trending: HomeProduct[] = trendingSection?.products ?? [];
   // 视频弹窗状态
   const [openVideoModal, setOpenVideoModal] = useState(false);
@@ -171,10 +138,19 @@ const Trending = ({ trendingSection }: newArrivalSectionProps) => {
                   {/* 价格 + 购物车图标 */}
                   <div className="flex items-center justify-between">
                     <div className="flex items-center gap-1">
-                      <span className="font-semibold">${item.min_price}</span>
-                      <span className="text-xs text-gray-500 line-through">
-                        ${item.price}
-                      </span>
+
+                      <Price
+                          className="text-ly-16 font-bold"
+                          amount={item.min_price}
+                          currencyCode={currencyCode}
+                      />
+
+                      <Price
+                          className="text-ly-14 text-ly-gray line-through"
+                          amount={item.price}
+                          currencyCode={currencyCode}
+                      />
+
                     </div>
                     {/* 购物车图标 */}
                     <OpenAddToCartModalButton
@@ -220,18 +196,7 @@ const Trending = ({ trendingSection }: newArrivalSectionProps) => {
           type="button"
           aria-label="Previous"
           onClick={handlePrev}
-          className="
-      absolute
-      left-18
-      top-1/2
-      z-10
-      flex
-      h-10
-      w-10
-      -translate-y-1/2
-      items-center
-      justify-center
-    "
+          className="absolute left-18 top-1/2 z-10 flex h-10 w-10 -translate-y-1/2 items-center justify-center"
         >
           <svg
             xmlns="http://www.w3.org/2000/svg"
@@ -260,18 +225,7 @@ const Trending = ({ trendingSection }: newArrivalSectionProps) => {
           type="button"
           aria-label="Next"
           onClick={handleNext}
-          className="
-      absolute
-      right-6
-      top-1/2
-      z-10
-      flex
-      h-10
-      w-10
-      -translate-y-1/2
-      items-center
-      justify-center
-    "
+          className="absolute right-6 top-1/2 z-10 flex h-10 w-10 -translate-y-1/2 items-center justify-center"
         >
           <svg
             xmlns="http://www.w3.org/2000/svg"
@@ -295,15 +249,7 @@ const Trending = ({ trendingSection }: newArrivalSectionProps) => {
 
       {/* Pagination */}
       {pageCount > 1 && (
-        <div
-          className="
-            mt-4
-            flex
-            items-center
-            justify-center
-            gap-2
-          "
-        >
+        <div className="mt-4 flex items-center justify-center gap-2">
           {Array.from({
             length: pageCount,
           }).map((_, index) => (

+ 2 - 4
src/app/(public)/category/[slug]/_components/ProductListing.tsx

@@ -150,9 +150,7 @@ export default function ProductListing({
    } else {
      params.delete("page"); // page<=1,删掉page参数,URL干净
    }
-    router.replace(`${pathname}?${params.toString()}`, {
-      scroll: false,
-    });
+    router.replace(`${pathname}?${params.toString()}`);
   };
   // 对比筛选对象
   function isFiltersEqual(a: Record<string, string>, b: Record<string, string>) {
@@ -237,7 +235,7 @@ export default function ProductListing({
   }, [currentPage, totalPages]);
   return (
     <> 
-      <div className="flex  justify-between  py-8  w-full mx-auto max-w-[1824px] gap-12">
+      <div className="flex  justify-between  py-8  w-full mx-auto max-w-456 gap-12">
         <Suspense fallback={<p>Loading Filter...</p>}>
           <NewMobileFilter
             filterAttributesPromise={filterAttributesPromise}

+ 5 - 5
src/components/common/AddToCartModal/AddToCartModal.tsx

@@ -250,7 +250,7 @@ export default function AddToCartModal() {
             body={
                 <div className="box-border w-full p-6 bg-white rounded-xl">
                     <div className="flex justify-end">
-                        <button className="flex-none w-6 h-6" onClick={closeModal}>
+                        <button className="flex-none w-6 h-6 cursor-pointer" onClick={closeModal}>
                             <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon" className="h-6 transition-all ease-in-out hover:scale-110"><path strokeLinecap="round" strokeLinejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg>
                         </button>
                     </div>
@@ -303,10 +303,10 @@ export default function AddToCartModal() {
                                 })}
                                 
                             </Swiper>
-                            <button className="addtocartmodal-main-swiper-prev-btn group [&.disable]:bg-black/50 bg-white z-1 absolute left-3 top-1/2 -translate-y-1/2 flex items-center justify-center w-10 h-10 rounded-full">
+                            <button className="cursor-pointer addtocartmodal-main-swiper-prev-btn group [&.disable]:bg-black/50 bg-white z-1 absolute left-3 top-1/2 -translate-y-1/2 flex items-center justify-center w-10 h-10 rounded-full">
                                 <svg className="w-6 h-6 stroke-black group-[.disable]:stroke-white" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24" fill="none"><path strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="square"  d="M15 18L9 12L15 6"></path></svg>
                             </button>
-                            <button className="addtocartmodal-main-swiper-next-btn group [&.disable]:bg-black/50 bg-white z-1 absolute right-3 top-1/2 -translate-y-1/2 flex items-center justify-center w-10 h-10 rounded-full">
+                            <button className="cursor-pointer addtocartmodal-main-swiper-next-btn group [&.disable]:bg-black/50 bg-white z-1 absolute right-3 top-1/2 -translate-y-1/2 flex items-center justify-center w-10 h-10 rounded-full">
                                 <svg className="w-6 h-6 stroke-black group-[.disable]:stroke-white" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24" fill="none"><path strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="square"  d="M9 18L15 12L9 6"></path></svg>
                             </button>
                         </div>
@@ -348,13 +348,13 @@ export default function AddToCartModal() {
                             </div>
                             <div className="flex-none">
                                 <div className="flex justify-between gap-3">
-                                    <button className="flex-1 flex justify-center items-center h-12 text-ly-16 font-bold text-white rounded-3xl bg-ly-deepgreen" 
+                                    <button className="cursor-pointer flex-1 flex justify-center items-center h-12 text-ly-16 font-bold text-white rounded-3xl bg-ly-deepgreen" 
                                         type="button"
                                         onClick={buyNowHandler}
                                     >
                                         Buy now
                                     </button>
-                                    <button className="flex-1 flex justify-center items-center h-12 text-ly-16 font-bold text-white rounded-3xl bg-ly-middlegreen" 
+                                    <button className="cursor-pointer flex-1 flex justify-center items-center h-12 text-ly-16 font-bold text-white rounded-3xl bg-ly-middlegreen" 
                                         type="button"
                                         onClick={addToCartHandler}
                                     >

+ 1 - 1
src/components/common/AddToCartModal/OpenAddToCartModalButton.tsx

@@ -93,7 +93,7 @@ export const OpenAddToCartModalButton: FC<OpenAddToCartModalButtonProps> = ({
     };
     return (
         <button onClick={openDialog} disabled={baseInfoLoading || optionsLoading}
-            className={clsx(className ? className : "flex justify-center items-center h-8 w-8 bg-ly-middlegreen rounded-lg")}
+            className={clsx("cursor-pointer",className ? className : "flex justify-center items-center h-8 w-8 bg-ly-middlegreen rounded-lg")}
         >
             {baseInfoLoading || optionsLoading ? (
                 <LoadingSpinner colorClassName={"text-ly-green"} />

+ 1 - 2
src/components/common/AddToCartModal/ProductOptionsInAddToCartModal.tsx

@@ -20,7 +20,6 @@ export default function ProductOptionsInAddToCartModal({
     }) => void;
 }) {
 
-    const classNameOptionValueBtn = "text-ly-16 leading-ly-24 border border-solid rounded-lg p-3 bg-white";
     // 处理选项点击
     const handleOptionClick = (optionId: number, valueId: number) => {
         onOptionClick({
@@ -42,7 +41,7 @@ export default function ProductOptionsInAddToCartModal({
                                 <button key={value.id}
                                     type="button"
                                     onClick={() => !isDisabled && handleOptionClick(option.id, value.id)}
-                                    className={clsx(classNameOptionValueBtn, {
+                                    className={clsx("text-ly-16 leading-ly-24 border border-solid rounded-lg p-3 bg-white cursor-pointer", {
                                         'border-ly-green text-ly-green': isSelected,
                                         'border-black text-black': !isSelected,
                                         'opacity-40 cursor-not-allowed strokeline-bg-disabled': isDisabled

Dosya farkı çok büyük olduğundan ihmal edildi
+ 40 - 66
src/components/common/CurrencySwitch/CurrencySwitch.tsx


+ 0 - 154
src/components/home/HomeImageBanner.tsx

@@ -1,154 +0,0 @@
-"use client";
-
-import { useRouter } from 'next/navigation';
-import { Swiper, SwiperSlide } from 'swiper/react';
-import {CurrencySwitch} from "@/components/common/CurrencySwitch/CurrencySwitch";
-import makeClient from "@/lib/ApolloClientBrowser";
-import { GET_CART_ITEM,GET_FILTER_ATTRIBUTES,CREATE_APPLY_COUPON, GET_COUNTRY_STATES} from "@/graphql";
-import { useMutation, useLazyQuery, useQuery } from "@apollo/client/react";
-import {handleApolloBusinessError} from "@/lib/ApolloErrorHandler";
-import { useCustomToast } from "@/utils/hooks/useToast";
-// interface ImageCarouselProps {
-//     options: {
-//         images: {
-//             image: string;
-//             link: string;
-//             title?: string;
-//         }[];
-//     };
-// }
-export default function HomeImageBanner() {
-  const router = useRouter();
-  const { showToast } = useCustomToast();
-  const apolloClient = makeClient();
-  const res = useQuery(GET_COUNTRY_STATES, {
-          variables: {
-              countryId: 1000
-          }
-      });
-      console.log('query state --- res', res);
-  const ttt = async () => {
-    try {
-      const res = await apolloClient.mutate({
-        mutation: GET_CART_ITEM,
-        fetchPolicy: 'network-only', // 按需调整
-      });
-      console.log('----------',res);
-    } catch(error) {
-      console.log('ttt----------',error);
-      handleApolloBusinessError(error,(err) => {
-          showToast(err.message, "danger");
-      });
-    }  
-  }
-  // 76|nlq9qGztR7qmSS72Kal56NCjhRRVrLCeVOdZdLLYa2c769e9
-const [getContent] = useLazyQuery(GET_FILTER_ATTRIBUTES,{
-        fetchPolicy: 'network-only'
-    });
-
-  const testLazyQuery = async () => { 
-      try {
-            const result = await getContent();
-            console.log('lazy query res---', result);
-      } catch(err) {
-          console.log('lazy query ---- ', err);
-      }
-  }
-
-    // useMutation
-    
-
-
-    const [mutateAsync] = useMutation(
-        GET_CART_ITEM,
-        {
-          onCompleted: (res) => {
-            console.log('useMutation onCompleted res ----- 0',res);
-          },
-    
-          onError: (err) => {
-            console.log('useMutation onCompleted err ----- 0',err);
-          },
-        },
-      );
-
-
-    const testMutation = async () => { 
-        
-            const res = await mutateAsync();
-        console.log('testMutation ---',res)
-        
-    };
-    const testFilter= () => {
-            return apolloClient.query({
-                query: GET_FILTER_ATTRIBUTES,
-                fetchPolicy: "no-cache",
-                context: {
-                    fetchOptions: {
-                        cache: 'no-store',
-                    },
-            
-                },
-                // variables: {
-                //     orderId: Number(orderid)
-                // }
-            }).then((res) => {
-                
-                console.log('testFilter res ---- ',res);
-            
-            
-            }).catch((err) => {
-                console.error('testFilter error ---- ',err);
-                handleApolloBusinessError(err,(error) => {
-          showToast(error.message, "danger");
-      });
-            });
-        };
-    
-        const testApplyCoupon = async () => { 
-            try {
-                await apolloClient.mutate({
-                    mutation: CREATE_APPLY_COUPON,
-                    variables: {
-                        couponCode: 'BIRTHDAY20'
-                    },
-                    fetchPolicy: 'network-only', // 按需调整
-                });
-            } catch (err) {
-                console.log('testApplyCoupon error ---- ',err);
-            }
-        };
-
-
-        const toggleLoginModal = () => {
-          // openLoginModal();
-          router.refresh();
-        };
-  
-  return (
-    <>
-    <p>
-      <button onClick={ttt}>get cart detail</button>
-    </p>
-
-    <p><button onClick={testLazyQuery}>testLazyQuery</button></p>
-    <p><button onClick={testMutation}>testMutation</button></p>
-    <p><button onClick={testFilter}>testFilter</button></p>
-    <p><button onClick={testApplyCoupon}>testApplyCoupon</button></p>
-    <Swiper
-      spaceBetween={50}
-      slidesPerView={3}
-      onSlideChange={() => console.log('slide change')}
-      onSwiper={(swiper) => console.log(swiper)}
-    >
-      <SwiperSlide>Slide 1</SwiperSlide>
-      <SwiperSlide>Slide 2</SwiperSlide>
-      <SwiperSlide>Slide 3</SwiperSlide>
-      <SwiperSlide>Slide 4</SwiperSlide>
-    </Swiper>
-    <CurrencySwitch/>
-
-    <p><button onClick={() => toggleLoginModal()}>show Login Modal</button></p>
-    </>
-  )
-}

+ 0 - 289
src/components/layout/navbar/MobileMenu.tsx

@@ -1,289 +0,0 @@
-"use client";
-
-import { AnimatePresence, motion } from "framer-motion";
-// import Link from "next/link";
-
-// import { MobileSearchBar } from "./MobileSearch";
-import { useBodyScrollLock } from "@utils/hooks/useBodyScrollLock";
-import{useState} from "react";
-import {useLoginModal} from "@/providers/LoginModalProvider";
-import { useCustomToast } from "@/utils/hooks/useToast";
-import { confirmDialog } from "@/components/theme/ui/kernel/confirm/api";
-import { useRouter } from 'next/navigation';
-import Image from "next/image";
-import type { TreefrontMenu } from "@/types/theme/menus";
-import {CurrencySwitch} from "@/components/common/CurrencySwitch/CurrencySwitch";
-interface MobileMenuProps {
-  menu: TreefrontMenu[];
-  isOpen: boolean;
-  onClose: () => void; // 接收关闭函数
-  isGuest:boolean;
-}
-export default function MobileMenu({ menu, isOpen, onClose,isGuest }: MobileMenuProps) {
-   const {openLoginModal} = useLoginModal();
-   const { showToast } = useCustomToast();
-   const router = useRouter();
-  // 当前选中一级菜单ID
-  const [activeMainId, setActiveMainId] = useState(menu[0]._id);
-  // 存储右侧二级菜单展开状态集合 key:二级id  value:是否展开boolean
-  const [expandedSubIds, setExpandedSubIds] = useState<Record<string, boolean>>({});
-
-  // 获取选中的一级菜单
-  const activeMainMenu = menu.find((item) => item._id === activeMainId);
-  // 当前一级下面全部二级菜单列表
-  const subMenuList = activeMainMenu?.children?.edges?.map((e) => e.node) ?? [];
-
-  // 切换右侧二级菜单展开/收起
-  const toggleSubExpand = (subId: number) => {
-    setExpandedSubIds((prev) => ({
-      ...prev,
-      [subId]: !prev[subId],
-    }));
-  };
-  useBodyScrollLock(isOpen);
-  const guestUserClick = () => {
-          openLoginModal({
-              onFinalResult: async (res) => {
-                  if(res.mergeCartSuccess) { // 购物车合并成功
-                      // if(!res.cartAfterMerge?.isVip && res.cartAfterMerge?.vipPlusAmount === 0) {
-                      //     await switchVipPlus(true);
-                      // }
-                      return
-                  } else { // 购物车合并失败
-                      // 三种 情况: 登录成功; 注册成功;
-                      if(res.loginSuccess) {
-                          // 登录成功 需要刷新页面
-                          showToast('You have logged in successfully. But something wrong','danger');
-                          await confirmDialog({
-                              title: "Warning",
-                              content: "You have logged in successfully. But something wrong. You must refresh the page.",
-                              noCancel: true,
-                          });
-                          window.location.reload();
-                      }
-                      if(res.registerSuccess && !res.loginSuccess) {
-                          // 注册成功,去登录
-                          await confirmDialog({
-                              title: "Warning",
-                              content: "You have registered successfully. But something wrong. You have to login.",
-                              noCancel: true,
-                          });
-                          router.replace('/customer/login');
-                      }
-                  }
-              }
-          });
-      };
-
-  return (
-    <>
-      <AnimatePresence>
-        {/* {isOpen && ( */}
-          <>
-            <motion.div
-              // initial={{ opacity: 0 }}
-              // animate={{ opacity: 1 }}
-              initial={false}
-              animate={{
-                opacity: isOpen ? 1 : 0,
-                pointerEvents: isOpen ? "auto" : "none"
-              }}
-              // exit={{ opacity: 0 }}
-              onClick={onClose}
-              className="fixed inset-0 z-40 bg-transparent lg:hidden"
-              style={{ top: "68px", bottom: "64px" }}
-            />
-
-            <motion.div
-              // initial={{ x: "-100%" }}
-              // animate={{ x: 0 }}
-              // exit={{ x: "-100%" }}
-              initial={false}
-              animate={{
-                x: isOpen ? 0 : "-100%"
-              }}
-              transition={{ type: "spring", damping: 25, stiffness: 200 }}
-              className="fixed left-0 z-50 w-full max-w-[448px] border-r border-neutral-200 bg-white dark:border-neutral-800 dark:bg-black lg:hidden drawer-scrollbar-hidden"
-              style={{
-                top: "0px",
-                bottom: "0px",
-                width: "100%",
-                maxWidth: "448px",
-                height: "calc(var(--visual-viewport-height) - 132px)",
-              }}
-            >
-              {/* <div className="h-full overflow-y-auto px-4 py-4 drawer-scrollbar-hidden">
-                <MobileSearchBar onClose={onClose} />
-
-                <h1 className="mt-4 px-2 text-2xl font-semibold text-black dark:text-white">
-                  Category
-                </h1>
-
-                <ul className="mt-2 flex w-full flex-col drawer-scrollbar-hidden">
-                  {menu.map((item: any) => (
-                    <li
-                      key={item.id + item.name}
-                      className="p-2 text-xl text-black dark:text-white"
-                    >
-                      <Link
-                        href={item.slug ? `/category/${item.slug}/${item._id}` : "/search"}
-                        aria-label={`${item?.name}`}
-                        onClick={onClose}
-                      >
-                        {item.name}{item._id} 4444
-                      </Link>
-                    </li>
-                  ))}
-                </ul>
-              </div> */}
-             <div className="h-screen flex flex-col overflow-hidden bg-white">
-             
-               <div className="flex justify-between items-center px-4 h-13.5 border-b border-[#E1E1E1FF]">
-                 <h2 className="text-base font-medium">VIP Rewards</h2>
-                 <div className="flex gap-3 items-center">
-                  {
-                    isGuest ? (
-                         <button onClick={guestUserClick} className="bg-emerald-700 text-white w-25.75 h-9 flex items-center justify-center  rounded-full text-xs font-normal">
-                            Register/Login
-                          </button>
-                    ) : null
-                  }
-                   <svg
-                     width="24"
-                     height="24"
-                     viewBox="0 0 24 24"
-                     fill="none"
-                     stroke="currentColor"
-                     strokeWidth="2"
-                    onClick={onClose}
-                   >
-                     <path d="M18 6L6 18M6 6l12 12" />
-                   </svg>
-                 </div>
-               </div>
-                       
-               <div className="flex flex-1 overflow-hidden">
-               
-                 <aside className="w-23 border-r border-gray-200 overflow-y-auto">
-                   {menu.map((mainItem) => (
-                     <div
-                       key={mainItem._id}
-                       onClick={() => setActiveMainId(mainItem._id)}
-                       className={`py-3 pl-4 pr-3   text-xs cursor-pointer border-r-2 border-b border-[#E1E1E1FF]
-                         ${
-                           activeMainId === mainItem._id
-                             ? "border-r-emerald-700 text-emerald-700 font-bold"
-                             : " text-gray-700 font-normal"
-                         }
-                       `}
-                     >
-                       {mainItem.name} {mainItem.showIcon&&(<Image
-                                     className=" block"
-                                     src="/image/theme/image_flame.webp"
-                                     alt={"userphoto"}
-                                     width={16}
-                                     height={16}
-                                   />)}
-                     </div>
-                   ))}
-                 </aside>
-                 
-          
-                 <main className="flex-1 overflow-y-auto p-3 pr-4">
-                   {/*顶部横幅占位 */}
-                   {activeMainMenu?.wapImage && 
-                   <div className="w-full  bg-gray-100 mb-4 flex items-end">
-                     {/* <span className="text-3xl text-white pl-6 pb-4">Shop By Feature</span> */}
-                      <Image
-                         src={activeMainMenu?.wapImage||''}
-                         alt={activeMainMenu?.name||''}
-                         className="object-cover"
-                         width={269}
-                         height={37}
-                       />
-                   </div>
-                   }
-                 
-                   {subMenuList.length === 0 ? (
-                     <div className="text-gray-500 text-xl">No sub categories</div>
-                   ) : (
-                     subMenuList.map((subItem) => {
-                       const isOpen = !!expandedSubIds[subItem._id];
-                      
-                       const cardEdges = subItem?.children?.edges ?? [];
-                     
-                       return (
-                         <div key={subItem._id} className="mb-6">
-                          
-                           <div
-                             onClick={() => toggleSubExpand(subItem._id)}
-                             className="flex justify-between items-center cursor-pointer py-2  px-3 h-10 bg-[#F9F9F9FF]"
-                           >
-                           <h3 className="text-2xl font-medium">{subItem.name}</h3>
-                            <svg xmlns="http://www.w3.org/2000/svg"  width="24" height="24" viewBox="0 0 24 24" fill="none" 
-                            className={`transition-transform duration-300 ${isOpen ? "rotate-0" : "rotate-180"}`}
-                            >
-                             <path    stroke="rgba(0, 0, 0, 1)" stroke-width="1.5" stroke-linejoin="round" stroke-linecap="square"  d="M18 15L12 9L6 15"></path>
-                            </svg>
-                           </div>
-                       
-                           {/*二级展开之后渲染三级卡片网格 */}
-                           {isOpen && cardEdges.length > 0 && (
-                             <div className="grid grid-cols-3 gap-2 pt-3">
-                               {cardEdges.map((edge) => {
-                                 const cardItem = edge.node;
-                                 return (
-                                   <div
-                                     key={cardItem._id}
-                                     className="flex flex-col items-center cursor-pointer"
-                                   >
-                                     <div className="w-full relative  bg-gray-200 mb-1 overflow-hidden">
-                                     
-                                         <Image
-                                           src={cardItem.image||''}
-                                           alt={cardItem.name||''}
-                                           width={84}
-                                           height={112}
-                                           className="object-cover"
-                                         />
-                                         {
-                                          cardItem.showIcon&&(
-                                             <Image
-                                                className=" block absolute top-0 left-0"
-                                                src="/image/theme/image_hot.webp"
-                                                alt={"userphoto"}
-                                                width={30}
-                                                height={14}
-                                              />
-                                          )
-                                         }
-                                     </div>
-                                     <span className="text-xs font-normal text-center">{cardItem.name}</span>
-                                   </div>
-                                 );
-                               })}
-                             </div>
-                           )}
-                           {isOpen && cardEdges.length === 0 && (
-                             <div className="py-3 text-gray-500">No feature items</div>
-                           )}
-                         </div>
-                       );
-                     })
-                   )}
-                 </main>
-               </div>
-                 
-               {/* =========底部固定货币选择栏 ========= */}
-               <div className="h-12 border-t border-gray-200 flex items-center px-4 gap-4">
-                  <CurrencySwitch/>
-               </div>
-             </div>
-
-            </motion.div>
-          </>
-        {/* )} */}
-      </AnimatePresence>
-    </>
-  );
-}

+ 0 - 28
src/components/layout/navbar/MobileMenuTrigger.tsx

@@ -1,28 +0,0 @@
-'use client';
-
-import { useState } from "react";
-import MobileMenu from "./MobileMenu";
-import type { TreefrontMenu } from "@/types/theme/menus";
-
-export default function MobileMenuTrigger({ menuData,isGuest }: { menuData: TreefrontMenu[],isGuest:boolean }) {
-  const [isOpen, setIsOpen] = useState(false);
-  const toggleMenu = () => setIsOpen((prev) => !prev);
-  const closeMenu = () => setIsOpen(false);
-
-  return (
-    <>
-      {/* 汉堡按钮 */}
-      <button className="flex-none w-6 h-6" onClick={toggleMenu}>
-        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
-          <rect x="0" y="0" width="24" height="24" fill="#FFFFFF" fillOpacity="0" />
-          <path stroke="currentColor" strokeWidth="1.5" d="M4 5L20 5" />
-          <path stroke="currentColor" strokeWidth="1.5" d="M4 12L20 12" />
-          <path stroke="currentColor" strokeWidth="1.5" d="M4 19L20 19" />
-        </svg>
-      </button>
-
-      {/* 抽屉菜单 */}
-      <MobileMenu menu={menuData} isGuest={isGuest} isOpen={isOpen} onClose={closeMenu} />
-    </>
-  );
-}

+ 3 - 10
src/components/layout/navbar/index.tsx

@@ -2,7 +2,6 @@ import Link from "next/link";
 import { Suspense } from "react";
 import LogoIcon from "@components/common/icons/LogoIcon";
 import { NavbarActions } from "./NavbarActions";
-// import { NavigationSkeleton } from "./NavigationSkeleton";
 import { NavbarErrorBoundary } from "@/components/error/ErrorBoundary";
 import  DesktopNavigation from "./DesktopNavigation";
 import { 
@@ -10,8 +9,6 @@ import {
 import { serverGraphqlFetch } from "@utils/bagisto/index";
 import NavbarSearchIcon from "./NavbarSearchIcon"
 import type { GetTreefrontMenusResult } from "@/types/theme/menus";
-// import { authOptions } from "@utils/auth";
-// import { getServerSession } from "next-auth";
 import { auth } from "@/utils/auth/auth-helper";
 import TopSwiperBanner from "./TopSwiperBanner"
 import type { AnnouncementItem } from "./TopSwiperBanner";
@@ -47,7 +44,7 @@ export default async function Navbar() {
       query: GET_TREEFRONT_MENUS,
       takeAuthorization: false,
     });
-    console.log('GetTreefrontMenusResult --- ',menudata)
+    // console.log('GetTreefrontMenusResult --- ',menudata)
     const menudatas =menudata? menudata.treefrontMenus:[];
 
   return (
@@ -61,13 +58,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 />}>
-                <MobileMenuTrigger isGuest={isGuest} menuData={menudatas} />
-              </Suspense> */}
+  
               <div className="flex-1 justify-center flex">
-                {/* <Suspense fallback={<SearchSkeleton />}>
-                  <Search search={false} />
-                </Suspense> */}
+
               <NavbarSearchIcon/>
               </div>
             </div>

+ 43 - 20
src/components/theme/ui/LyDropDown.tsx

@@ -6,38 +6,61 @@ import clsx from "clsx";
 
 export function LyDropDown({
     showDropDown,
+    trigger,
     children,
-    onClose
+    onClose,
+    className,
+    listClassName
 }: {
     showDropDown: boolean;
+    trigger: ReactNode;
     children: ReactNode;
     onClose: () => void;
+    className?: string;
+    listClassName?: string;
 }) {
     const listRef = useRef<HTMLDivElement>(null);
     const rootRef = useRef<HTMLDivElement>(null);
-    const [listPosition, setListPosition] = useState({
+    const triggerRef = useRef<HTMLDivElement>(null);
+    const [listPosition, setListPosition] = useState<React.CSSProperties>({
+        position: 'absolute',
         top: '0',
+        left: '0',
         transform: 'translate3d(0, 0%, 0)', 
     });
 
     useLayoutEffect(() => {
         if (listRef.current && rootRef.current && showDropDown) {
-            const { height } = listRef.current.getBoundingClientRect();
+            const { height, width } = listRef.current.getBoundingClientRect();
             // setListHeight(height);
             console.log('Measured tooltip height: ' + height);
 
-            const triggerRect = rootRef.current.getBoundingClientRect();
-            if(triggerRect.bottom + height > window.innerHeight) { // 显示在上方
-                setListPosition({
-                    top: '0',
-                    transform: 'translate3d(0, -100%, 0)',
-                });
+            // 标准模式下视口宽度和高度
+            const viewPortWidth = document.documentElement.clientWidth;
+            const viewPortHeight = document.documentElement.clientHeight;
+            const rootRect = rootRef.current.getBoundingClientRect();
+            let top = '0';
+            let left = '0';
+            let transform = 'translate3d(0, 0%, 0)';
+            if(rootRect.bottom + height > viewPortHeight) { // 显示在上方
+                top = '0';
+                transform = 'translate3d(0, -100%, 0)';
             } else { // 显示在下方
-                setListPosition({
-                    top: `${triggerRect.height}px`,
-                    transform: `translate3d(0, 0%, 0)`
-                });
+                top = `${rootRect.height}px`;
+                transform = 'translate3d(0, 0%, 0)';
+            }
+            if(rootRect.left + width > viewPortWidth) {
+                left = `-${rootRect.left + width - viewPortWidth}px`;
+            } else {
+                left = '0';
             }
+            setListPosition((pre) => {
+                return Object.assign({...pre},{
+                    top,
+                    transform,
+                    left
+                });
+            });
             
         }
     }, [showDropDown]);
@@ -53,10 +76,9 @@ export function LyDropDown({
 
             const target = event.target as Node;
 
-            if (
-                rootRef.current &&
-                !rootRef.current.contains(target)
-            ) {
+            if (triggerRef?.current?.contains(target)) return;
+
+            if (rootRef.current && !rootRef.current.contains(target)) {
                 onClose();
             }
         }
@@ -84,10 +106,11 @@ export function LyDropDown({
 
     return (
         <>
-            <div className="w-full relative" ref={rootRef}>
+            <div className={clsx("relative", className ? className : "w-full")} ref={rootRef}>
 
-                <div ref={listRef} className={clsx(
-                    "absolute w-full max-h-48 overflow-auto bg-white ly-thin-shadow border border-ly-gray rounded-md z-1",
+                <div className="w-full" ref={triggerRef}>{trigger}</div>
+                <div ref={listRef} className={clsx("absolute max-h-48 overflow-y-auto bg-white ly-thin-shadow border border-ly-gray rounded-md z-1",
+                    listClassName ? listClassName : "w-full",
                     showDropDown  ? "visible pointer-events-auto" : "invisible pointer-events-none"
                 )}
                     onClick={(e) => { e.stopPropagation(); }}

+ 1 - 1
src/lib/restApiClient.ts

@@ -17,7 +17,7 @@ export async function clientFetch<T = any>(apiUrl: string | URL, options: Reques
     // fetch 不会reject 非2xx http状态码的响应,而是resolve,所以不会走catch,如果要走catch,需要自己主动抛出异常
     const response = await fetch(apiUrl, options);
     const result = await response.json();
-    console.log('response -- ', response);
+
     if(response.status === 401) { // Unauthorized 需要登录
         emitAuthExpired();
     }