igneum/tools/ci/site-nav-check.mjs
igneum-labs a8461a2848 site-ui-4: the header on every page (six items, Download, the burger with its open state and aria), OS marks on the download cards, the footer redesign (icon row GitHub, Discord, Reddit; Contact eyebrow; one baseline grid; the state word and the year), the chip-model text (prize sentence cut, the bounded hot-set row), live-dag.js 2.0.2 narrow options for phones, the nav build check, the word-bounded rig-name check
The owner's orders of 7 October 2026 (header, logos, footer, phone scene) and the Counter ASIC lane's public text (docs/plans/counter-asic-3-public-text-2026-10-07.md, b10c7ac2) with the disclosure prize held back until its publish word.
Header: the one-screen home no longer hides items; the sheet carries exactly Litepaper, Miner, App, Wallet, Live devnet, Ledger and Download; 44 px bar links, 48 px sheet rows, the burger turns into an X; tools/ci/site-nav-check.mjs runs after every build and in the gate.
Cards: the Windows four-pane, Apple and Tux marks from 80c5618, white on the ember card, the card's own text colour on the mono cards (so they flip with the theme).
Footer: the ledger page renders through tools/ledger-page.mjs and now underlines Ledger; the Reddit profile is the one the owner named.
Renderer: narrow, narrowBreak 720, narrowWindow 30, narrowLanes 4, narrowMinNode 11; hairlines off except the selected chain; checkpoint labels as the percent; fps 60 on the home and /live mounts. Measured in headless chromium at 390 with 4x CPU throttling: 50 to 56 frames a second (the cap is 60).
Evidence row 17 rewritten in the table's eight columns. The forbidden list gains "disclosure prize" and the word-bounded rig names.
Tested with Playwright at 390 and 768 in both themes with real taps on every public page and the 404: 48 rows, 0 problems; captures in docs/plans/site-ui-4-shots/chrome.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 09:59:42 +00:00

26 lines
2.5 KiB
JavaScript

#!/usr/bin/env node
// Every served page carries the same header: the mark and wordmark, the six items (Litepaper, Miner, App, Wallet, Live devnet,
// Ledger) and the Download button, in the bar and in the sheet. A page with a shorter nav fails the build and the gate
// (the owner's rule, 7 October 2026: the header has all of these on every page and the mobile header works).
// node tools/ci/site-nav-check.mjs [site-dir]
import { readdirSync, readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const site = process.argv[2] || join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'site');
const ITEMS = [['/litepaper', 'Litepaper'], ['/miner', 'Miner'], ['/app', 'App'], ['/wallet', 'Wallet'], ['/live', 'Live devnet'], ['/ledger', 'Ledger']];
const pages = readdirSync(site).filter(f => f.endsWith('.html'));
const bad = [];
for (const page of pages) {
const html = readFileSync(join(site, page), 'utf8');
const nav = html.match(/<nav class="nav"[\s\S]*?<\/nav>/); if (!nav) { bad.push(`${page}: no <nav class="nav">`); continue; }
const bar = nav[0].match(/<div class="links" id="nav-links">[\s\S]*?<\/div>/), sheet = nav[0].match(/<div class="nav-sheet" id="nav-sheet">[\s\S]*?<\/div>/);
if (!bar || !sheet) { bad.push(`${page}: the bar or the sheet is missing`); continue; }
for (const [href, label] of ITEMS) for (const [name, part] of [['bar', bar[0]], ['sheet', sheet[0]]]) if (!new RegExp(`<a href="${href}"[^>]*>${label}<\\/a>`).test(part)) bad.push(`${page}: ${name} lacks ${label} (${href})`);
if (!/<a href="\/miner#get" class="btn primary small cta">Download<\/a>/.test(nav[0])) bad.push(`${page}: no Download button in the bar`);
if (!/<a href="\/miner#get" class="btn primary">Download<\/a>/.test(sheet[0])) bad.push(`${page}: no Download in the sheet`);
if (!/<button class="burger" id="nav-burger"[^>]*aria-expanded="false"[^>]*aria-controls="nav-sheet"/.test(nav[0])) bad.push(`${page}: the burger lacks its aria attributes`);
if (!/<span class="word">IGNEUM<\/span>/.test(nav[0])) bad.push(`${page}: no wordmark`);
if (/\.nav \.links a[^{]*\{[^}]*display:\s*none/.test(html) || /\.nav-sheet a[^{]*\{[^}]*display:\s*none/.test(html)) bad.push(`${page}: a page style hides header items`);
}
if (bad.length) { console.error('site nav check: ' + bad.length + ' problems\n' + bad.join('\n')); process.exit(1); }
console.log(`site nav check: ${pages.length} pages carry the six items, the Download button and the burger`);