diff --git a/frontend/src/components/FacetGroups.jsx b/frontend/src/components/FacetGroups.jsx new file mode 100644 index 0000000..d7fceef --- /dev/null +++ b/frontend/src/components/FacetGroups.jsx @@ -0,0 +1,97 @@ +// FacetGroups.jsx — §22.4a SLICE-3 faceted left-pane filters (§5.1). +// +// Renders one collapsible group per facet field returned by the API, each with +// per-value result counts and multi-select checkboxes. A `tags`-type field gets +// a "filter values…" search box so it stays usable at 30+ values. Selection +// state + the malformed toggle are owned by the parent (Catalog), which +// re-fetches server-side on change. + +import { useState } from 'react' + +// Human label for the built-in state facet; declared fields use their own name +// (or the schema `label` when the API supplies it on `fields`). +function groupLabel(field, fields) { + if (field === 'state') return 'State' + const def = fields?.[field] + return def?.label || field.charAt(0).toUpperCase() + field.slice(1) +} + +function FacetGroup({ field, fields, counts, selected, onToggle, isTags }) { + const [open, setOpen] = useState(true) + const [valueSearch, setValueSearch] = useState('') + const entries = Object.entries(counts).sort((a, b) => b[1] - a[1]) + const needle = valueSearch.trim().toLowerCase() + const shown = isTags && needle + ? entries.filter(([v]) => v.toLowerCase().includes(needle)) + : entries + return ( +