From 027a6055a4b3a791769dfc752ffda5fe7e68f935 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Sat, 8 Aug 2026 04:15:10 +0200 Subject: [PATCH] =?UTF-8?q?ux(picker):=20maker-first=20ordering=20?= =?UTF-8?q?=E2=80=94=20passives,=20analog=20and=20logic=20gates=20sink=20t?= =?UTF-8?q?o=20the=20end?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The component grid and the category filter now follow a fixed maker-first category order (sensors, outputs/LEDs, displays, input, motors, communication, electromech, other… then passive, analog, logic): Velxio's audience reaches for a DHT22 or an LED far more often than a bare transistor or a 74HC gate. Stable sort — order within a category is untouched, and search results group the same way. --- .../src/components/ComponentPickerModal.tsx | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/ComponentPickerModal.tsx b/frontend/src/components/ComponentPickerModal.tsx index a4f60091..b8506bef 100644 --- a/frontend/src/components/ComponentPickerModal.tsx +++ b/frontend/src/components/ComponentPickerModal.tsx @@ -102,6 +102,34 @@ const BOARD_DESCRIPTIONS: Record = { attiny85: '8-bit AVR, 8KB flash, 6 GPIO (browser)', }; +/** + * Maker-first category order for the picker grid and the category filter. + * Velxio's audience is hobbyist-heavy: everyday digital parts (sensors, + * LEDs/outputs, displays, buttons) lead, while diodes/resistors/capacitors + * ('passive'), transistors/op-amps/instruments ('analog') and logic gates + * sink to the end of the list. + */ +const CATEGORY_ORDER: string[] = [ + 'sensors', + 'output', + 'displays', + 'input', + 'motors', + 'communication', + 'electromech', + 'boards', + 'other', + 'passive', + 'analog', + 'logic', +]; + +function categoryRank(category: string): number { + const i = CATEGORY_ORDER.indexOf(category); + // Unknown/future categories land before the passive tail, not after it. + return i === -1 ? CATEGORY_ORDER.indexOf('other') : i; +} + const ALL_BOARDS: BoardKind[] = [ 'arduino-uno', 'arduino-nano', @@ -237,6 +265,14 @@ export const ComponentPickerModal: React.FC = ({ // (that is how "add a Pi 4" placed a 40-pin prop that never boots). components = components.filter((c) => !(c.id in BOARD_KIND_LABELS)); + // Maker-first ordering: most users reach for a sensor, an LED or a + // display far more often than a bare transistor or a 74HC gate, so + // passives / analog / logic sink to the end. Array.sort is stable — + // the registry's own order is preserved within each category. + components = [...components].sort( + (a, b) => categoryRank(a.category) - categoryRank(b.category), + ); + return components; // eslint-disable-next-line react-hooks/exhaustive-deps }, [searchQuery, selectedCategory, registry, isLoading, registryVersion, proBoardsVersion]); @@ -263,10 +299,12 @@ export const ComponentPickerModal: React.FC = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [registry, isLoading, searchQuery, selectedCategory, registryVersion, proBoardsVersion]); - // Get available categories + // Get available categories — same maker-first order as the grid. const categories = useMemo(() => { if (isLoading) return []; - return registry.getCategories(); + return [...registry.getCategories()].sort( + (a, b) => categoryRank(a) - categoryRank(b), + ); }, [registry, isLoading]); // Handle ESC key to close modal