Skip to content

Commit 75ecfe9

Browse files
Merge pull request steam-bell-92#1530 from aaniya22/feature/keyboard-accessibility-search
fix: add / shortcut, clear-on-Escape search, and remove orphaned navbar rule
2 parents 52b6bac + e9c2ae9 commit 75ecfe9

3 files changed

Lines changed: 63 additions & 16 deletions

File tree

web-app/css/styles.css

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,6 @@ img {
181181
opacity: 0 !important;
182182
}
183183

184-
nav[aria-label="Primary"] {
185-
display: none;
186-
}
187184

188185
main>.hero-section:has(.hero-code-snippets) {
189186
display: none;

web-app/js/main.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,10 @@ document.addEventListener("DOMContentLoaded", function () {
11891189

11901190
input.addEventListener("keydown", function (e) {
11911191
if (e.key === "Escape") {
1192+
input.value = "";
1193+
syncSearchInputs("", input);
1194+
currentSearchQuery = "";
1195+
performSearch(false);
11921196
closeDropdown();
11931197
input.blur();
11941198
}
@@ -1213,11 +1217,29 @@ document.addEventListener("DOMContentLoaded", function () {
12131217
}
12141218
});
12151219

1220+
function isTypingInField(target) {
1221+
if (!target) return false;
1222+
var tag = target.tagName ? target.tagName.toLowerCase() : "";
1223+
return (
1224+
tag === "input" ||
1225+
tag === "textarea" ||
1226+
tag === "select" ||
1227+
target.isContentEditable
1228+
);
1229+
}
1230+
12161231
document.addEventListener("keydown", function (e) {
12171232
if ((e.ctrlKey || e.metaKey) && e.key === "k") {
12181233
e.preventDefault();
12191234
if (navSearchInput) navSearchInput.focus();
12201235
else if (searchInput) searchInput.focus();
1236+
return;
1237+
}
1238+
1239+
if (e.key === "/" && !isTypingInField(e.target)) {
1240+
e.preventDefault();
1241+
if (navSearchInput) navSearchInput.focus();
1242+
else if (searchInput) searchInput.focus();
12211243
}
12221244
});
12231245

web-app/tests-e2e/search.spec.js

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,36 @@
11
const { test, expect } = require('@playwright/test');
2-
32
test.describe('Search & Filter', () => {
43
test('should show autocomplete suggestions on typing and filter cards by category', async ({ page }) => {
54
await page.goto('/');
6-
75
// Scroll to projects to show the sidebar search
86
const exploreBtn = page.locator('#exploreBtn');
97
await exploreBtn.click();
10-
118
// Wait for sidebar to be active
129
await expect(page.locator('body')).toHaveClass(/sidebar-active/);
13-
1410
const searchInput = page.locator('#searchInput');
1511
const searchDropdown = page.locator('#searchDropdown');
1612
const resultsList = page.locator('#resultsList');
17-
1813
// Wait for the search input to become visible
1914
await expect(searchInput).toBeVisible();
20-
2115
// 1. Focus search input and type query
2216
await searchInput.focus();
2317
await searchInput.fill('2048');
24-
2518
// Verify autocomplete dropdown is active and shows matching suggestions
2619
await expect(searchDropdown).toHaveClass(/active/);
2720
const suggestionText = resultsList.locator('.dropdown-item-text');
2821
await expect(suggestionText).toContainText('2048');
29-
3022
// Clear search input to restore all cards
3123
await searchInput.fill('');
3224
await page.keyboard.press('Enter');
33-
3425
// 2. Click category tab "games" from sidebar
3526
const gamesTab = page.locator('.sidebar-tab[data-category="games"]');
3627
await gamesTab.click();
37-
3828
// Verify that the games tab has the active class
3929
await expect(gamesTab).toHaveClass(/active/);
40-
4130
// Verify only games category cards are displayed, and others are hidden
4231
const projectCards = page.locator('.project-card');
4332
const count = await projectCards.count();
4433
expect(count).toBeGreaterThan(0);
45-
4634
for (let i = 0; i < count; i++) {
4735
const card = projectCards.nth(i);
4836
const isVisible = await card.isVisible();
@@ -54,4 +42,44 @@ test.describe('Search & Filter', () => {
5442
}
5543
}
5644
});
57-
});
45+
46+
test('should support / shortcut, ignore / while typing, and clear on Escape', async ({ page }) => {
47+
await page.goto('/');
48+
const exploreBtn = page.locator('#exploreBtn');
49+
await exploreBtn.click();
50+
await expect(page.locator('body')).toHaveClass(/sidebar-active/);
51+
52+
const searchInput = page.locator('#searchInput');
53+
const navSearchInput = page.locator('#navSearchInput');
54+
const searchDropdown = page.locator('#searchDropdown');
55+
await expect(searchInput).toBeVisible();
56+
57+
// The app focuses #navSearchInput preferentially when it exists,
58+
// falling back to #searchInput otherwise.
59+
const focusedAfterShortcut = (await navSearchInput.count()) > 0
60+
? navSearchInput
61+
: searchInput;
62+
63+
// 1. Pressing "/" anywhere on the page (not focused in a field) should focus the search input
64+
await page.evaluate(() => document.activeElement && document.activeElement.blur());
65+
await page.keyboard.press('/');
66+
await expect(focusedAfterShortcut).toBeFocused();
67+
68+
// 2. Typing "/" while already focused in a text field should NOT be intercepted
69+
// (i.e. it should be inserted as a literal character, not just re-focus/no-op)
70+
await searchInput.fill('a/b');
71+
await expect(searchInput).toHaveValue('a/b');
72+
73+
// 3. Ctrl+K / Cmd+K should still focus the search input (existing shortcut, unchanged)
74+
await page.evaluate(() => document.activeElement && document.activeElement.blur());
75+
await page.keyboard.press('Control+k');
76+
await expect(focusedAfterShortcut).toBeFocused();
77+
78+
// 4. Escape should clear the input and close the dropdown
79+
await searchInput.fill('2048');
80+
await expect(searchDropdown).toHaveClass(/active/);
81+
await page.keyboard.press('Escape');
82+
await expect(searchInput).toHaveValue('');
83+
await expect(searchDropdown).not.toHaveClass(/active/);
84+
});
85+
});

0 commit comments

Comments
 (0)