"use client"; import Image from "next/image"; import Link from "next/link"; import type { CSSProperties } from "react"; import { Autoplay, Navigation, Pagination } from "swiper/modules"; import { Swiper, SwiperSlide } from "swiper/react"; import "swiper/css"; import "swiper/css/pagination"; import { ChevronLeft, ChevronRight } from "./icons"; import { toCssAspectRatio } from "@/lib/format"; import type { StaticImageSlot } from "@/lib/types"; export interface Slide { id: string; image: string; mobileImage?: string; href: string; alt: string; } // Default aspect ratios match the fallback banner assets: 700x400 mobile art, // 1296x366 desktop, so neither crop loses the headline. Kept in sync with the // "slider" entry in src/app/meshkee/static-image-slots/route.ts — see the // note there: if this ratio ever changes, that entry must change with it. const FALLBACK_ASPECT_CLASSES = "aspect-[7/4] md:aspect-[1296/366]"; // `slot` is the "slider" static-image slot (kind: list, duplicatable) — when // it has images they win over the `slides` fallback prop entirely. A CMS // slide is one image for every breakpoint (not a separate mobile crop), and // slot.aspectRatio (if set) drives the frame instead of the built-in default. export default function HeroSlider({ slot, slides = [] }: { slot?: StaticImageSlot; slides?: Slide[] }) { const fromCms = (slot?.images.length ?? 0) > 0; const items: Slide[] = fromCms ? slot!.images.map((img, i) => ({ id: img.id, image: img.url, href: img.linkUrl || "/products", alt: img.titleFa || img.titleEn || `بنر فروشگاه موبایل معلم ${i + 1}`, })) : slides; if (items.length === 0) return null; const cssAspect = fromCms ? toCssAspectRatio(slot?.aspectRatio) : undefined; const aspectStyle = cssAspect ? ({ aspectRatio: cssAspect } as CSSProperties) : undefined; return (
1} autoplay={{ delay: 5000, disableOnInteraction: false }} pagination={{ clickable: true, el: ".hero-dots" }} navigation={{ prevEl: ".hero-prev", nextEl: ".hero-next" }} className={`w-full ${aspectStyle ? "" : FALLBACK_ASPECT_CLASSES}`} style={aspectStyle} > {items.map((slide) => ( {fromCms ? ( {slide.alt} ) : ( <> {slide.alt} {slide.alt} )} ))}
{/* Swiper's own .swiper-pagination rules set left:0/width:100% on this element, so it is centred with justify-content rather than a translate — a translate would fight those and push it off-canvas. */}
); }