Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <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="https://unpkg.com/instantsearch.css@7/themes/satellite-min.css"
- />
- <link
- rel="stylesheet"
- href="style.css"
- />
- <link
- rel="stylesheet"
- href="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-theme-classic"
- />
- <title>InstantSearch | Autocomplete</title>
- </head>
- <body>
- <header class="header">
- <div class="header-wrapper wrapper">
- <nav class="header-nav">
- <a href="/">Home</a>
- </nav>
- <div id="autocomplete"></div>
- </div>
- </header>
- <div class="container wrapper">
- <div>
- <div id="categories"></div>
- </div>
- <div>
- <img src="iphone-banner.png" alt="iPhone banner" class="banner" />
- <div id="hits"></div>
- <div id="pagination"></div>
- </div>
- </div>
- <!-- <script type="module" src="env.ts"></script>
- <script type="module" src="src/app.ts"></script> -->
- <script src="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-js"></script>
- <script src="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-plugin-query-suggestions"></script>
- <script src="https://cdn.jsdelivr.net/npm/@algolia/autocomplete-plugin-recent-searches"></script>
- <script
- src="https://cdn.jsdelivr.net/npm/[email protected]/dist/algoliasearch.umd.js"
- integrity="sha256-InehzjjnCqBlO9perxL3MsBXunj7aZttlr2ls+aH/N4="
- crossorigin="anonymous"
- ></script>
- <script src="https://cdn.jsdelivr.net/npm/instantsearch.js" crossorigin="anonymous"></script>
- <script type="module">
- const { autocomplete } = window['@algolia/autocomplete-js'];
- const { createQuerySuggestionsPlugin } = window['@algolia/autocomplete-plugin-query-suggestions'];
- const { createLocalStorageRecentSearchesPlugin } = window['@algolia/autocomplete-plugin-recent-searches'];
- const { InstantSearch } = window['instantsearch'];
- console.log(InstantSearch);
- // const INSTANT_SEARCH_INDEX_NAME = 'mystock-prod';
- // const INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE = 'childcategory_name';
- const INSTANT_SEARCH_INDEX_NAME = 'instant_search';
- const INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE =
- 'hierarchicalCategories.lvl0';
- const searchClient = algoliasearch(
- 'latency',
- '6be0576ff61c053d5f9a3225e2a90f76'
- );
- const { connectSearchBox } = instantsearch.connectors;
- const { instantSearchRouter } = instantsearch.routers.history();
- function debounce(fn, time) {
- let timerId = undefined;
- return function (...args) {
- if (timerId) {
- clearTimeout(timerId);
- }
- timerId = setTimeout(() => fn(...args), time);
- };
- }
- function setInstantSearchUiState(indexUiState) {
- search.setUiState((uiState) => ({
- ...uiState,
- [INSTANT_SEARCH_INDEX_NAME]: {
- ...uiState[INSTANT_SEARCH_INDEX_NAME],
- // We reset the page when the search state changes.
- page: 1,
- ...indexUiState,
- },
- }));
- }
- const debouncedSetInstantSearchUiState = debounce(
- setInstantSearchUiState,
- 500
- );
- function isModifierEvent(event) {
- const isMiddleClick = event.button === 1;
- return (
- isMiddleClick ||
- event.altKey ||
- event.ctrlKey ||
- event.metaKey ||
- event.shiftKey
- );
- }
- function getInstantSearchCurrentCategory() {
- const indexUiState = search.getUiState()[INSTANT_SEARCH_INDEX_NAME];
- const hierarchicalMenuUiState = indexUiState && indexUiState.hierarchicalMenu;
- const currentCategories =
- hierarchicalMenuUiState &&
- hierarchicalMenuUiState[INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE];
- return currentCategories && currentCategories[0];
- }
- function getInstantSearchUrl(indexUiState) {
- return search.createURL({ [INSTANT_SEARCH_INDEX_NAME]: indexUiState });
- }
- function onSelect({ setIsOpen, setQuery, event, query, category }) {
- // You want to trigger the default browser behavior if the event is modified.
- if (isModifierEvent(event)) {
- return;
- }
- setQuery(query);
- setIsOpen(false);
- setInstantSearchUiState({
- query,
- hierarchicalMenu: {
- [INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [category],
- },
- });
- }
- function getItemUrl({ query, category }) {
- return getInstantSearchUrl({
- query,
- hierarchicalMenu: {
- [INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [category],
- },
- });
- }
- function getItemWrapper({ html, children, query, category }) {
- const uiState = {
- query,
- hierarchicalMenu: {
- [INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [category],
- },
- };
- return html`<a
- class="aa-ItemLink"
- href=${getInstantSearchUrl(uiState)}
- onClick=${(event) => {
- if (!isModifierEvent(event)) {
- // Bypass the original link behavior if there's no event modifier
- // to set the InstantSearch UI state without reloading the page.
- event.preventDefault();
- }
- }}
- >
- ${children}
- </a>`;
- }
- const { panel } = instantsearch.widgets;
- const { configure } = instantsearch.widgets;
- const { hierarchicalMenu } = instantsearch.widgets;
- const { hits } = instantsearch.widgets;
- const { pagination } = instantsearch.widgets;
- const search = instantsearch({
- searchClient,
- indexName: INSTANT_SEARCH_INDEX_NAME,
- routing: instantSearchRouter,
- });
- const virtualSearchBox = connectSearchBox(() => {});
- const hierarchicalMenuWithHeader = panel({
- templates: { header: 'Categories' },
- })(hierarchicalMenu);
- search.addWidgets([
- configure({
- attributesToSnippet: ['name:7', 'description:15'],
- snippetEllipsisText: '…',
- }),
- // Mount a virtual search box to manipulate InstantSearch's `query` UI
- // state parameter.
- virtualSearchBox(),
- hierarchicalMenuWithHeader({
- container: '#categories',
- attributes: [
- INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE,
- 'hierarchicalCategories.lvl1',
- ],
- }),
- hits({
- container: '#hits',
- transformItems(items) {
- return items.map((item) => ({
- ...item,
- category: item.categories[0],
- comments: (item.popularity % 100).toLocaleString(),
- sale: item.free_shipping,
- // eslint-disable-next-line @typescript-eslint/camelcase
- sale_price: item.free_shipping
- ? (item.price - item.price / 10).toFixed(2)
- : item.price.toString(),
- }));
- },
- templates: {
- item: (hit, { html, components }) => html`
- <article class="hit">
- <div class="hit-image">
- <img src="${hit.image}" alt="${hit.name}" />
- </div>
- <div>
- <h1>${components.Snippet({ hit, attribute: 'name' })}</h1>
- <div>
- By <strong>${hit.brand}</strong> in
- <strong>${hit.category}</strong>
- </div>
- </div>
- <div
- style="
- display: grid;
- grid-auto-flow: column;
- justify-content: start;
- align-items: center;
- gap: 8px;
- "
- >
- ${hit.rating > 0 &&
- html`
- <div
- style="
- display: grid;
- grid-auto-flow: column;
- justify-content: start;
- align-items: center;
- gap: 4px;
- "
- >
- <svg
- width="16"
- height="16"
- viewBox="0 0 24 24"
- fill="#e2a400"
- stroke="#e2a400"
- stroke-width="1"
- stroke-linecap="round"
- stroke-linejoin="round"
- >
- <polygon
- points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"
- />
- </svg>
- ${hit.rating}
- </div>
- `}
- <div
- style="
- display: grid;
- grid-auto-flow: column;
- justify-content: start;
- align-items: center;
- gap: 4px;
- "
- >
- <svg
- width="16"
- height="16"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
- style="
- position: relative;
- top: 1px;
- "
- >
- <path
- d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
- ></path>
- </svg>
- <span>${hit.comments}</span>
- </div>
- </div>
- </article>
- `,
- },
- }),
- pagination({
- container: '#pagination',
- padding: 2,
- showFirst: false,
- showLast: false,
- }),
- ]);
- const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
- key: 'instantsearch',
- limit: 3,
- transformSource: function({ source }) {
- return {
- ...source,
- getItemUrl: function({ item }) {
- return getItemUrl({
- query: item.label,
- category: item.category,
- });
- },
- onSelect: function({ setIsOpen, setQuery, item, event }) {
- onSelect({
- setQuery,
- setIsOpen,
- event,
- query: item.label,
- category: item.category,
- });
- },
- templates: {
- ...source.templates,
- item: function(params) {
- const { children } = source.templates.item(params).props;
- const { item, html } = params;
- return getItemWrapper({
- query: item.label,
- category: item.category,
- html,
- children,
- });
- },
- },
- };
- },
- });
- const querySuggestionsPluginInCategory = createQuerySuggestionsPlugin({
- searchClient,
- indexName: 'instant_search_demo_query_suggestions',
- getSearchParams: function() {
- const currentCategory = getInstantSearchCurrentCategory();
- return recentSearchesPlugin.data.getAlgoliaSearchParams({
- hitsPerPage: 3,
- facetFilters: [
- `${INSTANT_SEARCH_INDEX_NAME}.facets.exact_matches.${INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE}.value:${currentCategory}`,
- ],
- });
- },
- transformSource: function({ source }) {
- const currentCategory = getInstantSearchCurrentCategory();
- return {
- ...source,
- sourceId: 'querySuggestionsPluginInCategory',
- getItemUrl: function({ item }) {
- return getItemUrl({
- query: item.query,
- category: currentCategory,
- });
- },
- onSelect: function({ setIsOpen, setQuery, event, item }) {
- onSelect({
- setQuery,
- setIsOpen,
- event,
- query: item.query,
- category: currentCategory,
- });
- },
- getItems: function(params) {
- if (!currentCategory) {
- return [];
- }
- return source.getItems(params);
- },
- templates: {
- ...source.templates,
- header: function({ html }) {
- return html`
- <span class="aa-SourceHeaderTitle">In ${currentCategory}</span>
- <div class="aa-SourceHeaderLine" />
- `;
- },
- item: function(params) {
- const { children } = source.templates.item(params).props;
- const { item, html } = params;
- return getItemWrapper({
- query: item.query,
- category: currentCategory,
- html,
- children,
- });
- },
- },
- };
- },
- });
- const querySuggestionsPlugin = createQuerySuggestionsPlugin({
- searchClient,
- indexName: 'instant_search_demo_query_suggestions',
- getSearchParams: function() {
- const currentCategory = getInstantSearchCurrentCategory();
- if (!currentCategory) {
- return recentSearchesPlugin.data.getAlgoliaSearchParams({
- hitsPerPage: 6,
- });
- }
- return recentSearchesPlugin.data.getAlgoliaSearchParams({
- hitsPerPage: 3,
- facetFilters: [
- `${INSTANT_SEARCH_INDEX_NAME}.facets.exact_matches.${INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE}.value:-${currentCategory}`,
- ],
- });
- },
- categoryAttribute: [
- INSTANT_SEARCH_INDEX_NAME,
- 'facets',
- 'exact_matches',
- INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE,
- ],
- transformSource: function({ source }) {
- const currentCategory = getInstantSearchCurrentCategory();
- return {
- ...source,
- sourceId: 'querySuggestionsPlugin',
- getItemUrl: function({ item }) {
- return getItemUrl({
- query: item.query,
- category: item.__autocomplete_qsCategory,
- });
- },
- onSelect: function({ setIsOpen, setQuery, event, item }) {
- onSelect({
- setQuery,
- setIsOpen,
- event,
- query: item.query,
- category: item.__autocomplete_qsCategory,
- });
- },
- getItems: function(params) {
- if (!params.state.query) {
- return [];
- }
- return source.getItems(params);
- },
- templates: {
- ...source.templates,
- header: function({ html }) {
- if (!currentCategory) {
- return null;
- }
- return html`
- <span class="aa-SourceHeaderTitle">In other categories</span>
- <div class="aa-SourceHeaderLine" />
- `;
- },
- item: function(params) {
- const { children } = source.templates.item(params).props;
- const { item, html } = params;
- return getItemWrapper({
- query: item.query,
- category: item.__autocomplete_qsCategory,
- html,
- children,
- });
- },
- },
- };
- },
- });
- const searchPageState = getInstantSearchUiState();
- function startAutocomplete(searchInstance) {
- let skipInstantSearchStateUpdate = false;
- const { setQuery } = autocomplete({
- container: '#autocomplete',
- placeholder: 'Search for products',
- insights: true,
- openOnFocus: true,
- plugins: [
- recentSearchesPlugin,
- querySuggestionsPluginInCategory,
- querySuggestionsPlugin,
- ],
- detachedMediaQuery: 'none',
- initialState: {
- query: searchPageState.query || '',
- },
- navigator: {
- navigate: function() {
- // We don't navigate to a new page because we leverage the InstantSearch
- // UI state API.
- },
- },
- onSubmit: function({ state }) {
- setInstantSearchUiState({ query: state.query });
- },
- onReset: function() {
- setInstantSearchUiState({
- query: '',
- hierarchicalMenu: {
- [INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [],
- },
- });
- },
- onStateChange: function({ prevState, state }) {
- if (!skipInstantSearchStateUpdate && prevState.query !== state.query) {
- debouncedSetInstantSearchUiState({ query: state.query });
- }
- skipInstantSearchStateUpdate = false;
- },
- });
- window.addEventListener('popstate', function() {
- skipInstantSearchStateUpdate = true;
- setQuery(
- (searchInstance.helper && searchInstance.helper.state.query) || ''
- );
- });
- }
- search.start();
- startAutocomplete(search);
- function getInstantSearchUiState() {
- const uiState = instantSearchRouter.read();
- return (uiState && uiState[INSTANT_SEARCH_INDEX_NAME]) || {};
- }
- </script>
- </body>
- </html>
Add Comment
Please, Sign In to add comment