feat: redesign CMD+K button as macOS Spotlight-style search bar

Replace simple search button with search bar design in action bar:
- Semi-transparent styling integrated with dark action bar
- Keyboard shortcut indicators (⌘ K) shown as individual kbd elements
- Search icon and "Search" text for better discoverability
- Responsive: kbd keys hidden on mobile (<900px)
- Remove unused cmd-k-button.html partial template

Update test to verify new search bar structure (styling, kbd elements, icon).
This commit is contained in:
juanatsap
2025-12-04 12:59:16 +00:00
parent b5a50ca3ef
commit 404748afb5
6 changed files with 163 additions and 81 deletions
+77 -62
View File
@@ -2,11 +2,11 @@
/**
* CMD+K BUTTON FUNCTIONALITY TEST
* ================================
* Tests that the CMD+K button:
* - Has a distinct icon from zoom button
* Tests that the CMD+K search bar button:
* - Exists in the action bar with search bar styling
* - Has keyboard shortcut indicators (⌘ K)
* - Click handler opens ninja-keys
* - At-bottom illumination works
* - Has distinct color from zoom button
* - Has search icon and text
*/
import { chromium } from 'playwright';
@@ -14,7 +14,7 @@ import { chromium } from 'playwright';
const URL = "http://localhost:1999";
async function testCmdKButton() {
console.log('🎯 CMD+K BUTTON FUNCTIONALITY TEST\n');
console.log('🎯 CMD+K SEARCH BAR BUTTON TEST\n');
console.log('='.repeat(70));
const browser = await chromium.launch({ headless: process.env.HEADLESS === 'true' });
@@ -26,85 +26,100 @@ async function testCmdKButton() {
await page.waitForTimeout(2000);
// ========================================================================
// TEST 1: Button exists with distinct icon
// TEST 1: Button exists with search bar class
// ========================================================================
console.log('\n1️⃣ Testing button exists with distinct icon...');
console.log('\n1️⃣ Testing button exists with search bar styling...');
const cmdKButton = await page.$('#cmd-k-button');
const buttonExists = cmdKButton !== null;
console.log(` Button exists: ${buttonExists}`);
let iconsDistinct = false;
let hasSearchBarClass = false;
if (buttonExists) {
const cmdKIcon = await page.$eval('#cmd-k-button iconify-icon', el => el.getAttribute('icon'));
const zoomIcon = await page.$eval('#zoom-toggle-button iconify-icon', el => el.getAttribute('icon'));
console.log(` CMD+K icon: ${cmdKIcon}`);
console.log(` Zoom icon: ${zoomIcon}`);
iconsDistinct = cmdKIcon !== zoomIcon;
console.log(` ${iconsDistinct ? '✅ PASS' : '❌ FAIL'} - Icons are distinct`);
hasSearchBarClass = await page.$eval('#cmd-k-button', el => el.classList.contains('search-bar-btn'));
console.log(` Has search-bar-btn class: ${hasSearchBarClass}`);
console.log(` ${hasSearchBarClass ? '✅ PASS' : '❌ FAIL'} - Button has search bar styling`);
}
testResults.push({ test: 'Icons are distinct', passed: buttonExists && iconsDistinct });
testResults.push({ test: 'Button has search bar styling', passed: buttonExists && hasSearchBarClass });
// ========================================================================
// TEST 2: Button click opens ninja-keys
// TEST 2: Button has keyboard shortcut keys (kbd elements)
// ========================================================================
console.log('\n2️⃣ Testing button click opens ninja-keys...');
console.log('\n2️⃣ Testing keyboard shortcut indicators...');
let hasKbdElements = false;
if (buttonExists) {
const kbdCount = await page.$$eval('#cmd-k-button kbd', els => els.length);
hasKbdElements = kbdCount === 2; // Should have ⌘ and K
console.log(` Kbd elements found: ${kbdCount}`);
if (kbdCount === 2) {
const kbdTexts = await page.$$eval('#cmd-k-button kbd', els => els.map(el => el.textContent.trim()));
console.log(` Kbd contents: ${kbdTexts.join(', ')}`);
}
console.log(` ${hasKbdElements ? '✅ PASS' : '❌ FAIL'} - Has ⌘ K keyboard indicators`);
}
testResults.push({ test: 'Has keyboard shortcut indicators', passed: hasKbdElements });
// ========================================================================
// TEST 3: Button has search icon
// ========================================================================
console.log('\n3️⃣ Testing search icon...');
let hasSearchIcon = false;
if (buttonExists) {
const icon = await page.$eval('#cmd-k-button iconify-icon', el => el.getAttribute('icon'));
hasSearchIcon = icon && icon.includes('magnify');
console.log(` Icon: ${icon}`);
console.log(` ${hasSearchIcon ? '✅ PASS' : '❌ FAIL'} - Has search/magnify icon`);
}
testResults.push({ test: 'Has search icon', passed: hasSearchIcon });
// ========================================================================
// TEST 4: Button click opens ninja-keys
// ========================================================================
console.log('\n4️⃣ Testing button click opens ninja-keys...');
// First click triggers lazy load of ninja-keys
await page.click('#cmd-k-button');
await page.waitForTimeout(500);
await page.waitForTimeout(3000); // Wait for module to load (lazy loading)
const ninjaKeysOpen = await page.$eval('#cmd-k-bar', el => el.hasAttribute('open'));
console.log(` Ninja-keys open: ${ninjaKeysOpen}`);
console.log(` ${ninjaKeysOpen ? '✅ PASS' : '❌ FAIL'} - Click opens ninja-keys`);
testResults.push({ test: 'Click opens ninja-keys', passed: ninjaKeysOpen });
// Check if ninja-keys element was created and is open
const ninjaKeysState = await page.evaluate(() => {
const nk = document.getElementById('cmd-k-bar');
if (!nk) return { exists: false, isOpen: false };
// ninja-keys uses shadow DOM with .modal.visible class
const shadow = nk.shadowRoot;
const modal = shadow?.querySelector('.modal');
return {
exists: true,
isOpen: modal?.classList?.contains('visible') || nk.hasAttribute('open') || false
};
});
console.log(` Ninja-keys exists: ${ninjaKeysState.exists}`);
console.log(` Ninja-keys open: ${ninjaKeysState.isOpen}`);
const ninjaKeysOpened = ninjaKeysState.exists && ninjaKeysState.isOpen;
console.log(` ${ninjaKeysOpened ? '✅ PASS' : '❌ FAIL'} - Click opens ninja-keys`);
testResults.push({ test: 'Click opens ninja-keys', passed: ninjaKeysOpened });
// Close ninja-keys
await page.keyboard.press('Escape');
await page.waitForTimeout(300);
// ========================================================================
// TEST 3: At-bottom illumination
// TEST 5: Button has Search text
// ========================================================================
console.log('\n3️⃣ Testing at-bottom illumination...');
console.log('\n5️⃣ Testing Search text...');
// Scroll to very top - use scroll() which fires event naturally
await page.evaluate(() => window.scrollTo(0, 0));
await page.waitForTimeout(100);
// Trigger handleScroll manually via hyperscript's behavior
await page.evaluate(() => window.dispatchEvent(new Event('scroll')));
await page.waitForTimeout(300);
const atTopClass = await page.$eval('#cmd-k-button', el => el.classList.contains('at-bottom'));
console.log(` At top - has at-bottom class: ${atTopClass}`);
// Scroll to bottom using mouse wheel to trigger actual scroll
await page.mouse.wheel(0, 100000);
await page.waitForTimeout(1000);
const atBottomClass = await page.$eval('#cmd-k-button', el => el.classList.contains('at-bottom'));
const zoomAtBottomClass = await page.$eval('#zoom-toggle-button', el => el.classList.contains('at-bottom'));
const infoAtBottomClass = await page.$eval('#info-button', el => el.classList.contains('at-bottom'));
console.log(` At bottom - CMD+K has at-bottom: ${atBottomClass}`);
console.log(` At bottom - Zoom has at-bottom: ${zoomAtBottomClass}`);
console.log(` At bottom - Info has at-bottom: ${infoAtBottomClass}`);
const illuminationWorks = !atTopClass && atBottomClass;
console.log(` ${illuminationWorks ? '✅ PASS' : '❌ FAIL'} - At-bottom illumination works`);
testResults.push({ test: 'At-bottom illumination', passed: illuminationWorks });
// ========================================================================
// TEST 4: Distinct color from zoom button
// ========================================================================
console.log('\n4️⃣ Testing distinct color at bottom...');
const cmdKBgColor = await page.$eval('#cmd-k-button', el => window.getComputedStyle(el).backgroundColor);
const zoomBgColor = await page.$eval('#zoom-toggle-button', el => window.getComputedStyle(el).backgroundColor);
console.log(` CMD+K bg color: ${cmdKBgColor}`);
console.log(` Zoom bg color: ${zoomBgColor}`);
const colorsDistinct = cmdKBgColor !== zoomBgColor;
console.log(` ${colorsDistinct ? '✅ PASS' : '❌ FAIL'} - Colors are distinct`);
testResults.push({ test: 'Colors are distinct', passed: colorsDistinct });
let hasSearchText = false;
if (buttonExists) {
const searchText = await page.$eval('#cmd-k-button .search-bar-text', el => el.textContent.trim());
hasSearchText = searchText.toLowerCase() === 'search';
console.log(` Search text: "${searchText}"`);
console.log(` ${hasSearchText ? '✅ PASS' : '❌ FAIL'} - Has "Search" text`);
}
testResults.push({ test: 'Has Search text', passed: hasSearchText });
// ========================================================================
// FINAL SUMMARY