Skip to content

Commit 7b1a69a

Browse files
Merge pull request steam-bell-92#1066 from priya05-git/fix/full-keyboard-navigation
Add: Full keyboard navigate
2 parents e604ebd + fa7340d commit 7b1a69a

2 files changed

Lines changed: 254 additions & 0 deletions

File tree

web-app/css/styles.css

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5269,6 +5269,36 @@ html[data-theme="dark"] body {
52695269
box-shadow: none;
52705270
}
52715271

5272+
:focus-visible {
5273+
outline: 3px solid var(--primary-color);
5274+
outline-offset: 4px;
5275+
}
5276+
5277+
button:focus-visible,
5278+
.tab:focus-visible,
5279+
.project-card:focus-visible,
5280+
.btn-play:focus-visible,
5281+
.btn-random-project:focus-visible,
5282+
.theme-toggle:focus-visible,
5283+
.modal-close:focus-visible,
5284+
.choice-btn:focus-visible,
5285+
.btn-reset:focus-visible,
5286+
.btn-roll:focus-visible,
5287+
.btn-flip:focus-visible,
5288+
.btn-generate:focus-visible,
5289+
.calc-btn:focus-visible,
5290+
.dropdown-item:focus-visible,
5291+
.dropdown-recent-text:focus-visible,
5292+
.dropdown-recent-remove:focus-visible {
5293+
outline: 3px solid var(--primary-color);
5294+
outline-offset: 4px;
5295+
}
5296+
5297+
/* Hero Section */
5298+
.hero {
5299+
padding: 4rem 0;
5300+
text-align: center;
5301+
background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(139, 92, 246, 0.1));
52725302
.btn-explore,
52735303
.btn-secondary-hero,
52745304
.btn-random-project,
@@ -5473,6 +5503,90 @@ html[data-theme="dark"] body {
54735503
border: 1px solid rgba(128, 104, 85, 0.08);
54745504
}
54755505

5506+
.dropdown-item,
5507+
.dropdown-recent-text,
5508+
.dropdown-recent-remove {
5509+
border: none;
5510+
background: transparent;
5511+
color: inherit;
5512+
cursor: pointer;
5513+
font: inherit;
5514+
}
5515+
5516+
.dropdown-item {
5517+
display: flex;
5518+
align-items: center;
5519+
width: 100%;
5520+
padding: 0.9rem 1rem;
5521+
gap: 0.75rem;
5522+
border-radius: 14px;
5523+
text-align: left;
5524+
transition: background 0.2s ease, color 0.2s ease;
5525+
}
5526+
5527+
.dropdown-item:hover,
5528+
.dropdown-item.selected,
5529+
.dropdown-recent-text:hover {
5530+
background: rgba(99, 102, 241, 0.12);
5531+
}
5532+
5533+
.dropdown-item-icon {
5534+
min-width: 2.4rem;
5535+
min-height: 2.4rem;
5536+
display: grid;
5537+
place-items: center;
5538+
border-radius: 12px;
5539+
background: rgba(99, 102, 241, 0.12);
5540+
}
5541+
5542+
.dropdown-item-text {
5543+
flex: 1;
5544+
color: var(--text-color);
5545+
}
5546+
5547+
.dropdown-item-tag {
5548+
font-size: 0.85rem;
5549+
color: var(--text-secondary);
5550+
border: 1px solid rgba(148, 163, 184, 0.3);
5551+
padding: 0.2rem 0.55rem;
5552+
border-radius: 999px;
5553+
}
5554+
5555+
.dropdown-recent-item {
5556+
display: flex;
5557+
align-items: center;
5558+
justify-content: space-between;
5559+
gap: 0.75rem;
5560+
margin-bottom: 0.5rem;
5561+
}
5562+
5563+
.dropdown-recent-text {
5564+
display: flex;
5565+
align-items: center;
5566+
gap: 0.75rem;
5567+
width: 100%;
5568+
padding: 0.9rem 1rem;
5569+
border-radius: 14px;
5570+
color: var(--text-secondary);
5571+
transition: background 0.2s ease;
5572+
}
5573+
5574+
.dropdown-recent-remove {
5575+
display: inline-flex;
5576+
align-items: center;
5577+
justify-content: center;
5578+
width: 2.4rem;
5579+
height: 2.4rem;
5580+
border-radius: 12px;
5581+
color: var(--text-secondary);
5582+
}
5583+
5584+
.dropdown-recent-remove:hover {
5585+
background: rgba(239, 68, 68, 0.12);
5586+
color: var(--danger-color);
5587+
}
5588+
5589+
/* Projects Section */
54765590
[data-theme="dark"] .progress-card {
54775591
background: rgba(255, 255, 255, 0.07);
54785592
border-color: rgba(255, 239, 223, 0.1);

web-app/js/main.js

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
import { updateProjectVisibility } from "./modules/utils.js";
66

7+
const html = document.documentElement;
8+
const themeToggle = document.getElementById('themeToggle');
9+
const themeColorMeta = document.querySelector('meta[name="theme-color"]');
10+
711
function prefersReducedMotion() {
812
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
913
}
@@ -34,6 +38,41 @@ function syncThemeColor(theme) {
3438
meta.setAttribute("content", theme === "light" ? "#f4f6f9" : "#0c0f1a");
3539
}
3640

41+
function updateThemeToggleAria(isLightTheme) {
42+
if (!themeToggle) return;
43+
themeToggle.setAttribute(
44+
'aria-label',
45+
isLightTheme ? 'Switch to dark mode' : 'Switch to light mode'
46+
);
47+
}
48+
49+
if (themeToggle) {
50+
themeToggle.addEventListener('click', () => {
51+
const currentTheme = html.getAttribute('data-theme');
52+
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
53+
54+
html.setAttribute('data-theme', newTheme);
55+
localStorage.setItem('theme', newTheme);
56+
syncThemeColor(newTheme);
57+
58+
themeToggle.innerHTML =
59+
newTheme === 'light'
60+
? '<i class="fas fa-sun" aria-hidden="true"></i>'
61+
: '<i class="fas fa-moon" aria-hidden="true"></i>';
62+
updateThemeToggleAria(newTheme === 'light');
63+
});
64+
}
65+
66+
const savedTheme = localStorage.getItem('theme') || 'dark';
67+
html.setAttribute('data-theme', savedTheme);
68+
syncThemeColor(savedTheme);
69+
if (themeToggle) {
70+
themeToggle.innerHTML =
71+
savedTheme === 'light'
72+
? '<i class="fas fa-sun" aria-hidden="true"></i>'
73+
: '<i class="fas fa-moon" aria-hidden="true"></i>';
74+
updateThemeToggleAria(savedTheme === 'light');
75+
}
3776
function escapeHtml(str) {
3877
var d = document.createElement("div");
3978
d.textContent = str;
@@ -79,6 +118,10 @@ function showInfoModal(title, steps) {
79118
listEl.appendChild(li);
80119
});
81120

121+
const toggleBackToTopButton = () => {
122+
if (!backToTopButton) return;
123+
backToTopButton.classList.toggle('visible', window.scrollY > 300);
124+
};
82125
overlay.classList.add("active");
83126

84127
function closeModal() {
@@ -88,6 +131,12 @@ function showInfoModal(title, steps) {
88131
overlay.removeEventListener("click", overlayClick);
89132
}
90133

134+
if (backToTopButton) {
135+
backToTopButton.addEventListener('click', () => {
136+
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
137+
window.scrollTo({ top: 0, behavior: prefersReducedMotion ? 'auto' : 'smooth' });
138+
});
139+
}
91140
function overlayClick(e) {
92141
if (e.target === overlay) closeModal();
93142
}
@@ -836,6 +885,30 @@ document.addEventListener("DOMContentLoaded", function () {
836885
if (noResultsMessage) noResultsMessage.style.display = "block";
837886
return;
838887
}
888+
889+
resultsList.innerHTML = '';
890+
matches.slice(0, 8).forEach((project, index) => {
891+
const item = document.createElement('button');
892+
item.type = 'button';
893+
item.className = 'dropdown-item' + (index === selectedSuggestionIndex ? ' selected' : '');
894+
item.setAttribute('aria-label', `Select ${project.title}`);
895+
item.innerHTML = `
896+
<div class="dropdown-item-icon">
897+
${project.card.querySelector('.card-icon').textContent}
898+
</div>
899+
<div class="dropdown-item-text">${highlightMatch(project.title, query)}</div>
900+
<span class="dropdown-item-tag">${project.category}</span>
901+
`;
902+
item.addEventListener('click', () => selectSuggestion(project.title));
903+
item.addEventListener('keydown', (e) => {
904+
if (e.key === 'Enter' || e.key === ' ') {
905+
e.preventDefault();
906+
selectSuggestion(project.title);
907+
}
908+
});
909+
item.addEventListener('mouseenter', () => {
910+
selectedSuggestionIndex = index;
911+
updateSuggestionHighlight();
839912

840913
if (noResultsMessage) noResultsMessage.style.display = "none";
841914

@@ -1192,6 +1265,41 @@ document.addEventListener("DOMContentLoaded", function () {
11921265
removeTrap();
11931266
removeTrap = null;
11941267
}
1268+
1269+
recentSearchesList.innerHTML = '';
1270+
recentSearches.slice(0, 5).forEach((search) => {
1271+
const item = document.createElement('div');
1272+
item.className = 'dropdown-recent-item';
1273+
item.innerHTML = `
1274+
<button type="button" class="dropdown-recent-text" aria-label="Search ${search}">
1275+
<i class="fas fa-history" style="opacity: 0.5; font-size: 0.9rem;"></i>
1276+
<span style="flex: 1; color: var(--text-secondary);">${search}</span>
1277+
</button>
1278+
<button type="button" class="dropdown-recent-remove" aria-label="Remove search">
1279+
<i class="fas fa-x"></i>
1280+
</button>
1281+
`;
1282+
1283+
const textButton = item.querySelector('.dropdown-recent-text');
1284+
const removeBtn = item.querySelector('.dropdown-recent-remove');
1285+
1286+
if (textButton) {
1287+
textButton.addEventListener('click', () => {
1288+
searchInput.value = search;
1289+
currentSearchQuery = search;
1290+
performSearch();
1291+
closeDropdown();
1292+
});
1293+
}
1294+
1295+
if (removeBtn) {
1296+
removeBtn.addEventListener('click', (e) => {
1297+
e.stopPropagation();
1298+
recentSearches = recentSearches.filter(s => s !== search);
1299+
localStorage.setItem('recentSearches', JSON.stringify(recentSearches));
1300+
renderRecentSearches();
1301+
});
1302+
}
11951303

11961304
// Clear content
11971305
if (modalBody) {
@@ -1582,6 +1690,38 @@ document.addEventListener("DOMContentLoaded", function () {
15821690
}
15831691
}
15841692

1693+
// Open Project Modal
1694+
projectCards.forEach(card => {
1695+
card.tabIndex = 0;
1696+
card.setAttribute('role', 'button');
1697+
card.setAttribute('aria-label', `Open ${card.querySelector('h3')?.textContent || 'project'}`);
1698+
1699+
const playButton = card.querySelector('.btn-play');
1700+
1701+
if (playButton) {
1702+
playButton.addEventListener('click', (e) => {
1703+
e.stopPropagation();
1704+
const projectName = card.getAttribute('data-project');
1705+
openProject(projectName);
1706+
});
1707+
}
1708+
1709+
card.addEventListener('click', () => {
1710+
const projectName = card.getAttribute('data-project');
1711+
openProject(projectName);
1712+
});
1713+
1714+
card.addEventListener('keydown', (e) => {
1715+
if (e.key === 'Enter' || e.key === ' ') {
1716+
e.preventDefault();
1717+
const projectName = card.getAttribute('data-project');
1718+
openProject(projectName);
1719+
}
1720+
});
1721+
});
1722+
/* ── Activate item based on viewport center crossing timeline dots ── */
1723+
var activeIdx = -1;
1724+
var dots = document.querySelectorAll(".timeline-dot");
15851725
/* ── Timeline Fill Progress ───────────────────────────── */
15861726
function updateTimelineFill() {
15871727
if (!timelineSection) return;

0 commit comments

Comments
 (0)