Skip to content

Commit f33bd9f

Browse files
Merge pull request steam-bell-92#983 from samarthchawla2005/search-history-fix
fix: preserve search history
2 parents d9a9d51 + a40dd68 commit f33bd9f

3 files changed

Lines changed: 239 additions & 53 deletions

File tree

web-app/css/styles.css

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,111 @@ body.sidebar-active .sidebar-dock {
22942294
opacity: 1;
22952295
}
22962296

2297+
2298+
.recent-clear-all-btn {
2299+
background: none;
2300+
border: none;
2301+
color: var(--accent);
2302+
cursor: pointer;
2303+
font-size: 0.85rem;
2304+
padding: 0 6px;
2305+
margin-left: 12px;
2306+
display: inline-flex;
2307+
align-items: center;
2308+
gap: 8px;
2309+
transition: color var(--duration-fast) ease, text-shadow var(--duration-fast) ease;
2310+
}
2311+
2312+
.recent-clear-all-btn:hover {
2313+
color: var(--accent-glow);
2314+
text-shadow: 0 0 8px var(--accent-glow);
2315+
}
2316+
2317+
.dropdown-clear-all {
2318+
padding: 12px 16px;
2319+
border-top: 1px solid var(--border);
2320+
justify-content: center;
2321+
}
2322+
2323+
.dropdown-clear-all-btn {
2324+
background: none;
2325+
border: none;
2326+
color: var(--text-secondary);
2327+
cursor: pointer;
2328+
font-size: 0.8rem;
2329+
padding: 0;
2330+
display: flex;
2331+
align-items: center;
2332+
gap: 6px;
2333+
transition: color var(--duration-fast) ease;
2334+
}
2335+
2336+
.dropdown-clear-all-btn:hover {
2337+
color: var(--accent);
2338+
}
2339+
2340+
/* Confirm modal styles */
2341+
.confirm-modal-overlay {
2342+
position: fixed;
2343+
inset: 0;
2344+
display: none;
2345+
align-items: center;
2346+
justify-content: center;
2347+
background: rgba(0,0,0,0.45);
2348+
z-index: 1200;
2349+
}
2350+
2351+
.confirm-modal-overlay.active {
2352+
display: flex;
2353+
}
2354+
2355+
.confirm-modal-content {
2356+
background: var(--surface);
2357+
color: var(--text);
2358+
border-radius: 10px;
2359+
padding: 18px;
2360+
width: 320px;
2361+
max-width: calc(100% - 40px);
2362+
box-shadow: 0 8px 30px rgba(2,6,23,0.6);
2363+
text-align: left;
2364+
}
2365+
2366+
.confirm-modal-content h3 {
2367+
margin: 0 0 8px 0;
2368+
font-size: 1.05rem;
2369+
}
2370+
2371+
.confirm-modal-content p {
2372+
margin: 0 0 16px 0;
2373+
color: var(--text-secondary);
2374+
font-size: 0.95rem;
2375+
}
2376+
2377+
.confirm-modal-actions {
2378+
display: flex;
2379+
justify-content: flex-end;
2380+
gap: 8px;
2381+
}
2382+
2383+
.btn {
2384+
padding: 8px 12px;
2385+
border-radius: 6px;
2386+
border: none;
2387+
cursor: pointer;
2388+
}
2389+
2390+
.btn-primary {
2391+
background: var(--accent);
2392+
color: var(--bg-on-accent, #fff);
2393+
}
2394+
2395+
.btn-primary:hover { box-shadow: 0 0 10px var(--accent-glow); }
2396+
2397+
.btn-secondary {
2398+
background: transparent;
2399+
color: var(--text-secondary);
2400+
}
2401+
22972402
.tips-section p {
22982403
font-size: 0.85rem;
22992404
color: var(--text-secondary);

web-app/index.html

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -89,33 +89,27 @@
8989
</button>
9090
</div>
9191
</div>
92-
</nav>
93-
94-
<!-- Mobile Sidebar Toggle -->
95-
<button
96-
type="button"
97-
class="mobile-sidebar-toggle"
98-
id="mobileSidebarToggle"
99-
aria-label="Toggle sidebar menu"
100-
aria-expanded="false"
101-
>
102-
<i class="fas fa-bars" aria-hidden="true"></i>
103-
</button>
104-
105-
<!-- Sidebar -->
106-
<aside
107-
class="sidebar-dock"
108-
id="mainSidebar"
109-
aria-label="Primary Navigation"
110-
>
111-
<div class="sidebar-brand">
112-
<a class="logo-wrap" href="index.html">
113-
<div class="logo-top-row">
114-
<div class="logo-text">
115-
<span class="logo-py">py</span>
116-
<span class="logo-mini">.mini</span>
117-
<span class="logo-parens">()</span>
92+
<span class="logo-tagline">games, math &amp; terminal toys</span>
93+
</a>
94+
</div>
95+
96+
<div class="sidebar-search">
97+
<div class="search-box" style="position:relative">
98+
<i class="fas fa-search" aria-hidden="true"></i>
99+
<input aria-label="Search projects" id="searchInput" placeholder="Search projects or tags..." type="text" role="combobox" aria-autocomplete="list" aria-controls="resultsList" aria-expanded="false"/>
100+
<div class="search-dropdown" id="searchDropdown" aria-live="polite">
101+
<div class="dropdown-content" id="searchDropdownContent">
102+
<div class="search-loader" id="searchLoader" style="display:none"><div class="spinner"></div></div>
103+
<div class="recent-searches-section" id="recentSearchesSection">
104+
<div class="dropdown-section-title">
105+
<span>Recent</span>
106+
<button id="clearRecentBtn" class="recent-clear-all-btn" aria-label="Clear recent searches">Clear All</button>
118107
</div>
108+
<div class="dropdown-list" id="recentSearchesList"></div>
109+
</div>
110+
<div class="results-section" id="resultsSection" style="display:none">
111+
<div class="dropdown-section-title">Projects</div>
112+
<div class="dropdown-list" id="resultsList" role="listbox"></div>
119113
</div>
120114
<span class="logo-tagline">games, math &amp; terminal toys</span>
121115
</a>
@@ -1461,19 +1455,38 @@ <h2>${projectName.replace(/-/g, " ").toUpperCase()}</h2>
14611455
if (typeof window.openProjectSafe !== "function") {
14621456
window.openProjectSafe = window.openProjectModal;
14631457
}
1464-
1465-
console.log("✅ Modal fix loaded");
1466-
})();
1467-
</script>
1468-
1469-
<!-- Info Modal Popup -->
1470-
<div id="infoModalOverlay" class="info-modal-overlay">
1471-
<div class="info-modal-content">
1472-
<button class="info-modal-close" id="infoModalClose">&times;</button>
1473-
<h3 id="infoModalTitle">How to Play</h3>
1474-
<ul id="infoModalList"></ul>
1475-
<button class="info-modal-btn" id="infoModalGotIt">Got it</button>
1476-
</div>
1458+
});
1459+
1460+
// Override the existing openProjectSafe if needed
1461+
if (typeof window.openProjectSafe !== 'function') {
1462+
window.openProjectSafe = window.openProjectModal;
1463+
}
1464+
1465+
console.log('✅ Modal fix loaded');
1466+
})();
1467+
</script>
1468+
1469+
<!-- Info Modal Popup -->
1470+
<div id="infoModalOverlay" class="info-modal-overlay">
1471+
<div class="info-modal-content">
1472+
<button class="info-modal-close" id="infoModalClose">&times;</button>
1473+
<h3 id="infoModalTitle">How to Play</h3>
1474+
<ul id="infoModalList"></ul>
1475+
<button class="info-modal-btn" id="infoModalGotIt">Got it</button>
1476+
</div>
1477+
</div>
1478+
1479+
<!-- Themed Confirm Modal (used for Clear All) -->
1480+
<div id="confirmModalOverlay" class="confirm-modal-overlay" aria-hidden="true">
1481+
<div class="confirm-modal-content" role="dialog" aria-modal="true" aria-labelledby="confirmModalTitle">
1482+
<h3 id="confirmModalTitle">Confirm</h3>
1483+
<p id="confirmModalMessage"></p>
1484+
<div class="confirm-modal-actions">
1485+
<button id="confirmCancelBtn" class="btn btn-secondary">Cancel</button>
1486+
<button id="confirmOkBtn" class="btn btn-primary">Confirm</button>
14771487
</div>
1478-
</body>
1488+
</div>
1489+
</div>
1490+
1491+
</body>
14791492
</html>

web-app/js/main.js

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,42 @@ function showInfoModal(title, steps) {
100100
overlay.addEventListener("click", overlayClick);
101101
}
102102

103+
// Themed confirmation modal (in-page) helper
104+
function showConfirm(message, onConfirm, onCancel) {
105+
var overlay = document.getElementById('confirmModalOverlay');
106+
var msg = document.getElementById('confirmModalMessage');
107+
var okBtn = document.getElementById('confirmOkBtn');
108+
var cancelBtn = document.getElementById('confirmCancelBtn');
109+
if (!overlay || !msg || !okBtn || !cancelBtn) {
110+
// fallback to window.confirm
111+
var ok = window.confirm(message);
112+
if (ok && typeof onConfirm === 'function') onConfirm();
113+
else if (!ok && typeof onCancel === 'function') onCancel();
114+
return;
115+
}
116+
117+
msg.textContent = message;
118+
overlay.classList.add('active');
119+
120+
function cleanup() {
121+
overlay.classList.remove('active');
122+
okBtn.removeEventListener('click', okHandler);
123+
cancelBtn.removeEventListener('click', cancelHandler);
124+
overlay.removeEventListener('click', overlayClick);
125+
document.removeEventListener('keydown', keyHandler);
126+
}
127+
128+
function okHandler(e) { e.stopPropagation(); cleanup(); if (typeof onConfirm === 'function') onConfirm(); }
129+
function cancelHandler(e) { e.stopPropagation(); cleanup(); if (typeof onCancel === 'function') onCancel(); }
130+
function overlayClick(e) { if (e.target === overlay) { cancelHandler(e); } }
131+
function keyHandler(e) { if (e.key === 'Escape') cancelHandler(e); }
132+
133+
okBtn.addEventListener('click', okHandler);
134+
cancelBtn.addEventListener('click', cancelHandler);
135+
overlay.addEventListener('click', overlayClick);
136+
document.addEventListener('keydown', keyHandler);
137+
}
138+
103139
var currentProjectName = "";
104140

105141
function setupModalInfoButton(projectName) {
@@ -743,7 +779,7 @@ document.addEventListener("DOMContentLoaded", function () {
743779
label.addEventListener("click", function () {
744780
syncSearchInputs(search, searchInput);
745781
currentSearchQuery = search;
746-
performSearch();
782+
performSearch(true);
747783
closeDropdown();
748784
});
749785

@@ -759,9 +795,27 @@ document.addEventListener("DOMContentLoaded", function () {
759795
renderRecentSearches();
760796
});
761797

762-
recentSearchesList.appendChild(item);
763-
});
764-
}
798+
recentSearchesList.appendChild(item);
799+
});
800+
801+
// Wire up header Clear All button (if present)
802+
var headerClearBtn = document.getElementById('clearRecentBtn');
803+
if (headerClearBtn) {
804+
headerClearBtn.style.display = recentSearches.length ? 'inline-flex' : 'none';
805+
headerClearBtn.onclick = function (e) {
806+
e.stopPropagation();
807+
if (!recentSearches || recentSearches.length === 0) return;
808+
showConfirm('Clear all recent searches? This cannot be undone.', function () {
809+
recentSearches = [];
810+
localStorage.setItem('recentSearches', JSON.stringify(recentSearches));
811+
renderRecentSearches();
812+
closeDropdown();
813+
}, function () {
814+
// cancelled
815+
});
816+
};
817+
}
818+
}
765819

766820
recentSearchesSection.style.display = "block";
767821
if (resultsSection) resultsSection.style.display = "none";
@@ -843,7 +897,7 @@ document.addEventListener("DOMContentLoaded", function () {
843897
if (!searchInput) return;
844898
searchInput.value = title;
845899
currentSearchQuery = title.toLowerCase();
846-
performSearch();
900+
performSearch(true);
847901
closeDropdown();
848902
if (projectsSection) {
849903
projectsSection.scrollIntoView({
@@ -853,7 +907,8 @@ document.addEventListener("DOMContentLoaded", function () {
853907
}
854908
}
855909

856-
function performSearch() {
910+
function performSearch(commit) {
911+
if (commit === undefined) commit = true;
857912
var query = currentSearchQuery;
858913
if (!query) {
859914
applyCategoryFilter(currentCategory);
@@ -869,12 +924,14 @@ document.addEventListener("DOMContentLoaded", function () {
869924
syncStickyTabs("all");
870925
}
871926

872-
recentSearches = recentSearches.filter(function (s) {
873-
return s !== query;
874-
});
875-
recentSearches.unshift(query);
876-
recentSearches = recentSearches.slice(0, 10);
877-
localStorage.setItem("recentSearches", JSON.stringify(recentSearches));
927+
if (commit) {
928+
recentSearches = recentSearches.filter(function (s) {
929+
return s !== query;
930+
});
931+
recentSearches.unshift(query);
932+
recentSearches = recentSearches.slice(0, 10);
933+
localStorage.setItem("recentSearches", JSON.stringify(recentSearches));
934+
}
878935

879936
var visibleCount = 0;
880937
var favorites = JSON.parse(localStorage.getItem("favorites") || "[]");
@@ -928,7 +985,7 @@ document.addEventListener("DOMContentLoaded", function () {
928985
currentSearchQuery = query;
929986
if (searchLoader) searchLoader.style.display = query ? "block" : "none";
930987
debouncedSearch(query);
931-
performSearch();
988+
performSearch(false);
932989
});
933990

934991
input.addEventListener("focus", function () {
@@ -938,11 +995,22 @@ document.addEventListener("DOMContentLoaded", function () {
938995
renderRecentSearches();
939996
});
940997

998+
input.addEventListener("blur", function () {
999+
if (currentSearchQuery && currentSearchQuery.trim()) {
1000+
performSearch(true);
1001+
}
1002+
});
1003+
9411004
input.addEventListener("keydown", function (e) {
9421005
if (e.key === "Escape") {
9431006
closeDropdown();
9441007
input.blur();
9451008
}
1009+
if (e.key === "Enter") {
1010+
e.preventDefault();
1011+
performSearch(true);
1012+
closeDropdown();
1013+
}
9461014
});
9471015
});
9481016
}

0 commit comments

Comments
 (0)