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.
 
 
 

94 lines
3.7 KiB

import React from "react";
import Image from "next/image";
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 rounded-[20px] border border-[rgba(17,138,244,0.12)] bg-white/95 overflow-hidden shadow-[0_18px_42px_rgba(17,138,244,0.08)] transition-transform group-hover:-translate-y-0.5 group-hover:shadow-[0_18px_48px_rgba(17,138,244,0.16)]">
{/* 第一行:图片 */}
<div className="w-full aspect-[16/9] bg-gradient-to-br from-[#f0f9ff] to-[#e4f2ff] flex items-center justify-center p-4 md:p-6">
<div className="w-full h-full max-w-[400px] flex items-center justify-center relative">
<div className="w-full h-full flex items-center justify-center bg-gradient-to-br from-[#f0f9ff] to-[#e4f2ff] rounded-lg relative">
<Image
src={item.image}
alt={item.name}
fill
sizes="(max-width: 768px) 100vw, 400px"
className="object-contain"
style={{
mixBlendMode: 'multiply',
filter: 'contrast(1.1) brightness(1.02)'
}}
priority={false}
/>
</div>
</div>
</div>
{/* 第二行:文字内容 */}
<div className="p-4 md:p-5">
{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-2.5 text-[22px] font-semibold leading-tight text-[#0f1f39] group-hover:text-[#0b1a30] md:text-[24px]">
{item.name}
</h3>
{summary && (
<p className="mt-2 text-sm leading-relaxed text-[#4b5565] md:text-base">
{summary}
</p>
)}
{item.bullets && item.bullets.length > 0 && (
<ul className="mt-3 space-y-1.5 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] flex-shrink-0" aria-hidden="true" />
<span className="leading-relaxed">{bullet}</span>
</li>
))}
</ul>
)}
{item.badges && item.badges.length > 0 && (
<div className="mt-3.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-4 text-lg font-semibold text-[#118af4]">¥{item.price}</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>
);
}