From 921d73bf0852f34c632797bb91458dd554b62bd7 Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Thu, 23 Apr 2026 13:08:51 -0600 Subject: [PATCH] feat: add search filter to board selector --- src/components/BoardSelector.svelte | 189 ++++++++++++++++++---------- 1 file changed, 126 insertions(+), 63 deletions(-) diff --git a/src/components/BoardSelector.svelte b/src/components/BoardSelector.svelte index 64fd5e0..622ae29 100644 --- a/src/components/BoardSelector.svelte +++ b/src/components/BoardSelector.svelte @@ -9,10 +9,7 @@ let { selected, onselect }: Props = $props(); - const esp32Boards = boards.filter((b) => b.family === "esp32"); - const espBoards = boards.filter((b) => b.family === "esp32s3"); - const rpBoards = boards.filter((b) => b.family === "rp2040"); - const nrfBoards = boards.filter((b) => b.family === "nrf52840"); + let query = $state(""); function badgeText(board: BoardDef): string { switch (board.flashMethod) { @@ -35,76 +32,142 @@ return "text-warn"; } } + + function matches(board: BoardDef, q: string): boolean { + const needle = q.trim().toLowerCase(); + if (!needle) return true; + const haystack = [ + board.name, + board.mcu, + board.radio, + board.family, + badgeText(board), + board.notes ?? "", + ] + .join(" ") + .toLowerCase(); + return haystack.includes(needle); + } + + const esp32Boards = $derived(boards.filter((b) => b.family === "esp32" && matches(b, query))); + const espBoards = $derived(boards.filter((b) => b.family === "esp32s3" && matches(b, query))); + const nrfBoards = $derived(boards.filter((b) => b.family === "nrf52840" && matches(b, query))); + const rpBoards = $derived(boards.filter((b) => b.family === "rp2040" && matches(b, query))); + + const totalVisible = $derived( + esp32Boards.length + espBoards.length + nrfBoards.length + rpBoards.length, + ); + const isFiltering = $derived(query.trim().length > 0); + + function handleKeydown(e: KeyboardEvent) { + if (e.key === "Escape" && query !== "") { + query = ""; + e.preventDefault(); + } + } +{#snippet boardCard(board: BoardDef)} + +{/snippet} + +{#snippet familySection(label: string, list: BoardDef[], gridCols: string)} + {#if list.length > 0} +

{label}

+
+ {#each list as board (board.id)} + {@render boardCard(board)} + {/each} +
+ {/if} +{/snippet} +
-

Select Board

- -

ESP32

-
- {#each esp32Boards as board} - - {/each} +
+

Select Board

+ {#if isFiltering} +

+ {totalVisible} of {boards.length} +

+ {/if}
-

ESP32-S3

-
- {#each espBoards as board} +
+ + + {#if query} - {/each} + {/if}
-

nRF52840

-
- {#each nrfBoards as board} + {#if totalVisible === 0} +
+

+ No boards match "{query}" +

- {/each} -
- -

RP2040

-
- {#each rpBoards as board} - - {/each} -
+
+ {:else} + {@render familySection("ESP32", esp32Boards, "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4")} + {@render familySection("ESP32-S3", espBoards, "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4")} + {@render familySection("nRF52840", nrfBoards, "grid-cols-1 sm:grid-cols-2")} + {@render familySection("RP2040", rpBoards, "grid-cols-1 sm:grid-cols-2")} + {/if}