mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-06-05 06:22:10 +00:00
440bda6244
## Summary Fixes the channel color picker UX issues on both Live page and Channels page. Closes #681 ## Repro Evidence (on master at HEAD) - **Live feed dots**: 12px inline — too small to reliably click in a fast-moving feed - **Right-click hijack**: `contextmenu` listener on live feed conflicts with browser context menu - **Channels page**: No way to clear an assigned color without opening the picker popover - **Popover positioning**: 8px edge margin causes overlap with panel borders ## Root Cause | Issue | File:Line | |-------|-----------| | Tiny dots | `public/live.js:2847` — inline `width:12px;height:12px` | | Context menu hijack | `public/channel-color-picker.js:231` — `feed.addEventListener('contextmenu', ...)` | | No clear affordance | `public/channels.js:1101` — dot rendered without adjacent clear button | | Popover overlap | `public/channel-color-picker.js:108-109` — `vw - pw - 8` margin | ## Fix 1. Increased feed color dots to 18px (visible, clickable) 2. Removed contextmenu listener from live feed — dots are the interaction point 3. Added inline `✕` clear button next to colored dots on channels page 4. Increased popover edge margin to 14px ## TDD Evidence - **Red commit:** `2034071` — 6/8 tests fail (dot size, contextmenu, clear affordance, margins) - **Green commit:** `49636e5` — all 8 tests pass ## Verification - `node test-color-picker-ux.js` — 8/8 pass - `node test-channel-color-picker.js` — 17/17 pass (existing tests unbroken) --------- Co-authored-by: you <you@example.com>
100 lines
3.8 KiB
JavaScript
100 lines
3.8 KiB
JavaScript
/**
|
|
* Tests for channel color picker UX fixes (#681)
|
|
*
|
|
* Verifies:
|
|
* 1. Live feed color dots are >= 16px (not tiny 12px)
|
|
* 2. No contextmenu handler on live feed that hijacks right-click
|
|
* 3. Channels page color dots with assigned color show clear affordance
|
|
* 4. Popover positioning respects viewport bounds with margin
|
|
*/
|
|
|
|
'use strict';
|
|
const vm = require('vm');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
|
|
function assert(condition, msg) {
|
|
if (condition) {
|
|
passed++;
|
|
console.log(` ✓ ${msg}`);
|
|
} else {
|
|
failed++;
|
|
console.error(` ✗ FAIL: ${msg}`);
|
|
}
|
|
}
|
|
|
|
// --- Test 1: Live feed dot size ---
|
|
console.log('\n=== Live feed color dot size (#681) ===');
|
|
|
|
const liveSource = fs.readFileSync(path.join(__dirname, 'public/live.js'), 'utf8');
|
|
|
|
// The feed-color-dot inline style should use width >= 16px
|
|
const dotMatch = liveSource.match(/feed-color-dot.*?width:(\d+)px/);
|
|
assert(dotMatch !== null, 'feed-color-dot has width in inline style');
|
|
if (dotMatch) {
|
|
const dotWidth = parseInt(dotMatch[1], 10);
|
|
assert(dotWidth >= 16, `feed-color-dot width is ${dotWidth}px (should be >= 16px)`);
|
|
}
|
|
|
|
// Height should match
|
|
const dotHeightMatch = liveSource.match(/feed-color-dot.*?height:(\d+)px/);
|
|
if (dotHeightMatch) {
|
|
const dotHeight = parseInt(dotHeightMatch[1], 10);
|
|
assert(dotHeight >= 16, `feed-color-dot height is ${dotHeight}px (should be >= 16px)`);
|
|
}
|
|
|
|
// --- Test 2: No contextmenu hijack on live feed ---
|
|
console.log('\n=== No right-click hijack on live feed (#681) ===');
|
|
|
|
const pickerSource = fs.readFileSync(path.join(__dirname, 'public/channel-color-picker.js'), 'utf8');
|
|
|
|
// The picker should NOT install a contextmenu listener on the live feed
|
|
// Look for the installLiveFeedHandlers function and check it doesn't add contextmenu
|
|
const liveFeedHandlerMatch = pickerSource.match(/function installLiveFeedHandlers\(\)[\s\S]*?^ \}/m);
|
|
if (liveFeedHandlerMatch) {
|
|
const handlerBody = liveFeedHandlerMatch[0];
|
|
assert(!handlerBody.includes("'contextmenu'") && !handlerBody.includes('"contextmenu"'),
|
|
'installLiveFeedHandlers does NOT add contextmenu listener');
|
|
} else {
|
|
// Alternative: check the entire picker source for liveFeed + contextmenu combo
|
|
// The feed variable + contextmenu listener pattern
|
|
const hasLiveFeedContextMenu = /feed\.addEventListener\(['"]contextmenu['"]/.test(pickerSource);
|
|
assert(!hasLiveFeedContextMenu, 'No contextmenu listener on liveFeed element');
|
|
}
|
|
|
|
// --- Test 3: Channels page clear affordance ---
|
|
console.log('\n=== Channels page clear affordance (#681) ===');
|
|
|
|
const channelsSource = fs.readFileSync(path.join(__dirname, 'public/channels.js'), 'utf8');
|
|
|
|
// Channels page should render a clear button/icon next to colored dots
|
|
// without requiring the picker to be opened
|
|
const hasClearAffordance = channelsSource.includes('ch-color-clear') ||
|
|
channelsSource.includes('color-clear');
|
|
assert(hasClearAffordance, 'Channels page has inline clear affordance for colored dots');
|
|
|
|
// --- Test 4: Popover positioning margin ---
|
|
console.log('\n=== Popover positioning margin (#681) ===');
|
|
|
|
// The popover positioning should use a margin of at least 12px from edges
|
|
// (not just 8px which causes overlap with panel borders)
|
|
const posMatch = pickerSource.match(/vw - pw - (\d+)/);
|
|
assert(posMatch !== null, 'Popover has horizontal edge margin');
|
|
if (posMatch) {
|
|
const margin = parseInt(posMatch[1], 10);
|
|
assert(margin >= 12, `Popover edge margin is ${margin}px (should be >= 12px)`);
|
|
}
|
|
|
|
const posMatchV = pickerSource.match(/vh - ph - (\d+)/);
|
|
if (posMatchV) {
|
|
const marginV = parseInt(posMatchV[1], 10);
|
|
assert(marginV >= 12, `Popover vertical margin is ${marginV}px (should be >= 12px)`);
|
|
}
|
|
|
|
// --- Summary ---
|
|
console.log(`\n${passed + failed} tests: ${passed} passed, ${failed} failed`);
|
|
process.exit(failed > 0 ? 1 : 0);
|