Amir Hossein Moghiseh 2025-02-19 16:11:53 +03:30
parent 58051d3fcf
commit d6e2dbf8da
8 changed files with 174 additions and 296 deletions

View File

@ -1,4 +1,13 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "storage.adhorizonintl.com",
}
],
},
};
export default nextConfig;

View File

@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"embla-carousel-autoplay": "^8.5.2",
"embla-carousel-react": "^8.5.2",
"framer-motion": "^12.4.2",
"lucide-react": "^0.475.0",

View File

@ -5,6 +5,9 @@ settings:
excludeLinksFromLockfile: false
dependencies:
embla-carousel-autoplay:
specifier: ^8.5.2
version: 8.5.2(embla-carousel@8.5.2)
embla-carousel-react:
specifier: ^8.5.2
version: 8.5.2(react@19.0.0)
@ -1105,6 +1108,14 @@ packages:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
dev: true
/embla-carousel-autoplay@8.5.2(embla-carousel@8.5.2):
resolution: {integrity: sha512-27emJ0px3q/c0kCHCjwRrEbYcyYUPfGO3g5IBWF1i7714TTzE6L9P81V6PHLoSMAKJ1aHoT2e7YFOsuFKCbyag==}
peerDependencies:
embla-carousel: 8.5.2
dependencies:
embla-carousel: 8.5.2
dev: false
/embla-carousel-react@8.5.2(react@19.0.0):
resolution: {integrity: sha512-Tmx+uY3MqseIGdwp0ScyUuxpBgx5jX1f7od4Cm5mDwg/dptEiTKf9xp6tw0lZN2VA9JbnVMl/aikmbc53c6QFA==}
peerDependencies:

View File

@ -1,7 +1,8 @@
"use client";
import graphql from "src/utils/graphql";
import Landing from "src/view/Landing";
export default function Home() {
export default async function Home() {
return <Landing />;
}

View File

@ -1,77 +1,62 @@
"use client";
import React, { useContext } from "react";
import logo from "../../../assets/images/logo.png";
import Image from "next/image";
import test1 from "../../../assets/images/product/1.png";
import test2 from "../../../assets/images/product/2.png";
import test3 from "../../../assets/images/product/3.png";
import test4 from "../../../assets/images/product/4.png";
import Link from "next/link";
const CardNormal = ({ data, priority }) => {
const CardNormal = ({ product, priority }) => {
return (
<div className="group">
{" "}
<>
<Link href={`/products/${data.id}`} onClick={(e)=>e.preventDefault()} >
<Link href={`/products/${product.slug}`} onClick={(e) => e.preventDefault()} >
<div
className={` tr03 py-2 overflow-hidden xs:h-[270px] lg:h-[270px] border border-gray-200 ${1 == 1 ? "bg-white rounded-xl rounded-tl-[40px]" : " opacity-70"
className={`tr03 py-2 overflow-hidden xs:h-[270px] lg:h-[270px] border border-gray-200 ${1 == 1 ? "bg-white rounded-xl rounded-tl-[40px]" : " opacity-70"
}`}
>
<div className="w-full h-fit flex justify-center ">
{!!data.mainImage ? (
<div className="w-full h-full flex justify-center relative p-2 ">
{!!product?.images?.[0]?.url ? (
<Image
src={
data.mainImage == "1"
? test1
: data.mainImage == "2"
? test2
: data.mainImage == "3"
? test3
: data.mainImage == "4"
? test4
: test1
product?.images?.[0]?.url
}
width={200}
height={200}
className="xs:!w-[110px] lg:!w-[130px] mx-auto"
fill
className="object-contain"
priority={!!priority}
alt={`${data.persianName} - ${data.englishName}`}
alt={`${product?.images?.[0]?.alternativeText}`}
/>
) : (
<div className="xs:!w-[85px] lg:!w-[85px] h-[90px] xs:mt-5 lg:mt-10 ">
<Image
src={logo}
className="xs:!w-[70px] lg:!w-[70px] mx-auto opacity-25 mt-5"
alt="وسمه"
/>
</div>
)}
</div>
<div className="p-3 text-left">
<p className="mb-0 text-[16px] max-h-[44px] overflow-hidden font-bold ">
{data.englishName}
</p>
<p className="mb-0 text-[13px] text-gray-600 mt-2">
{data.description}
</p>
</div>
</div>
</Link>
</>
<div className="relative">
<div className="absolute w-full bottom-0 ">
<div className="bg-gray-100 rounded-t-3xl flex ltr mt-2 border border-gray-100 p-2 items-center">
<div className="flex w-full">
<div className="bg-gray-100 rounded-t-3xl ltr mt-2 border border-gray-100 p-2 flex flex-col gap-1">
<p className="mb-0 text-base text-left">
{product.title}
</p>
{/* <div className="flex w-full">
<p className="mb-0 text-base ">${data.cost.toLocaleString()}</p>
</div>
</div> */}
<div className="w-full text-right rounded-full pr-2">
<p className="mb-0 text-base rounded-lg underline">Detail</p>
<p className="mb-0 text-sm rounded-lg text-left">{product.category.title} - {product.brand.title}</p>
</div>
</div>
</div>

View File

@ -1,57 +1,69 @@
"use client"
import { useCallback } from "react"
import useEmblaCarousel from "embla-carousel-react"
import { ChevronLeft, ChevronRight } from "lucide-react"
import { useCallback } from "react"
import CardNormal from "../Cards/CardNormal/page"
import Autoplay from "embla-carousel-autoplay"
export function ProductCarouselSection({products}) {
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: false, align: "start" })
const scrollPrev = useCallback(() => {
if (emblaApi) emblaApi.scrollPrev()
}, [emblaApi])
const scrollNext = useCallback(() => {
if (emblaApi) emblaApi.scrollNext()
}, [emblaApi])
return (
<section className="py-12 px-4 md:px-6 lg:px-8">
<div className="max-w-7xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-2">Our Featured Products</h2>
<p className="text-xl text-center text-gray-600 mb-8">Discover our handpicked selection of top-quality items</p>
<div className="relative">
<div className="overflow-hidden" ref={emblaRef}>
<div className="flex">
{products.map((product) => (
<div
key={product.id}
className="flex-[0_0_100%] min-w-0 sm:flex-[0_0_50%] md:flex-[0_0_33.33%] lg:flex-[0_0_25%] pl-4"
>
<CardNormal {...product} />
</div>
))}
</div>
</div>
<button
variant="outline"
size="icon"
className="absolute top-1/2 left-4 transform -translate-y-1/2"
onClick={scrollPrev}
>
<ChevronLeft className="h-4 w-4" />
</button>
<button
variant="outline"
size="icon"
className="absolute top-1/2 right-4 transform -translate-y-1/2"
onClick={scrollNext}
>
<ChevronRight className="h-4 w-4" />
</button>
</div>
</div>
</section>
export default function ProductCarousel({ title, subtitle, products }) {
const [emblaRef, emblaApi] = useEmblaCarousel(
{ loop: true, align: "start" },
[
Autoplay({ delay: 3000, stopOnInteraction: true }),
]
)
}
const scrollPrev = useCallback(() => {
if (emblaApi) emblaApi.scrollPrev()
}, [emblaApi])
const scrollNext = useCallback(() => {
if (emblaApi) emblaApi.scrollNext()
}, [emblaApi])
return (
<section className="py-12 px-4 md:px-6 lg:px-8">
<div className="max-w-7xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-2">{title}</h2>
<p className="text-xl text-center text-gray-600 mb-8">{subtitle}</p>
<div className="relative">
<div className="overflow-hidden" ref={emblaRef}>
<div className="flex">
{products.map((product) => (
<div
key={product.id}
className="flex-[0_0_100%] min-w-0 sm:flex-[0_0_50%] md:flex-[0_0_33.33%] lg:flex-[0_0_25%] pl-4"
>
<CardNormal product={product} priority={true} />
</div>
))}
</div>
</div>
<button
variant="outline"
size="icon"
className="absolute top-1/2 left-4 transform -translate-y-1/2 bg-gray-200 rounded-full size-4"
onClick={scrollPrev}
>
<ChevronLeft className="h-4 w-4" />
</button>
<button
variant="outline"
size="icon"
className="absolute top-1/2 right-4 transform -translate-y-1/2 bg-gray-200 rounded-full size-4"
onClick={scrollNext}
>
<ChevronRight className="h-4 w-4" />
</button>
</div>
</div>
</section>
)
}

View File

@ -1,207 +1,11 @@
import Link from "next/link";
import React from "react";
import CardNormal from "src/components/Cards/CardNormal/page";
import ProductCarousel from "src/components/Carousel/ProductCarousel";
const Products = () => {
const data = [
{
id: 1,
persianName: "Hydrating Cream",
englishName: "Hydrating Cream",
description:
"A deeply moisturizing cream that keeps your skin hydrated all day long.",
cost: 250000,
costWithDiscount: 200000,
hasDiscount: true,
discountPercent: 20,
stock: 5,
mainImage: "4",
},
{
id: 2,
persianName: "Hair Strengthening Shampoo",
englishName: "Hair Strengthening Shampoo",
description:
"A nourishing shampoo that strengthens hair roots and prevents hair fall.",
cost: 180000,
costWithDiscount: 150000,
hasDiscount: true,
discountPercent: 17,
stock: 2,
mainImage: "3",
},
{
id: 3,
persianName: "Vitamin C Serum",
englishName: "Vitamin C Serum",
description:
"An antioxidant-rich serum that brightens skin and reduces signs of aging.",
cost: 300000,
costWithDiscount: 270000,
hasDiscount: true,
discountPercent: 10,
stock: 3,
mainImage: "1",
},
{
id: 4,
persianName: "Charcoal Face Mask",
englishName: "Charcoal Face Mask",
description:
"A detoxifying mask that removes impurities and unclogs pores for a fresh look.",
cost: 220000,
costWithDiscount: 220000,
hasDiscount: false,
discountPercent: 0,
stock: 8,
mainImage: "4",
},
{
id: 5,
persianName: "Body Lotion",
englishName: "Body Lotion",
description:
"A lightweight body lotion that nourishes and hydrates dry skin.",
cost: 210000,
costWithDiscount: 185000,
hasDiscount: true,
discountPercent: 12,
stock: 6,
mainImage: "2",
},
{
id: 6,
persianName: "Aloe Vera Gel",
englishName: "Aloe Vera Gel",
description:
"A soothing gel enriched with aloe vera to calm irritated skin.",
cost: 160000,
costWithDiscount: 160000,
hasDiscount: false,
discountPercent: 0,
stock: 10,
mainImage: "3",
},
{
id: 7,
persianName: "Sunscreen SPF 50",
englishName: "Sunscreen SPF 50",
description:
"A broad-spectrum sunscreen that protects against UV rays and prevents sunburn.",
cost: 280000,
costWithDiscount: 230000,
hasDiscount: true,
discountPercent: 18,
stock: 4,
mainImage: "1",
},
{
id: 8,
persianName: "Face Cleanser",
englishName: "Face Cleanser",
description:
"A gentle face cleanser that removes dirt and oil without stripping moisture.",
cost: 190000,
costWithDiscount: 170000,
hasDiscount: true,
discountPercent: 10,
stock: 7,
mainImage: "2",
},
{
id: 9,
persianName: "Moisturizing Cream",
englishName: "Moisturizing Cream",
description:
"A rich cream that provides deep hydration for soft and smooth skin.",
cost: 260000,
costWithDiscount: 260000,
hasDiscount: false,
discountPercent: 0,
stock: 9,
mainImage: "4",
},
{
id: 10,
persianName: "Eye Serum",
englishName: "Eye Serum",
description:
"A lightweight eye serum that reduces puffiness and dark circles.",
cost: 350000,
costWithDiscount: 310000,
hasDiscount: true,
discountPercent: 12,
stock: 5,
mainImage: "3",
},
{
id: 11,
persianName: "Lip Balm",
englishName: "Lip Balm",
description:
"A moisturizing lip balm that prevents chapped lips and adds a subtle shine.",
cost: 90000,
costWithDiscount: 80000,
hasDiscount: true,
discountPercent: 11,
stock: 12,
mainImage: "1",
},
{
id: 12,
persianName: "Hand Cream",
englishName: "Hand Cream",
description:
"A fast-absorbing hand cream that keeps hands soft and hydrated.",
cost: 170000,
costWithDiscount: 150000,
hasDiscount: true,
discountPercent: 12,
stock: 6,
mainImage: "2",
},
{
id: 13,
persianName: "Night Repair Serum",
englishName: "Night Repair Serum",
description:
"A serum that works overnight to repair and rejuvenate your skin.",
cost: 390000,
costWithDiscount: 350000,
hasDiscount: true,
discountPercent: 10,
stock: 4,
mainImage: "3",
},
{
id: 14,
persianName: "Shaving Cream",
englishName: "Shaving Cream",
description:
"A rich shaving cream that provides a smooth and irritation-free shave.",
cost: 200000,
costWithDiscount: 200000,
hasDiscount: false,
discountPercent: 0,
stock: 9,
mainImage: "4",
},
{
id: 15,
persianName: "Shaving ",
englishName: "Shaving ",
description:
"A fast-absorbing hand cream that keeps hands soft and hydrated.",
cost: 200000,
costWithDiscount: 200000,
hasDiscount: false,
discountPercent: 0,
stock: 9,
mainImage: "1",
},
];
const Products = ({ products }) => {
console.log(products)
return (
<div className="my-[120px]">
<div className="xs:px-3 md:px-10 md:container md:mx-auto mb-10">
@ -210,17 +14,26 @@ const Products = () => {
ADVANCED HORIZON SERVICES LLC Products{" "}
</h2>
<p className="mb-0 text-sm text-gray-400 xs:text-center lg:text-left">
</p>
</div>
<div className="grid xs:grid-cols-2 lg:grid-cols-5 gap-5">
{data?.map((e, index) => (
<div>
<ProductCarousel products={products.filter(p => p.brand.title === "active")} subtitle={""} title={"Active Products"} />
</div>
<div>
<ProductCarousel products={products.filter(p => p.brand.title === "savin")} subtitle={""} title={"Savin Products"} />
</div>
{/* <div className="grid grid-cols-1 lg:grid-cols-3 gap-5">
{products?.map((product, index) => (
<div key={index} className="relative">
<CardNormal data={e} priority />
<CardNormal product={product} priority />
</div>
))}
</div>
</div> */}
{/* <div className="flex justify-center">
<Link href={"categories/Product-20Listing-Page"}>

View File

@ -3,17 +3,63 @@ import AboutUs from "./components/AboutUs";
import Footer from "./components/Footer";
import Products from "./components/Products";
import Sides from "./components/Sides";
import graphql from "src/utils/graphql";
const Landing = () => {
const gql = `
query Products_connection($locale: I18NLocaleCode, $page: Int, $pageSize: Int) {
products_connection(
pagination: { page: $page, pageSize: $pageSize }
locale: $locale,
sort: ["createdAt:asc"]
) {
nodes {
title
documentId
images {
alternativeText
documentId
url
}
category {
documentId
title
slug
}
brand {
title
documentId
slug
}
slug
}
}
}
`
const getProducts = async () => {
const products = await graphql(gql, {
page: 1,
pageSize: 20,
locale: "en"
})
return products.products_connection.nodes;
}
const Landing = async () => {
const products = await getProducts()
console.log(products)
return (
<div className=" text-center text-6xl">
{" "}
<Navbar theme={1} />
{/* <HeroSection /> */}
<AboutUs />
<Sides/>
<Sides />
{/* <CounterDetail /> */}
<Products />
<Products products={products} />
{/* <WhyHorizon/> */}
<Footer />
</div>