feat: hide search results container if no keyword is given (#1288)
feat: hide search results container if no keyword is given and add typing
This commit is contained in:
@@ -79,3 +79,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-result {
|
||||||
|
&.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
-13
@@ -26,15 +26,15 @@ const tagsToReplace = {
|
|||||||
'…': '…'
|
'…': '…'
|
||||||
};
|
};
|
||||||
|
|
||||||
function replaceTag(tag) {
|
function replaceTag(tag: string) {
|
||||||
return tagsToReplace[tag] || tag;
|
return (tagsToReplace as Record<string, string>)[tag] || tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceHTMLEnt(str) {
|
function replaceHTMLEnt(str: string) {
|
||||||
return str.replace(/[&<>"]/g, replaceTag);
|
return str.replace(/[&<>"]/g, replaceTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeRegExp(string) {
|
function escapeRegExp(string: string) {
|
||||||
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
|
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,13 +45,21 @@ class Search {
|
|||||||
private list: HTMLDivElement;
|
private list: HTMLDivElement;
|
||||||
private resultTitle: HTMLHeadElement;
|
private resultTitle: HTMLHeadElement;
|
||||||
private resultTitleTemplate: string;
|
private resultTitleTemplate: string;
|
||||||
|
private container: HTMLDivElement;
|
||||||
|
|
||||||
constructor({ form, input, list, resultTitle, resultTitleTemplate }) {
|
constructor({ form, input, list, resultTitle, resultTitleTemplate }: {
|
||||||
|
form: HTMLFormElement,
|
||||||
|
input: HTMLInputElement,
|
||||||
|
list: HTMLDivElement,
|
||||||
|
resultTitle: HTMLHeadingElement,
|
||||||
|
resultTitleTemplate: string
|
||||||
|
}) {
|
||||||
this.form = form;
|
this.form = form;
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.list = list;
|
this.list = list;
|
||||||
this.resultTitle = resultTitle;
|
this.resultTitle = resultTitle;
|
||||||
this.resultTitleTemplate = resultTitleTemplate;
|
this.resultTitleTemplate = resultTitleTemplate;
|
||||||
|
this.container = list.parentElement as HTMLDivElement;
|
||||||
|
|
||||||
/// Check if there's already value in the search input
|
/// Check if there's already value in the search input
|
||||||
if (this.input.value.trim() !== '') {
|
if (this.input.value.trim() !== '') {
|
||||||
@@ -203,16 +211,18 @@ class Search {
|
|||||||
const endTime = performance.now();
|
const endTime = performance.now();
|
||||||
|
|
||||||
this.resultTitle.innerText = this.generateResultTitle(results.length, ((endTime - startTime) / 1000).toPrecision(1));
|
this.resultTitle.innerText = this.generateResultTitle(results.length, ((endTime - startTime) / 1000).toPrecision(1));
|
||||||
|
|
||||||
|
this.container?.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateResultTitle(resultLen, time) {
|
private generateResultTitle(resultLen: number, time: string) {
|
||||||
return this.resultTitleTemplate.replace("#PAGES_COUNT", resultLen).replace("#TIME_SECONDS", time);
|
return this.resultTitleTemplate.replace("#PAGES_COUNT", resultLen.toString()).replace("#TIME_SECONDS", time);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getData() {
|
public async getData() {
|
||||||
if (!this.data) {
|
if (!this.data) {
|
||||||
/// Not fetched yet
|
/// Not fetched yet
|
||||||
const jsonURL = this.form.dataset.json;
|
const jsonURL = this.form.dataset.json as string;
|
||||||
this.data = await fetch(jsonURL).then(res => res.json());
|
this.data = await fetch(jsonURL).then(res => res.json());
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
|
|
||||||
@@ -227,7 +237,7 @@ class Search {
|
|||||||
private bindSearchForm() {
|
private bindSearchForm() {
|
||||||
let lastSearch = '';
|
let lastSearch = '';
|
||||||
|
|
||||||
const eventHandler = (e) => {
|
const eventHandler = (e: Event) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const keywords = this.input.value.trim();
|
const keywords = this.input.value.trim();
|
||||||
|
|
||||||
@@ -251,6 +261,7 @@ class Search {
|
|||||||
private clear() {
|
private clear() {
|
||||||
this.list.innerHTML = '';
|
this.list.innerHTML = '';
|
||||||
this.resultTitle.innerText = '';
|
this.resultTitle.innerText = '';
|
||||||
|
this.container.classList.add('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
private bindQueryStringChange() {
|
private bindQueryStringChange() {
|
||||||
@@ -261,7 +272,7 @@ class Search {
|
|||||||
|
|
||||||
private handleQueryString() {
|
private handleQueryString() {
|
||||||
const pageURL = new URL(window.location.toString());
|
const pageURL = new URL(window.location.toString());
|
||||||
const keywords = pageURL.searchParams.get('keyword');
|
const keywords = pageURL.searchParams.get('keyword') || '';
|
||||||
this.input.value = keywords;
|
this.input.value = keywords;
|
||||||
|
|
||||||
if (keywords) {
|
if (keywords) {
|
||||||
@@ -291,7 +302,8 @@ class Search {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static render(item: pageData) {
|
public static render(item: pageData) {
|
||||||
return <article>
|
return (
|
||||||
|
<article>
|
||||||
<a href={item.permalink}>
|
<a href={item.permalink}>
|
||||||
<div class="article-details">
|
<div class="article-details">
|
||||||
<h2 class="article-title" dangerouslySetInnerHTML={{ __html: item.title }}></h2>
|
<h2 class="article-title" dangerouslySetInnerHTML={{ __html: item.title }}></h2>
|
||||||
@@ -303,7 +315,8 @@ class Search {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</a>
|
</a>
|
||||||
</article>;
|
</article>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,10 +329,12 @@ declare global {
|
|||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
const searchForm = document.querySelector('.search-form') as HTMLFormElement,
|
const searchForm = document.querySelector('.search-form') as HTMLFormElement,
|
||||||
searchInput = searchForm.querySelector('input') as HTMLInputElement,
|
searchInput = searchForm?.querySelector('input') as HTMLInputElement,
|
||||||
searchResultList = document.querySelector('.search-result--list') as HTMLDivElement,
|
searchResultList = document.querySelector('.search-result--list') as HTMLDivElement,
|
||||||
searchResultTitle = document.querySelector('.search-result--title') as HTMLHeadingElement;
|
searchResultTitle = document.querySelector('.search-result--title') as HTMLHeadingElement;
|
||||||
|
|
||||||
|
if (!searchForm || !searchInput || !searchResultList || !searchResultTitle) return;
|
||||||
|
|
||||||
new Search({
|
new Search({
|
||||||
form: searchForm,
|
form: searchForm,
|
||||||
input: searchInput,
|
input: searchInput,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="search-result">
|
<div class="search-result hidden">
|
||||||
<h3 class="search-result--title section-title"></h3>
|
<h3 class="search-result--title section-title"></h3>
|
||||||
<div class="search-result--list article-list--compact"></div>
|
<div class="search-result--list article-list--compact"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user