This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
У Остання стаття Я показав вам, як встановити повний текстовий пошук, використовуючи вбудовані можливості повнотекстового пошуку у Postgres. Поки я викривав апі, у мене не було можливості його використати, так що це було трохи насмішкою. У цій статті я покажу вам, як використовувати api пошуку для пошуку тексту у вашій базі даних.
Попередні частини цієї серії:
Наступні частини цієї серії:
За допомогою цього пункту можна додати невеличке поле пошуку до заголовка сайта, за допомогою якого користувачі зможуть шукати текст у дописах блогу.
Зверніть увагу на те, що я не вважаю, як найкраще це зробити. Щоб підтримати багатомовність, мені потрібен супер комплекс (мені потрібна інша колонка на мову) і я повинен мати справу з сплетенням та іншими специфічними для мови речами. Зараз я це проігнорую і зосередити увагу на англійській. ПОНАД того ми продемонструємо, як поводитися з цим у OpenSearch.
Щоб додати можливість пошуку, я повинен був зробити деякі зміни в api пошуку. Я додав обробки для фраз, використовуючи EF.Functions.WebSearchToTsQuery("english", processedQuery)
private async Task<List<(string Title, string Slug)>> GetSearchResultForQuery(string query)
{
var processedQuery = query;
var posts = await context.BlogPosts
.Include(x => x.Categories)
.Include(x => x.LanguageEntity)
.Where(x =>
// Search using the precomputed SearchVector
(x.SearchVector.Matches(EF.Functions.WebSearchToTsQuery("english", processedQuery)) // Use precomputed SearchVector for title and content
|| x.Categories.Any(c =>
EF.Functions.ToTsVector("english", c.Name)
.Matches(EF.Functions.WebSearchToTsQuery("english", processedQuery)))) // Search in categories
&& x.LanguageEntity.Name == "en")// Filter by language
.OrderByDescending(x =>
// Rank based on the precomputed SearchVector
x.SearchVector.Rank(EF.Functions.WebSearchToTsQuery("english", processedQuery))) // Use precomputed SearchVector for ranking
.Select(x => new { x.Title, x.Slug, })
.Take(5)
.ToListAsync();
return posts.Select(x=> (x.Title, x.Slug)).ToList();
}
Це, за бажання, використовується, якщо у запиті є пробіл
if (!query.Contains(" "))
{
posts = await GetSearchResultForComplete(query);
}
else
{
posts = await GetSearchResultForQuery(query);
}
У іншому випадку буде використано існуючий метод пошуку, за допомогою якого буде додано символ префікса.
EF.Functions.ToTsQuery("english", query + ":*")
Користування Альпійський.js Я зробив простий частковий контроль, який забезпечує надпросту скриньку для пошуку.
<div x-data="window.mostlylucid.typeahead()" class="relative" x-on:click.outside="results = []">
<label class="input input-sm dark:bg-custom-dark-bg bg-white input-bordered flex items-center gap-2">
<input
type="text"
x-model="query"
x-on:input.debounce.300ms="search"
x-on:keydown.down.prevent="moveDown"
x-on:keydown.up.prevent="moveUp"
x-on:keydown.enter.prevent="selectHighlighted"
placeholder="Search..."
class="border-0 grow input-sm text-black dark:text-white bg-transparent w-full"/>
<i class="bx bx-search"></i>
</label>
<!-- Dropdown -->
<ul x-show="results.length > 0"
class="absolute z-10 my-2 w-full bg-white dark:bg-custom-dark-bg border border-1 text-black dark:text-white border-b-neutral-600 dark:border-gray-300 rounded-lg shadow-lg">
<template x-for="(result, index) in results" :key="result.slug">
<li
x-on:click="selectResult(result)"
:class="{
'dark:bg-blue-dark bg-blue-light': index === highlightedIndex,
'dark:hover:bg-blue-dark hover:bg-blue-light': true
}"
class="cursor-pointer text-sm p-2 m-2"
x-text="result.title"
></li>
</template>
</ul>
</div>
Це має набір класів CSS, які правильно відтворюються для темного або світлого режиму. Кодекс альпійських.js досить простий. Це просте керування типом шапки, яке викликає api пошуку, якщо користувач вводить у поле пошуку. У нас також є невеликий код, за допомогою якого ми можемо не фокусувати фокус, щоб закрити результати пошуку.
x-on:click.outside="results = []"
Помітьте, у нас тут дебют, щоб не забивати сервер просьбами.
Це викликає в нашу функцію JS (визначений в src/js/main.js
)
window.mostlylucid = window.mostlylucid || {};
window.mostlylucid.typeahead = function () {
return {
query: '',
results: [],
highlightedIndex: -1, // Tracks the currently highlighted index
search() {
if (this.query.length < 2) {
this.results = [];
this.highlightedIndex = -1;
return;
}
fetch(`/api/search/${encodeURIComponent(this.query)}`)
.then(response => response.json())
.then(data => {
this.results = data;
this.highlightedIndex = -1; // Reset index on new search
});
},
moveDown() {
if (this.highlightedIndex < this.results.length - 1) {
this.highlightedIndex++;
}
},
moveUp() {
if (this.highlightedIndex > 0) {
this.highlightedIndex--;
}
},
selectHighlighted() {
if (this.highlightedIndex >= 0 && this.highlightedIndex < this.results.length) {
this.selectResult(this.results[this.highlightedIndex]);
}
},
selectResult(result) {
window.location.href = result.url;
this.results = []; // Clear the results
this.highlightedIndex = -1; // Reset the highlighted index
}
}
}
Як ви можете бачити, це досить просто (багато складністю є керування клавішами вгору і вниз для вибору результатів).
Це дописи до нашого SearchApi
Коли буде обрано результат, ми перейдемо до адреси url результату.
search() {
if (this.query.length < 2) {
this.results = [];
this.highlightedIndex = -1;
return;
}
fetch(`/api/search/${encodeURIComponent(this.query)}`)
.then(response => response.json())
.then(data => {
this.results = data;
this.highlightedIndex = -1; // Reset index on new search
});
},
Я також змінив отримання на роботу з HTMX, це просто змінює search
Метод для використання оновлення HTMX:
selectResult(result) {
htmx.ajax('get', result.url, {
target: '#contentcontainer', // The container to update
swap: 'innerHTML', // Replace the content inside the target
}).then(function() {
history.pushState(null, '', result.url); // Push the new url to the history
});
this.results = []; // Clear the results
this.highlightedIndex = -1; // Reset the highlighted index
this.query = ''; // Clear the query
}
Зауважте, що ми змінюємо внутрішній HTML contentcontainer
з результатами пошуку. Це простий спосіб оновлення вмісту сторінки з результатом пошуку без оновлення сторінки.
Ми також змінюємо URL в історії на новий URL.
За допомогою цього пункту можна додати до сайта потужну, але просту можливість пошуку. Це чудовий спосіб допомогти користувачам знайти те, що вони шукають. Це надає цьому сайту більш професійного відчуття і полегшує навігацію.