mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-06-06 04:21:46 +00:00
58282c91d8
## Summary Three follow-up fixes for #1065 gesture-hint discoverability: 1. **Touch-capability gate.** New `hasTouchCapability()` helper probes `'ontouchstart' in window`, `navigator.maxTouchPoints`, and `(pointer: coarse)`. Every `HINTS[*].relevant()` predicate now returns `false` immediately on mouse-only viewports, so desktop browsers no longer get "swipe a row left" tips. 2. **`width: fit-content` on the pill wrap.** The `.gesture-hint` block previously had no explicit width and defaulted to block-level full-width. Combined with `translateX(-50%)` on `.gesture-hint-bottom` this rendered as a 100vw-wide bar centered with a negative-X transform, i.e. pushed off-screen-left on narrow viewports (384px wrap on 390px viewport). 3. **CSS-parse safety.** Moved the in-body comment (which contained an em-dash) outside the rule block. An earlier attempt to add `width: fit-content` together with an in-body em-dash comment caused the parent `.gesture-hint` rule to vanish from the CSSOM in Chrome (children `.gesture-hint-*` remained). Putting the comment above the block sidesteps the parser bug. ## Test `test-issue-1065-gesture-hints-gates.js` — pure source-file assertions, no browser required. Red commit first (7 fails), green commit second (10/10 pass). Wired into `test-all.sh`. ## Verification After hot-deploy on staging: - Desktop (no touch): `document.querySelectorAll('.gesture-hint').length` === 0 - Mobile emulated (touch): hint rendered, `getBoundingClientRect().x >= 0`, `width <= 360`, `width < viewport_width` - CSSOM: parent `.gesture-hint` rule present with `width: fit-content` + `max-width: 360px` --------- Co-authored-by: openclaw-bot <bot@openclaw.local>
83 lines
3.7 KiB
JavaScript
83 lines
3.7 KiB
JavaScript
#!/usr/bin/env node
|
|
/* Issue #1065 follow-up — gesture hints must:
|
|
* 1. Define a hasTouchCapability() helper that probes ontouchstart,
|
|
* maxTouchPoints, and (pointer: coarse).
|
|
* 2. Gate every HINTS[*].relevant() body on hasTouchCapability() at the
|
|
* very top (no hint should fire on mouse-only viewports).
|
|
* 3. Ship a .gesture-hint parent CSS rule that includes
|
|
* `width: fit-content` AND `max-width: 360px` so the pill shrinks to
|
|
* its content instead of stretching full-bleed and being pushed
|
|
* off-screen by translateX(-50%) on narrow viewports.
|
|
*
|
|
* Pure source-file assertions — no browser required.
|
|
*/
|
|
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const JS_PATH = path.join(__dirname, 'public', 'gesture-hints.js');
|
|
const CSS_PATH = path.join(__dirname, 'public', 'style.css');
|
|
|
|
let failures = 0, passes = 0;
|
|
const fail = (m) => { failures++; console.error(' FAIL: ' + m); };
|
|
const pass = (m) => { passes++; console.log(' PASS: ' + m); };
|
|
|
|
const js = fs.readFileSync(JS_PATH, 'utf8');
|
|
const css = fs.readFileSync(CSS_PATH, 'utf8');
|
|
|
|
// (1) helper exists and probes the three signals
|
|
if (/function\s+hasTouchCapability\s*\(/.test(js)) pass('hasTouchCapability() defined');
|
|
else fail('hasTouchCapability() not defined in gesture-hints.js');
|
|
|
|
if (/ontouchstart/.test(js)) pass('hasTouchCapability probes ontouchstart');
|
|
else fail('hasTouchCapability missing ontouchstart probe');
|
|
|
|
if (/maxTouchPoints/.test(js)) pass('hasTouchCapability probes maxTouchPoints');
|
|
else fail('hasTouchCapability missing maxTouchPoints probe');
|
|
|
|
if (/pointer:\s*coarse/.test(js)) pass('hasTouchCapability probes (pointer: coarse)');
|
|
else fail('hasTouchCapability missing (pointer: coarse) probe');
|
|
|
|
// (2) every relevant() body must start with the touch gate
|
|
// Find each `relevant: function () { ... }` block and check.
|
|
const relevantRe = /relevant:\s*function\s*\(\s*\)\s*\{([\s\S]*?)\n\s{6}\}/g;
|
|
let m, count = 0, gated = 0;
|
|
while ((m = relevantRe.exec(js)) !== null) {
|
|
count++;
|
|
const body = m[1];
|
|
// First non-comment statement must be hasTouchCapability gate
|
|
if (/^\s*if\s*\(\s*!\s*hasTouchCapability\s*\(\s*\)\s*\)\s*return\s+false\s*;/m.test(body)) {
|
|
gated++;
|
|
}
|
|
}
|
|
if (count >= 4) pass(`found ${count} relevant() predicates`);
|
|
else fail(`expected ≥4 relevant() predicates, found ${count}`);
|
|
if (gated === count && count > 0) pass(`all ${gated}/${count} relevant() bodies start with !hasTouchCapability() return false`);
|
|
else fail(`only ${gated}/${count} relevant() bodies gate on hasTouchCapability()`);
|
|
|
|
// (3) .gesture-hint parent rule has width: fit-content + max-width: 360px
|
|
// Locate the rule block starting `.gesture-hint {` (NOT .gesture-hint-...).
|
|
const ruleRe = /\n\.gesture-hint\s*\{([\s\S]*?)\}/;
|
|
const ruleMatch = ruleRe.exec(css);
|
|
if (!ruleMatch) {
|
|
fail('.gesture-hint parent CSS rule not found in style.css');
|
|
} else {
|
|
pass('.gesture-hint parent CSS rule present');
|
|
const body = ruleMatch[1];
|
|
if (/\bwidth:\s*fit-content\b/.test(body)) pass('.gesture-hint declares width: fit-content');
|
|
else fail('.gesture-hint missing width: fit-content (pill must shrink to content)');
|
|
if (/\bmax-width:\s*360px\b/.test(body)) pass('.gesture-hint declares max-width: 360px');
|
|
else fail('.gesture-hint missing max-width: 360px');
|
|
}
|
|
|
|
// (4) defensive: no em-dash or stray "*/" inside .gesture-hint rule body
|
|
if (ruleMatch) {
|
|
const body = ruleMatch[1];
|
|
if (/[\u2014\u2013]/.test(body)) fail('em-dash / en-dash inside .gesture-hint rule body (CSS-parse-fragile)');
|
|
else pass('no em-dash inside .gesture-hint rule body');
|
|
}
|
|
|
|
console.log(`\ntest-issue-1065-gesture-hints-gates.js: ${passes} passed, ${failures} failed`);
|
|
process.exit(failures > 0 ? 1 : 0);
|