|
| 1 | +/** @jsxRuntime classic */ |
| 2 | +/** @jsx h */ |
| 3 | +import { |
| 4 | + autocomplete, |
| 5 | + AutocompleteComponents, |
| 6 | + AutocompleteOptions, |
| 7 | + getAlgoliaResults, |
| 8 | + GetSources, |
| 9 | +} from '@algolia/autocomplete-js'; |
| 10 | +import { Hit } from '@algolia/client-search'; |
| 11 | +import algoliasearch from 'algoliasearch/lite'; |
| 12 | +import { h } from 'preact'; |
| 13 | + |
| 14 | +import '@algolia/autocomplete-theme-classic'; |
| 15 | + |
| 16 | +const appId = 'latency'; |
| 17 | +const apiKey = '6be0576ff61c053d5f9a3225e2a90f76'; |
| 18 | +const searchClient = algoliasearch(appId, apiKey); |
| 19 | + |
| 20 | +type AutocompleteItem = Hit<{ |
| 21 | + brand: string; |
| 22 | + categories: string[]; |
| 23 | + description: string; |
| 24 | + image: string; |
| 25 | + name: string; |
| 26 | + price: number; |
| 27 | + rating: number; |
| 28 | + type: string; |
| 29 | + url: string; |
| 30 | +}>; |
| 31 | + |
| 32 | +const getSources: GetSources<AutocompleteItem> = ({ query }) => { |
| 33 | + return [ |
| 34 | + { |
| 35 | + sourceId: 'products', |
| 36 | + getItems() { |
| 37 | + return getAlgoliaResults<AutocompleteItem>({ |
| 38 | + searchClient, |
| 39 | + queries: [ |
| 40 | + { |
| 41 | + indexName: 'instant_search', |
| 42 | + query, |
| 43 | + }, |
| 44 | + ], |
| 45 | + }); |
| 46 | + }, |
| 47 | + templates: { |
| 48 | + item({ item, components }) { |
| 49 | + return <ProductItem item={item} components={components} />; |
| 50 | + }, |
| 51 | + noResults() { |
| 52 | + return 'No products matching.'; |
| 53 | + }, |
| 54 | + }, |
| 55 | + }, |
| 56 | + ]; |
| 57 | +}; |
| 58 | + |
| 59 | +const search = autocomplete<AutocompleteItem>({ |
| 60 | + container: '#autocomplete', |
| 61 | + panelContainer: '.parent', |
| 62 | + placeholder: 'Search', |
| 63 | + getSources, |
| 64 | + insights: true, |
| 65 | +}); |
| 66 | + |
| 67 | +const searchLeft = autocomplete<AutocompleteItem>({ |
| 68 | + container: '#autocomplete-left', |
| 69 | + panelContainer: '.parent', |
| 70 | + placeholder: 'Search', |
| 71 | + getSources, |
| 72 | + insights: true, |
| 73 | +}); |
| 74 | + |
| 75 | +const searchRight = autocomplete<AutocompleteItem>({ |
| 76 | + container: '#autocomplete-right', |
| 77 | + panelContainer: '.parent', |
| 78 | + placeholder: 'Search', |
| 79 | + getSources, |
| 80 | + insights: true, |
| 81 | +}); |
| 82 | + |
| 83 | +type ProductItemProps = { |
| 84 | + item: AutocompleteItem; |
| 85 | + components: AutocompleteComponents; |
| 86 | +}; |
| 87 | + |
| 88 | +const ProductItem = ({ item, components }: ProductItemProps) => ( |
| 89 | + <a href={item.url} className="aa-ItemLink"> |
| 90 | + <div className="aa-ItemContent"> |
| 91 | + <div className="aa-ItemIcon aa-ItemIcon--picture aa-ItemIcon--alignTop"> |
| 92 | + <img src={item.image} alt={item.name} width="40" height="40" /> |
| 93 | + </div> |
| 94 | + |
| 95 | + <div className="aa-ItemContentBody"> |
| 96 | + <div className="aa-ItemContentTitle"> |
| 97 | + <components.ReverseHighlight hit={item} attribute="name" /> |
| 98 | + </div> |
| 99 | + <div className="aa-ItemContentDescription"> |
| 100 | + By <strong>{item.brand}</strong> in{' '} |
| 101 | + <strong>{item.categories[0]}</strong> |
| 102 | + </div> |
| 103 | + </div> |
| 104 | + </div> |
| 105 | + </a> |
| 106 | +); |
| 107 | + |
| 108 | +document |
| 109 | + .querySelectorAll<HTMLInputElement>('input[name="placement"]') |
| 110 | + .forEach((radio) => { |
| 111 | + radio.addEventListener('change', (event) => { |
| 112 | + const target = event.target as HTMLInputElement; |
| 113 | + const panelPlacement = target.value as Required< |
| 114 | + AutocompleteOptions<AutocompleteItem>['panelPlacement'] |
| 115 | + >; |
| 116 | + |
| 117 | + search.update({ panelPlacement }); |
| 118 | + searchLeft.update({ panelPlacement }); |
| 119 | + searchRight.update({ panelPlacement }); |
| 120 | + }); |
| 121 | + }); |
0 commit comments