Wire homepage banners to Meshkee static-image slots.
Publish a slot catalog so the dashboard can import keys, and keep local placeholders when a slot is empty. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
46e4835360
commit
49b83223f1
+92
-28
@@ -1,47 +1,111 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { SlotImage } from "@/components/SlotImage";
|
||||
import { banners3, banners4 } from "@/lib/data";
|
||||
import type { StaticImageWithUrl } from "@/lib/static-images";
|
||||
import { slotAlt, slotAspectStyle } from "@/lib/static-images";
|
||||
import { Media } from "./Media";
|
||||
|
||||
export function BannerGrid4() {
|
||||
const banner4Overlay = {
|
||||
background: "linear-gradient(to top, rgba(0,0,0,0.88) 0%, rgba(0,0,0,0.55) 45%, transparent 100%)",
|
||||
};
|
||||
|
||||
type BannerSlotProps = {
|
||||
images?: StaticImageWithUrl[];
|
||||
aspectRatio?: string;
|
||||
};
|
||||
|
||||
export function BannerGrid4({ images = [], aspectRatio }: BannerSlotProps) {
|
||||
return (
|
||||
<section className="container-site mt-12">
|
||||
<div className="grid grid-cols-2 gap-3 md:gap-4">
|
||||
{banners4.map((banner) => (
|
||||
<Link key={banner.href} href={banner.href} className="relative block overflow-hidden rounded-2xl">
|
||||
<div className="relative aspect-[21/9] min-h-[140px]">
|
||||
<Image src={banner.image} alt="" fill sizes="50vw" className="object-cover object-center" />
|
||||
</div>
|
||||
<div
|
||||
className="pointer-events-none absolute inset-x-0 bottom-0 h-[70%]"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(to top, rgba(0,0,0,0.88) 0%, rgba(0,0,0,0.55) 45%, transparent 100%)",
|
||||
}}
|
||||
/>
|
||||
<div className="absolute inset-x-0 bottom-3 md:bottom-4 px-3 text-center text-white">
|
||||
<p className="text-base md:text-xl font-extrabold leading-none">{banner.title}</p>
|
||||
<p dir="ltr" className="mt-0.5 font-carter text-[9px] md:text-[10px] tracking-[0.4em] text-brand uppercase">
|
||||
{banner.english}
|
||||
</p>
|
||||
<p className="mt-0.5 text-sm md:text-base leading-tight text-white/90">{banner.subtitle}</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
{images.length > 0
|
||||
? images.map((image) => {
|
||||
const title = image.titleFa?.trim();
|
||||
const english = image.titleEn?.trim();
|
||||
const subtitle = image.subtext?.trim();
|
||||
const hasCopy = Boolean(title || english || subtitle);
|
||||
const frame = (
|
||||
<div
|
||||
className="relative overflow-hidden rounded-2xl"
|
||||
style={slotAspectStyle(aspectRatio, "21:9")}
|
||||
>
|
||||
<SlotImage image={{ ...image, linkUrl: null }} fill alt={slotAlt(image)} />
|
||||
{hasCopy ? (
|
||||
<>
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-[70%]" style={banner4Overlay} />
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-3 md:bottom-4 px-3 text-center text-white">
|
||||
{title ? (
|
||||
<p className="text-base md:text-xl font-extrabold leading-none">{title}</p>
|
||||
) : null}
|
||||
{english ? (
|
||||
<p
|
||||
dir="ltr"
|
||||
className="mt-0.5 font-carter text-[9px] md:text-[10px] tracking-[0.4em] text-brand uppercase"
|
||||
>
|
||||
{english}
|
||||
</p>
|
||||
) : null}
|
||||
{subtitle ? (
|
||||
<p className="mt-0.5 text-sm md:text-base leading-tight text-white/90">{subtitle}</p>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
return image.linkUrl ? (
|
||||
<a key={image.id} href={image.linkUrl} className="block">
|
||||
{frame}
|
||||
</a>
|
||||
) : (
|
||||
<div key={image.id}>{frame}</div>
|
||||
);
|
||||
})
|
||||
: banners4.map((banner) => (
|
||||
<Link key={banner.href} href={banner.href} className="relative block overflow-hidden rounded-2xl">
|
||||
<div className="relative aspect-[21/9] min-h-[140px]">
|
||||
<Image src={banner.image} alt={banner.title} fill sizes="50vw" className="object-cover object-center" />
|
||||
</div>
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-[70%]" style={banner4Overlay} />
|
||||
<div className="absolute inset-x-0 bottom-3 md:bottom-4 px-3 text-center text-white">
|
||||
<p className="text-base md:text-xl font-extrabold leading-none">{banner.title}</p>
|
||||
<p
|
||||
dir="ltr"
|
||||
className="mt-0.5 font-carter text-[9px] md:text-[10px] tracking-[0.4em] text-brand uppercase"
|
||||
>
|
||||
{banner.english}
|
||||
</p>
|
||||
<p className="mt-0.5 text-sm md:text-base leading-tight text-white/90">{banner.subtitle}</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export function BannerRow3() {
|
||||
export function BannerRow3({ images = [], aspectRatio }: BannerSlotProps) {
|
||||
return (
|
||||
<section className="container-site mt-12">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 md:gap-4">
|
||||
{banners3.map((banner) => (
|
||||
<Link key={banner.href} href={banner.href} className="overflow-hidden rounded-2xl">
|
||||
<Media src={banner.image} alt="" className="aspect-[2.4/1]" sizes="33vw" />
|
||||
</Link>
|
||||
))}
|
||||
{images.length > 0
|
||||
? images.map((image) => (
|
||||
<div key={image.id} className="overflow-hidden rounded-2xl">
|
||||
<SlotImage
|
||||
image={image}
|
||||
alt={slotAlt(image)}
|
||||
imgClassName="h-auto w-full object-cover"
|
||||
aspectRatio={aspectRatio}
|
||||
fallbackAspect="12:5"
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
: banners3.map((banner) => (
|
||||
<Link key={banner.href} href={banner.href} className="overflow-hidden rounded-2xl">
|
||||
<Media src={banner.image} alt={banner.alt} className="aspect-[2.4/1]" sizes="33vw" />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user