diff --git a/public/logo.png b/public/logo.png index 9fe3397..dece0d9 100644 Binary files a/public/logo.png and b/public/logo.png differ diff --git a/src/components/HeroBanner.tsx b/src/components/HeroBanner.tsx index b10b865..71481e3 100644 --- a/src/components/HeroBanner.tsx +++ b/src/components/HeroBanner.tsx @@ -28,14 +28,25 @@ export default function HeroBanner({ className, }: HeroBannerProps) { const videoRef = useRef(null); - const [isMuted, setIsMuted] = useState(true); + // 默认目标:带音播放。但浏览器对"带声音自动播放"有严格限制 —— + // 只有当用户与本站已有交互历史(autoplay policy "high engagement")时才允许。 + // 真实初始状态由下面的 effect 试播后写回:成功 → false,被拦截 → true。 + const [isMuted, setIsMuted] = useState(false); useEffect(() => { const v = videoRef.current; if (!v || !videoSrc) return; - v.muted = isMuted; - v.play().catch(() => {}); - // 仅在 videoSrc 变化时执行 · 不依赖 isMuted(mute 切换由按钮处理) + // 先尝试带音播放,失败立刻 fallback 静音播放(并把声音按钮置为静音态)。 + // 几乎所有首次访问场景都会走到 fallback,用户点声音按钮再解除静音。 + v.muted = false; + v.play() + .then(() => setIsMuted(false)) + .catch(() => { + v.muted = true; + setIsMuted(true); + v.play().catch(() => {}); + }); + // 仅在 videoSrc 变化时执行 · 不依赖 isMuted(mute 切换由按钮处理) // eslint-disable-next-line react-hooks/exhaustive-deps }, [videoSrc]); @@ -93,7 +104,7 @@ export default function HeroBanner({ {/* Eyebrow 左上 · 紧贴导航下方 */}

- Top 12 · Virtual Idol Debut Project + Top 12 · Cyber Star Debut Survival

diff --git a/src/components/Logo.tsx b/src/components/Logo.tsx index d91aba2..a65f4fd 100644 --- a/src/components/Logo.tsx +++ b/src/components/Logo.tsx @@ -25,9 +25,10 @@ export default function Logo({ // 用原生 绕开 Next/Image 的格式转换 —— 某些环境下 sharp 把透明 PNG // 转 webp/avif 时会铺白底,导致 logo 在深色 nav 上出现白色矩形。 + // ?v=2 缓存破坏:logo 改版时 +1,浏览器立刻拉新版而不读老缓存。 const inner = ( CYBER STAR diff --git a/src/components/cards/ArtistCard.tsx b/src/components/cards/ArtistCard.tsx index b774bd9..2539891 100644 --- a/src/components/cards/ArtistCard.tsx +++ b/src/components/cards/ArtistCard.tsx @@ -40,8 +40,8 @@ export default function ArtistCard({ className="block" aria-label={`查看 ${artist.name} 详情`} > - {/* 立绘区(13+ 卡片轻度暗化) */} -
+ {/* 立绘区 · Top12 区分仅靠紫色边框 + 辉光,不再降低非 Top12 卡片亮度 */} +
{artist.rank}
- - {/* 顶部轻微渐变蒙层 */} -
{/* 信息区(黑色背景明显分隔) */} diff --git a/src/lib/mock-data.ts b/src/lib/mock-data.ts index aa1c933..8e4f4d5 100644 --- a/src/lib/mock-data.ts +++ b/src/lib/mock-data.ts @@ -11,8 +11,9 @@ import { tosUrl } from "./tos"; * 票数 / 排名是运行时计算(store 投票后会更新)。除此之外不再有任何虚构数据。 */ -/** 没有 solo.mp4 的艺人编号(docx 标注"缺视频") */ -const MISSING_VIDEO: ReadonlySet = new Set(["003", "010", "017", "027"]); +/** 没有 solo.mp4 的艺人编号(docx 标注"缺视频")。 + 003/010/017/027 在 v2 物料里已补上,033 已替换,这些都从集合里移除。 */ +const MISSING_VIDEO: ReadonlySet = new Set(); /** * 自定义封面:这些艺人的卡片/详情主立绘改用单独上传的 cover 图, diff --git a/src/lib/tos.ts b/src/lib/tos.ts index de883fb..03674c0 100644 --- a/src/lib/tos.ts +++ b/src/lib/tos.ts @@ -14,7 +14,7 @@ * 立即看到更新后的内容,不必等 TTL 过期或手动 invalidate。 */ const TOS_BASE = (process.env.NEXT_PUBLIC_TOS_DOMAIN ?? "").replace(/\/+$/, ""); -const TOS_VERSION = "2"; +const TOS_VERSION = "3"; export function tosUrl(path: string): string { const clean = path.replace(/^\/+/, "");