11import { liteClient as algoliasearch } from "algoliasearch/lite" ;
2- import { useEffect } from "react" ;
2+ import { useEffect , useState } from "react" ;
33import {
44 InstantSearch ,
55 Highlight ,
@@ -8,7 +8,19 @@ import {
88 type UseSearchBoxProps ,
99 useInfiniteHits ,
1010 type UseInfiniteHitsProps ,
11+ useRefinementList ,
1112} from "react-instantsearch" ;
13+ import {
14+ useFloating ,
15+ useInteractions ,
16+ useClick ,
17+ useDismiss ,
18+ shift ,
19+ offset ,
20+ autoUpdate ,
21+ FloatingPortal ,
22+ } from "@floating-ui/react" ;
23+ import { PiCaretDownBold } from "react-icons/pi" ;
1224
1325function SearchBox ( props : UseSearchBoxProps ) {
1426 const { query, refine } = useSearchBox ( props ) ;
@@ -75,6 +87,102 @@ function InfiniteHits(props: UseInfiniteHitsProps) {
7587 ) ;
7688}
7789
90+ function FilterDropdown ( {
91+ attribute,
92+ label,
93+ } : {
94+ attribute : string ;
95+ label : string ;
96+ } ) {
97+ const [ isOpen , setIsOpen ] = useState ( false ) ;
98+ const { items, refine } = useRefinementList ( { attribute } ) ;
99+
100+ useEffect ( ( ) => {
101+ const params = new URLSearchParams ( window . location . search ) ;
102+ const values = params . get ( attribute ) ?. split ( "," ) ;
103+
104+ if ( values && values . length !== 0 ) {
105+ for ( const value of values ) {
106+ refine ( value ) ;
107+ }
108+ }
109+ } , [ ] ) ;
110+
111+ useEffect ( ( ) => {
112+ const refined = items
113+ . filter ( ( item ) => item . isRefined )
114+ . map ( ( item ) => item . value ) ;
115+ if ( refined . length === 0 ) return ;
116+
117+ history . pushState (
118+ null ,
119+ "" ,
120+ `${ window . location . pathname } ?${ attribute } =${ refined . join ( "," ) } ` ,
121+ ) ;
122+ } , [ items ] ) ;
123+
124+ const { refs, floatingStyles, context } = useFloating ( {
125+ open : isOpen ,
126+ onOpenChange : setIsOpen ,
127+ middleware : [ shift ( ) , offset ( 5 ) ] ,
128+ whileElementsMounted : autoUpdate ,
129+ } ) ;
130+
131+ const click = useClick ( context ) ;
132+ const dismiss = useDismiss ( context ) ;
133+
134+ const { getReferenceProps, getFloatingProps } = useInteractions ( [
135+ click ,
136+ dismiss ,
137+ ] ) ;
138+
139+ const selectedItems = items . filter ( ( item ) => item . isRefined ) ;
140+
141+ return (
142+ < >
143+ < button
144+ ref = { refs . setReference }
145+ { ...getReferenceProps ( ) }
146+ className = "flex cursor-pointer items-center justify-center gap-2 rounded border border-cl1-gray-8 bg-transparent p-2 dark:border-cl1-gray-2"
147+ >
148+ < span >
149+ { label }
150+ { selectedItems . length > 0 && ` (${ selectedItems . length } )` }
151+ </ span >
152+ < PiCaretDownBold />
153+ </ button >
154+ { isOpen && (
155+ < FloatingPortal >
156+ < div
157+ ref = { refs . setFloating }
158+ style = { floatingStyles }
159+ { ...getFloatingProps ( ) }
160+ className = "rounded border border-cl1-gray-8 bg-cl1-white p-4 shadow-md dark:border-cl1-gray-1 dark:bg-cl1-gray-0"
161+ >
162+ < div className = "max-h-60 space-y-2 overflow-y-auto" >
163+ { items . map ( ( item ) => (
164+ < label
165+ key = { item . value }
166+ className = "flex items-center gap-2 text-sm"
167+ >
168+ < input
169+ type = "checkbox"
170+ checked = { item . isRefined }
171+ onChange = { ( ) => refine ( item . value ) }
172+ />
173+ < span >
174+ { item . label } ({ item . count } )
175+ </ span >
176+ </ label >
177+ ) ) }
178+ </ div >
179+ </ div >
180+ </ FloatingPortal >
181+ ) }
182+ </ >
183+ ) ;
184+ }
185+
78186export default function InstantSearchComponent ( ) {
79187 return (
80188 < InstantSearch
@@ -87,9 +195,14 @@ export default function InstantSearchComponent() {
87195 preserveSharedStateOnUnmount : true ,
88196 } }
89197 >
90- < Configure facetFilters = { [ "type:content" ] } />
91- < SearchBox />
92- < InfiniteHits />
198+ < Configure filters = "type:content" />
199+ < div className = "space-y-4" >
200+ < SearchBox />
201+ < div className = "flex gap-2" >
202+ < FilterDropdown attribute = "product" label = "Products" />
203+ </ div >
204+ < InfiniteHits />
205+ </ div >
93206 </ InstantSearch >
94207 ) ;
95208}
0 commit comments