responsive home page and layout

This commit is contained in:
hamid zarghami
2026-07-19 16:29:37 +03:30
parent 2adaac8ec4
commit cd266c057c
20 changed files with 198 additions and 137 deletions
+39 -5
View File
@@ -35,11 +35,37 @@ function useCarousel() {
return context; return context;
} }
type ResponsiveNumber = number | { base: number; md?: number; lg?: number };
function useResponsiveNumber(value: ResponsiveNumber): number {
const base = typeof value === "number" ? value : value.base;
const md = typeof value === "number" ? undefined : value.md;
const lg = typeof value === "number" ? undefined : value.lg;
const resolve = () => {
if (typeof window === "undefined") return base;
if (window.matchMedia("(min-width: 1024px)").matches) return lg ?? md ?? base;
if (window.matchMedia("(min-width: 768px)").matches) return md ?? base;
return base;
};
const [resolved, setResolved] = useState(base);
useEffect(() => {
const update = () => setResolved(resolve());
update();
window.addEventListener("resize", update);
return () => window.removeEventListener("resize", update);
}, [base, md, lg]);
return resolved;
}
type CarouselProps = { type CarouselProps = {
children: ReactNode; children: ReactNode;
slidesPerView?: number; slidesPerView?: ResponsiveNumber;
slidesToScroll?: number; slidesToScroll?: number;
gap?: number; gap?: ResponsiveNumber;
direction?: "rtl" | "ltr"; direction?: "rtl" | "ltr";
className?: string; className?: string;
}; };
@@ -52,10 +78,14 @@ const Carousel: FC<CarouselProps> = ({
direction = "rtl", direction = "rtl",
className, className,
}) => { }) => {
const resolvedSlidesPerView = useResponsiveNumber(slidesPerView);
const resolvedGap = useResponsiveNumber(gap);
const scrollBy = slidesToScroll ?? Math.max(1, Math.floor(resolvedSlidesPerView));
const [emblaRef, emblaApi] = useEmblaCarousel({ const [emblaRef, emblaApi] = useEmblaCarousel({
align: "start", align: "start",
direction, direction,
slidesToScroll: slidesToScroll ?? slidesPerView, slidesToScroll: scrollBy,
containScroll: "trimSnaps", containScroll: "trimSnaps",
}); });
@@ -80,6 +110,10 @@ const Carousel: FC<CarouselProps> = ({
}; };
}, [emblaApi]); }, [emblaApi]);
useEffect(() => {
emblaApi?.reInit({ slidesToScroll: scrollBy });
}, [emblaApi, scrollBy, resolvedSlidesPerView, resolvedGap]);
return ( return (
<CarouselContext.Provider <CarouselContext.Provider
value={{ value={{
@@ -87,8 +121,8 @@ const Carousel: FC<CarouselProps> = ({
scrollNext: () => emblaApi?.scrollNext(), scrollNext: () => emblaApi?.scrollNext(),
canScrollPrev, canScrollPrev,
canScrollNext, canScrollNext,
slidesPerView, slidesPerView: resolvedSlidesPerView,
gap, gap: resolvedGap,
}} }}
> >
<CarouselViewportContext.Provider value={emblaRef}> <CarouselViewportContext.Provider value={emblaRef}>
+4 -4
View File
@@ -20,10 +20,10 @@ const Home = () => {
<OrderRegistrationSteps /> <OrderRegistrationSteps />
<BlogsSection /> <BlogsSection />
<div className="mt-[120px] px-[120px]"> <div className="mt-12 px-4 sm:mt-16 sm:px-8 lg:mt-[120px] lg:px-[120px]">
<div className="bg-[#004A9005] p-16 w-full rounded-4xl border border-[#E9EEF2]"> <div className="bg-[#004A9005] p-6 sm:p-10 lg:p-16 w-full rounded-3xl lg:rounded-4xl border border-[#E9EEF2]">
<div className="font-bold text-2xl">چاپ جعبه، بستهبندی و محصولات تبلیغاتی با طراحی اختصاصی</div> <div className="font-bold text-lg sm:text-xl lg:text-2xl">چاپ جعبه، بستهبندی و محصولات تبلیغاتی با طراحی اختصاصی</div>
<div className="mt-6 leading-6 font-bold text-[#194873] text-sm"> <div className="mt-4 sm:mt-6 leading-6 font-bold text-[#194873] text-sm">
جعبه، اولین چیزی است که مشتری از برند شما میبیند. ما با ارائه خدمات چاپ جعبه، لیبل، استیکر، کارت ویزیت و سایر محصولات تبلیغاتی، به شما کمک میکنیم تا بستهبندی حرفهای و ماندگاری برای جعبه، اولین چیزی است که مشتری از برند شما میبیند. ما با ارائه خدمات چاپ جعبه، لیبل، استیکر، کارت ویزیت و سایر محصولات تبلیغاتی، به شما کمک میکنیم تا بستهبندی حرفهای و ماندگاری برای
محصولات خود داشته باشید. با استفاده از متریال باکیفیت، طراحی اختصاصی و چاپ دقیق، سفارش شما در کوتاهترین زمان آماده و ارسال میشود. محصولات خود داشته باشید. با استفاده از متریال باکیفیت، طراحی اختصاصی و چاپ دقیق، سفارش شما در کوتاهترین زمان آماده و ارسال میشود.
</div> </div>
+13 -7
View File
@@ -8,20 +8,26 @@ const BannerSection: FC = () => {
return ( return (
<div className="w-full"> <div className="w-full">
<div className="relative"> <div className="relative">
<Image src={banner} alt="banner" width={2000} height={574} className="w-full max-h-[574px] object-cover" /> <Image
<div className="absolute h-full right-[120px] top-0 bottom-0 m-auto flex flex-col justify-center"> src={banner}
<div className="text-base">چاپ و بسته بندی به روش هوشمندانه</div> alt="banner"
<div className="text-2xl font-black mt-4">مجــتمع تخصصــــــی</div> width={2000}
<div className="text-2xl font-black mt-4"> height={574}
className="w-full h-[420px] sm:h-[480px] lg:h-auto lg:max-h-[574px] object-cover"
/>
<div className="absolute inset-y-0 right-4 sm:right-8 lg:right-[120px] flex flex-col justify-center max-w-[min(100%,420px)] lg:max-w-none">
<div className="text-sm sm:text-base">چاپ و بسته بندی به روش هوشمندانه</div>
<div className="text-xl sm:text-2xl font-black mt-3 sm:mt-4">مجــتمع تخصصــــــی</div>
<div className="text-xl sm:text-2xl font-black mt-3 sm:mt-4">
چــــــاپ و بستــــه بندی <span className="text-primary">دستی</span> و <span className="text-primary">هوشمند</span>{" "} چــــــاپ و بستــــه بندی <span className="text-primary">دستی</span> و <span className="text-primary">هوشمند</span>{" "}
</div> </div>
<div className="mt-4 text-base flex flex-col gap-3"> <div className="mt-3 sm:mt-4 text-sm sm:text-base flex flex-col gap-2 sm:gap-3">
<div>قیمتهای عالی</div> <div>قیمتهای عالی</div>
<div>خدمات مشتریان بینظیر</div> <div>خدمات مشتریان بینظیر</div>
<div>سیستم سفارشگیری ساده</div> <div>سیستم سفارشگیری ساده</div>
</div> </div>
<div className="mt-4 flex gap-6 items-center"> <div className="mt-4 flex flex-wrap gap-3 sm:gap-6 items-center">
<Button> <Button>
<div className="flex gap-2.5"> <div className="flex gap-2.5">
<div>محصولات</div> <div>محصولات</div>
+10 -10
View File
@@ -32,20 +32,20 @@ const CategoryTile: FC<CategoryTileProps> = ({ title, image, featured }) => {
return ( return (
<div <div
className={cn( className={cn(
"relative overflow-hidden rounded-[40px]", "relative overflow-hidden rounded-[24px] sm:rounded-[40px]",
featured ? "col-span-2 row-span-2" : "aspect-square", featured ? "col-span-2 row-span-2 min-h-[220px] sm:min-h-0" : "aspect-square",
)} )}
> >
<Image src={image} alt={title} fill className="object-cover" sizes={featured ? "50vw" : "25vw"} /> <Image src={image} alt={title} fill className="object-cover" sizes={featured ? "(max-width: 768px) 100vw, 50vw" : "(max-width: 768px) 50vw, 25vw"} />
<div <div
className={cn( className={cn(
"absolute inset-x-4 bottom-4 flex items-center justify-between rounded-3xl bg-[#0A1B2C]/60 backdrop-blur-[2px]", "absolute inset-x-3 bottom-3 sm:inset-x-4 sm:bottom-4 flex items-center justify-between rounded-2xl sm:rounded-3xl bg-[#0A1B2C]/60 backdrop-blur-[2px]",
featured ? "px-6 py-3.5" : "px-5 py-3", featured ? "px-4 py-3 sm:px-6 sm:py-3.5" : "px-3 py-2.5 sm:px-5 sm:py-3",
)} )}
> >
<div className={cn("text-white font-bold", featured ? "text-lg" : "text-base")}>{title}</div> <div className={cn("text-white font-bold", featured ? "text-base sm:text-lg" : "text-sm sm:text-base")}>{title}</div>
<div className="flex items-center gap-1.5 text-white"> <div className="flex items-center gap-1.5 text-white">
<span className={cn("font-bold", featured ? "text-sm" : "text-xs")}>مشاهده</span> <span className={cn("font-bold", featured ? "text-xs sm:text-sm" : "text-xs")}>مشاهده</span>
<ArrowLeft size={featured ? 20 : 18} color="currentColor" /> <ArrowLeft size={featured ? 20 : 18} color="currentColor" />
</div> </div>
</div> </div>
@@ -55,10 +55,10 @@ const CategoryTile: FC<CategoryTileProps> = ({ title, image, featured }) => {
const BestSellerCategories: FC = () => { const BestSellerCategories: FC = () => {
return ( return (
<div className="mt-[120px] px-[120px]"> <div className="mt-12 px-4 sm:mt-16 sm:px-8 lg:mt-[120px] lg:px-[120px]">
<div className="font-bold text-2xl">دسته بندی های پرفروش</div> <div className="font-bold text-lg sm:text-2xl">دسته بندی های پرفروش</div>
<div className="mt-12 grid grid-cols-4 gap-10"> <div className="mt-8 sm:mt-12 grid grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6 lg:gap-10">
{categories.map((category) => ( {categories.map((category) => (
<CategoryTile key={category.title} title={category.title} image={category.image} featured={category.featured} /> <CategoryTile key={category.title} title={category.title} image={category.image} featured={category.featured} />
))} ))}
+4 -5
View File
@@ -1,17 +1,16 @@
import GridWrapper from "@/app/components/GridWrapper";
import { FC } from "react"; import { FC } from "react";
import BlogCard from "./BlogCard"; import BlogCard from "./BlogCard";
const BlogsSection: FC = () => { const BlogsSection: FC = () => {
return ( return (
<div className="mt-[120px] px-[120px]"> <div className="mt-12 px-4 sm:mt-16 sm:px-8 lg:mt-[120px] lg:px-[120px]">
<div className="text-2xl font-bold">مقالات ما</div> <div className="text-lg sm:text-2xl font-bold">مقالات ما</div>
<GridWrapper desktop={4} mobile={1} className="mt-12"> <div className="mt-8 sm:mt-12 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 lg:gap-10">
<BlogCard /> <BlogCard />
<BlogCard /> <BlogCard />
<BlogCard /> <BlogCard />
<BlogCard /> <BlogCard />
</GridWrapper> </div>
</div> </div>
); );
}; };
+3 -3
View File
@@ -9,9 +9,9 @@ type CategoryCardProps = {
const CategoryCard: FC<CategoryCardProps> = ({ title }) => { const CategoryCard: FC<CategoryCardProps> = ({ title }) => {
return ( return (
<div className="w-full bg-[#D4E3F154]/33 rounded-[40px] p-6"> <div className="w-full bg-[#D4E3F154]/33 rounded-[24px] sm:rounded-[40px] p-4 sm:p-6">
<div className="flex justify-between items-center"> <div className="flex justify-between items-center gap-2">
<div className="text-[#21588C] font-bold">{title}</div> <div className="text-[#21588C] font-bold text-sm sm:text-base">{title}</div>
<div className="bg-white/40 flex justify-center items-center"> <div className="bg-white/40 flex justify-center items-center">
<ArrowLeft size={20} color="currentColor" className="text-primary rotate-45" /> <ArrowLeft size={20} color="currentColor" className="text-primary rotate-45" />
</div> </div>
+5 -5
View File
@@ -16,14 +16,14 @@ const categories = [
const CategorySection = () => { const CategorySection = () => {
return ( return (
<div className="mt-[120px] px-[120px]"> <div className="mt-12 px-4 sm:mt-16 sm:px-8 lg:mt-[120px] lg:px-[120px]">
<Carousel slidesPerView={5} gap={40}> <Carousel slidesPerView={{ base: 1.4, md: 3, lg: 5 }} gap={{ base: 16, md: 24, lg: 40 }}>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center gap-4">
<div className="font-bold text-2xl">دسته بندی های محصولات</div> <div className="font-bold text-lg sm:text-2xl">دسته بندی های محصولات</div>
<CarouselControls prevLabel="دسته‌بندی‌های قبلی" nextLabel="دسته‌بندی‌های بعدی" /> <CarouselControls prevLabel="دسته‌بندی‌های قبلی" nextLabel="دسته‌بندی‌های بعدی" />
</div> </div>
<CarouselTrack className="mt-12"> <CarouselTrack className="mt-8 sm:mt-12">
{categories.map((title) => ( {categories.map((title) => (
<CarouselSlide key={title}> <CarouselSlide key={title}>
<CategoryCard title={title} /> <CategoryCard title={title} />
+7 -5
View File
@@ -6,13 +6,15 @@ import { type FC } from "react";
const ContactCtaSection: FC = () => { const ContactCtaSection: FC = () => {
return ( return (
<div className="mt-[120px] flex items-center justify-center gap-6 bg-linear-to-l from-primary/10 to-transparent py-10"> <div className="mt-12 sm:mt-16 lg:mt-[120px] flex flex-col sm:flex-row items-center justify-center gap-4 sm:gap-6 bg-linear-to-l from-primary/10 to-transparent px-4 py-8 sm:py-10">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3 text-center sm:text-right">
<Image src={deliveryTruckImage} alt="" width={40} height={40} className="size-10 object-contain" /> <Image src={deliveryTruckImage} alt="" width={40} height={40} className="size-10 object-contain shrink-0" />
<p className="text-xl font-bold text-[#0A1B2C] whitespace-nowrap">ارسال سریع به سراسر ایران | مشاوره رایگان قبل از سفارش</p> <p className="text-base sm:text-xl font-bold text-[#0A1B2C] sm:whitespace-nowrap">
ارسال سریع به سراسر ایران | مشاوره رایگان قبل از سفارش
</p>
</div> </div>
<Button className="gap-2 ps-5 pe-6 font-bold"> <Button className="gap-2 ps-5 pe-6 font-bold shrink-0">
<CallCalling size={20} color="currentColor" variant="Linear" /> <CallCalling size={20} color="currentColor" variant="Linear" />
تماس با ما تماس با ما
</Button> </Button>
+6 -6
View File
@@ -5,11 +5,11 @@ import ProductCard from "./ProductCard";
const OrderByApplication: FC = () => { const OrderByApplication: FC = () => {
return ( return (
<div className="p-[120px] bg-[#F1F6FA] mt-[120px]"> <div className="px-4 py-12 sm:px-8 sm:py-16 lg:p-[120px] bg-[#F1F6FA] mt-12 sm:mt-16 lg:mt-[120px]">
<div className="text-2xl font-bold">سفارش بر اساس کاربرد</div> <div className="text-lg sm:text-2xl font-bold">سفارش بر اساس کاربرد</div>
<Carousel slidesPerView={5} gap={40}> <Carousel slidesPerView={{ base: 1.4, md: 3, lg: 5 }} gap={{ base: 16, md: 24, lg: 40 }}>
<div className="flex mt-12 justify-between items-center"> <div className="flex mt-8 sm:mt-12 justify-between items-center gap-4">
<div> <div className="min-w-0 flex-1 max-w-[240px] sm:max-w-none sm:flex-none">
<Select <Select
options={[ options={[
{ {
@@ -30,7 +30,7 @@ const OrderByApplication: FC = () => {
<CarouselControls prevLabel="محصولات قبلی" nextLabel="محصولات بعدی" /> <CarouselControls prevLabel="محصولات قبلی" nextLabel="محصولات بعدی" />
</div> </div>
<CarouselTrack className="mt-12 px-3 py-4 -mx-3"> <CarouselTrack className="mt-8 sm:mt-12 px-2 sm:px-3 py-4 -mx-2 sm:-mx-3">
{Array.from({ length: 10 }).map((_, index) => ( {Array.from({ length: 10 }).map((_, index) => (
<CarouselSlide key={index}> <CarouselSlide key={index}>
<ProductCard /> <ProductCard />
@@ -4,9 +4,15 @@ import { FC } from "react";
const OrderRegistrationSteps: FC = () => { const OrderRegistrationSteps: FC = () => {
return ( return (
<div className="p-[120px] bg-[#F1F6FA] mt-[120px]"> <div className="px-4 py-12 sm:px-8 sm:py-16 lg:p-[120px] bg-[#F1F6FA] mt-12 sm:mt-16 lg:mt-[120px]">
<div className="text-2xl font-bold">سفارش بر اساس کاربرد</div> <div className="text-lg sm:text-2xl font-bold">سفارش بر اساس کاربرد</div>
<Image src={ImageSrc} alt="Order Registration Steps" width={1000} height={1000} className="w-full mt-12 h-auto object-contain" /> <Image
src={ImageSrc}
alt="Order Registration Steps"
width={1000}
height={1000}
className="w-full mt-8 sm:mt-12 h-auto object-contain"
/>
</div> </div>
); );
}; };
+5 -5
View File
@@ -4,14 +4,14 @@ import ProductCard from "./ProductCard";
const ProductSection: FC = () => { const ProductSection: FC = () => {
return ( return (
<div className="mt-[120px] px-[120px]"> <div className="mt-12 px-4 sm:mt-16 sm:px-8 lg:mt-[120px] lg:px-[120px]">
<Carousel slidesPerView={5} gap={40}> <Carousel slidesPerView={{ base: 1.4, md: 3, lg: 5 }} gap={{ base: 16, md: 24, lg: 40 }}>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center gap-4">
<div className="font-bold text-2xl">محبوبترین محصولات</div> <div className="font-bold text-lg sm:text-2xl">محبوبترین محصولات</div>
<CarouselControls prevLabel="محصولات قبلی" nextLabel="محصولات بعدی" /> <CarouselControls prevLabel="محصولات قبلی" nextLabel="محصولات بعدی" />
</div> </div>
<CarouselTrack className="mt-12 px-3 py-4 -mx-3"> <CarouselTrack className="mt-8 sm:mt-12 px-2 sm:px-3 py-4 -mx-2 sm:-mx-3">
{Array.from({ length: 10 }).map((_, index) => ( {Array.from({ length: 10 }).map((_, index) => (
<CarouselSlide key={index}> <CarouselSlide key={index}>
<ProductCard /> <ProductCard />
+17 -24
View File
@@ -1,32 +1,25 @@
import { ColorSwatch, Element4, LampCharge, Magicpen, Setting2, TruckFast } from "iconsax-reactjs"; import { ColorSwatch, Element4, LampCharge, Magicpen, Setting2, TruckFast } from "iconsax-reactjs";
import { FC } from "react"; import { FC } from "react";
const steps = [
{ label: "تحلیل نیاز برند", Icon: LampCharge },
{ label: "طراحی و آماده‌سازی فایل", Icon: Magicpen },
{ label: "انتخاب فناوری و متریال", Icon: Element4 },
{ label: "کنترل رنگ و نمونه‌گیری", Icon: ColorSwatch },
{ label: "عملیات تکمیلی", Icon: Setting2 },
{ label: "تحویل به موقع", Icon: TruckFast },
];
const StepSection: FC = () => { const StepSection: FC = () => {
return ( return (
<div className="w-full px-[120px] bg-secondary flex justify-between items-center h-[80px]"> <div className="w-full px-4 sm:px-8 lg:px-[120px] bg-secondary">
<div className="flex gap-4 3tems-center"> <div className="flex gap-6 lg:gap-4 lg:justify-between items-center h-auto py-4 lg:py-0 lg:h-[80px] overflow-x-auto scrollbar-none [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden">
<LampCharge variant="Bulk" size={24} color="currentColor" className="text-primary" /> {steps.map(({ label, Icon }) => (
<div className="font-bold text-sm">تحلیل نیاز برند</div> <div key={label} className="flex gap-3 items-center shrink-0">
</div> <Icon variant="Bulk" size={24} color="currentColor" className="text-primary" />
<div className="flex gap-3 items-center"> <div className="font-bold text-sm whitespace-nowrap">{label}</div>
<Magicpen variant="Bulk" size={24} color="currentColor" className="text-primary" /> </div>
<div className="font-bold text-sm">طراحی و آمادهسازی فایل</div> ))}
</div>
<div className="flex gap-3 items-center">
<Element4 variant="Bulk" size={24} color="currentColor" className="text-primary" />
<div className="font-bold text-sm">انتخاب فناوری و متریال</div>
</div>
<div className="flex gap-4 i3ems-center">
<ColorSwatch variant="Bulk" size={24} color="currentColor" className="text-primary" />
<div className="font-bold text-sm">کنترل رنگ و نمونهگیری</div>
</div>
<div className="flex gap-3 items-center">
<Setting2 variant="Bulk" size={24} color="currentColor" className="text-primary" />
<div className="font-bold text-sm">عملیات تکمیلی</div>
</div>
<div className="flex gap-43items-center">
<TruckFast variant="Bulk" size={24} color="currentColor" className="text-primary" />
<div className="font-bold text-sm">تحویل به موقع</div>
</div> </div>
</div> </div>
); );
+8 -8
View File
@@ -15,8 +15,8 @@ const categoryLinks = ["چاپ جعبه و بسته‌بندی", "جعبه ها
const Footer: FC = () => { const Footer: FC = () => {
return ( return (
<footer className="mt-auto border-t border-[#E9EEF2] bg-[#F7F9FB]"> <footer className="mt-auto border-t border-[#E9EEF2] bg-[#F7F9FB]">
<div className="px-[120px] pt-12 pb-6"> <div className="px-4 sm:px-8 lg:px-[120px] pt-8 sm:pt-12 pb-6">
<div className="flex justify-between gap-8"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:flex xl:justify-between gap-8 xl:gap-6">
<FooterContact /> <FooterContact />
<FooterLinkColumn title="راهنمای خرید" links={guideLinks} /> <FooterLinkColumn title="راهنمای خرید" links={guideLinks} />
<FooterLinkColumn title="خدمات مشتریان" links={serviceLinks} /> <FooterLinkColumn title="خدمات مشتریان" links={serviceLinks} />
@@ -25,19 +25,19 @@ const Footer: FC = () => {
<FooterTrustValues /> <FooterTrustValues />
</div> </div>
<Seprator className="my-8 h-px w-full" /> <Seprator className="my-6 sm:my-8 h-px w-full" />
<div className="flex items-center justify-between gap-8"> <div className="flex flex-col lg:flex-row items-center lg:items-start justify-between gap-8">
<FooterSocial /> <FooterSocial />
<Seprator className="h-16 w-px shrink-0" /> <Seprator className="hidden lg:block h-16 w-px shrink-0" />
<FooterTrustBadges /> <FooterTrustBadges />
<Seprator className="h-16 w-px shrink-0" /> <Seprator className="hidden lg:block h-16 w-px shrink-0" />
<FooterNewsletter /> <FooterNewsletter />
</div> </div>
<Seprator className="my-8 h-px w-full" /> <Seprator className="my-6 sm:my-8 h-px w-full" />
<p className="text-center text-xs text-[#6C7680]">تمامی حقوق برای سایت نیکوپکجینگ بوده و با ذکر نام لینک به منبع مجاز میباشد.</p> <p className="text-center text-xs text-[#6C7680] leading-5 px-2">تمامی حقوق برای سایت نیکوپکجینگ بوده و با ذکر نام لینک به منبع مجاز میباشد.</p>
</div> </div>
</footer> </footer>
); );
+34 -15
View File
@@ -8,33 +8,51 @@ import HeaderMenu from "./components/HeaderMenu";
const Header = () => { const Header = () => {
return ( return (
<div> <div>
<div className="h-12 bg-secondary flex items-center justify-between px-[120px]"> <div className="min-h-12 bg-secondary flex items-center justify-between gap-3 px-4 sm:px-8 lg:px-[120px] py-2">
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center min-w-0">
<span className="text-primary flex items-center gap-2"> <span className="text-primary flex items-center gap-2 min-w-0">
<Truck size={24} color="currentColor" /> <Truck size={20} color="currentColor" className="shrink-0 sm:size-6" />
<div className="text-[#3A4147] text-sm font-bold">ارسال رایگان برای خرید بالای ۱۰۰ میلیون تومان</div> <div className="text-[#3A4147] text-xs sm:text-sm font-bold truncate">ارسال رایگان برای خرید بالای ۱۰۰ میلیون تومان</div>
</span> </span>
</div> </div>
<div className="flex text-sm font-bold gap-2 items-center"> <div className="hidden md:flex text-sm font-bold gap-2 items-center shrink-0">
<span className="text-primary">20%</span> <span className="text-primary">20%</span>
<span>تخفیف برای اولین سفارش خود دریافت کنید |</span> <span className="hidden lg:inline">تخفیف برای اولین سفارش خود دریافت کنید |</span>
<span> <span>
کد تخفیف : <span className="text-primary">FIRSTORDER</span> کد تخفیف : <span className="text-primary">FIRSTORDER</span>
</span> </span>
</div> </div>
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center shrink-0">
<Profile className="text-primary" size={24} color="currentColor" /> <Profile className="text-primary" size={20} color="currentColor" />
<div>سلام حمید</div> <div className="hidden sm:block text-sm">سلام حمید</div>
</div> </div>
</div> </div>
<div className="bg-white h-[120px] flex gap-16 items-center border border-secondary px-[120px]">
<Image src={logo} alt="logo" width={116} height={72} /> <div className="bg-white flex flex-col gap-4 lg:flex-row lg:gap-16 lg:items-center lg:h-[120px] border border-secondary px-4 sm:px-8 lg:px-[120px] py-4 lg:py-0">
<div className="flex-1"> <div className="flex items-center justify-between gap-4 lg:contents">
<Image src={logo} alt="logo" width={116} height={72} className="h-12 w-auto sm:h-[72px] shrink-0" />
<div className="flex gap-4 items-center lg:hidden">
<button type="button" aria-label="پیگیری سفارش" className="text-[#6C7680]">
<TruckFast variant="Bold" color="currentColor" size={22} />
</button>
<button type="button" aria-label="تماس" className="text-[#6C7680]">
<Call variant="Bold" color="currentColor" size={22} />
</button>
<div className="relative">
<ShoppingCart variant="Bold" color="black" size={22} />
<div className="absolute -top-1.5 -right-1.5 bg-primary text-white text-xs font-medium rounded-full size-4 flex items-center justify-center">0</div>
</div>
</div>
</div>
<div className="flex-1 w-full">
<Input variant="search" placeholder="جستجوی محصول" /> <Input variant="search" placeholder="جستجوی محصول" />
</div> </div>
<div className="flex gap-8 items-center">
<div className="hidden lg:flex gap-8 items-center shrink-0">
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center">
<TruckFast variant="Bold" color="black" /> <TruckFast variant="Bold" color="black" />
<div className="text-[#6C7680] text-sm">پیگیری سفارش</div> <div className="text-[#6C7680] text-sm">پیگیری سفارش</div>
@@ -44,7 +62,7 @@ const Header = () => {
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center">
<Call variant="Bold" color="black" /> <Call variant="Bold" color="black" />
<div className="text-[#6C7680] text-sm">(30 خط) 02134782000</div> <div className="text-[#6C7680] text-sm whitespace-nowrap">(30 خط) 02134782000</div>
</div> </div>
<Seprator className="h-5 w-px" /> <Seprator className="h-5 w-px" />
@@ -55,6 +73,7 @@ const Header = () => {
</div> </div>
</div> </div>
</div> </div>
<HeaderMenu /> <HeaderMenu />
</div> </div>
); );
+23 -21
View File
@@ -42,28 +42,30 @@ const columns: CategoryGroup[][] = [
const AllProductsMenu: FC = () => { const AllProductsMenu: FC = () => {
return ( return (
<div className="absolute top-full right-[120px] z-50 mt-2 w-[1099px] rounded-[32px] bg-[#F9FAFB]/90 px-8 pt-8 pb-10"> <div className="absolute top-full z-50 mt-2 inset-x-4 sm:inset-x-8 lg:inset-x-auto lg:right-[120px] w-auto lg:w-[min(1099px,calc(100vw-240px))] max-h-[70vh] overflow-y-auto rounded-2xl sm:rounded-[32px] bg-[#F9FAFB]/95 backdrop-blur-sm px-4 sm:px-8 pt-6 sm:pt-8 pb-6 sm:pb-10 shadow-lg border border-[#E9EEF2]/80">
<div className="flex w-full items-start justify-between"> <div className="flex w-full flex-col lg:flex-row items-start justify-between gap-8">
{columns.map((groups) => ( <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-0 lg:contents w-full lg:w-auto">
<div key={groups[0].title} className="flex w-[228px] shrink-0 flex-col gap-6"> {columns.map((groups) => (
{groups.map((group) => ( <div key={groups[0].title} className="flex w-full lg:w-[228px] shrink-0 flex-col gap-6">
<div key={group.title} className="flex flex-col gap-2"> {groups.map((group) => (
<div className="flex h-10 items-center px-4 text-base font-bold text-black">{group.title}</div> <div key={group.title} className="flex flex-col gap-2">
{group.items.map((item) => ( <div className="flex h-10 items-center px-2 sm:px-4 text-sm sm:text-base font-bold text-black">{group.title}</div>
<button {group.items.map((item) => (
key={item} <button
type="button" key={item}
className="flex h-6 w-full items-center px-4 text-right text-base font-medium text-[#011E3A] transition-colors hover:text-primary" type="button"
> className="flex h-6 w-full items-center px-2 sm:px-4 text-right text-sm sm:text-base font-medium text-[#011E3A] transition-colors hover:text-primary"
{item} >
</button> {item}
))} </button>
</div> ))}
))} </div>
</div> ))}
))} </div>
))}
</div>
<div className="relative h-[157px] w-[163px] shrink-0 overflow-hidden rounded-2xl"> <div className="relative mx-auto lg:mx-0 h-[140px] w-[145px] sm:h-[157px] sm:w-[163px] shrink-0 overflow-hidden rounded-2xl">
<Image src={businessCardMenu} alt="کارت ویزیت" fill className="object-cover" sizes="163px" /> <Image src={businessCardMenu} alt="کارت ویزیت" fill className="object-cover" sizes="163px" />
</div> </div>
</div> </div>
+1 -1
View File
@@ -17,7 +17,7 @@ const ContactItem: FC<ContactItemProps> = ({ icon, children }) => {
const FooterContact: FC = () => { const FooterContact: FC = () => {
return ( return (
<div className="flex max-w-[280px] flex-col gap-5"> <div className="flex max-w-none sm:max-w-[280px] flex-col gap-5">
<ContactItem icon={<Location size={18} color="currentColor" variant="Linear" />}> <ContactItem icon={<Location size={18} color="currentColor" variant="Linear" />}>
جاده خاوران، شریف آباد، شهرک صنعتی شنزار، بعد از میدان چهارم، خیابان بوستان پنجم، خیابان گلبهار، پلاک ۱۲۲ جاده خاوران، شریف آباد، شهرک صنعتی شنزار، بعد از میدان چهارم، خیابان بوستان پنجم، خیابان گلبهار، پلاک ۱۲۲
</ContactItem> </ContactItem>
+1 -1
View File
@@ -3,7 +3,7 @@ import { type FC } from "react";
const FooterNewsletter: FC = () => { const FooterNewsletter: FC = () => {
return ( return (
<div className="flex max-w-[360px] flex-col gap-4"> <div className="flex w-full max-w-[360px] flex-col gap-4 lg:ms-auto">
<p className="text-sm leading-6 font-bold text-[#0A1B2C]">برای دریافت آخرین پیشنهادها، اخبار و مطالب الهامبخش، در خبرنامه ما عضو شوید.</p> <p className="text-sm leading-6 font-bold text-[#0A1B2C]">برای دریافت آخرین پیشنهادها، اخبار و مطالب الهامبخش، در خبرنامه ما عضو شوید.</p>
<form className="relative" action="#"> <form className="relative" action="#">
<input <input
+2 -2
View File
@@ -62,9 +62,9 @@ const socialLinks: SocialLink[] = [
const FooterSocial: FC = () => { const FooterSocial: FC = () => {
return ( return (
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4 items-center lg:items-start text-center lg:text-right">
<h3 className="text-sm font-bold text-[#0A1B2C]">ما را در شبکههای اجتماعی دنبال کنید</h3> <h3 className="text-sm font-bold text-[#0A1B2C]">ما را در شبکههای اجتماعی دنبال کنید</h3>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3 flex-wrap justify-center lg:justify-start">
{socialLinks.map((item) => ( {socialLinks.map((item) => (
<a key={item.label} href={item.href} aria-label={item.label} className={`flex size-9 items-center justify-center rounded-full ${item.bg}`}> <a key={item.label} href={item.href} aria-label={item.label} className={`flex size-9 items-center justify-center rounded-full ${item.bg}`}>
{item.icon} {item.icon}
+2 -2
View File
@@ -6,9 +6,9 @@ const FooterTrustBadges: FC = () => {
return ( return (
<div className="flex flex-col items-center gap-4"> <div className="flex flex-col items-center gap-4">
<h3 className="text-sm font-bold text-[#0A1B2C]">نماد های اعتماد</h3> <h3 className="text-sm font-bold text-[#0A1B2C]">نماد های اعتماد</h3>
<div className="flex items-center gap-4"> <div className="flex items-center gap-3 sm:gap-4 flex-wrap justify-center">
{badges.map((badge) => ( {badges.map((badge) => (
<div key={badge} className="flex size-16 items-center justify-center rounded-full border border-[#E9EEF2] bg-white text-center text-[10px] font-bold text-[#6C7680]"> <div key={badge} className="flex size-14 sm:size-16 items-center justify-center rounded-full border border-[#E9EEF2] bg-white text-center text-[10px] font-bold text-[#6C7680]">
{badge} {badge}
</div> </div>
))} ))}
+5 -5
View File
@@ -36,21 +36,21 @@ const HeaderMenu: FC = () => {
}, [isAllProductsOpen]); }, [isAllProductsOpen]);
return ( return (
<div ref={containerRef} className="relative h-[72px] w-full flex-1 px-[120px]"> <div ref={containerRef} className="relative h-14 sm:h-[72px] w-full flex-1 px-4 sm:px-8 lg:px-[120px]">
<div className="flex h-full items-center justify-center gap-8"> <div className="flex h-full items-center gap-4 sm:gap-6 lg:gap-8 overflow-x-auto scrollbar-none [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden lg:justify-center">
<button <button
type="button" type="button"
className={cn("flex items-center gap-2 font-bold transition-colors", isAllProductsOpen && "text-primary")} className={cn("flex items-center gap-2 font-bold transition-colors shrink-0 text-sm sm:text-base", isAllProductsOpen && "text-primary")}
onClick={() => setIsAllProductsOpen((open) => !open)} onClick={() => setIsAllProductsOpen((open) => !open)}
aria-expanded={isAllProductsOpen} aria-expanded={isAllProductsOpen}
aria-haspopup="true" aria-haspopup="true"
> >
<HamburgerMenu size={24} color="currentColor" /> <HamburgerMenu size={22} color="currentColor" />
<span>همه محصولات</span> <span>همه محصولات</span>
</button> </button>
{menuItems.map((item) => ( {menuItems.map((item) => (
<div key={item} className="font-bold"> <div key={item} className="font-bold shrink-0 whitespace-nowrap text-sm sm:text-base">
{item} {item}
</div> </div>
))} ))}