You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

83 lines
3.2 KiB

import React from "react";
import type { Product } from "../types";
export function ProductCard({ item, basePath = "" }: { item: Product; basePath?: string }) {
const hasLink = Boolean(item.href);
const summary = item.summary ?? item.description;
const Wrapper = hasLink ? "a" : "div";
const wrapperProps = hasLink ? { href: `${basePath}${item.href}` } : {};
const content = (
<div className="flex flex-col gap-6 rounded-[20px] border border-[rgba(17,138,244,0.12)] bg-white/95 p-6 shadow-[0_18px_42px_rgba(17,138,244,0.08)] transition-transform md:flex-row md:p-8 group-hover:-translate-y-0.5 group-hover:shadow-[0_18px_48px_rgba(17,138,244,0.16)]">
<div className="flex-1">
{item.eyebrow && (
<div className="inline-flex items-center gap-2 rounded-full bg-[#e4f2ff] px-3.5 py-1 text-[11px] font-semibold uppercase tracking-[0.24em] text-[#118af4]">
{item.eyebrow}
</div>
)}
<h3 className="mt-4 text-[22px] font-semibold leading-tight text-[#0f1f39] group-hover:text-[#0b1a30] md:text-[24px]">
{item.name}
</h3>
{summary && (
<p className="mt-3 text-sm leading-relaxed text-[#4b5565] md:text-base">
{summary}
</p>
)}
{item.bullets && item.bullets.length > 0 && (
<ul className="mt-4 space-y-2 text-sm text-[#1f2937] md:text-base">
{item.bullets.map((bullet, index) => (
<li key={index} className="flex items-start gap-2">
<span className="mt-[6px] inline-block h-1.5 w-1.5 rounded-full bg-[#118af4]" aria-hidden="true" />
<span className="leading-relaxed">{bullet}</span>
</li>
))}
</ul>
)}
{item.badges && item.badges.length > 0 && (
<div className="mt-5 flex flex-wrap gap-2.5">
{item.badges.map((badge, index) => {
const isPrimary = index === 0;
return (
<span
key={index}
className={[
"rounded-full px-4 py-2 text-xs font-semibold",
isPrimary
? "border border-[#d8e8fb] bg-[#f0f9ff] text-[#118af4]"
: "border border-transparent bg-[#f9fafb] text-[#4b5565]",
].join(" ")}
>
{badge}
</span>
);
})}
</div>
)}
{item.price != null && (
<div className="mt-6 text-lg font-semibold text-[#118af4]">¥{item.price}</div>
)}
</div>
<div className="mx-auto w-full max-w-[220px] md:w-52">
<div className="overflow-hidden rounded-2xl border border-[#d9e6f8] bg-white shadow-[0_10px_28px_rgba(15,31,57,0.12)]">
<img
src={item.image}
alt={item.name}
className="h-full w-full object-cover"
loading="lazy"
/>
</div>
</div>
</div>
);
return (
<Wrapper
{...(wrapperProps as Record<string, unknown>)}
className="group block focus:outline-none focus-visible:ring-2 focus-visible:ring-[#118af4]/60"
>
{content}
</Wrapper>
);
}