O que é um dicionário sem um mecanismo de busca ou ummm o recurso de busca!?
Durante a implementação do dicionário base, criei esses formulários de pesquisa estáticos (um na página inicial e outro na barra de navegação usada no layout da palavra) em preparação para esse recurso específico.
Eu só precisava começar a partir daí e fazê-lo funcionar, um trabalho fácil - se isso fosse verdade.
Algo do passado
É importante reiterar que meu plano inicial era construir jargons.dev com Nextra como admiti no commit inicial que:
...Nextra (este era de fato meu cavaleiro de armadura brilhante, eu estava querendo construir com Nextra).
Eu sou um fã do React ⚛️, grande em Next.js; Nextra é uma estrutura da web com foco em conteúdo construída em Next.js. Então eu acho que você pode entender por que Nextra parecia aquele cavaleiro. Durante minha exploração inicial do Nextra, um recurso se destacou para mim; a pesquisa de texto completo - eu babava por causa disso (devo confessar).
O recurso foi desenvolvido com flexsearch – uma biblioteca de pesquisa de texto completo com profundidade zero; ooh cara, sou um grande fã de dependências leves e sem/baixas. Pesquisei como o Nextra usa isso para indexar conteúdo em tempo de construção para pesquisa; foi interessante.
Então!?
Eu me peguei hackeando com flexsearch durante meu primeiro encontro com o Astro; ao seguir o tutorial de construção de um blog do astro doc, fui um pouco além para implementar um recurso de pesquisa com muita facilidade.
Então, a experiência dessa implementação; Passei para o mecanismo de pesquisa jargons.dev.
O mecanismo de pesquisa
A tarefa foi bem simples, eu precisava..
Obtenha acesso ou chame-o de referência a todos os arquivos dentro do diretório do dicionário de palavras - neste ponto era o diretório src/pages/word -
Obtenha o conteúdo desses arquivos indexado com flexsearch -
Conecte o formulário de pesquisa e pronto ?-
Parece muito fácil! Talvez para a indexação da pesquisa e a pesquisa real fosse; mas houve muitas coisas necessárias para chegar lá.
Integrando a primeira "Ilha" em jargons.dev
O Astro, por padrão, adota uma abordagem que prioriza o servidor, o que significa que ele cria o HTML/CSS do seu site no servidor, removendo todo o javascript (JS) do lado do cliente automaticamente (a menos que você indique o contrário). A remoção de todo JS garante melhoria de desempenho, mas nenhum JS significa nenhuma interatividade; Mas se você quer interatividade, a Astro Island é um dos caminhos a percorrer. Preciso de interatividade para o mecanismo de pesquisa, então é Island!
O que é uma “Ilha”!?
Vou simplificar que uma Ilha é um componente interativo isolado em uma página da Web, cujo HTML/CSS é renderizado no lado do servidor e/mas o JavaScript do lado do cliente também é (hidratado) incluído nele - NÃO removido.
Dei uma palestra sobre Island na TILConf'24, confira para saber mais.
Oferta do Astro
Astro ofereceu suporte para integração de Ilhas prontas para uso com minha biblioteca de UI favorita (sim, você adivinhou, React) de muitas outras. Isso me permitiu transformar meus formulários de pesquisa estáticos em algo funcional.
Coisas que eu fiz
Comecei adicionando o módulo de integração (@astrojs/react) para a Ilha que precisava integrar; feito facilmente com o comando npx astro add react
- Transferi todos os formulários de pesquisa estáticos para um único componente React (são dois formulários de tamanhos diferentes); configurou o componente para renderizá-los no tamanho necessário com base em determinados adereços.
- Eu também implementei alguns subcomponentes que só são consumidos localmente no mesmo componente de pesquisa, estes são...
- O SearchDialog - componente principal onde é realizada a operação de pesquisa
- O componente SearchResult, etc...
-
Implementei alguns atalhos de teclado personalizados e combinações de teclas que permitem interações com o componente de pesquisa (gostaria de chamar isso de "Ilha de Pesquisa" de agora em diante), estes são...
-
CTRL K ou ⌘K para iniciar a pesquisa
-
ESC para fechar a pesquisa
- ...e botões de navegação básicos necessários para navegar nos resultados da pesquisa
-
Eu também adicionei alguns ganchos personalizados para permitir uma navegação tranquila no funcionamento da ilha de busca, estes são...
-
useLockBody - um gancho que desativa a rolagem quando a caixa de diálogo de pesquisa é aberta
-
useRouter - um gancho que fiz como wrapper em torno de alguns métodos window.location, fazendo com que eles se parecessem com as bibliotecas de roteador conhecidas no React, este é um gancho que consumi particularmente no manipulador de clique do botão ENTER no atalho de teclado do botão de navegação no componente de resultados de pesquisa na ilha de busca.
- e useIsMacOS - que verifica se uma máquina é MacOS para determinar o texto de descrição apropriado a ser renderizado no gatilho do formulário de pesquisa; ou seja, CTRL K ou ⌘K
-
Eu adicionei o módulo imperativo - flexsearch;
- Recuperei o acesso aos arquivos do diretório de palavras usando a função Astro.glob() com muita facilidade (uma pena que não pude falar sobre o quão poderosa essa função é; estou feliz por ela ter existido imediatamente no Astro e quanta facilidade isso trouxe para o fluxo de colocar esse mecanismo de pesquisa em funcionamento) e conectou a matriz retornada de objetos de palavras em um estado $dictionary (talvez eu deva chamar isso de loja) alimentado por nanostore (outra coisa linda ali mesmo)
- Este $dictionary é então indexado com flexsearch, preparando-os para pesquisa posterior.
-
Outra característica imperativa: as pesquisas recentes
Este é outro recurso imperativo sobre o qual devo falar; Este recurso rastreia os itens pesquisados e os armazena no armazenamento local para persisti-los no recarregamento da página; esses itens pesquisados na loja são então renderizados em uma lista na página inicial do dicionário.
Também foi necessária a integração como uma ilha, juntamente com a retenção do valor em um estado $recentSearches alimentado por nanostore.
Minha implementação desse recurso não é exatamente perfeita, e aqui está uma lista de alguns problemas que precisavam de correção (no momento da escrita) para dar um passo adiante nesse caminho (mesmo que nunca possamos alcançar a perfeição, SIM claro que sim)
Adicionar componente de carregamento à ilha de pesquisas recentes - https://github.com/devjargons/jargons.dev/issues/31
- Bug: operação de pesquisa realizada com formulário de pesquisa na barra de navegação substitui LocalStorage - https://github.com/devjargons/jargons.dev/issues/10
- Aprimoramento: Editor de Word - Recursos de segunda iteração - https://github.com/devjargons/jargons.dev/issues/9
-
As relações públicas
Esta é uma leitura longa agora, desejo mantê-la curta... Aqui está o PR
talento: implementar mecanismo de busca de dicionário
#5
Esta solicitação pull implementa a funcionalidade de pesquisa no projeto de dicionário. Ele usa integração @astro/react para alimentar as ilhas, juntamente com nanostore para gerenciamento de estado e flexsearch como biblioteca de pesquisa de texto.
Alterações feitas
Adicionada a seguinte integração astrojs e lib necessária para pesquisa de texto
- @astrojs/react
- @nanoslojas/react
- pesquisa flexível
-
Implementou a Ilha de Pesquisa (um componente de reação) onde outros subcomponentes são implementados para uso interno
- Implementado o componente SearchTrigger que renderiza um campo de pesquisa de dois tamanhos diferentes e usado em dois locais diferentes na página web...
- tamanho md - usado na página principal do aplicativo web
- tamanho sm - usado na seção de navegação de layout de palavras do dicionário
-
Implementado o componente SearchDialog, que é renderizado somente quando o SearchTrigger é clicado
- Implementado o componente SearchInfo, renderizado como espaço reservado padrão quando nenhum termo de pesquisa foi inserido no campo do formulário
- Implementado o componente SearchResult, renderiza resultados de pesquisa ou uma mensagem para resultados de pesquisa não encontrados
- Atalhos de teclado implementados na ilha de pesquisa para permitir a seguinte operação com os atalhos de teclado indicados
-
CTRL K ou ⌘K para abrir a caixa de diálogo de pesquisa sem clicar no tigger de pesquisa
-
ArrowUp, ArrowDown e Enter para permitir a navegação na lista de resultados da pesquisa
-
ESC para permitir o fechamento da caixa de diálogo de pesquisa
-
Adicionados ganchos personalizados para consumo na ilha de pesquisa
-
useIsMacOS – verifique se o usuário atual está navegando no aplicativo web com uma máquina MacOS; isso é usado para determinar o short apropriado para renderizar no gatilho de pesquisa; ou seja, CTRL K ou ⌘K
-
useLockBody - usado para desativar a rolagem da janela de visualização atual quando a caixa de diálogo de pesquisa é aberta
-
useRouter - (em vez de adicionar react-router ao deps) este gancho envolve window.location e usa o objeto de atribuição como push; usado principalmente no componente SearchResult para direcionar para a página de resultados selecionada/clicada
-
SearchIndexing implementado na ilha de pesquisa com o método Document do flexsearch como opção preferencial
- Adicionada uma nova loja de pesquisa para gerenciar os estados relacionados à pesquisa com nanostores e integração @nanostores/react
- Adicionados os seguintes valores e ações de armazenamento
-
$isSearchOpen – estado global para gerenciar o estado de SearchDialog
-
$recentSearches - estado para acompanhar as palavras pesquisadas recentemente; ele funciona em colaboração com o localStorage para persistir seu valor mesmo após o recarregamento da guia
-
$addToRecentSearchesFn - uma ação de loja que adiciona um novo item ao valor da loja $recentSearches
-
Adicionado um armazenamento $dictionary para gerenciar todas as entradas do dicionário; mantendo-o acessível ao cliente e usado como valor para searchIndex na ilha de pesquisa
- Valor calculado para o armazenamento de dicionário o mais cedo possível a partir do layout/base com o método Astro.glob() indexando todo o diretório do dicionárioAdicionada a ilha RecentSearches que lê o valor da loja $recentSearches e o renderiza na página inicial
-
Transmissão de tela
Demonstração completa
screencast-bpconcjcammlapcogcnnelfmaeghhagj-2024.03.25-13_32_30.webm
?
Ver no GitHub