- 原生 Next.js App Router + 严格 TypeScript 实现花魁短剧 PC/H5 页面,按 src/features/{catalog,content,playback} 组织,保留完整 SEO(metadata、JSON-LD、canonical、robots、llms、sitemap、IndexNow)。
- 主域名通过 SITE_URL=https://huakuidj.com 强制覆盖后端 foreverUrlAddr(config/*.env、src/server/config.ts、src/server/seo/shared.ts、src/server/services/shared.ts),支持邮箱改为 support@huakuidj.com。
- 移除登录与账户体系:删除 /account 全部页面、登录/注册/充值弹窗、收藏点赞、评论、金币解锁及对应 BFF 接口;旧账户地址 GET/HEAD 统一 301 到首页(src/lib/routes.ts REMOVED_ACCOUNT_PATHS),保留游客会话、反馈、图片上传、观看上报与搜索联想。
- 播放页:评论位改为同类推荐 + 热播榜单,锁定集改为 App 观看遮罩与底部弹层,新增简介标签、分集图例与独立视觉皮肤(src/features/playback、src/styles/pages/playback.css)。
- 卡片:短剧/视频卡状态与时长移至信息行胶囊标签,封面角标移至左上角(src/components/catalog/Cards.tsx、src/styles/foundations/base.css)。
- 同步更新单元测试、浏览器冒烟脚本、路由清单与 README。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
65 lines
3.1 KiB
TypeScript
65 lines
3.1 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
import { readFile } from "node:fs/promises";
|
|
import { basename, join } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
// Legacy fixture keys stay inside test infrastructure. Production imports semantic CSS paths.
|
|
const sourceStyles: Record<string, string> = {
|
|
"about-mobile": "src/styles/pages/about-responsive.css",
|
|
"about": "src/styles/pages/about.css",
|
|
"ads": "src/styles/components/advertising-compat.css",
|
|
"base": "src/styles/foundations/base.css",
|
|
"dialogAd": "src/styles/components/advertisement-dialog.css",
|
|
"downloadPop": "src/styles/components/app-download-dialog.css",
|
|
"eighteen": "src/styles/components/age-gate.css",
|
|
"feedback": "src/styles/pages/feedback.css",
|
|
"footer": "src/styles/components/site-footer.css",
|
|
"header": "src/styles/components/site-header.css",
|
|
"help": "src/styles/pages/help.css",
|
|
"index": "src/styles/pages/home.css",
|
|
"installGuide": "src/styles/components/installation-guide.css",
|
|
"legal": "src/styles/pages/legal.css",
|
|
"list": "src/styles/pages/drama-list.css",
|
|
"mobile-search": "src/styles/pages/mobile-search.css",
|
|
"mobileTabbar": "src/styles/components/mobile-tabbar.css",
|
|
"moreList": "src/styles/pages/expanded-list.css",
|
|
"nav": "src/styles/pages/site-navigation.css",
|
|
"notFound": "src/styles/pages/not-found.css",
|
|
"pagination": "src/styles/components/pagination.css",
|
|
"play": "src/styles/pages/playback.css",
|
|
"playLinks": "src/styles/components/playback-links.css",
|
|
"popularRecommend": "src/styles/pages/popular-recommendations.css",
|
|
"promo-grid": "src/styles/components/promotional-grid.css",
|
|
"promo": "src/styles/components/promotional-banner.css",
|
|
"pwa": "src/styles/overrides/pwa-safe-area.css",
|
|
"rank": "src/styles/pages/rankings.css",
|
|
"recentlyAdded": "src/styles/pages/recently-added.css",
|
|
"search": "src/styles/pages/search-results.css",
|
|
"series": "src/styles/pages/series-list.css",
|
|
"tags": "src/styles/pages/tag-detail.css",
|
|
"toast": "src/styles/components/toast.css",
|
|
"topic": "src/styles/pages/topics.css",
|
|
"topicDetail": "src/styles/pages/topic-detail.css",
|
|
"player": "src/styles/components/video-player.css"
|
|
};
|
|
|
|
export async function createStyleFixture(keys: readonly string[]) {
|
|
const root = fileURLToPath(new URL("..", import.meta.url));
|
|
const layout = await readFile(join(root, "src/app/layout.tsx"), "utf8");
|
|
const order = [...layout.matchAll(/^import ["']@\/([^"']+\.css)["'];/gm)].map((match) => "src/" + match[1]);
|
|
const files = [...new Set(keys.map((key) => {
|
|
const file = sourceStyles[key];
|
|
if (!file) throw new Error("Unknown fixture stylesheet: " + key);
|
|
return file;
|
|
}))].sort((first, second) => order.indexOf(first) - order.indexOf(second));
|
|
for (const file of files) {
|
|
if (!order.includes(file)) throw new Error("Fixture stylesheet is not imported by the root layout: " + file);
|
|
}
|
|
const css = (await Promise.all(files.map((file) => readFile(join(root, file), "utf8")))).join("\n");
|
|
return {
|
|
css,
|
|
href: "/fixture-" + createHash("sha256").update(css).digest("hex").slice(0, 12) + ".css",
|
|
tokens: files.map((file) => basename(file, ".css")).join(" "),
|
|
};
|
|
}
|