Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d8451baa3 | |||
| aba9eee0c6 | |||
| 85717d557d | |||
| 034bb7ff42 | |||
| 1236df31b8 | |||
| 74a7b0ea16 | |||
| 49be38ff77 |
BIN
public/logo.png
BIN
public/logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 358 KiB After Width: | Height: | Size: 1.4 MiB |
@ -35,7 +35,7 @@ export default function HeroBanner({
|
||||
if (!v || !videoSrc) return;
|
||||
v.muted = isMuted;
|
||||
v.play().catch(() => {});
|
||||
// 仅在 videoSrc 变化时执行 · 不依赖 isMuted(mute 切换由按钮处理)
|
||||
// 仅在 videoSrc 变化时执行 · 不依赖 isMuted(mute 切换由按钮处理)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [videoSrc]);
|
||||
|
||||
@ -93,7 +93,7 @@ export default function HeroBanner({
|
||||
{/* Eyebrow 左上 · 紧贴导航下方 */}
|
||||
<div className="absolute top-[6.5rem] sm:top-[7.5rem] left-4 sm:left-6 lg:left-8 z-10">
|
||||
<p className="font-label text-[10px] sm:text-xs tracking-[0.4em] uppercase text-purple-200/90">
|
||||
Top 12 · Virtual Idol Debut Project
|
||||
Top 12 · Cyber Star Debut Survival
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@ -25,9 +25,10 @@ export default function Logo({
|
||||
|
||||
// 用原生 <img> 绕开 Next/Image 的格式转换 —— 某些环境下 sharp 把透明 PNG
|
||||
// 转 webp/avif 时会铺白底,导致 logo 在深色 nav 上出现白色矩形。
|
||||
// ?v=2 缓存破坏:logo 改版时 +1,浏览器立刻拉新版而不读老缓存。
|
||||
const inner = (
|
||||
<img
|
||||
src="/logo.png"
|
||||
src="/logo.png?v=3"
|
||||
alt="CYBER STAR"
|
||||
decoding="async"
|
||||
draggable={false}
|
||||
@ -35,8 +36,6 @@ export default function Logo({
|
||||
height: `${h}px`,
|
||||
width: "auto",
|
||||
background: "transparent",
|
||||
// 保留紫色辉光,但 drop-shadow 不会引入白底
|
||||
filter: "drop-shadow(0 0 14px rgba(139,92,246,0.4))",
|
||||
}}
|
||||
className={`block select-none ${className}`}
|
||||
/>
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import Logo from "./Logo";
|
||||
import NavLinks from "./NavLinks";
|
||||
import SearchTrigger from "./SearchTrigger";
|
||||
import AuthMenu from "./auth/AuthMenu";
|
||||
@ -82,9 +81,7 @@ export default function Navigation() {
|
||||
)}
|
||||
/>
|
||||
<nav className="relative max-w-[1500px] mx-auto h-20 px-4 sm:px-6 lg:px-8 flex items-center gap-8">
|
||||
<Logo size="md" />
|
||||
|
||||
{/* 中部:首页 / 排行榜 / 我的 */}
|
||||
{/* 左侧:首页 / 排行榜 / 我的(logo 已移除) */}
|
||||
<NavLinks className="hidden md:flex" />
|
||||
|
||||
{/* 右侧:搜索 + 今日余票 + 登录/注册 (或 头像+下拉) */}
|
||||
|
||||
@ -40,8 +40,8 @@ export default function ArtistCard({
|
||||
className="block"
|
||||
aria-label={`查看 ${artist.name} 详情`}
|
||||
>
|
||||
{/* 立绘区(13+ 卡片轻度暗化) */}
|
||||
<div className={cn("relative aspect-[4/5]", !inTop12 && "opacity-[0.78]")}>
|
||||
{/* 立绘区 · Top12 区分仅靠紫色边框 + 辉光,不再降低非 Top12 卡片亮度 */}
|
||||
<div className="relative aspect-[4/5]">
|
||||
<ArtistPortrait
|
||||
artist={artist}
|
||||
rounded="rounded-none"
|
||||
@ -59,9 +59,6 @@ export default function ArtistCard({
|
||||
>
|
||||
{artist.rank}
|
||||
</div>
|
||||
|
||||
{/* 顶部轻微渐变蒙层 */}
|
||||
<div className="absolute inset-x-0 top-0 h-12 bg-gradient-to-b from-black/40 to-transparent pointer-events-none" />
|
||||
</div>
|
||||
|
||||
{/* 信息区(黑色背景明显分隔) */}
|
||||
|
||||
@ -324,7 +324,7 @@ export const ARTIST_SEEDS: ArtistSeed[] = [
|
||||
{
|
||||
no: `021`,
|
||||
name: `温景然`,
|
||||
enName: `RYAN`,
|
||||
enName: `KINGSTON`,
|
||||
age: 27,
|
||||
gender: `M`,
|
||||
height: 178,
|
||||
|
||||
@ -11,22 +11,34 @@ import { tosUrl } from "./tos";
|
||||
* 票数 / 排名是运行时计算(store 投票后会更新)。除此之外不再有任何虚构数据。
|
||||
*/
|
||||
|
||||
/** 没有 solo.mp4 的艺人编号(docx 标注"缺视频") */
|
||||
const MISSING_VIDEO: ReadonlySet<string> = new Set(["003", "010", "017", "027"]);
|
||||
/** 没有 solo.mp4 的艺人编号(docx 标注"缺视频")。
|
||||
003/010/017/027 在 v2 物料里已补上,033 已替换,这些都从集合里移除。 */
|
||||
const MISSING_VIDEO: ReadonlySet<string> = new Set<string>();
|
||||
|
||||
/** 缺氛围图3 的艺人编号(资料文件夹里实际只到氛围图2) */
|
||||
const MISSING_ATMOSPHERE_3: ReadonlySet<string> = new Set(["036"]);
|
||||
/**
|
||||
* 自定义封面:这些艺人的卡片/详情主立绘改用单独上传的 cover 图,
|
||||
* 而不是默认的氛围图1。氛围图1/2/3 在画廊里保持不变。
|
||||
* (调整.xlsx 里 "封面图用氛围图N" 的实现 —— 新封面已转 webp 上传到
|
||||
* portraits/{no}-cover.webp,这里把 portrait 字段切到该路径。)
|
||||
*/
|
||||
const CUSTOM_COVERS: ReadonlySet<string> = new Set([
|
||||
"002",
|
||||
"003",
|
||||
"005",
|
||||
"012",
|
||||
"013",
|
||||
"014",
|
||||
"019",
|
||||
"025",
|
||||
]);
|
||||
|
||||
/** 画廊 = 三张氛围图(1/2/3)。不包含三视图,因为长宽比与卡片不一致。 */
|
||||
function buildGallery(no: string): string[] {
|
||||
const items = [
|
||||
return [
|
||||
tosUrl(`portraits/${no}.webp`),
|
||||
tosUrl(`portraits/${no}-2.webp`),
|
||||
tosUrl(`portraits/${no}-3.webp`),
|
||||
];
|
||||
if (!MISSING_ATMOSPHERE_3.has(no)) {
|
||||
items.push(tosUrl(`portraits/${no}-3.webp`));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
function buildArtists(): Artist[] {
|
||||
@ -39,7 +51,11 @@ function buildArtists(): Artist[] {
|
||||
age: seed.age,
|
||||
gender: seed.gender,
|
||||
bio: seed.bio,
|
||||
portrait: tosUrl(`portraits/${seed.no}.webp`),
|
||||
portrait: tosUrl(
|
||||
CUSTOM_COVERS.has(seed.no)
|
||||
? `portraits/${seed.no}-cover.webp`
|
||||
: `portraits/${seed.no}.webp`,
|
||||
),
|
||||
avatar: "",
|
||||
gallery: buildGallery(seed.no),
|
||||
videoUrl: MISSING_VIDEO.has(seed.no)
|
||||
|
||||
@ -3,16 +3,21 @@
|
||||
*
|
||||
* 用法:
|
||||
* tosUrl("portraits/001.webp")
|
||||
* → https://cyberstar.tos-cn-shanghai.volces.com/cyber-star/portraits/001.webp
|
||||
* → https://cyberstar.tos-cn-shanghai.volces.com/cyber-star/portraits/001.webp?v=2
|
||||
*
|
||||
* 环境变量 NEXT_PUBLIC_TOS_DOMAIN 配置:
|
||||
* .env.local / .env.production → 完整的桶 + 路径前缀 (含 scheme, 不含末尾 /)
|
||||
* 未设置时 fallback 到相对路径 (/path/...), 适合本地用 public/ 静态文件托管的场景。
|
||||
*
|
||||
* 缓存版本号 TOS_VERSION:每次有 TOS 文件被原地覆盖更新(图片/视频),
|
||||
* 把这个数字 +1。浏览器和 CDN 会把带新版本号的 URL 当作全新资源,
|
||||
* 立即看到更新后的内容,不必等 TTL 过期或手动 invalidate。
|
||||
*/
|
||||
const TOS_BASE = (process.env.NEXT_PUBLIC_TOS_DOMAIN ?? "").replace(/\/+$/, "");
|
||||
const TOS_VERSION = "7";
|
||||
|
||||
export function tosUrl(path: string): string {
|
||||
const clean = path.replace(/^\/+/, "");
|
||||
if (!TOS_BASE) return `/${clean}`;
|
||||
return `${TOS_BASE}/${clean}`;
|
||||
const base = TOS_BASE ? `${TOS_BASE}/${clean}` : `/${clean}`;
|
||||
return `${base}?v=${TOS_VERSION}`;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user