search: saved searches via bookmark button
Small bookmark icon in the search header bar opens a popup listing localStorage-persisted search strings. Clicking an entry fills the input and runs the search; the x button deletes it; "save current search" at the bottom saves the active input (no dupes). List persists across sessions, no server round-trip. Tests: 6 cases covering button/popup toggle, save + recall, delete, save-current-button, and duplicate rejection. All snapshot/restore localStorage in try/finally so they don't leak into user data or cross-test state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
be28080439
commit
883640e20c
5 files changed
+218
-2
No files matched your search
@@ -403,3 +403,88 @@ replaceAllBtn?.addEventListener('click', async () => {
|
||||
search(input.value);
|
||||
setTimeout(() => { replaceStatus.style.color = ''; }, 3000);
|
||||
});
|
||||
|
||||
// ── Saved searches ──────────────────────────────────────────────
|
||||
// localStorage-persisted list of search strings. The bookmark button
|
||||
// toggles a popup that lets the user pick one (fills input + runs),
|
||||
// save the current input value, or delete saved entries.
|
||||
|
||||
const SAVED_KEY = 'hyprcrd-saved-searches';
|
||||
const savedBtn = $('search-saved-btn');
|
||||
const savedPopup = $('search-saved-popup');
|
||||
const savedList = $('search-saved-list');
|
||||
const savedAdd = $('search-saved-add');
|
||||
|
||||
function loadSaved() {
|
||||
try { return JSON.parse(localStorage.getItem(SAVED_KEY) || '[]'); } catch { return []; }
|
||||
}
|
||||
function storeSaved(arr) {
|
||||
localStorage.setItem(SAVED_KEY, JSON.stringify(arr));
|
||||
}
|
||||
|
||||
function renderSavedList() {
|
||||
if (!savedList) return;
|
||||
const items = loadSaved();
|
||||
if (!items.length) {
|
||||
savedList.innerHTML = '<div class="px-3 py-3 text-[10px] text-t-dim font-pixel text-center">no saved searches</div>';
|
||||
return;
|
||||
}
|
||||
savedList.innerHTML = items.map((q, i) => `
|
||||
<div class="flex items-center gap-2 px-3 py-1.5 hover:bg-t-raised cursor-pointer transition-colors search-saved-row" data-idx="${i}">
|
||||
<i class="ph ph-magnifying-glass text-xs text-t-dim"></i>
|
||||
<span class="flex-1 text-xs text-t-muted truncate">${esc(q)}</span>
|
||||
<button class="search-saved-del text-t-dim hover:text-t-danger text-xs px-1" data-idx="${i}" title="remove"><i class="ph ph-x"></i></button>
|
||||
</div>
|
||||
`).join('');
|
||||
savedList.querySelectorAll('.search-saved-row').forEach(row => {
|
||||
row.addEventListener('click', (e) => {
|
||||
if (e.target.closest('.search-saved-del')) return;
|
||||
const q = items[parseInt(row.dataset.idx)];
|
||||
if (q !== undefined) {
|
||||
input.value = q;
|
||||
search(q);
|
||||
closeSavedPopup();
|
||||
}
|
||||
});
|
||||
});
|
||||
savedList.querySelectorAll('.search-saved-del').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const idx = parseInt(btn.dataset.idx);
|
||||
const arr = loadSaved();
|
||||
arr.splice(idx, 1);
|
||||
storeSaved(arr);
|
||||
renderSavedList();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function openSavedPopup() {
|
||||
renderSavedList();
|
||||
savedPopup?.classList.remove('hidden');
|
||||
const close = (e) => {
|
||||
if (savedPopup?.contains(e.target) || e.target === savedBtn) return;
|
||||
closeSavedPopup();
|
||||
document.removeEventListener('mousedown', close, true);
|
||||
};
|
||||
setTimeout(() => document.addEventListener('mousedown', close, true), 0);
|
||||
}
|
||||
function closeSavedPopup() {
|
||||
savedPopup?.classList.add('hidden');
|
||||
}
|
||||
|
||||
savedBtn?.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
if (savedPopup?.classList.contains('hidden')) openSavedPopup();
|
||||
else closeSavedPopup();
|
||||
});
|
||||
|
||||
savedAdd?.addEventListener('click', () => {
|
||||
const q = input.value.trim();
|
||||
if (!q) return;
|
||||
const arr = loadSaved();
|
||||
if (arr.includes(q)) return; // no dupes
|
||||
arr.unshift(q);
|
||||
storeSaved(arr);
|
||||
renderSavedList();
|
||||
});
|
||||
Reference in new issue
Block a user