diff --git a/src/components/BehaviorCatalog.tsx b/src/components/BehaviorCatalog.tsx index 5e75744..bdeb049 100644 --- a/src/components/BehaviorCatalog.tsx +++ b/src/components/BehaviorCatalog.tsx @@ -6,6 +6,7 @@ import { BehaviorCard } from "./BehaviorCard"; import type { Behavior } from "@registry/schema/behavior"; import { DuckMark } from "./DuckMark"; import { QuackButton } from "./QuackAction"; +import { formatRobotdSlot } from "@/lib/labels"; interface BehaviorCatalogProps { initialBehaviors: Behavior[]; @@ -16,10 +17,16 @@ export function BehaviorCatalog({ initialBehaviors }: BehaviorCatalogProps) { const [category, setCategory] = useState("all"); const [verification, setVerification] = useState("all"); const [accessory, setAccessory] = useState("all"); + const [slot, setSlot] = useState("all"); + + const slots = useMemo(() => Array.from(new Set(initialBehaviors.map((behavior) => behavior.compatibility.robotd_slot))) + .sort((a, b) => formatRobotdSlot(a).localeCompare(formatRobotdSlot(b))) + .map((id) => ({ id, label: formatRobotdSlot(id) })), [initialBehaviors]); const filteredBehaviors = useMemo(() => initialBehaviors.filter((behavior) => { if (category !== "all" && behavior.category !== category) return false; if (verification !== "all" && behavior.verification.status !== verification) return false; + if (slot !== "all" && behavior.compatibility.robotd_slot !== slot) return false; if (accessory === "none" && behavior.compatibility.accessories_required.length > 0) return false; if (accessory !== "all" && accessory !== "none" && !behavior.compatibility.accessories_required.includes(accessory)) return false; @@ -35,15 +42,17 @@ export function BehaviorCatalog({ initialBehaviors }: BehaviorCatalogProps) { behavior.sources.task_id || "", behavior.category, behavior.verification.status, + behavior.compatibility.robotd_slot, ...behavior.compatibility.accessories_required, ].some((value) => value.toLowerCase().includes(query)); - }), [accessory, category, initialBehaviors, search, verification]); + }), [accessory, category, initialBehaviors, search, slot, verification]); const resetFilters = () => { setSearch(""); setCategory("all"); setVerification("all"); setAccessory("all"); + setSlot("all"); }; return ( @@ -58,6 +67,9 @@ export function BehaviorCatalog({ initialBehaviors }: BehaviorCatalogProps) { setSelectedVerification={setVerification} selectedAccessory={accessory} setSelectedAccessory={setAccessory} + selectedSlot={slot} + setSelectedSlot={setSlot} + slots={slots} totalCount={initialBehaviors.length} filteredCount={filteredBehaviors.length} /> diff --git a/src/components/FilterBar.tsx b/src/components/FilterBar.tsx index f9cf1f7..cb72b4a 100644 --- a/src/components/FilterBar.tsx +++ b/src/components/FilterBar.tsx @@ -11,6 +11,9 @@ interface FilterBarProps { setSelectedVerification: (v: string) => void; selectedAccessory: string; setSelectedAccessory: (a: string) => void; + selectedSlot: string; + setSelectedSlot: (s: string) => void; + slots: Array<{ id: string; label: string }>; totalCount: number; filteredCount: number; } @@ -48,6 +51,9 @@ export function FilterBar({ setSelectedVerification, selectedAccessory, setSelectedAccessory, + selectedSlot, + setSelectedSlot, + slots, totalCount, filteredCount, }: FilterBarProps) { @@ -55,13 +61,15 @@ export function FilterBar({ search.trim() !== "" || selectedCategory !== "all" || selectedVerification !== "all" || - selectedAccessory !== "all"; + selectedAccessory !== "all" || + selectedSlot !== "all"; const clearAllFilters = () => { setSearch(""); setSelectedCategory("all"); setSelectedVerification("all"); setSelectedAccessory("all"); + setSelectedSlot("all"); }; return ( @@ -104,6 +112,13 @@ export function FilterBar({ {accessories.map((item) => )} +