Files
jiang13-bbs/frontend/components/AdText.tsx
freefire d7c6b3a961 feat: 帖子收藏与用户关注
- 新增收藏功能:favorite 服务与 handler、FavoriteButton 组件
- 新增关注功能:follow 服务与 handler、FollowButton 组件
- 用户主页适配关注/粉丝与收藏展示
- flash 消息工具、广告与侧边栏组件微调
2026-09-26 03:02:40 +08:00

93 lines
2.3 KiB
TypeScript
Raw 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 { useEffect, useRef, useState, type CSSProperties } from "react";
import { AD_TIP_DELAY_MS, adHoverTip } from "@/lib/ads";
type AdTextProps = {
title: string;
textColor?: string;
bgColor?: string;
href?: string;
/** 广告到期时间(ISO 字符串):有值时气泡首行展示,无值时仅显示免责声明 */
endsAt?: string | null;
className?: string;
};
/**
* 文字广告:仅当文字宽度超出容器时才启用跑马灯滚动,
* 能完整显示时居中静止。结构与样式复用侧栏 .j13-ad-text。
*/
export function AdText({
title,
textColor,
bgColor,
href,
endsAt,
className = "",
}: AdTextProps) {
const trackRef = useRef<HTMLSpanElement>(null);
const [overflow, setOverflow] = useState(false);
useEffect(() => {
const track = trackRef.current;
if (!track) return;
const measure = () => {
const run = track.querySelector<HTMLElement>(".j13-ad-text-run");
const container = track.parentElement;
if (!run || !container) return;
setOverflow(run.scrollWidth > container.clientWidth);
};
measure();
window.addEventListener("resize", measure);
return () => window.removeEventListener("resize", measure);
}, [title]);
const cls = `j13-ad-text${overflow ? " is-overflow" : ""}${className ? ` ${className}` : ""}`;
const style: CSSProperties = { color: textColor, background: bgColor };
// 气泡首行:到期时间;第二行:免责声明
const tip = adHoverTip(endsAt);
const inner = (
<span
className={`j13-ad-text-track${overflow ? " is-overflow" : ""}`}
ref={trackRef}
>
<span className="j13-ad-text-run">{title}</span>
{overflow ? (
<span className="j13-ad-text-run" aria-hidden>
{title}
</span>
) : null}
</span>
);
if (href) {
return (
<a
href={href}
target="_blank"
rel="noopener noreferrer sponsored"
className={cls}
style={style}
data-tip={tip}
data-tip-delay={AD_TIP_DELAY_MS}
>
{inner}
</a>
);
}
return (
<span
className={cls}
style={style}
data-tip={tip}
data-tip-delay={AD_TIP_DELAY_MS}
>
{inner}
</span>
);
}
export default AdText;