fiux
parent
586da8367c
commit
67e84dbfa2
|
@ -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",
|
||||
|
|
|
@ -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'}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 198 KiB |
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
Binary file not shown.
After Width: | Height: | Size: 233 KiB |
|
@ -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 (
|
||||
<div className="max-w-screen-xl mx-auto px-4 py-8 bg-red-50">
|
||||
|
||||
<div className="max-w-screen-xl mx-auto px-4 py-8 ">
|
||||
{/* <ColorAvg image={product.brand.image.url}/> */}
|
||||
|
||||
|
||||
<div className="flex flex-col lg:flex-row gap-8 items-center lg:items-start">
|
||||
|
@ -250,6 +263,7 @@ export default async function ProductPage({ params }) {
|
|||
category={product.category}
|
||||
summery={product.summery}
|
||||
brand={product.brand}
|
||||
subcategories={product.subcategories}
|
||||
/>
|
||||
|
||||
|
||||
|
|
|
@ -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 (
|
||||
<section
|
||||
className="relative h-screen max-h-screen w-full overflow-hidden top-0 text-center"
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
{/* Carousel Slides */}
|
||||
{images.map((slide, index) => (
|
||||
<div
|
||||
key={slide.id}
|
||||
className={`absolute inset-0 h-full w-full transition-opacity duration-1000 ${index === activeIndex ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||
}`}
|
||||
>
|
||||
<div className="absolute inset-0 bg-black/60 lg:bg-black/80 z-10" />
|
||||
<img src={slide.image || "/placeholder.svg"} alt={slide.title} className="h-full w-full object-cover" />
|
||||
</div>
|
||||
))}
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center text-white z-20">
|
||||
<h2 className="text-3xl sm:text-4xl md:text-6xl font-bold mb-4"> {t("brandName")}</h2>
|
||||
<p className="text-lg sm:text-xl md:text-2xl max-w-2xl text-center"> {t("description.0")}</p>
|
||||
</div>
|
||||
|
||||
{/* Navigation Arrows */}
|
||||
<button
|
||||
onClick={goToPrevSlide}
|
||||
className="absolute left-4 top-1/2 z-30 -translate-y-1/2 rounded-full bg-white/20 p-2 text-white backdrop-blur-sm transition-all hover:bg-white/40"
|
||||
aria-label="Previous slide"
|
||||
>
|
||||
<ChevronLeft className="h-6 w-6" />
|
||||
</button>
|
||||
<button
|
||||
onClick={goToNextSlide}
|
||||
className="absolute right-4 top-1/2 z-30 -translate-y-1/2 rounded-full bg-white/20 p-2 text-white backdrop-blur-sm transition-all hover:bg-white/40"
|
||||
aria-label="Next slide"
|
||||
>
|
||||
<ChevronRight className="h-6 w-6" />
|
||||
</button>
|
||||
|
||||
{/* Dot Navigation with Stretching Effect */}
|
||||
<div className="absolute bottom-20 left-1/2 z-30 flex -translate-x-1/2 items-center gap-2">
|
||||
{images.map((slide, index) => (
|
||||
<Link href={slide.link}
|
||||
key={slide.id}
|
||||
onClick={(e) =>{
|
||||
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 && (
|
||||
<span className="whitespace-nowrap text-xs font-medium text-black transition-opacity duration-300 inline-flex gap-2 items-center">
|
||||
{slide.title}
|
||||
<Link2/>
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -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 (
|
||||
<div className="bg-white rounded-lg shadow-md overflow-hidden" dir={locale === "en" ? "ltr": "rtl"} >
|
||||
<div className="relative h-48 w-full overflow-hidden rounded-lg">
|
||||
<div className="bg-white rounded-lg shadow-md overflow-hidden" dir={locale === "en" ? "ltr" : "rtl"} >
|
||||
<div className="relative h-48 w-full overflow-hidden rounded-lg " id={`container-${documentId}`}>
|
||||
<Image src={images?.[0]?.url} alt={images?.[0]?.alternativeText ?? ""} layout="fill" className="object-contain border" />
|
||||
{isValidDiscount && (
|
||||
<div className="absolute top-2 right-2 bg-red-500 text-white text-xs font-semibold px-2 py-1 rounded-full">
|
||||
|
@ -73,8 +90,8 @@ export default function ProductCard({ product }) {
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Link href={`/product/${slug}`.toLowerCase()}
|
||||
className={`w-full flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors ${locale === "en" ? "flex-row" : "flex-row-reverse"}`}>
|
||||
<Link href={`/product/${slug}`.toLowerCase()}
|
||||
className={`w-full flex items-center justify-center px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors ${locale === "en" ? "flex-row" : "flex-row-reverse"}`}>
|
||||
{t("Utils.moreDetail")}
|
||||
<ChevronRight className="h-4 w-4 ml-2" />
|
||||
</Link>
|
||||
|
|
|
@ -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
|
|
@ -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 }) => {
|
|||
{/* <div className="bg-sky-900 p-3 flex">
|
||||
<p className="mb-0 text-white"> salam</p>
|
||||
</div> */}
|
||||
{isScrolled && (
|
||||
<div className="w-full lg:h-[76px] h-2">
|
||||
|
||||
<div
|
||||
className={` max-w-screen-xl hidden lg:block tr03 mx-auto px-4 lg:px-0`}
|
||||
>
|
||||
<div className="mx-auto w-full flex justify-center p-2">
|
||||
<Image src={`/images/1.png`} width={125} height={125} className="lg:w-auto" />
|
||||
</div>
|
||||
{isScrolled && (
|
||||
<div className="w-full h-[76px]">
|
||||
)}
|
||||
<div
|
||||
className={` max-w-screen-xl hidden lg:block tr03 mx-auto px-4 lg:px-0 absolute top-0 left-0 right-0 z-50`}
|
||||
>
|
||||
{
|
||||
pathname === "/" && (
|
||||
<Link href={"/"} className="mx-auto w-full flex justify-center p-2">
|
||||
<Image src={`/images/1.png`} width={125} height={125} className="lg:w-auto" />
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
{
|
||||
!isScrolled && (
|
||||
<nav
|
||||
className={`${locale === "en" ? "rtl pl-1" : "ltr pr-1"} flex justify-between w-full items-center ${isScrolled ? "bg-gray-200 fixed top-0 z-50 rounded-b-3xl py-2 px-2 left-1/2 -translate-x-1/2 " : "bg-transparent rounded-full"
|
||||
}
|
||||
}`}
|
||||
>
|
||||
|
||||
</div>
|
||||
)}
|
||||
<nav
|
||||
className={`${locale === "en" ? "rtl pl-1" : "ltr pr-1"} flex justify-between w-full items-center ${isScrolled ? "bg-gray-100 fixed top-0 z-50 rounded-b-3xl py-2 px-2 left-1/2 -translate-x-1/2 " : " rounded-2xl"
|
||||
}
|
||||
bg-gray-100 }`}
|
||||
>
|
||||
|
||||
{
|
||||
isScrolled &&
|
||||
(
|
||||
<div className="relative rounded-lg flex flex-col items-center rounded-tl-2xl justify-center my-auto">
|
||||
<Image
|
||||
src={"/images/1.png"}
|
||||
width={75} height={75}
|
||||
alt="llc "
|
||||
className="mx-auto object-contain"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{/* <div className={`w-full ${locale === "en" ? "rtl" : "ltr"} px-4 py-4`}>
|
||||
|
||||
{/* <div className={`w-full ${locale === "en" ? "rtl" : "ltr"} px-4 py-4`}>
|
||||
<div className="flex">
|
||||
|
||||
<button onClick={changeLocale} className="mr-2 w-fit px-3 p-2 text-sm bg-white flex rounded-xl ">
|
||||
|
@ -114,57 +118,145 @@ const Navbar = ({ items }) => {
|
|||
|
||||
</div>
|
||||
</div> */}
|
||||
<div className={`w-full flex p-2 ${locale === "en" ? "ltr" : "rtl"} `}>
|
||||
<div className={`w-full flex p-2 mx-auto justify-center pt-8 ${locale === "en" ? "ltr" : "rtl"} `}>
|
||||
|
||||
|
||||
|
||||
{items.map((item, index) => (
|
||||
{items.map((item, index) => (
|
||||
|
||||
<div
|
||||
key={index}
|
||||
className={`mx-2 px-2 w-fit text-sm bg-visa2-200 rounded-full !text-white text-shadow relative group`}
|
||||
onMouseEnter={() => {
|
||||
// setHoverItemNavbar(index);
|
||||
setActiveStepNavbar(item.documentId);
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
// setHoverItemNavbar(-1);
|
||||
setActiveStepNavbar(null);
|
||||
}}
|
||||
// onClick={() => context.setOpenNavBarServices(false)}
|
||||
>
|
||||
<Link
|
||||
href={`${item.link}`}
|
||||
<div
|
||||
key={index}
|
||||
className={`mx-2 px-2 w-fit text-sm rounded-full !text-white text-shadow relative group`}
|
||||
onMouseEnter={() => {
|
||||
// setHoverItemNavbar(index);
|
||||
setActiveStepNavbar(item.documentId);
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
// setHoverItemNavbar(-1);
|
||||
setActiveStepNavbar(null);
|
||||
}}
|
||||
// onClick={() => context.setOpenNavBarServices(false)}
|
||||
>
|
||||
<Link
|
||||
href={`${item.link}`}
|
||||
|
||||
className={`text-base whitespace-nowrap text-black py-1 px-4 inline-flex items-center gap-4 rounded-lg group-hover:bg-gray-200`}
|
||||
>
|
||||
{item.title}
|
||||
{item.children.length > 0 && <ChevronDown size={16} />}
|
||||
</Link>
|
||||
className={`text-base whitespace-nowrap py-1 px-4 inline-flex items-center gap-4 border-2 border-gray-100 p-4 text-white font-medium rounded-full group-hover:bg-black/60`}
|
||||
>
|
||||
{item.title}
|
||||
{item.children.length > 0 && <ChevronDown size={16} />}
|
||||
</Link>
|
||||
|
||||
{item.children.length > 0 && item.documentId == activeStepNavbar && (
|
||||
<ul className="absolute left-0 w-48 bg-white text-black rounded-lg shadow-lg z-50 overflow-hidden">
|
||||
{
|
||||
item.children.map((c, index) => (
|
||||
{item.children.length > 0 && item.documentId == activeStepNavbar && (
|
||||
<ul className="absolute left-0 w-48 bg-black/80 text-white rounded-lg shadow-lg z-50 overflow-hidden">
|
||||
{
|
||||
item.children.map((c, index) => (
|
||||
|
||||
<li key={index} className="px-4 py-2 hover:bg-gray-100 cursor-pointer text-base">
|
||||
<Link href={c.link}>
|
||||
{c.title}
|
||||
</Link>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
<Link href={c.link} className="w-full h-full">
|
||||
<li key={index} className="px-4 py-2 hover:bg-gray-400 cursor-pointer text-base w-full">
|
||||
{c.title}
|
||||
</li>
|
||||
</Link>
|
||||
))
|
||||
}
|
||||
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
|
||||
))}
|
||||
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
|
||||
))}
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
</nav>
|
||||
{
|
||||
isScrolled &&
|
||||
|
||||
<nav
|
||||
className={`${locale === "en" ? "rtl pl-1" : "ltr pr-1"} flex justify-between w-full items-center ${isScrolled ? "bg-gray-100 border-b shadow-md fixed top-0 z-50 rounded-b-3xl py-2 px-2 left-1/2 -translate-x-1/2 " : "bg-transparent rounded-full"
|
||||
}
|
||||
}`}
|
||||
>
|
||||
|
||||
{
|
||||
isScrolled &&
|
||||
(
|
||||
<div className="relative rounded-lg flex flex-col items-center rounded-tl-2xl justify-center my-auto">
|
||||
<Image
|
||||
src={"/images/1.png"}
|
||||
width={75} height={75}
|
||||
alt="llc "
|
||||
className="mx-auto object-contain"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{/* <div className={`w-full ${locale === "en" ? "rtl" : "ltr"} px-4 py-4`}>
|
||||
<div className="flex">
|
||||
|
||||
<button onClick={changeLocale} className="mr-2 w-fit px-3 p-2 text-sm bg-white flex rounded-xl ">
|
||||
<p className="mb-0">{locale === "en" ? "العربیه" : "English"}</p>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div> */}
|
||||
<div className={`w-full flex p-2 ${locale === "en" ? "ltr" : "rtl"} `}>
|
||||
|
||||
|
||||
|
||||
{items.map((item, index) => (
|
||||
|
||||
<div
|
||||
key={index}
|
||||
className={`mx-2 px-2 w-fit text-sm bg-visa2-200 rounded-full !text-white text-shadow relative group`}
|
||||
onMouseEnter={() => {
|
||||
// setHoverItemNavbar(index);
|
||||
setActiveStepNavbar(item.documentId);
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
// setHoverItemNavbar(-1);
|
||||
setActiveStepNavbar(null);
|
||||
}}
|
||||
// onClick={() => context.setOpenNavBarServices(false)}
|
||||
>
|
||||
<Link
|
||||
href={`${item.link}`}
|
||||
|
||||
className={`text-base whitespace-nowrap text-black py-1 px-4 inline-flex items-center gap-4 rounded-lg group-hover:bg-gray-200`}
|
||||
>
|
||||
{item.title}
|
||||
{item.children.length > 0 && <ChevronDown size={16} />}
|
||||
</Link>
|
||||
|
||||
{item.children.length > 0 && item.documentId == activeStepNavbar && (
|
||||
<ul className="absolute left-0 w-48 bg-white text-black rounded-lg shadow-lg z-50 overflow-hidden">
|
||||
{
|
||||
item.children.map((c, index) => (
|
||||
|
||||
<Link href={c.link} className="w-full h-full">
|
||||
<li key={index} className="px-4 py-2 hover:bg-gray-100 cursor-pointer text-base w-full">
|
||||
{c.title}
|
||||
</li>
|
||||
</Link>
|
||||
))
|
||||
}
|
||||
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
|
||||
))}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</nav>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
{/* reponsive navbar */}
|
||||
|
@ -175,7 +267,7 @@ const Navbar = ({ items }) => {
|
|||
{/* responsive part */}
|
||||
|
||||
<div
|
||||
className={`sm:block lg:hidden ${isScrolled & !closeNavbar ? "sticky top-0 z-[100] w-full" : " pt-2"
|
||||
className={`block lg:hidden ${isScrolled & !closeNavbar ? "sticky top-0 z-[100] w-full" : " pt-2 absolute left-0 right-0 top-0 z-50"
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
|
@ -186,23 +278,22 @@ const Navbar = ({ items }) => {
|
|||
>
|
||||
|
||||
{/* <Link href={"/"} className="w-full"> */}
|
||||
<div className=" w-full mx-1 flex items-center ">
|
||||
<div className=" w-full mx-1 flex items-center relative -mt-2 ">
|
||||
{/* <button onClick={changeLocale} className="mr-2 w-fit px-3 p-2 h-fit text-sm bg-white flex rounded-xl ">
|
||||
<p className="mb-0">{locale === "en" ? "العربیه" : "English"}</p>
|
||||
</button> */}
|
||||
</div>
|
||||
<div className=" ">
|
||||
<Image
|
||||
src={"/images/1.png"}
|
||||
width={200}
|
||||
height={200}
|
||||
width={70}
|
||||
height={70}
|
||||
alt="llc"
|
||||
className="mx-auto"
|
||||
className="ml-auto object-contain"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* </Link> */}
|
||||
<div
|
||||
className=" p-3 w-full mx-1 text-left"
|
||||
className=" w-full mx-1 text-left"
|
||||
onClick={() => setClosNavbar(true)}
|
||||
>
|
||||
<svg
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import { ChevronLeft, ChevronRight, X } from "lucide-react";
|
||||
import { FastAverageColor } from 'fast-average-color';
|
||||
|
||||
|
||||
export default function ProductGallery({ images }) {
|
||||
const [selectedImage, setSelectedImage] = useState(images[0]);
|
||||
|
@ -26,30 +28,44 @@ export default function ProductGallery({ images }) {
|
|||
setLightboxIndex((prevIndex) => (prevIndex - 1 + images.length) % images.length);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fac = new FastAverageColor();
|
||||
fac.getColorAsync(selectedImage.url)
|
||||
.then(color => {
|
||||
const container = document.querySelector("#container")
|
||||
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);
|
||||
});
|
||||
}, [selectedImage])
|
||||
|
||||
return (
|
||||
<div className="max-w-[500px] lg:min-w-[500px]">
|
||||
<div className="aspect-w-1 aspect-h-1 w-full overflow-hidden border-r pr-4">
|
||||
<div className="max-w-[500px] lg:min-w-[500px] pr-4 lg:border-r">
|
||||
<div className="aspect-w-1 aspect-h-1 w-full overflow-hidden" id="container">
|
||||
<Image
|
||||
|
||||
src={selectedImage.url || "/placeholder.svg"}
|
||||
alt={selectedImage.alternativeText ?? ""}
|
||||
width={500}
|
||||
height={500}
|
||||
className="object-contain cursor-pointer aspect-square"
|
||||
className="object-contain cursor-pointer aspect-square mx-auto"
|
||||
onClick={() => openLightbox(images.findIndex((img) => img.documentId === selectedImage.documentId))}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-4 grid grid-cols-4 gap-1">
|
||||
{images.slice(0,4).map((image, index) => (
|
||||
{images.slice(0, 4).map((image, index) => (
|
||||
<Image
|
||||
key={image.documentId}
|
||||
src={image.url || "/placeholder.svg"}
|
||||
alt={image.alternativeText ?? ""}
|
||||
width={100}
|
||||
height={100}
|
||||
className={`object-cover cursor-pointer rounded-lg overflow-hidden ${
|
||||
selectedImage.documentId === image.documentId ? "ring-2 ring-primary/50" : ""
|
||||
}`}
|
||||
className={`object-cover cursor-pointer rounded-lg overflow-hidden ${selectedImage.documentId === image.documentId ? "ring-2 ring-primary/50" : ""
|
||||
}`}
|
||||
onClick={() => setSelectedImage(image)}
|
||||
/>
|
||||
))}
|
||||
|
|
|
@ -13,7 +13,7 @@ import { Share2 } from "lucide-react";
|
|||
import { toast } from "react-toastify";
|
||||
|
||||
|
||||
export default function ProductInfo({ title, price, discount, showPrice, category, summery, brand }) {
|
||||
export default function ProductInfo({ title, price, discount, showPrice, category, summery, brand, subcategories }) {
|
||||
|
||||
const locale = useLocale()
|
||||
|
||||
|
@ -68,12 +68,34 @@ export default function ProductInfo({ title, price, discount, showPrice, categor
|
|||
<div className="flex items-start w-full justify-between lg:flex-row flex-col-reverse gap-4">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">{title}</h1>
|
||||
<Link href={`/products/${category.slug}`} className="mt-4 flex items-center">
|
||||
<span className={`inline-flex items-center rounded-md bg-gray-100 px-2.5 py-0.5 text-sm font-medium text-gray-800 ltr`}>
|
||||
<CategoryIcon className="h-4 w-4 mx-1" />
|
||||
{category.title}
|
||||
</span>
|
||||
</Link>
|
||||
<div className="flex gap-2">
|
||||
<Link href={`/products/${category.slug}`} className="mt-4 flex items-center underline">
|
||||
<span className={`inline-flex items-center rounded-md bg-gray-100 hover:bg-gray-200 px-2.5 py-0.5 text-sm font-medium text-gray-800 ltr`}>
|
||||
<CategoryIcon className="h-4 w-4 mx-1" />
|
||||
{category.title}
|
||||
</span>
|
||||
</Link>
|
||||
{
|
||||
brand?.slug &&
|
||||
<Link href={`/products/${brand?.slug}`} className="mt-4 flex items-center underline">
|
||||
<span className={`inline-flex items-center rounded-md bg-gray-100 hover:bg-gray-200 px-2.5 py-0.5 text-sm font-medium text-gray-800 ltr`}>
|
||||
|
||||
{brand.title}
|
||||
</span>
|
||||
</Link>
|
||||
}
|
||||
{
|
||||
[...(brand?.subcategories ?? []), ...(subcategories ?? [])].map(sub => (
|
||||
|
||||
<Link key={sub.documentId} href={`/products/${sub.slug}`} className="mt-4 flex items-center underline">
|
||||
<span className={`inline-flex items-center rounded-md bg-gray-100 hover:bg-gray-200 px-2.5 py-0.5 text-sm font-medium text-gray-800 ltr`}>
|
||||
|
||||
{sub.title}
|
||||
</span>
|
||||
</Link>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<p className="text-sm opacity-75">
|
||||
{
|
||||
summery
|
||||
|
@ -138,10 +160,10 @@ export default function ProductInfo({ title, price, discount, showPrice, categor
|
|||
</div>
|
||||
<div className="mt-10 w-full border-t pt-10 flex gap-2 items-center">
|
||||
{/* Replaced Button with Tailwind CSS */}
|
||||
<button onClick={openModal} className="w-full lg:w-fit px-8 ltr flex items-center justify-center py-2 bg-primary text-white rounded-md hover:bg-primary-dark transition-colors">
|
||||
<button onClick={openModal} className="w-full lg:w-fit px-8 ltr flex items-center justify-center py-2 bg-gradient-to-r from-primary-600 to-primary-400 text-white rounded-md hover:bg-primary-dark transition-colors">
|
||||
<ShoppingCart className="mr-2 h-4 w-4" /> {t("cta")}
|
||||
</button>
|
||||
<button className="btn shadow-none" onClick={() => shareLink()}>
|
||||
<button className="border p-2 rounded-lg flex flex-col items-center justify-center shadow-none text-black/60" onClick={() => shareLink()}>
|
||||
<Share2 size={24} />
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
"construction": {
|
||||
"title": "Construction",
|
||||
"subtitle": "Building the Future",
|
||||
"description": "Our Construction arm is dedicated to creating lasting infrastructure and innovative building solutions.From residential projects to commercial complexes, we bring expertise, quality, and sustainability to every construction endeavor"
|
||||
"description": "Our Construction arm is dedicated to creating lasting infrastructure and innovative building solutions. From residential projects to commercial complexes, we bring expertise, quality, and sustainability to every construction endeavor"
|
||||
}
|
||||
},
|
||||
"products":{
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import { clsx } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
|
@ -25,9 +25,10 @@ const CheckboxGroup = ({ title, items, selectedItem, onItemSelect }) => {
|
|||
)
|
||||
}
|
||||
|
||||
const Filters = ({ brands, categories }) => {
|
||||
const Filters = ({ brands, categories,subCategories }) => {
|
||||
const [selectedCategory, setSelectedCategory] = useState(null)
|
||||
const [selectedBrand, setSelectedBrand] = useState(null)
|
||||
const [selectedSubcategoty, setSelectedSubcategory] = useState(null)
|
||||
const params = useParams()
|
||||
const router = useRouter()
|
||||
const handleCategorySelect = (documentId) => {
|
||||
|
@ -40,6 +41,12 @@ const Filters = ({ brands, categories }) => {
|
|||
router.push("/products/"+(documentId ? `${brands.find(b=>b.documentId === documentId)?.slug}` : ""))
|
||||
}
|
||||
|
||||
|
||||
const handleSubSelect = (documentId) => {
|
||||
setSelectedSubcategory((prevSelected) => (prevSelected === documentId ? null : documentId))
|
||||
router.push("/products/"+(documentId ? `${subCategories.find(b=>b.documentId === documentId)?.slug}` : ""))
|
||||
}
|
||||
|
||||
|
||||
useEffect(()=>{
|
||||
|
||||
|
@ -48,6 +55,7 @@ const Filters = ({ brands, categories }) => {
|
|||
|
||||
setSelectedBrand(brands.find(b=>b.slug === categoryOrBrand)?.documentId)
|
||||
setSelectedCategory(categories.find(c=>c.slug === categoryOrBrand)?.documentId)
|
||||
setSelectedSubcategory(subCategories.find(c=>c.slug === categoryOrBrand)?.documentId)
|
||||
},[params])
|
||||
const t = useTranslations("PLP.filter")
|
||||
return (
|
||||
|
@ -63,6 +71,7 @@ const Filters = ({ brands, categories }) => {
|
|||
onItemSelect={handleCategorySelect}
|
||||
/>
|
||||
<CheckboxGroup title="Brands" items={brands} selectedItem={selectedBrand} onItemSelect={handleBrandSelect} />
|
||||
<CheckboxGroup title="Use Case" items={subCategories} selectedItem={selectedSubcategoty} onItemSelect={handleSubSelect} />
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@ const brandAndCategoriesGQL = `
|
|||
documentId
|
||||
slug
|
||||
}
|
||||
subcategories(locale: $locale, pagination: { start: 0, limit: 50 }) {
|
||||
title
|
||||
documentId
|
||||
slug
|
||||
}
|
||||
}
|
||||
|
||||
`
|
||||
|
@ -29,6 +34,7 @@ query Products_connection(
|
|||
$pageSize: Int
|
||||
$category: String
|
||||
$brand: String
|
||||
$subcategory: String
|
||||
) {
|
||||
products_connection(
|
||||
pagination: { page: $page, pageSize: $pageSize }
|
||||
|
@ -36,6 +42,8 @@ query Products_connection(
|
|||
or: [
|
||||
{ category: { slug: { eqi: $category } } }
|
||||
{ brand: { slug: { eqi: $brand } } }
|
||||
{ brand: { subcategories: { slug: { containsi: $subcategory } } } }
|
||||
{ subcategories: { slug: { containsi: $subcategory } } }
|
||||
]
|
||||
}
|
||||
locale: $locale
|
||||
|
@ -52,7 +60,6 @@ query Products_connection(
|
|||
title
|
||||
documentId
|
||||
slug
|
||||
|
||||
}
|
||||
brand {
|
||||
documentId
|
||||
|
@ -91,10 +98,12 @@ const ProductsListingPage = () => {
|
|||
const [products, setProducts] = React.useState([])
|
||||
const [brands, setBrands] = React.useState([])
|
||||
const [categories, setCategories] = React.useState([])
|
||||
const [subcategories, setSubcategories] = React.useState([])
|
||||
const getBrandsAndCategories = async () => {
|
||||
const { brands, categories } = await graphql(brandAndCategoriesGQL, { locale: "en" });
|
||||
const { brands, categories,subcategories } = await graphql(brandAndCategoriesGQL, { locale: "en" });
|
||||
setBrands(brands)
|
||||
setCategories(categories)
|
||||
setSubcategories(subcategories)
|
||||
|
||||
}
|
||||
const getProducts = async () => {
|
||||
|
@ -106,7 +115,8 @@ const ProductsListingPage = () => {
|
|||
page: page,
|
||||
pageSize: 12,
|
||||
brand: category,
|
||||
category: category
|
||||
category: category,
|
||||
subcategory: category,
|
||||
})
|
||||
setProducts(nodes)
|
||||
setPageInfo(pageInfo)
|
||||
|
@ -128,7 +138,7 @@ const ProductsListingPage = () => {
|
|||
<>
|
||||
{
|
||||
brands && brands.length > 0 && categories && categories.length > 0 &&
|
||||
<Filters brands={brands} categories={categories} />
|
||||
<Filters subCategories={subcategories} brands={brands} categories={categories} />
|
||||
}
|
||||
<div className="flex flex-col w-full items-center justify-center ">
|
||||
<div className="px-2 pb-20 w-full">
|
||||
|
|
|
@ -55,7 +55,7 @@ const CategoriesData = async ({ category }) => {
|
|||
|
||||
</div>
|
||||
{
|
||||
content.title &&
|
||||
content?.title &&
|
||||
<Content content={content} />
|
||||
}
|
||||
|
||||
|
|
|
@ -1,69 +1,115 @@
|
|||
import { useLocale, useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
import React from "react";
|
||||
"use client"
|
||||
import { Globe, TrendingUp, Truck, Users } from "lucide-react"
|
||||
import Image from "next/image"
|
||||
import { useState } from "react";
|
||||
import ContactModal from "src/components/ContactUs"
|
||||
|
||||
|
||||
const AboutUs = () => {
|
||||
const t = useTranslations("HomePage.AboutUs")
|
||||
const locale = useLocale()
|
||||
export default function AboutUs() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const openModal = () => {
|
||||
setOpen(true);
|
||||
};
|
||||
const closeModal = () => {
|
||||
setOpen(false);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" className="absolute left-0 top-0 bottom-0 -z-10 right-0">
|
||||
<pattern id="diagonalLines" width="10" height="10" patternTransform="rotate(45)" patternUnits="userSpaceOnUse">
|
||||
<line x1="0" y1="0" x2="0" y2="10" stroke="#e2e8f0" stroke-width="1" />
|
||||
</pattern>
|
||||
<rect width="100%" height="100%" fill="url(#diagonalLines)" />
|
||||
</svg>
|
||||
<div className="min-h-[calc(100vh-108px)] flex flex-col items-center justify-center relative mt-8 -z-10 text-center ">
|
||||
<div className="max-w-screen-xl mx-auto">
|
||||
<section className="relative overflow-hidden bg-gradient-to-br from-primary-100 to-white py-20 flex flex-col text-base">
|
||||
{/* Background Elements */}
|
||||
<div className="absolute top-0 left-0 w-full h-full overflow-hidden opacity-10 pointer-events-none">
|
||||
<div className="absolute -top-24 -left-24 w-96 h-96 rounded-full bg-blue-400 blur-3xl"></div>
|
||||
<div className="absolute top-1/2 -right-24 w-80 h-80 rounded-full bg-indigo-500 blur-3xl"></div>
|
||||
<div className="absolute -bottom-24 left-1/3 w-72 h-72 rounded-full bg-purple-400 blur-3xl"></div>
|
||||
</div>
|
||||
|
||||
<div className="container mx-auto px-4 relative z-10">
|
||||
{/* Header */}
|
||||
<div className="flex flex-col items-center text-center mb-16">
|
||||
<div className="inline-block p-3 bg-white bg-opacity-80 rounded-xl shadow-lg mb-6">
|
||||
<Image
|
||||
src="/images/1.png"
|
||||
alt="AHS Logo"
|
||||
width={100}
|
||||
height={80}
|
||||
className="rounded"
|
||||
/>
|
||||
</div>
|
||||
<h2 className="text-3xl md:text-5xl font-bold text-gray-800 mb-4 tracking-tight">
|
||||
Advanced Horizon Services
|
||||
</h2>
|
||||
<div className="w-24 h-1 bg-gradient-to-r from-blue-500 to-indigo-600 rounded-full mb-6"></div>
|
||||
<p className="text-lg text-gray-600 max-w-xl">
|
||||
Revolutionizing wholesale supply chain solutions with excellence and reliability
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
{/* Left Side - Description */}
|
||||
<div className="bg-white bg-opacity-90 rounded-2xl p-8 md:p-10 shadow-xl transform transition-all duration-500 hover:shadow-2xl">
|
||||
<h3 className="text-2xl font-bold text-gray-800 mb-6 border-l-4 border-blue-500 pl-4">Who We Are</h3>
|
||||
<p className="text-gray-700 leading-relaxed mb-8 text-justify">
|
||||
Advanced Horizon Services is a leading trade company specializing in wholesale supply chain solutions for
|
||||
a diverse range of products, including high-quality detergents and food items. With years of experience
|
||||
and extensive relations in the industry, we pride ourselves on our commitment to excellence, reliability,
|
||||
and customer satisfaction.
|
||||
</p>
|
||||
<h3 className="text-2xl font-bold text-gray-800 mb-6 border-l-4 border-indigo-500 pl-4">Our Approach</h3>
|
||||
<p className="text-gray-700 leading-relaxed text-justify">
|
||||
At AHS, we understand the complexities of the supply chain and strive to simplify the process for our
|
||||
partners. Our extensive network of suppliers and manufacturers allows us to source top-notch products at
|
||||
competitive prices, ensuring that you receive the best value for your investment.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="xs:px-3 md:px-10 md:container md:mx-auto ">
|
||||
<div className="gap-5 items-center">
|
||||
|
||||
<div className="relative mb-10 col-span-2">
|
||||
|
||||
<h2 className={
|
||||
`text-5xl font-bold relative z-10`
|
||||
}>
|
||||
{t("brandName")}
|
||||
|
||||
</h2>
|
||||
|
||||
<p className={`mb-0 text-xl mt-5 text-center leading-7 px-5`}>
|
||||
<span className="text-primary-800 font-semibold text-2xl">
|
||||
{t("description.0")}
|
||||
</span>
|
||||
<br />
|
||||
<br />
|
||||
<p className="text-justify leading-8">
|
||||
{t("description.1")} <br />
|
||||
</p>
|
||||
<br />
|
||||
<p className="text-justify leading-8">
|
||||
|
||||
{t("description.2")}
|
||||
</p>
|
||||
</p>
|
||||
{/*
|
||||
<div className="flex gap-2 mx-auto mt-5 w-full justify-center lg:justify-end">
|
||||
<button className="btn btn-primary text-base py-3 px-10 ">
|
||||
{" "}
|
||||
Export
|
||||
</button>
|
||||
<button className="btn btn-primary text-base p-3 px-10">
|
||||
{" "}
|
||||
Industrial
|
||||
</button>
|
||||
</div> */}
|
||||
{/* Right Side - Features */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Feature 1 */}
|
||||
<div className="bg-white bg-opacity-80 rounded-xl p-6 shadow-lg transform transition-all duration-300 hover:-translate-y-1 hover:shadow-xl">
|
||||
<div className="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-4">
|
||||
<Globe className="w-6 h-6 text-blue-600" />
|
||||
</div>
|
||||
<h4 className="text-xl font-semibold text-gray-800 mb-2">Global Network</h4>
|
||||
<p className="text-gray-600">Extensive connections with suppliers and manufacturers worldwide.</p>
|
||||
</div>
|
||||
|
||||
{/* Feature 2 */}
|
||||
<div className="bg-white bg-opacity-80 rounded-xl p-6 shadow-lg transform transition-all duration-300 hover:-translate-y-1 hover:shadow-xl">
|
||||
<div className="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-4">
|
||||
<TrendingUp className="w-6 h-6 text-indigo-600" />
|
||||
</div>
|
||||
<h4 className="text-xl font-semibold text-gray-800 mb-2">Competitive Pricing</h4>
|
||||
<p className="text-gray-600">Best value products sourced at optimal market rates.</p>
|
||||
</div>
|
||||
|
||||
{/* Feature 3 */}
|
||||
<div className="bg-white bg-opacity-80 rounded-xl p-6 shadow-lg transform transition-all duration-300 hover:-translate-y-1 hover:shadow-xl">
|
||||
<div className="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center mb-4">
|
||||
<Truck className="w-6 h-6 text-purple-600" />
|
||||
</div>
|
||||
<h4 className="text-xl font-semibold text-gray-800 mb-2">Supply Chain Experts</h4>
|
||||
<p className="text-gray-600">Simplifying complex logistics for seamless operations.</p>
|
||||
</div>
|
||||
|
||||
{/* Feature 4 */}
|
||||
<div className="bg-white bg-opacity-80 rounded-xl p-6 shadow-lg transform transition-all duration-300 hover:-translate-y-1 hover:shadow-xl">
|
||||
<div className="w-12 h-12 bg-rose-100 rounded-lg flex items-center justify-center mb-4">
|
||||
<Users className="w-6 h-6 text-rose-600" />
|
||||
</div>
|
||||
<h4 className="text-xl font-semibold text-gray-800 mb-2">Customer Focused</h4>
|
||||
<p className="text-gray-600">Dedicated to excellence and partner satisfaction.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AboutUs;
|
||||
{/* Call to Action */}
|
||||
<div className="mt-20 text-center">
|
||||
<button onClick={()=>setOpen(true)} className="px-8 py-4 bg-gradient-to-r from-primary-600 to-primary-300 text-white font-medium rounded-lg shadow-lg transform transition-all duration-300 hover:-translate-y-1 hover:shadow-xl">
|
||||
Partner With Us
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ContactModal close={closeModal} open={open} />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ const CounterDetail = ({ stats }) => {
|
|||
}
|
||||
return (
|
||||
|
||||
<div className="w-full bg-couner-data-landing py-32 mb-44">
|
||||
<div className="w-full bg-couner-data-landing py-32 text-center">
|
||||
<div className="grid xs:grid-cols-1 lg:grid-cols-3">
|
||||
{
|
||||
stats.map(s => (
|
||||
|
|
|
@ -73,7 +73,7 @@ const Products = async () => {
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<ProductCarousel products={products2} subtitle={""} title={t.HomePage.products.title[1]} showMoreLink={"/products/constructions"} />
|
||||
<ProductCarousel products={products2} subtitle={""} title={t.HomePage.products.title[1]} showMoreLink={"/products/construction"} />
|
||||
</div>
|
||||
|
||||
{/* <div className="grid grid-cols-1 lg:grid-cols-3 gap-5">
|
||||
|
|
|
@ -1,49 +1,88 @@
|
|||
import React from 'react';
|
||||
import { ShoppingCart, Building2 } from 'lucide-react'; // Assuming you're using lucide-react for icons
|
||||
import { useTranslations } from 'next-intl';
|
||||
import Link from 'next/link';
|
||||
import { ShoppingBag, Construction } from "lucide-react"
|
||||
import { useTranslations } from "next-intl"
|
||||
import Link from "next/link"
|
||||
import { cn } from "src/utils"
|
||||
|
||||
const Sides = () => {
|
||||
|
||||
export default function ExpertiseSection() {
|
||||
const t = useTranslations("HomePage.Sides")
|
||||
return (
|
||||
<section className="w-full py-12 md:py-24 lg:py-32 bg-background text-sm bg-primary-800/40 ">
|
||||
<div className="max-w-screen-xl px-4 md:px-6 mx-auto">
|
||||
<h2 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl text-center mb-12">
|
||||
{t("title")}
|
||||
</h2>
|
||||
<div className="grid gap-6 lg:grid-cols-2">
|
||||
{/* First Card */}
|
||||
<Link href={"/products/fmcg"} className="flex flex-col items-center text-center w-full bg-white shadow-lg rounded-lg p-6 hover:scale-105 transition-all">
|
||||
<div className="flex flex-col items-center">
|
||||
<ShoppingCart className="w-12 h-12 mb-4 text-primary" />
|
||||
<h3 className="text-2xl font-bold">{t("fmcg.title")}</h3>
|
||||
<p className="text-muted-foreground">{t("fmcg.subtitle")}</p>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<p className="text-muted-foreground text-base text-justify">
|
||||
{t("fmcg.description")}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
{/* Second Card */}
|
||||
<Link href={"/products/construction"} className="flex flex-col items-center text-center bg-white shadow-lg rounded-lg p-6 hover:scale-105 transition-all">
|
||||
<div className="flex flex-col items-center">
|
||||
<Building2 className="w-12 h-12 mb-4 text-primary" />
|
||||
<h3 className="text-2xl font-bold">{t("construction.title")}</h3>
|
||||
<p className="text-muted-foreground">{t("construction.subtitle")}</p>
|
||||
const services = [
|
||||
{
|
||||
key: "fmcg",
|
||||
icon: ShoppingBag,
|
||||
color: "bg-blue-50 dark:bg-blue-950",
|
||||
iconColor: "text-blue-600 dark:text-blue-400",
|
||||
borderColor: "border-blue-100 dark:border-blue-800",
|
||||
},
|
||||
{
|
||||
key: "construction",
|
||||
icon: Construction,
|
||||
color: "bg-amber-50 dark:bg-amber-950",
|
||||
iconColor: "text-amber-600 dark:text-amber-400",
|
||||
borderColor: "border-amber-100 dark:border-amber-800",
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<section className="w-full py-20 bg-gradient-to-b from-slate-50 to-white dark:from-slate-950 dark:to-black mx-auto max-w-screen-xl">
|
||||
<div className="container px-4 md:px-6 mx-auto">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-4xl md:text-5xl font-bold tracking-tight mb-4 bg-clip-text text-transparent bg-gradient-to-r from-slate-900 to-slate-700 dark:from-slate-100 dark:to-slate-300">
|
||||
{t("title")}
|
||||
</h2>
|
||||
<div className="w-20 h-1 bg-gradient-to-r from-blue-500 to-amber-500 mx-auto rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mx-auto">
|
||||
{services.map((service) => (
|
||||
<div
|
||||
key={service.key}
|
||||
className={cn(
|
||||
"group relative overflow-hidden rounded-2xl border p-8 transition-all duration-300 hover:shadow-lg",
|
||||
service.borderColor,
|
||||
service.color,
|
||||
)}
|
||||
>
|
||||
<div className="absolute -right-16 -top-16 h-40 w-40 rounded-full border border-slate-100 dark:border-slate-800 opacity-50 group-hover:opacity-100 transition-opacity duration-500"></div>
|
||||
|
||||
<div className="relative z-10">
|
||||
<div className={cn("p-3 rounded-xl inline-block mb-4", service.color)}>
|
||||
<service.icon className={cn("w-8 h-8", service.iconColor)} />
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-bold tracking-tight mb-2 text-slate-900 dark:text-white">
|
||||
{t(`${service.key}.title`)}
|
||||
</h3>
|
||||
|
||||
<p className="text-sm font-medium text-slate-600 dark:text-slate-400 mb-4">
|
||||
{t(`${service.key}.subtitle`)}
|
||||
</p>
|
||||
|
||||
<p className="text-base text-slate-700 dark:text-slate-300 leading-relaxed text-justify">
|
||||
{t(`${service.key}.description`)}
|
||||
</p>
|
||||
|
||||
<div className="mt-6">
|
||||
<Link href={`/products/${service.key}`} className="inline-flex items-center text-sm font-medium text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 transition-colors">
|
||||
Learn more
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="w-4 h-4 ml-1"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<p className="text-muted-foreground text-base text-justify">
|
||||
{t("construction.description")}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Sides;
|
|
@ -6,7 +6,26 @@ import Sides from "./components/Sides";
|
|||
import graphql from "src/utils/graphql";
|
||||
import CounterDetail from "./components/CounterDetail";
|
||||
import { getLocale } from "next-intl/server";
|
||||
|
||||
import BackgroundCarousel from "src/components/BackgroundCarousel";
|
||||
const images = [
|
||||
{
|
||||
image: "/images/fmcg.jpg",
|
||||
title: "FMCG",
|
||||
link: "/products/fmcg",
|
||||
|
||||
},
|
||||
{
|
||||
image: "/images/construction.jpg",
|
||||
title: "Construction",
|
||||
link: "/products/construction",
|
||||
|
||||
},
|
||||
// {
|
||||
// url:"/images/feed.jpg",
|
||||
// name:"Feed",
|
||||
// link:"/products/feed"
|
||||
// }
|
||||
]
|
||||
|
||||
const gql_stats = `
|
||||
query Stats($locale:I18NLocaleCode) {
|
||||
|
@ -37,14 +56,15 @@ const Landing = async () => {
|
|||
const stats = await getStats()
|
||||
|
||||
return (
|
||||
<div className=" text-center text-6xl">
|
||||
<div className=" ">
|
||||
{" "}
|
||||
|
||||
{/* <HeroSection /> */}
|
||||
<BackgroundCarousel images={images} />
|
||||
<AboutUs />
|
||||
<Sides />
|
||||
<CounterDetail stats={stats} />
|
||||
|
||||
<Sides />
|
||||
|
||||
<Products />
|
||||
{/* <WhyHorizon/> */}
|
||||
|
||||
|
|
Loading…
Reference in New Issue