-
Notifications
You must be signed in to change notification settings - Fork 332
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(recent-searches): export storage and search APIs (#473)
- Loading branch information
1 parent
a49a106
commit 09be485
Showing
32 changed files
with
543 additions
and
172 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/** @jsx h */ | ||
import { | ||
autocomplete, | ||
getAlgoliaHits, | ||
highlightHit, | ||
} from '@algolia/autocomplete-js'; | ||
import algoliasearch from 'algoliasearch'; | ||
import { h, Fragment } from 'preact'; | ||
|
||
import '@algolia/autocomplete-theme-classic'; | ||
|
||
import { createLocalStorageRecentlyViewedItems } from './recentlyViewedItemsPlugin'; | ||
import { ProductItem, ProductHit } from './types/ProductHit'; | ||
|
||
const appId = 'latency'; | ||
const apiKey = '6be0576ff61c053d5f9a3225e2a90f76'; | ||
const searchClient = algoliasearch(appId, apiKey); | ||
|
||
const recentlyViewedItems = createLocalStorageRecentlyViewedItems({ | ||
key: 'RECENTLY_VIEWED', | ||
limit: 5, | ||
}); | ||
|
||
autocomplete({ | ||
container: '#autocomplete', | ||
placeholder: 'Search', | ||
openOnFocus: true, | ||
plugins: [recentlyViewedItems], | ||
getSources({ query }) { | ||
if (!query) { | ||
return []; | ||
} | ||
|
||
return [ | ||
{ | ||
sourceId: 'products', | ||
getItems() { | ||
return getAlgoliaHits<ProductItem>({ | ||
searchClient, | ||
queries: [ | ||
{ | ||
indexName: 'instant_search', | ||
query, | ||
params: { | ||
clickAnalytics: true, | ||
attributesToSnippet: ['name:10', 'description:35'], | ||
snippetEllipsisText: '…', | ||
}, | ||
}, | ||
], | ||
}); | ||
}, | ||
onSelect({ item }) { | ||
recentlyViewedItems.data.addItem({ | ||
id: item.objectID, | ||
label: item.name, | ||
image: item.image, | ||
}); | ||
}, | ||
templates: { | ||
header() { | ||
return ( | ||
<Fragment> | ||
<span className="aa-SourceHeaderTitle">Products</span> | ||
<div className="aa-SourceHeaderLine" /> | ||
</Fragment> | ||
); | ||
}, | ||
item({ item }) { | ||
return <AutocompleteProductItem hit={item} />; | ||
}, | ||
noResults() { | ||
return ( | ||
<div className="aa-ItemContent">No products for this query.</div> | ||
); | ||
}, | ||
}, | ||
}, | ||
]; | ||
}, | ||
}); | ||
|
||
type ProductItemProps = { | ||
hit: ProductHit; | ||
}; | ||
|
||
function AutocompleteProductItem({ hit }: ProductItemProps) { | ||
return ( | ||
<Fragment> | ||
<div className="aa-ItemIcon aa-ItemIcon--align-top"> | ||
<img src={hit.image} alt={hit.name} width="40" height="40" /> | ||
</div> | ||
<div className="aa-ItemContent"> | ||
<div className="aa-ItemContentTitle"> | ||
{highlightHit<ProductHit>({ hit, attribute: 'name' })} | ||
</div> | ||
</div> | ||
<div className="aa-ItemActions"> | ||
<button | ||
className="aa-ItemActionButton aa-TouchOnly aa-ActiveOnly" | ||
type="button" | ||
title="Select" | ||
> | ||
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"> | ||
<path d="M18.984 6.984h2.016v6h-15.188l3.609 3.609-1.406 1.406-6-6 6-6 1.406 1.406-3.609 3.609h13.172v-4.031z" /> | ||
</svg> | ||
</button> | ||
</div> | ||
</Fragment> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { h } from 'preact'; | ||
|
||
// Parcel picks the `source` field of the monorepo packages and thus doesn't | ||
// apply the Babel config to replace our `__DEV__` global expression. | ||
// We therefore need to manually override it in the example app. | ||
// See https://twitter.com/devongovett/status/1134231234605830144 | ||
(global as any).__DEV__ = process.env.NODE_ENV !== 'production'; | ||
(global as any).__TEST__ = false; | ||
(global as any).h = h; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
|
||
<link rel="shortcut icon" href="favicon.png" type="image/x-icon" /> | ||
<link rel="stylesheet" href="style.css" /> | ||
|
||
<title>Recently Viewed Items Sandbox</title> | ||
</head> | ||
|
||
<body> | ||
<div class="container"> | ||
<div id="autocomplete"></div> | ||
</div> | ||
|
||
<script src="env.ts"></script> | ||
<script src="app.tsx"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"name": "@algolia/recently-viewed-items-example", | ||
"description": "Autocomplete Recently Viewed Items Sandbox", | ||
"version": "1.0.0-alpha.44", | ||
"private": true, | ||
"license": "MIT", | ||
"main": "index.html", | ||
"scripts": { | ||
"build": "parcel build index.html", | ||
"start": "parcel index.html" | ||
}, | ||
"dependencies": { | ||
"@algolia/autocomplete-js": "1.0.0-alpha.44", | ||
"@algolia/autocomplete-plugin-recent-searches": "1.0.0-alpha.44", | ||
"@algolia/autocomplete-theme-classic": "1.0.0-alpha.44", | ||
"@algolia/client-search": "4.8.3", | ||
"algoliasearch": "4.8.3", | ||
"preact": "10.5.7" | ||
}, | ||
"devDependencies": { | ||
"parcel-bundler": "1.12.4" | ||
}, | ||
"keywords": [ | ||
"algolia", | ||
"autocomplete", | ||
"javascript" | ||
] | ||
} |
136 changes: 136 additions & 0 deletions
136
examples/recently-viewed-items/recentlyViewedItemsPlugin.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
/** @jsx h */ | ||
import { AutocompletePlugin, highlightHit } from '@algolia/autocomplete-js'; | ||
import { | ||
createLocalStorageRecentSearchesPlugin, | ||
search, | ||
} from '@algolia/autocomplete-plugin-recent-searches'; | ||
import { h, Fragment } from 'preact'; | ||
|
||
type RecentlyViewedItem = { | ||
id: string; | ||
label: string; | ||
image: string; | ||
_highlightResult: { | ||
label: { | ||
value: string; | ||
}; | ||
}; | ||
}; | ||
|
||
type CreateLocalStorageRecentlyViewedItemsParams<TItem> = { | ||
key: string; | ||
limit?: number; | ||
search?(params: any): any[]; | ||
}; | ||
|
||
type RecentlyViewedItemsPluginData<TItem> = { | ||
addItem(item: TItem): void; | ||
removeItem(id: string): void; | ||
getAll(query?: string): any[]; | ||
}; | ||
|
||
export function createLocalStorageRecentlyViewedItems< | ||
TItem extends RecentlyViewedItem | ||
>( | ||
params: CreateLocalStorageRecentlyViewedItemsParams<TItem> | ||
): AutocompletePlugin<TItem, RecentlyViewedItemsPluginData<TItem>> { | ||
const { | ||
onReset, | ||
onSubmit, | ||
subscribe, | ||
...plugin | ||
} = createLocalStorageRecentSearchesPlugin({ | ||
...params, | ||
search(params) { | ||
if (params.query) { | ||
return []; | ||
} | ||
|
||
return search(params); | ||
}, | ||
transformSource({ source, onRemove }) { | ||
const transformedSource = params.transformSource | ||
? params.transformSource({ source, onRemove }) | ||
: source; | ||
|
||
return { | ||
...transformedSource, | ||
getItemUrl({ item }) { | ||
return item.url; | ||
}, | ||
templates: { | ||
...transformedSource.templates, | ||
header({ items }) { | ||
if (items.length === 0) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<Fragment> | ||
<span className="aa-SourceHeaderTitle">Recently viewed</span> | ||
<div className="aa-SourceHeaderLine" /> | ||
</Fragment> | ||
); | ||
}, | ||
item({ item, createElement }) { | ||
return ( | ||
<a className="aa-ItemLink" href={item.url}> | ||
{item.image ? ( | ||
<div className="aa-ItemIcon"> | ||
<img src={item.image} alt={item.label} /> | ||
</div> | ||
) : ( | ||
<div className="aa-ItemIcon aa-ItemIcon--no-border"> | ||
<svg | ||
viewBox="0 0 24 24" | ||
width="18" | ||
height="18" | ||
fill="currentColor" | ||
> | ||
<path d="M12.516 6.984v5.25l4.5 2.672-0.75 1.266-5.25-3.188v-6h1.5zM12 20.016q3.281 0 5.648-2.367t2.367-5.648-2.367-5.648-5.648-2.367-5.648 2.367-2.367 5.648 2.367 5.648 5.648 2.367zM12 2.016q4.125 0 7.055 2.93t2.93 7.055-2.93 7.055-7.055 2.93-7.055-2.93-2.93-7.055 2.93-7.055 7.055-2.93z" /> | ||
</svg> | ||
</div> | ||
)} | ||
|
||
<div className="aa-ItemContent"> | ||
<div className="aa-ItemContentTitle"> | ||
{highlightHit<RecentlyViewedItem>({ | ||
hit: item, | ||
attribute: 'label', | ||
createElement, | ||
})} | ||
</div> | ||
</div> | ||
<div className="aa-ItemActions"> | ||
<button | ||
className="aa-ItemActionButton" | ||
title="Remove this search" | ||
onClick={(event) => { | ||
event.stopPropagation(); | ||
onRemove(item.id); | ||
}} | ||
> | ||
<svg | ||
viewBox="0 0 24 24" | ||
width="18" | ||
height="18" | ||
fill="currentColor" | ||
> | ||
<path d="M18 7v13c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-10c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-13zM17 5v-1c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879h-4c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v1h-4c-0.552 0-1 0.448-1 1s0.448 1 1 1h1v13c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h10c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-13h1c0.552 0 1-0.448 1-1s-0.448-1-1-1zM9 5v-1c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293h4c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707v1zM9 11v6c0 0.552 0.448 1 1 1s1-0.448 1-1v-6c0-0.552-0.448-1-1-1s-1 0.448-1 1zM13 11v6c0 0.552 0.448 1 1 1s1-0.448 1-1v-6c0-0.552-0.448-1-1-1s-1 0.448-1 1z" /> | ||
</svg> | ||
</button> | ||
</div> | ||
</a> | ||
); | ||
}, | ||
}, | ||
}; | ||
}, | ||
}); | ||
const { getAlgoliaSearchParams, ...data } = plugin.data; | ||
|
||
return { | ||
...plugin, | ||
data, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
* { | ||
box-sizing: border-box; | ||
} | ||
|
||
body { | ||
background-color: rgb(244, 244, 249); | ||
color: rgb(65, 65, 65); | ||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', | ||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', | ||
sans-serif; | ||
-webkit-font-smoothing: antialiased; | ||
-moz-osx-font-smoothing: grayscale; | ||
padding: 1rem; | ||
} | ||
|
||
.container { | ||
margin: 0 auto; | ||
max-width: 640px; | ||
width: 100%; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Hit } from '@algolia/client-search'; | ||
|
||
export type ProductItem = { | ||
name: string; | ||
image: string; | ||
description: string; | ||
}; | ||
|
||
export type ProductHit = Hit<ProductItem> & { | ||
__autocomplete_indexName: string; | ||
__autocomplete_queryID: string; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
packages/autocomplete-plugin-recent-searches/src/addHighlightedAttribute.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { Highlighted, HistoryItem } from './types'; | ||
|
||
type HighlightParams<TItem> = { | ||
item: TItem; | ||
query: string; | ||
}; | ||
|
||
export function addHighlightedAttribute<TItem extends HistoryItem>({ | ||
item, | ||
query, | ||
}: HighlightParams<TItem>): Highlighted<TItem> { | ||
return { | ||
...item, | ||
_highlightResult: { | ||
label: { | ||
value: query | ||
? item.label.replace( | ||
new RegExp(query.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'), 'gi'), | ||
(match) => { | ||
return `__aa-highlight__${match}__/aa-highlight__`; | ||
} | ||
) | ||
: item.label, | ||
}, | ||
}, | ||
}; | ||
} |
File renamed without changes.
Oops, something went wrong.