Files
2026-03-16 09:32:35 -05:00

79 lines
3.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"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;
}
/** 移动端优先尝试唤醒小红书 appPC 新窗口打开。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>
);
}