All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m44s
- useSyncMe: 登录后拉 /api/me 用 votedArtists 覆盖本地 store,登出清本地 - Providers: SyncMeBridge 接入 SessionProvider - Logo v3 替换登录页/弹窗/Footer 的旧 <Logo> 组件 - Footer 删除 logo,简化为版权行 - Navigation 删除 mobile 第二行 NavLinks,合并到第一行 - NavLinks 统一布局,响应式 gap+字号(gap-5 sm:gap-8 / text-[13px] sm:text-sm) - HeroVoteProgress 窄屏(< md)隐藏 12 格点,只留文字 - scripts/screenshot-narrow.mjs 验证脚本(可配宽高) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
87 lines
4.1 KiB
JavaScript
87 lines
4.1 KiB
JavaScript
import { spawn } from "node:child_process";
|
|
import { writeFile } from "node:fs/promises";
|
|
import { setTimeout as wait } from "node:timers/promises";
|
|
|
|
const CHROME = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
|
|
const PORT = 9333;
|
|
const PROFILE = "C:\\Users\\10419\\AppData\\Local\\Temp\\cs-narrow-shot";
|
|
const OUT = process.env.SHOT_OUT || "d:/ClaudeProjects/虚拟明星/UI-UX/docs/screenshots/nav-overlap-narrow.png";
|
|
const WIDTH = Number(process.env.SHOT_WIDTH || 740);
|
|
const HEIGHT = Number(process.env.SHOT_HEIGHT || 1000);
|
|
|
|
const proc = spawn(CHROME, [
|
|
`--headless=new`, `--disable-gpu`, `--remote-debugging-port=${PORT}`,
|
|
`--user-data-dir=${PROFILE}`, `--hide-scrollbars`, `--no-first-run`, `about:blank`,
|
|
], { stdio: "ignore", detached: true });
|
|
proc.unref();
|
|
for (let i = 0; i < 30; i++) {
|
|
try { if ((await fetch(`http://127.0.0.1:${PORT}/json/version`)).ok) break; } catch {}
|
|
await wait(300);
|
|
}
|
|
const t = await (await fetch(`http://127.0.0.1:${PORT}/json/new?about:blank`, { method: "PUT" })).json();
|
|
const ws = new WebSocket(t.webSocketDebuggerUrl);
|
|
await new Promise(r => ws.addEventListener("open", () => r(), { once: true }));
|
|
let id = 0; const pending = new Map();
|
|
ws.addEventListener("message", (e) => {
|
|
const m = JSON.parse(e.data);
|
|
if (m.id && pending.has(m.id)) { const { resolve, reject } = pending.get(m.id); pending.delete(m.id);
|
|
if (m.error) reject(new Error(m.error.message)); else resolve(m.result); }
|
|
});
|
|
const cmd = (method, params = {}) => new Promise((resolve, reject) => {
|
|
pending.set(++id, { resolve, reject });
|
|
ws.send(JSON.stringify({ id, method, params }));
|
|
});
|
|
|
|
await cmd("Emulation.setDeviceMetricsOverride", {
|
|
width: WIDTH, height: HEIGHT, deviceScaleFactor: 1, mobile: false,
|
|
});
|
|
await cmd("Page.navigate", { url: "http://localhost:3000" });
|
|
await wait(3500);
|
|
await cmd("Runtime.evaluate", {
|
|
expression: `document.querySelectorAll('video').forEach(v => { try { v.pause(); } catch{} });`,
|
|
});
|
|
await wait(500);
|
|
const r = await cmd("Page.captureScreenshot", { format: "png" });
|
|
await writeFile(OUT, Buffer.from(r.data, "base64"));
|
|
|
|
// 同时取关键元素的位置信息
|
|
const layout = await cmd("Runtime.evaluate", {
|
|
returnByValue: true,
|
|
expression: `(() => {
|
|
const get = sel => {
|
|
const el = document.querySelector(sel);
|
|
if (!el) return null;
|
|
const r = el.getBoundingClientRect();
|
|
return { top: Math.round(r.top), left: Math.round(r.left), width: Math.round(r.width), height: Math.round(r.height), text: el.textContent?.trim().slice(0, 30) ?? '' };
|
|
};
|
|
return {
|
|
headerNav: get('header > nav'),
|
|
mobileNavLinks: get('header ul.md\\\\:hidden') || get('header [class*="md:hidden"] ul') || (() => {
|
|
// mobile NavLinks 在 header 下方第二行,找 header 内最后一个 ul
|
|
const uls = document.querySelectorAll('header ul');
|
|
const last = uls[uls.length - 1];
|
|
if (!last) return null;
|
|
const r = last.getBoundingClientRect();
|
|
return { top: Math.round(r.top), left: Math.round(r.left), width: Math.round(r.width), height: Math.round(r.height), text: last.textContent?.trim().slice(0, 30) ?? '' };
|
|
})(),
|
|
heroEyebrow: (() => {
|
|
const els = Array.from(document.querySelectorAll('p'));
|
|
const m = els.find(p => /Top 12.*Cyber Star/i.test(p.textContent || ''));
|
|
if (!m) return null;
|
|
const r = m.getBoundingClientRect();
|
|
return { top: Math.round(r.top), left: Math.round(r.left), width: Math.round(r.width), height: Math.round(r.height), text: m.textContent?.trim().slice(0, 40) ?? '' };
|
|
})(),
|
|
heroProgress: get('[data-hero-vote-progress]'),
|
|
};
|
|
})()`,
|
|
});
|
|
console.log("\n=== 关键元素位置(viewport 坐标)===");
|
|
for (const [k, v] of Object.entries(layout.result.value)) {
|
|
if (v) console.log(` ${k.padEnd(16)} top=${String(v.top).padStart(3)}px left=${String(v.left).padStart(3)}px w=${v.width} h=${v.height} "${v.text}"`);
|
|
else console.log(` ${k.padEnd(16)} (未找到)`);
|
|
}
|
|
console.log(`\n✓ ${OUT}`);
|
|
ws.close();
|
|
try { process.kill(proc.pid); } catch {}
|
|
spawn("taskkill", ["/F", "/PID", String(proc.pid), "/T"], { stdio: "ignore" });
|