Add search capability via astro-pagefind#118
Conversation
b1d4c41 to
a48025f
Compare
kunman93
left a comment
There was a problem hiding this comment.
Nice addition overall — pagefind is a solid choice for static-site search, and the styling integration looks clean. I have a few findings, two of which are functional bugs.
| function handleKeydown(event: KeyboardEvent) { | ||
| if (event.key === 'Escape' && !searchModal?.classList.contains('hidden')) { | ||
| closeModal(); | ||
| } | ||
| } | ||
|
|
||
| document.removeEventListener('keydown', handleKeydown); | ||
| document.addEventListener('keydown', handleKeydown); |
There was a problem hiding this comment.
Bug: keydown listeners accumulate on every page navigation
handleKeydown is defined inside initSearchModal(), so each call to initSearchModal creates a brand-new function reference. The removeEventListener on line 183 tries to remove that freshly-created reference — but it was never registered. The old handler from the previous call is still alive. After n page navigations there will be n active keydown listeners.
The cleanest fix is to hoist the handler or use an AbortController:
let keydownController: AbortController | null = null;
function initSearchModal() {
// ...existing cloneNode logic...
keydownController?.abort();
keydownController = new AbortController();
document.addEventListener('keydown', (event: KeyboardEvent) => {
if (event.key === 'Escape' && !searchModal?.classList.contains('hidden')) {
closeModal();
}
}, { signal: keydownController.signal });
}| padding: 0 10px; | ||
| max-height: 66vh; | ||
| overflow-y: scroll; | ||
| scrollbar-color: var(--color-zag-dark); |
There was a problem hiding this comment.
Bug: scrollbar-color requires two values
scrollbar-color accepts exactly two values: <thumb-color> <track-color>. Providing a single value is invalid CSS and will be ignored by the browser. The same applies to the dark-mode variant on line 104.
/* suggestion */
scrollbar-color: var(--color-zag-dark) transparent;And for dark mode:
scrollbar-color: var(--color-zag-light) transparent;| #search-modal.hidden { | ||
| animation: fadeOut 0.2s ease-out; | ||
| } |
There was a problem hiding this comment.
Visual bug: fadeOut animation never plays
When closeModal() adds the Tailwind hidden class, it immediately sets display: none. The browser removes the element from layout before the animation has a chance to run, so the fade-out is skipped entirely — the modal just disappears instantly.
The fade-in works fine because hidden is removed before the animation starts. For the fade-out you'd need a different approach, e.g. listen for animationend before adding hidden, or switch to an opacity/pointer-events toggle instead of display:
/* instead of toggling hidden, toggle a .visible class */
#search-modal {
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease-out;
}
#search-modal.visible {
opacity: 1;
pointer-events: auto;
}function openModal() { searchModal?.classList.add('visible'); ... }
function closeModal() { searchModal?.classList.remove('visible'); ... }And remove the hidden class from the initial markup (<div id="search-modal" class="fixed inset-0 z-50">).
Alternatively, if the instant-close behaviour is acceptable, just remove the #search-modal.hidden animation rule to avoid the false expectation.
| .backdrop-blur-sm { | ||
| backdrop-filter: blur(4px); | ||
| -webkit-backdrop-filter: blur(4px); | ||
| } |
There was a problem hiding this comment.
Minor: Redundant .backdrop-blur-sm vendor-prefix override
Tailwind v4 already emits backdrop-filter with the -webkit- vendor prefix automatically. Redefining .backdrop-blur-sm here is a no-op and adds noise. This block can be removed safely.
|
I let Copilot review the code to save some time. :) |
This PR adds search functionality to The Dev Exchange blog by using pagefind through astro-pagefind.
A new icon is added to the navigation bar:
Which opens a modal with a search input field and blurs the background:
This PR really just restyles the
<Search />component provided by astro-pagefind to match the look and feel of the blog.pagefind works by indexing the blog posts at build time, thus there's no dynamic backend component required. It offers a bunch of options like filters for authors or tags, which could be considered at a later point.