diff --git a/package.json b/package.json index 4c468ad..bccc1ad 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "p": "git pull && yarn install && yarn build && pm2 restart next" }, "dependencies": { + "clsx": "^2.1.1", "embla-carousel-autoplay": "^8.5.2", "embla-carousel-react": "^8.5.2", "fast-average-color": "^9.4.0", @@ -23,7 +24,8 @@ "react-dom": "^19.0.0", "react-intersection-observer": "^9.15.1", "react-toastify": "^11.0.3", - "swiper": "^11.2.2" + "swiper": "^11.2.2", + "tailwind-merge": "^3.0.2" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01810aa..2af746b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: + clsx: + specifier: ^2.1.1 + version: 2.1.1 embla-carousel-autoplay: specifier: ^8.5.2 version: 8.5.2(embla-carousel@8.5.2) @@ -47,6 +50,9 @@ dependencies: swiper: specifier: ^11.2.2 version: 11.2.4 + tailwind-merge: + specifier: ^3.0.2 + version: 3.0.2 devDependencies: '@eslint/eslintrc': @@ -3223,6 +3229,10 @@ packages: engines: {node: '>= 4.7.0'} dev: false + /tailwind-merge@3.0.2: + resolution: {integrity: sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==} + dev: false + /tailwindcss@3.4.17: resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} engines: {node: '>=14.0.0'} diff --git a/public/images/construction.jpg b/public/images/construction.jpg new file mode 100644 index 0000000..2eca962 Binary files /dev/null and b/public/images/construction.jpg differ diff --git a/public/images/feed.jpg b/public/images/feed.jpg new file mode 100644 index 0000000..6d04857 Binary files /dev/null and b/public/images/feed.jpg differ diff --git a/public/images/fmcg.jpg b/public/images/fmcg.jpg new file mode 100644 index 0000000..cbc28f8 Binary files /dev/null and b/public/images/fmcg.jpg differ diff --git a/src/app/[locale]/product/[slug]/page.jsx b/src/app/[locale]/product/[slug]/page.jsx index b857084..0e63395 100644 --- a/src/app/[locale]/product/[slug]/page.jsx +++ b/src/app/[locale]/product/[slug]/page.jsx @@ -2,6 +2,7 @@ import { ChevronRight, Home } from "lucide-react"; import { getLocale, getMessages } from "next-intl/server"; import Link from "next/link"; import { notFound } from "next/navigation"; +import ColorAvg from "src/components/ColorAvg"; import ProductDescription from "src/components/Product/ProductDescription"; import ProductGallery from "src/components/Product/ProductGallery"; import ProductInfo from "src/components/Product/ProductInfo"; @@ -10,7 +11,7 @@ import ProductRelated from "src/components/Product/ProductRelated"; import graphql from "src/utils/graphql"; const gql = ` - query Products($locale: I18NLocaleCode, $slug: String!) { +query Products($locale: I18NLocaleCode, $slug: String!) { products(filters: { slug: { eqi: $slug } }, locale: $locale) { documentId title @@ -37,6 +38,11 @@ const gql = ` url } slug + subcategories { + title + documentId + slug + } } slug discount @@ -73,9 +79,16 @@ const gql = ` key value } + subcategories { + title + documentId + slug + } } } + + `; const gql_static = ` query Products($locale:I18NLocaleCode,$start:Int,$limit:Int) { @@ -200,10 +213,10 @@ export default async function ProductPage({ params }) { } const locale = await getLocale(); const t = await getMessages({ locale }); - console.log(t) + return ( -
- +
+ {/* */}
@@ -250,6 +263,7 @@ export default async function ProductPage({ params }) { category={product.category} summery={product.summery} brand={product.brand} + subcategories={product.subcategories} /> diff --git a/src/components/BackgroundCarousel/index.jsx b/src/components/BackgroundCarousel/index.jsx new file mode 100644 index 0000000..4041359 --- /dev/null +++ b/src/components/BackgroundCarousel/index.jsx @@ -0,0 +1,110 @@ +"use client" + +import { useState, useEffect } from "react" +import { ChevronLeft, ChevronRight } from "lucide-react" +import { useTranslations } from "next-intl" +import Link from "next/link" +import { Link2 } from "lucide-react" + + +// Sample data for the carousel + + +export default function BackgroundCarousel({ images }) { + const [activeIndex, setActiveIndex] = useState(0) + const [isAutoPlaying, setIsAutoPlaying] = useState(true) + + // Auto-play functionality + useEffect(() => { + if (!isAutoPlaying) return + + const interval = setInterval(() => { + setActiveIndex((prev) => (prev + 1) % images.length) + }, 5000) + + return () => clearInterval(interval) + }, [isAutoPlaying]) + + // Pause auto-play on hover + const handleMouseEnter = () => setIsAutoPlaying(false) + const handleMouseLeave = () => setIsAutoPlaying(true) + + const goToSlide = (index) => { + setActiveIndex(index) + } + + const goToPrevSlide = () => { + setActiveIndex((prev) => (prev - 1 + images.length) % images.length) + } + + const goToNextSlide = () => { + setActiveIndex((prev) => (prev + 1) % images.length) + } + const t = useTranslations("HomePage.AboutUs") + + return ( +
+ {/* Carousel Slides */} + {images.map((slide, index) => ( +
+
+ {slide.title} +
+ ))} +
+

{t("brandName")}

+

{t("description.0")}

+
+ + {/* Navigation Arrows */} + + + + {/* Dot Navigation with Stretching Effect */} +
+ {images.map((slide, index) => ( + { + if (index !== activeIndex) { + e.preventDefault(); + } + goToSlide(index) + }} + className={`relative flex h-3 items-center rounded-full bg-white/50 transition-all duration-300 ${index === activeIndex ? "w-auto min-w-3 bg-white p-4" : "w-3 hover:bg-white/70" + }`} + aria-label={`Go to slide ${index + 1}`} + > + {index === activeIndex && ( + + {slide.title} + + + )} + + ))} +
+
+ ) +} + diff --git a/src/components/Cards/CardNormal/index.jsx b/src/components/Cards/CardNormal/index.jsx index 2f9c0e6..9794998 100644 --- a/src/components/Cards/CardNormal/index.jsx +++ b/src/components/Cards/CardNormal/index.jsx @@ -4,13 +4,14 @@ import { ShoppingCart, HardHat, ChevronRight } from "lucide-react" import Link from "next/link" import { useLocale } from "next-intl" import { useTranslations } from "next-intl" - +import { useEffect } from "react" +import { FastAverageColor } from 'fast-average-color'; export default function ProductCard({ product }) { - const { title, brand, category, price, discount, images, slug } = product + const { title, brand, category, price, discount, images, slug,documentId } = product const isValidPrice = typeof price === "number" && !isNaN(price) const isValidDiscount = typeof discount === "number" && !isNaN(discount) && discount > 0 && discount <= 100 @@ -23,9 +24,25 @@ export default function ProductCard({ product }) { const fallbackBrandLetter = brand?.title ? brand.title.charAt(0).toUpperCase() : "#" const locale = useLocale() const t = useTranslations("") + useEffect(() => { + const fac = new FastAverageColor(); + if (images?.[0]?.url) { + fac.getColorAsync(images?.[0]?.url) + .then(color => { + const container = document.querySelector(`#container-${documentId}`) + // document.body.style.background = color.rgba + // document.body.style.color = color.isDark ? '#fff' : '#000'; + container.style.backgroundColor = color.rgba; + // container.style.color = color.isDark ? '#fff' : '#000'; + }) + .catch(e => { + console.log(e); + }); + } + }, []) return ( -
-
+
+
{images?.[0]?.alternativeText {isValidDiscount && (
@@ -73,8 +90,8 @@ export default function ProductCard({ product }) { )}
- + {t("Utils.moreDetail")} diff --git a/src/components/ColorAvg/index.jsx b/src/components/ColorAvg/index.jsx new file mode 100644 index 0000000..0bc6d36 --- /dev/null +++ b/src/components/ColorAvg/index.jsx @@ -0,0 +1,24 @@ +"use client" +import React, { useEffect } from 'react' +import { FastAverageColor } from 'fast-average-color'; +const ColorAvg = ({image}) => { + useEffect(() => { + const fac = new FastAverageColor(); + fac.getColorAsync(image) + .then(color => { + console.log("color",color) + // document.body.style.background = color.rgba + // document.body.style.color = color.isDark ? '#fff' : '#000'; + // container.style.backgroundColor = color.rgba; + // container.style.color = color.isDark ? '#fff' : '#000'; + }) + .catch(e => { + console.log(e); + }); + }, []) + return ( + <> + ) +} + +export default ColorAvg \ No newline at end of file diff --git a/src/components/NavBar/index.jsx b/src/components/NavBar/index.jsx index 85fcfb5..c6720d1 100644 --- a/src/components/NavBar/index.jsx +++ b/src/components/NavBar/index.jsx @@ -45,23 +45,34 @@ const Navbar = ({ items }) => { transition: { delay: custom * 0.06 }, }), }; - + const locale = useLocale() + const pathname = usePathname() useEffect(() => { const handleScroll = () => { const scrollTop = window.scrollY; - setIsScrolled(scrollTop > 96); + if (pathname !== "/") { + setIsScrolled(true) + return + } + if (pathname === "/") { + setIsScrolled(scrollTop > 182); + } + }; + + setIsScrolled(pathname !== "/") + + window.addEventListener("scroll", handleScroll); return () => { window.removeEventListener("scroll", handleScroll); }; - }, []); + }, [pathname]); - const locale = useLocale() - const pathname = usePathname() + const changeLocale = () => { const newLocale = locale === "en" ? "ar-OM" : "en"; @@ -74,38 +85,31 @@ const Navbar = ({ items }) => { {/*

salam

*/} + {isScrolled && ( +
-