From 64929f432e1f83bed35ff17cd3be78af4d1253a6 Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 5 Nov 2026 22:47:27 +0000 Subject: [PATCH] fix: implement instant real-time and server-side search filtering on storefront The search box was dead on every page except the catalog. It lives in the shared Navbar, but the only handler was in index.astro, so typing on /plugin/*, /publisher/* or /dashboard did nothing at all. There was also no form, so Enter never submitted, no clear (X) control, and ?q= was handled client-side only. Client-side instant filtering (typing narrows the grid, zero matches reveal the ROMeo empty state) already worked on the homepage and is kept as-is. The changes: - Navbar: the box is now a real GET form to "/" with name="q", so Enter searches from any route. It pre-fills from ?q= and gains an X button that appears only when there is text; clearing re-requests "/" when the grid holds a server-filtered subset, or resets the filter in place otherwise. - index.astro: read ?q= and answer it in D1, so results are correct at first paint with no flash of the unfiltered catalog. The "catalog is empty" state is skipped while searching, so a zero-match search shows the grid + ROMeo no-results panel instead of claiming the catalog has no extensions. The result heading names the term. - db.ts: add searchPlugins(), a bound LIKE over LOWER(name/description/category) reusing the shared column list and publisher join. The term is bound, never interpolated, so the only pattern syntax reaching SQL is the % wildcard. tests/search.test.ts pins that down along with the matched columns and the row mapping. Co-authored-by: openhands --- src/components/Navbar.astro | 58 ++++++++++++++++++-- src/lib/db.ts | 21 ++++++++ src/pages/index.astro | 28 ++++++---- tests/search.test.ts | 104 ++++++++++++++++++++++++++++++++++++ 4 files changed, 198 insertions(+), 13 deletions(-) create mode 100644 tests/search.test.ts diff --git a/src/components/Navbar.astro b/src/components/Navbar.astro index 324bba8..fcd5aa1 100644 --- a/src/components/Navbar.astro +++ b/src/components/Navbar.astro @@ -12,6 +12,11 @@ interface Props { } const { user = null } = Astro.props; + +// The navbar is shared by every route, so the search box pre-fills from the +// current ?q= and submits back to the catalog. That keeps search working from +// pages that have no catalog of their own (a plugin or publisher page). +const searchValue = Astro.url.searchParams.get('q') ?? ''; ---
@@ -30,7 +35,12 @@ const { user = null } = Astro.props; -
+
+ +