Поиск Algolia

Algolia - это поисковая платформа, которая предоставляет набор функций и API, позволяющих легко реализовать мощные поисковые возможности для пользователей. Фактически из коробки она предлагает инструменты и инфраструктуру для интеграции функции быстрого и релевантного поиска в нашем приложении. Благодаря API Algolia её очень просто интегрировать в ваше приложение Qwik.

Решение

Чтобы начать пользоваться этой платформой, вам нужно стать зарегистрированным пользователем Algolia и получить ключи API, которые будут использоваться для взаимодействия с Algolia.

  • Название индекса: Индекс - это место, где хранятся данные, используемые Algolia. Это эквивалент таблицы в базе данных, но оптимизированный для операций поиска и обнаружения.
  • ID приложения: Это ваш уникальный идентификатор приложения. Он используется для идентификации вас при использовании API Algolia.
  • Ключ API для поиска: Это открытый ключ API, который нужно использовать в коде фронтенда. Этот ключ можно использовать только для поисковых запросов и отправки данных в Insights API.

Итак, как только вы получили эту информацию, вы можете определить переменные окружения, создав или отредактировав файл .env или .env.local в корне вашего проекта.

.env
VITE_ALGOLIA_INDEX=
VITE_ALGOLIA_APP_ID=
VITE_ALGOLIA_SEARCH_KEY=

Ниже представлен рабочий пример первой пригодной для использования реализации. Затем, очевидно, вы можете настроить и создать свой графический интерфейс. Во многих случаях имеет смысл создать модальное окно, в котором будет отображаться поиск и результаты, как, например, в этой документации по Qwik. Вы можете проверить, что возвращает Algolia, через официальную документацию.

import { $, component$, useSignal, useStylesScoped$ } from '@builder.io/qwik';
 
type AlgoliaResult = {
  hits: {
    type: string;
    anchor?: string;
    content?: string;
    url: string;
  }[];
};
 
export default component$(() => {
  useStylesScoped$(`
    .search {
      font-size: 100%;
      width: calc(100% - 38px);
      border-radius: 0.5rem;
      border: 1px black solid;
      padding: 1rem;
      color: black;
      outline: none;
    }
 
    .search-button {
      border: none;
      padding: 6px 0px;
      cursor: pointer;
      background-color: transparent;
      position: absolute;
      right: 2.4rem;
      padding: 0.85rem 0.5rem 0.4rem 0.5rem;
      outline: none;
    }
 
    .list {
      display: flex;
      flex-direction: column;
      align-items: center;
    }
 
    .list li {
      counter-increment: cardCount;
      display: flex;
      color: white;
      margin-top: 1rem;
      margin-bottom: 1rem;
      max-width: 500px;
    }
 
    .list li::before {
      content: counter(cardCount, decimal-leading-zero);
      background: white;
      color: var(--cardColor);
      font-size: 2em;
      font-weight: 700;
      transform: translateY(calc(-1 * 1rem));
      margin-right: calc(-1 * 1rem);
      z-index: 1;
      display: flex;
      align-items: center;
      padding-inline: 0.5em;
      border: 1px solid black;
    }
 
    .list li .content {
      background-color: var(--cardColor);
      display: grid;
      padding: 0.5em calc(1em + 1.5rem) 0.5em calc(1em + 1rem);
      grid-template-areas:
        "icon title"
        "icon text";
      gap: 0.25em;
      clip-path: polygon(
        0 0,
        calc(100% - 1.5rem) 0,
        100% 50%,
        calc(100% - 1.5rem) 100%,
        calc(100% - 1.5rem) calc(100% + 1rem),
        0 calc(100% + 1rem)
      );
    }
 
    .list li .content .title {
      grid-area: title;
      font-size: 1.25em;
    }
 
    .list li .content .text {
      grid-area: text;
      color: black;
    }
  `);
  const termSignal = useSignal('');
  const hitsSig = useSignal<AlgoliaResult['hits']>([]);
 
  const onSearch = $(async (query: string) => {
    const algoliaURL = new URL(
      `/1/indexes/${import.meta.env.VITE_ALGOLIA_INDEX}/query`,
      `https://${import.meta.env.VITE_ALGOLIA_APP_ID}-dsn.algolia.net`
    );
    const response = await fetch(algoliaURL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Algolia-Application-Id': import.meta.env.VITE_ALGOLIA_APP_ID!,
        'X-Algolia-API-Key': import.meta.env.VITE_ALGOLIA_SEARCH_KEY!,
      },
      body: JSON.stringify({ query }),
    });
    const algoliaResult: AlgoliaResult = await response.json();
    hitsSig.value = algoliaResult.hits;
  });
 
  return (
    <div>
      <div style="margin: 1rem;">
        <div style="position: relative;">
          <input
            class="search"
            placeholder="Algolia search: type here and press enter"
            bind:value={termSignal}
            onKeyDown$={(e) => {
              if (e.key === 'Enter') {
                onSearch(termSignal.value);
              }
            }}
          />
          <button
            type="submit"
            class="search-button"
            onClick$={() => onSearch(termSignal.value)}
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="32"
              height="32"
              viewBox="0 0 24 24"
            >
              <path
                fill="currentColor"
                d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5A6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5S14 7.01 14 9.5S11.99 14 9.5 14z"
              />
            </svg>
          </button>
        </div>
      </div>
      <div class="list">
        {hitsSig.value.map(({ anchor, content, url }, key) => (
          <li
            key={key}
            style={`--cardColor:${key % 2 === 0 ? '#19b6f6' : '#ac7ef4'}`}
          >
            <div class="content">
              <div class="title">
                {(anchor || content || url || '').substring(0, 30)}
              </div>
              <a class="text" href={url}>
                Документация
              </a>
            </div>
          </li>
        ))}
      </div>
    </div>
  );
});

Участники

Спасибо всем участникам, которые помогли сделать эту документацию лучше!

  • gioboa