feat(site): phase 18 - the Rust screenshots, web and app
All checks were successful
PR checks / checks (pull_request) Successful in 2m55s

Nine captures tagged rust (D65): the server list, feed, leaderboard,
live map, permissions and the RunicNPC profile editor on the web, and a
server's feed, its map and the player's Rust account in the app, from
an Android-app edge debug build.

D80: every name in a capture is a role (admin, moderator, player...),
from this phase on. D81: the Rust demo's players are mock data written
by scripts/mockRustDemo.mjs; the server, its status, map, permission
groups and RunicNPC sync state are the real Oxide test server's. The
captions and /modules/rust/ and /app/ say which part is a demo cast.

seedDemo.mjs gains --game rust (server row with a weekly wipe, public
presence for the demo, two NPC profiles, a VIP group). captureScreens.mjs
gains a click list per screen. The homepage shows the Rust live map beside
the UO capture (D76); three Rust docs pages carry their screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-10-22 22:05:06 -05:00
parent 4f38e29ad7
commit c47e9c1aa4
21 changed files with 745 additions and 29 deletions

View File

@@ -138,6 +138,23 @@ for (const shot of todo) {
try {
await page.goto(url, { waitUntil: 'networkidle2', timeout: 30_000 });
// A screen whose subject is behind a tab or a button the route cannot reach. Each step is
// the visible text the element starts with; the first visible button, link or tab that
// matches is clicked. A step that matches nothing fails the shot rather than capturing
// the wrong screen.
for (const label of shot.click ?? []) {
const clicked = await page.evaluate((text) => {
const candidates = [...document.querySelectorAll('button, a, [role="tab"], [role="button"], li')];
const hit = candidates.find(
(el) => el.offsetParent !== null && el.textContent.trim().startsWith(text),
);
if (hit) hit.click();
return Boolean(hit);
}, label);
if (!clicked) throw new Error(`nothing to click starting "${label}"`);
await new Promise((resolve) => setTimeout(resolve, 800));
}
if (shot.scrollY) {
await page.evaluate((y) => window.scrollTo(0, y), shot.scrollY);
}