nimiq-branding-cli 1.3.1 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LINT.md +9 -4
- package/package.json +1 -1
- package/scripts/lint.mjs +18 -8
package/LINT.md
CHANGED
|
@@ -129,13 +129,18 @@ Weight/tracking are heading-scoped (buttons and bold body labels are legitimatel
|
|
|
129
129
|
orphan check is general (it caught a body banner, not a heading) but gated at ≥ 20px so calibrated
|
|
130
130
|
fine-print under 20px — which wasn't measured on the reference — is never flagged.
|
|
131
131
|
|
|
132
|
-
**
|
|
132
|
+
**Responsive sweep (360 · 414 · 768 · 1024 · 1280px)**
|
|
133
|
+
|
|
134
|
+
The desktop pass renders at 1440; this sweep re-measures at five more widths so a layout that's
|
|
135
|
+
clean at phone *and* desktop but **breaks in the tablet / small-laptop no-man's-land** is caught —
|
|
136
|
+
the single most common responsive bug a fixed 390+1440 check misses. Measured: nimiq.com has **zero
|
|
137
|
+
horizontal overflow at every width** 320→1440, so overflow-at-a-breakpoint is calibrated to 0.
|
|
133
138
|
|
|
134
139
|
| Check | Threshold |
|
|
135
140
|
|---|---|
|
|
136
|
-
| horizontal overflow | `scrollWidth > viewport` by > 4px |
|
|
137
|
-
| tap targets too small | a button / input / link-button under 30px (
|
|
138
|
-
| text smaller than 12px | any text element below 12px at
|
|
141
|
+
| horizontal overflow at a breakpoint | `scrollWidth > viewport` by > 4px at **any** swept width (reports which widths and by how much) |
|
|
142
|
+
| tap targets too small | a button / input / link-button under 30px at any width (reports the worst breakpoint) |
|
|
143
|
+
| text smaller than 12px | any text element below 12px at any width (reports the worst breakpoint) |
|
|
139
144
|
|
|
140
145
|
The curated spacing scale (from `assets/css/modern/spacing.css`, desktop max of each step):
|
|
141
146
|
`8 · 12 · 16 · 24 · 32 · 40 · 48 · 72 · 80 · 96 · 144 · 200`. Sub-8px is treated as optical
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nimiq-branding-cli",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"description": "nq — pixel-verified Nimiq UI component registry + CLI. 39 components (Vue 3 + plain HTML) diffed against the real Nimiq apps, plus the team's real asset library. Unofficial community tool.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/scripts/lint.mjs
CHANGED
|
@@ -483,10 +483,20 @@ export async function lint(target, opts = {}) {
|
|
|
483
483
|
try { const en = page.locator('button.flag-btn', { hasText: 'English' }).first(); if (await en.count()) { await en.click({ timeout: 3000 }); await page.waitForLoadState('networkidle', { timeout: 12000 }).catch(() => {}); await page.waitForTimeout(1000); } } catch {}
|
|
484
484
|
await page.evaluate(async () => { const s = innerHeight * 0.8; for (let y = 0; y < document.body.scrollHeight; y += s) { scrollTo(0, y); await new Promise((r) => setTimeout(r, 200)); } scrollTo(0, 0); await new Promise((r) => setTimeout(r, 350)); });
|
|
485
485
|
const r = await page.evaluate(pageProbe, { SPACING_SCALE, ANCHORS, RADIUS_SCALE });
|
|
486
|
-
//
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
const
|
|
486
|
+
// responsive sweep — overflow / tap-targets / tiny-text across standard breakpoints. The 1440
|
|
487
|
+
// desktop pass above already covered the wide end; overflow at ANY intermediate width is the
|
|
488
|
+
// "no-man's-land" bug a fixed 390+1440 check misses. nimiq.com is overflow-clean at every width.
|
|
489
|
+
const SWEEP = [360, 414, 768, 1024, 1280];
|
|
490
|
+
const sweep = [];
|
|
491
|
+
for (const w of SWEEP) {
|
|
492
|
+
await page.setViewportSize({ width: w, height: 900 });
|
|
493
|
+
await page.waitForTimeout(350);
|
|
494
|
+
await page.evaluate(async () => { const s = innerHeight * 0.8; for (let y = 0; y < document.body.scrollHeight; y += s) { scrollTo(0, y); await new Promise((r) => setTimeout(r, 80)); } scrollTo(0, 0); await new Promise((r) => setTimeout(r, 120)); });
|
|
495
|
+
sweep.push({ w, ...(await page.evaluate(mobileProbe)) });
|
|
496
|
+
}
|
|
497
|
+
const overflowAt = sweep.filter((s) => s.overflowPx > 4);
|
|
498
|
+
const tapWorst = sweep.reduce((a, s) => (s.smallTargetN > a.smallTargetN ? s : a), sweep[0]);
|
|
499
|
+
const tinyWorst = sweep.reduce((a, s) => (s.tinyText > a.tinyText ? s : a), sweep[0]);
|
|
490
500
|
|
|
491
501
|
// social-icon exemption (run in Node — SOCIAL anchors aren't in the page context)
|
|
492
502
|
const socialName = (rgb) => { let best = Infinity, name = null; for (const [k, v] of Object.entries(SOCIAL)) { const d = Math.hypot(rgb[0] - v[0], rgb[1] - v[1], rgb[2] - v[2]); if (d < best) { best = d; name = k; } } return best <= SOCIAL_DELTA ? name : null; };
|
|
@@ -550,13 +560,13 @@ export async function lint(target, opts = {}) {
|
|
|
550
560
|
['flat-fill navy/colored section (use radial)', r.flatNavySection.length, r.flatNavySection[0]],
|
|
551
561
|
['focus outline removed w/o :focus-visible', r.noFocusRing ? 1 : 0, r.noFocusRing ? 'add a :focus-visible ring' : ''],
|
|
552
562
|
['Mulish not loaded (system-font fallback)', r.fontsNotLoaded ? 1 : 0, r.fontsNotLoaded ? 'load Mulish' : ''],
|
|
553
|
-
['
|
|
554
|
-
['
|
|
555
|
-
['text smaller than 12px
|
|
563
|
+
['horizontal overflow at a breakpoint', overflowAt.length, overflowAt.map((s) => `${s.w}px:${s.overflowPx}px`).join(' ')],
|
|
564
|
+
['tap targets < 36px (any breakpoint)', tapWorst.smallTargetN, tapWorst.smallTargetN ? `@${tapWorst.w}px ${tapWorst.smallTargets[0] || ''}` : ''],
|
|
565
|
+
['text smaller than 12px (any breakpoint)', tinyWorst.tinyText, tinyWorst.tinyText ? `@${tinyWorst.w}px, ${tinyWorst.tinyText} type(s)` : ''],
|
|
556
566
|
];
|
|
557
567
|
warnCount = warns.reduce((n, w) => n + (w[1] ? 1 : 0), 0);
|
|
558
568
|
|
|
559
|
-
if (opts.json) { out(JSON.stringify({ url, errorCount, warnCount, raw: r,
|
|
569
|
+
if (opts.json) { out(JSON.stringify({ url, errorCount, warnCount, raw: r, responsive: sweep, exemptSocial: exemptSocial.map(([c, v]) => ({ color: c, icon: v.social })) }, null, 2)); return { errorCount, warnCount }; }
|
|
560
570
|
|
|
561
571
|
out(`\n══════ nq lint — ${target} ══════\n`);
|
|
562
572
|
out('ERRORS (off-brand / a11y — must fix to pass)');
|