173 lines
6.4 KiB
TypeScript
173 lines
6.4 KiB
TypeScript
import Image from "next/image";
|
|
import { Check } from "lucide-react";
|
|
import type { CmsProductContent } from "@/types/cms-landing";
|
|
|
|
const DEFAULT_TITLE =
|
|
"The product we offer is designed to meet your business needs.";
|
|
const DEFAULT_BODY =
|
|
"Social media marketing services are provided by companies or individuals who specialize in marketing strategies through social media platforms.";
|
|
|
|
function cardImageUrl(p: CmsProductContent) {
|
|
return p.images?.[0]?.image_url?.trim() || "/image/p1.png";
|
|
}
|
|
|
|
export default function ProductSection({
|
|
products,
|
|
}: {
|
|
products?: CmsProductContent[] | null;
|
|
}) {
|
|
const list = products?.filter((p) => p.id) ?? [];
|
|
|
|
if (list.length === 0) {
|
|
return (
|
|
<section className="bg-white py-32">
|
|
<div className="container mx-auto px-6">
|
|
<div className="mb-20 text-center">
|
|
<p className="mb-4 text-sm font-semibold uppercase tracking-widest text-gray-400">
|
|
Our Product
|
|
</p>
|
|
<h2 className="mx-auto max-w-3xl text-4xl font-extrabold leading-tight md:text-5xl whitespace-pre-line">
|
|
{DEFAULT_TITLE}
|
|
</h2>
|
|
</div>
|
|
<div className="grid grid-cols-1 items-center gap-16 md:grid-cols-2">
|
|
<div className="flex justify-center">
|
|
<Image
|
|
src="/image/p1.png"
|
|
alt="Product illustration"
|
|
width={520}
|
|
height={420}
|
|
className="object-contain"
|
|
/>
|
|
</div>
|
|
<div className="max-w-xl">
|
|
<div className="mb-6 flex h-12 w-12 items-center justify-center rounded-xl bg-[#fdecc8]">
|
|
<Image
|
|
src="/image/product-icon.png"
|
|
alt=""
|
|
width={22}
|
|
height={22}
|
|
/>
|
|
</div>
|
|
<h3 className="mb-4 text-2xl font-bold text-gray-900">
|
|
MediaHUB Content Aggregator
|
|
</h3>
|
|
<p className="mb-8 text-sm leading-relaxed text-gray-600 whitespace-pre-line">
|
|
{DEFAULT_BODY}
|
|
</p>
|
|
<button
|
|
type="button"
|
|
className="text-sm font-semibold text-[#966314] hover:underline"
|
|
>
|
|
Learn More →
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
const first = list[0];
|
|
const sectionTitle =
|
|
first?.primary_title?.trim() || "Products tailored to your business";
|
|
const subtitle = first?.secondary_title?.trim();
|
|
|
|
return (
|
|
<section className="bg-white py-32">
|
|
<div className="container mx-auto px-6">
|
|
<div className="mb-16 text-center">
|
|
<p className="mb-4 text-sm font-semibold uppercase tracking-widest text-gray-400">
|
|
Our Product
|
|
</p>
|
|
<h2 className="mx-auto max-w-3xl text-4xl font-extrabold leading-tight md:text-5xl whitespace-pre-line">
|
|
{list.length > 1 ? "Our Products" : sectionTitle}
|
|
</h2>
|
|
{subtitle && list.length > 1 ? (
|
|
<p className="mx-auto mt-4 max-w-2xl text-lg text-gray-600">{subtitle}</p>
|
|
) : null}
|
|
</div>
|
|
|
|
<div className="grid gap-10 md:grid-cols-2 lg:grid-cols-3">
|
|
{list.map((p) => {
|
|
const imgSrc = cardImageUrl(p);
|
|
const external = /^https?:\/\//i.test(imgSrc);
|
|
const rawDesc = p.description?.trim();
|
|
const lines = rawDesc
|
|
? rawDesc.split(/\r?\n/).map((l) => l.trim()).filter(Boolean)
|
|
: [];
|
|
const useBullets = lines.length > 1;
|
|
const bodyText = lines.length === 0 ? DEFAULT_BODY : rawDesc ?? "";
|
|
|
|
return (
|
|
<div
|
|
key={p.id}
|
|
className="flex flex-col overflow-hidden rounded-2xl border border-gray-100 bg-white shadow-sm"
|
|
>
|
|
<div className="relative flex aspect-[4/3] items-center justify-center bg-gray-50">
|
|
{external ? (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img
|
|
src={imgSrc}
|
|
alt=""
|
|
className="h-full w-full object-cover"
|
|
/>
|
|
) : (
|
|
<Image
|
|
src={imgSrc}
|
|
alt=""
|
|
width={480}
|
|
height={360}
|
|
className="object-contain"
|
|
/>
|
|
)}
|
|
</div>
|
|
<div className="flex flex-1 flex-col p-6">
|
|
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-xl bg-[#fdecc8]">
|
|
<Image
|
|
src="/image/product-icon.png"
|
|
alt=""
|
|
width={22}
|
|
height={22}
|
|
/>
|
|
</div>
|
|
<h3 className="mb-3 text-xl font-bold text-gray-900 whitespace-pre-line">
|
|
{p.primary_title?.trim() || "Product"}
|
|
</h3>
|
|
{p.secondary_title?.trim() ? (
|
|
<p className="mb-3 text-sm font-medium text-gray-500">
|
|
{p.secondary_title.trim()}
|
|
</p>
|
|
) : null}
|
|
{useBullets ? (
|
|
<ul className="mb-4 space-y-3">
|
|
{lines.map((item) => (
|
|
<li key={item} className="flex gap-3 text-sm text-gray-600">
|
|
<span className="mt-1 flex h-8 w-16 shrink-0 items-center justify-center rounded-full bg-[#fdecc8]">
|
|
<Check size={12} className="text-[#966314]" />
|
|
</span>
|
|
{item}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
) : (
|
|
<p className="mb-4 flex-1 text-sm leading-relaxed text-gray-600 whitespace-pre-line line-clamp-6">
|
|
{bodyText}
|
|
</p>
|
|
)}
|
|
<button
|
|
type="button"
|
|
className="mt-auto text-left text-sm font-semibold text-[#966314] hover:underline"
|
|
>
|
|
Learn More →
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|