Skip to content

Instantly share code, notes, and snippets.

@tao
Last active June 15, 2021 15:02
Show Gist options
  • Save tao/b827a4c3a4c0fad06fa52eee4208f0cc to your computer and use it in GitHub Desktop.
Save tao/b827a4c3a4c0fad06fa52eee4208f0cc to your computer and use it in GitHub Desktop.
Statamic Typesense: search single index on the client example
<html>
<head>
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
<script src="//unpkg.com/alpinejs" defer></script>
<style>
[x-cloak] {
display: none !important;
}
</style>
</head>
<body>
<div class="relative"
x-data="{
searchString: '',
currentIndex: window.searchIndex,
results: {
hits: [],
},
indexes: {
results: [],
},
async search() {
this.state = 'searching';
let searchConfig = {
q: this.searchString,
query_by: 'title, content',
highlight_affix_num_tokens: 20,
highlight_start_tag: '<mark>',
highlight_end_tag: '</mark>',
filter_by: 'locale:en',
};
// SINGLE SEARCH
this.results = await window.typesense
.collections(this.currentIndex)
.documents()
.search(searchConfig)
.then(function (searchResults) {
// format highlights in each search result
let _formatted = searchResults.hits.map(result => {
// convert highlights to object
let highlights = {};
result.highlights.map(el => {
highlights[el.field] = el.snippet
});
return { ...result, highlights };
})
// response
return { ...searchResults, hits: _formatted }
}).catch(function (error) {
console.log(error)
})
},
}"
>
<div class="flex flex-col justify-center p-8">
<!-- search input -->
<form id="js-search-form" action="javascript:void(0);" class="flex w-full items-center space-x-4">
<input x-model="searchString" x-on:input="search()" type="search" id="js-search-bar" class="shadow appearance-none border border-medium rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" name="q" placeholder="Start typing to search..." autocomplete="off" autofocus>
</form>
<!-- search results -->
<div
x-cloak
x-show="searchString.length > 0"
>
<template x-if="results.hits.length > 0">
<div class="py-16">
<div class="flex justify-between text-gray-500 pb-4">
<h3 x-text="currentIndex" class="font-bold capitalize"></h3>
<p class="text-meta" x-text="results.hits.length === 0 ? 'No results.' : ''"></p>
</div>
<div class="content">
<ul class="space-y-4 divide-y divide-dashed search--results">
<template x-for='result in results.hits' :key="result.document.id">
<li class="p-4 hover:bg-gray-100 rounded">
<a
:href="result.document.url"
class="mt-8"
>
<p class="text-base font-medium text-blue-600 mb-0" x-html="result.highlights.title ?? result.document.title"></p>
<p class="text-meta text-sm mb-0" x-html="result.highlights.content ?? result.document.synopsis ?? ''"></p>
</a>
</li>
</template>
</ul>
</div>
</div>
</template>
</div>
</div>
</div>
<!-- Alpine: add x-html -->
<script>
document.addEventListener('alpine:initializing', () => {
Alpine.directive('html', (el, { expression }, { evaluateLater, effect }) => {
let getHtml = evaluateLater(expression)
effect(() => {
getHtml(html => {
el.innerHTML = html
})
})
})
})
</script>
<!-- Typesense -->
<script src="https://cdn.jsdelivr.net/npm/typesense@latest/dist/typesense.min.js"></script>
<script>
window.typesense = new Typesense.Client({
'nodes': [
{
'host': TYPESENSE_SERVER_URL,
'port': '443',
'protocol': 'https'
}
],
'apiKey': TYPESENSE_API_KEY,
'numRetries': 3, // A total of 4 tries (1 original try + 3 retries)
'connectionTimeoutSeconds': 10,
'logLevel': 'debug'
});
window.searchIndex = 'movies';
window.locale = 'en';
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment