79 lines
3.0 KiB
TypeScript
79 lines
3.0 KiB
TypeScript
"use client";
|
||
|
||
import Link from "next/link";
|
||
import Image from "next/image";
|
||
|
||
interface HostLinkProps {
|
||
host: { id: string; name: string; avatar: string; bio: string; link?: string };
|
||
/** 志愿者招募:无审核通过时显示「立即申请」+ 免费标识 */
|
||
ctaText?: string;
|
||
showFreeBadge?: boolean;
|
||
/** 卡片有 link 样式但不可点击跳转 */
|
||
noLink?: boolean;
|
||
}
|
||
|
||
/** 移动端优先尝试唤醒小红书 app,PC 新窗口打开。noLink 时仅展示,不跳转 */
|
||
export default function HostLink({ host, ctaText, showFreeBadge, noLink }: HostLinkProps) {
|
||
const href = "link" in host ? host.link : `/host/${host.id}`;
|
||
const isXiaohongshu = typeof href === "string" && (href.includes("xhslink.com") || href.includes("xiaohongshu.com"));
|
||
|
||
const handleClick = (e: React.MouseEvent) => {
|
||
if (noLink) {
|
||
e.preventDefault();
|
||
return;
|
||
}
|
||
if (!isXiaohongshu || typeof href !== "string") return;
|
||
const isMobile = /Android|iPhone|iPad|iPod|webOS|Mobile/i.test(navigator.userAgent);
|
||
if (isMobile) {
|
||
e.preventDefault();
|
||
// 移动端:同窗口打开,xhslink.com 会尝试唤起小红书 app,未安装则打开网页
|
||
window.location.assign(href);
|
||
}
|
||
};
|
||
|
||
if (typeof href !== "string") return null;
|
||
|
||
const cardClassName = "flex gap-3 sm:gap-4 p-4 sm:p-5 rounded-xl sm:rounded-2xl bg-white dark:bg-stone-900/80 border border-stone-200/80 dark:border-stone-700/80 hover:border-amber-200 dark:hover:border-amber-900/50 hover:shadow-lg transition-all";
|
||
const cardContent = (
|
||
<>
|
||
<div className="relative w-14 h-14 sm:w-16 sm:h-16 shrink-0 rounded-full overflow-hidden border-2 border-amber-100 dark:border-amber-900/30">
|
||
<Image src={host.avatar} alt={host.name} fill sizes="64px" className="object-cover" unoptimized />
|
||
</div>
|
||
<div className="min-w-0 flex-1 text-left">
|
||
<div className="flex items-center gap-2 flex-wrap">
|
||
<h3 className="font-semibold text-stone-800 dark:text-stone-100 text-sm sm:text-base">{host.name}</h3>
|
||
{showFreeBadge && (
|
||
<span className="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[10px] font-medium bg-emerald-100 dark:bg-emerald-900/40 text-emerald-700 dark:text-emerald-300">
|
||
FREE
|
||
</span>
|
||
)}
|
||
</div>
|
||
<p className="mt-0.5 text-xs sm:text-sm text-stone-500 dark:text-stone-400 line-clamp-2">{host.bio}</p>
|
||
<span className="inline-flex items-center gap-1 mt-2 text-amber-600 dark:text-amber-400 text-xs font-medium">
|
||
{ctaText ?? "查看主页"} →
|
||
</span>
|
||
</div>
|
||
</>
|
||
);
|
||
|
||
if (noLink) {
|
||
return (
|
||
<div className={`${cardClassName} cursor-default`}>
|
||
{cardContent}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<Link
|
||
href={href}
|
||
target={href.startsWith("http") ? "_blank" : undefined}
|
||
rel={href.startsWith("http") ? "noopener noreferrer" : undefined}
|
||
onClick={handleClick}
|
||
className={cardClassName}
|
||
>
|
||
{cardContent}
|
||
</Link>
|
||
);
|
||
}
|