Files
web_huakui_web/scripts/compose-placeholder.ts
谢宇宁andClaude Opus 5.5 d2ddb1c321 [Ai] feat: 花魁短剧 Next.js 站点初始提交
- 原生 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>
2026-10-16 11:33:31 +07:00

46 lines
2.5 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.
import { createHash } from 'node:crypto';
import { readFile, writeFile } from 'node:fs/promises';
// Preserve the complete Figma SVG export as an image; never redraw or recolor its paths.
const brandFile = new URL('../public/static/brand/footer.svg', import.meta.url);
const outputFile = new URL('../public/static/brand/placeholder.svg', import.meta.url);
const manifestFile = new URL('../public/static/brand/placeholder.manifest.json', import.meta.url);
const brand = await readFile(brandFile);
const sha256 = (bytes: Buffer): string => createHash('sha256').update(bytes).digest('hex');
const width = 240;
const logoOpacity = 0.2;
const height = width * 44 / 124;
const x = (480 - width) / 2;
const y = (480 - height) / 2;
const svg = Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg" width="480" height="480" viewBox="0 0 480 480" role="img" aria-labelledby="placeholder-title">
<title id="placeholder-title">花魁短剧内容占位</title>
<rect width="480" height="480" fill="#26272f"/>
<image x="${x}" y="${y.toFixed(6)}" width="${width}" height="${height.toFixed(6)}" opacity="${logoOpacity}" preserveAspectRatio="xMidYMid meet" href="data:image/svg+xml;base64,${brand.toString('base64')}"/>
</svg>
`);
const manifest = Buffer.from(JSON.stringify({
file: 'public/static/brand/placeholder.svg',
width: 480, height: 480, sha256: sha256(svg),
source: 'Composition using the unmodified Figma brand export and the design panel background token.',
background: { color: '#26272f', source: 'Figma global panel token' },
composition: {
type: 'svg-container',
embeddedImage: {
file: 'public/static/brand/footer.svg',
source: 'https://www.figma.com/design/1vUq4wf5xOs8ZOlmt26Q3O/?node-id=1-706',
nodeId: '1:706', sha256: sha256(brand), encoding: 'base64', unmodified: true,
x, y: Number(y.toFixed(6)), width, height: Number(height.toFixed(6)), opacity: logoOpacity,
},
},
}, null, 2) + '\n');
if (process.argv.includes('--check')) {
const existing = await Promise.all([readFile(outputFile), readFile(manifestFile)]);
if (!existing[0].equals(svg) || !existing[1].equals(manifest)) {
throw new Error('Brand placeholder is out of date. Run tsx scripts/compose-placeholder.ts.');
}
console.log('Brand placeholder matches the complete unmodified Figma footer.svg export.');
} else {
await Promise.all([writeFile(outputFile, svg), writeFile(manifestFile, manifest)]);
console.log('Composed 480×480 brand placeholder from the complete unmodified Figma footer.svg export.');
}