feat(search.html): update to disable and show loading state w/load more button; improve fuzzy search + debounce
This commit is contained in:
parent
63db0cf32a
commit
8a6e84cb35
35 changed files with 119 additions and 395 deletions
|
@ -36,7 +36,7 @@ permalink: "{{ feed.permalink }}.xml"
|
|||
{%- endif -%}
|
||||
<description><![CDATA[
|
||||
{%- if feedItem.image -%}
|
||||
<img src="{{ feedItem.image | encodeAmp }}?class=w800" alt="Image from {{ feedItem.title }}" />
|
||||
<img src="{{ feedItem.image | encodeAmp }}?class=w800" alt="Image from {{ feedItem.title }}">
|
||||
{%- endif -%}
|
||||
{%- if feedItem.content -%}
|
||||
{{ feedItem.content | markdown | convertRelativeLinks: globals.url }}
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
decoding="async"
|
||||
width="720"
|
||||
height="480"
|
||||
/>
|
||||
>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
{%- for block in blocks -%}
|
||||
{%- case block.type -%}
|
||||
{%- when "youtube_player" -%}
|
||||
{% render "blocks/youtube-player.liquid",
|
||||
url:block.url
|
||||
{%- when "calendar_banner" -%}
|
||||
{% render "blocks/banners/calendar.liquid",
|
||||
url:block.url,
|
||||
text:block.text
|
||||
%}
|
||||
{%- when "divider" -%}
|
||||
{{ block.markup | markdown }}
|
||||
{%- when "forgejo_banner" -%}
|
||||
{% render "blocks/banners/forgejo.liquid",
|
||||
url:block.url
|
||||
|
@ -12,6 +15,14 @@
|
|||
{% render "blocks/banners/github.liquid",
|
||||
url:block.url
|
||||
%}
|
||||
{%- when "hero" -%}
|
||||
{% render "blocks/hero.liquid",
|
||||
globals:globals,
|
||||
image:block.image,
|
||||
alt:block.alt
|
||||
%}
|
||||
{%- when "markdown" -%}
|
||||
{{ block.text | markdown }}
|
||||
{%- when "npm_banner" -%}
|
||||
{% render "blocks/banners/npm.liquid",
|
||||
url:block.url,
|
||||
|
@ -22,15 +33,9 @@
|
|||
url:block.url,
|
||||
text:block.text
|
||||
%}
|
||||
{%- when "hero" -%}
|
||||
{% render "blocks/hero.liquid",
|
||||
globals:globals,
|
||||
image:block.image,
|
||||
alt:block.alt
|
||||
{%- when "youtube_player" -%}
|
||||
{% render "blocks/youtube-player.liquid",
|
||||
url:block.url
|
||||
%}
|
||||
{%- when "markdown" -%}
|
||||
{{ block.text | markdown }}
|
||||
{%- when "divider" -%}
|
||||
{{ block.markup | markdown }}
|
||||
{%- endcase -%}
|
||||
{%- endfor -%}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
require __DIR__ . "/../../server/utils/init.php";
|
||||
|
||||
use App\Classes\ArtistFetcher;
|
||||
use voku\helper\HtmlMin;
|
||||
|
||||
$requestUri = $_SERVER["REQUEST_URI"];
|
||||
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
|
||||
|
@ -21,7 +20,6 @@
|
|||
$page = $artist;
|
||||
|
||||
extract(setupPageMetadata($page, $requestUri));
|
||||
ob_start();
|
||||
header("Cache-Control: public, max-age=3600");
|
||||
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT");
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
require __DIR__ . "/../../server/utils/init.php";
|
||||
|
||||
use App\Classes\BookFetcher;
|
||||
use voku\helper\HtmlMin;
|
||||
|
||||
$requestUri = $_SERVER["REQUEST_URI"];
|
||||
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
|
||||
|
@ -22,7 +21,6 @@
|
|||
$globals = $page["globals"];
|
||||
|
||||
extract(setupPageMetadata($page, $requestUri));
|
||||
ob_start();
|
||||
header("Cache-Control: public, max-age=3600");
|
||||
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT");
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
require __DIR__ . "/../../server/utils/init.php";
|
||||
|
||||
use App\Classes\GenreFetcher;
|
||||
use voku\helper\HtmlMin;
|
||||
|
||||
$requestUri = $_SERVER["REQUEST_URI"];
|
||||
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
|
||||
|
@ -21,8 +20,6 @@
|
|||
$globals = $page["globals"];
|
||||
|
||||
extract(setupPageMetadata($page, $requestUri));
|
||||
|
||||
ob_start();
|
||||
header("Cache-Control: public, max-age=3600");
|
||||
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT");
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
require __DIR__ . "/../../server/utils/init.php";
|
||||
|
||||
use App\Classes\MovieFetcher;
|
||||
use voku\helper\HtmlMin;
|
||||
|
||||
$requestUri = $_SERVER["REQUEST_URI"];
|
||||
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
|
||||
|
@ -22,7 +21,6 @@
|
|||
$globals = $page["globals"];
|
||||
|
||||
extract(setupPageMetadata($page, $requestUri));
|
||||
ob_start();
|
||||
header("Cache-Control: public, max-age=3600");
|
||||
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT");
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
require __DIR__ . "/../../server/utils/init.php";
|
||||
|
||||
use App\Classes\ShowFetcher;
|
||||
use voku\helper\HtmlMin;
|
||||
|
||||
$requestUri = $_SERVER["REQUEST_URI"];
|
||||
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
|
||||
|
@ -22,7 +21,6 @@
|
|||
$globals = $page["globals"];
|
||||
|
||||
extract(setupPageMetadata($page, $requestUri));
|
||||
ob_start();
|
||||
header("Cache-Control: public, max-age=3600");
|
||||
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT");
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
use App\Classes\TagFetcher;
|
||||
use App\Classes\GlobalsFetcher;
|
||||
use voku\helper\HtmlMin;
|
||||
|
||||
$requestUri = $_SERVER["REQUEST_URI"];
|
||||
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
|
||||
|
@ -63,7 +62,6 @@
|
|||
];
|
||||
|
||||
extract(setupPageMetadata($page, $requestUri));
|
||||
ob_start();
|
||||
header("Cache-Control: public, max-age=3600");
|
||||
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT");
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
"
|
||||
sizes="(max-width: 450px) 100px, 200px"
|
||||
class="icon" src="{{ globals.avatar_header }}?class=w100&v={% appVersion %}"
|
||||
alt="{{ globals.site_name }}"
|
||||
alt="An avatar representing {{ globals.site_name }}"
|
||||
width="100"
|
||||
height="145"
|
||||
/>
|
||||
>
|
||||
<span>Cory</span> <span>Dransfeldt</span>
|
||||
{%- endcapture -%}
|
||||
<section class="main-title">
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
decoding="async"
|
||||
width="{{ width }}"
|
||||
height="{{ height }}"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
</a>
|
||||
{%- endfor -%}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
decoding="async"
|
||||
width="64"
|
||||
height="64"
|
||||
/>
|
||||
>
|
||||
</a>
|
||||
<div class="meta-text">
|
||||
<a class="title" href="{{ item.chart.url }}">{{ item.chart.title }}</a>
|
||||
|
|
|
@ -83,23 +83,22 @@ Redirect {{ redirect.status_code | default: "301" }} {{ redirect.source_url }} {
|
|||
</FilesMatch>
|
||||
{% endfor %}
|
||||
|
||||
{%- assign userAgents = "" -%}
|
||||
{% for robot in robots -%}
|
||||
{%- for userAgent in robot.user_agents -%}
|
||||
{%- if userAgent != "*" and userAgent != "NaN" -%}
|
||||
{%- assign userAgents = userAgents | append: userAgent %}
|
||||
{%- unless forloop.last -%}
|
||||
{%- assign userAgents = userAgents | append: "|" -%}
|
||||
{%- endunless -%}
|
||||
{%- assign escapedAgents = "" -%}
|
||||
{%- for robot in robots -%}
|
||||
{%- for agent in robot.user_agents -%}
|
||||
{%- if agent != "*" and agent != "NaN" -%}
|
||||
{%- assign escaped = agent | regexEscape -%}
|
||||
{%- assign escapedAgents = escapedAgents | append: escaped | append: "|" -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endfor %}
|
||||
{% if userAgents != "" or referers != "" -%}
|
||||
RewriteCond %{HTTP_USER_AGENT} "{{ userAgents }}" [NC]
|
||||
{%- endfor -%}
|
||||
{%- assign userAgentsRegex = escapedAgents | slice: 0, escapedAgents.size | rstrip: "|" -%}
|
||||
{% if userAgentsRegex != "" %}
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTP_USER_AGENT} "{{ userAgentsRegex }}" [NC]
|
||||
RewriteCond %{REQUEST_URI} !^/robots\.txt$ [NC]
|
||||
RewriteRule .* /403/index.html [L,R=403]
|
||||
{%- endif %}
|
||||
|
||||
RewriteRule ^.*$ - [F,L]
|
||||
{% endif %}
|
||||
<IfModule mod_deflate.c>
|
||||
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
|
||||
</IfModule>
|
||||
|
|
|
@ -10,7 +10,7 @@ schema: artist
|
|||
class="media-image"
|
||||
srcset="
|
||||
<?= htmlspecialchars($artist["image"]) ?>?class=w200&type=webp 200w,
|
||||
<?= htmlspecialchars($artist["image"]) ?>?class=w600&type=webp 400w,
|
||||
<?= htmlspecialchars($artist["image"]) ?>?class=w400&type=webp 400w,
|
||||
<?= htmlspecialchars($artist["image"]) ?>?class=w800&type=webp 800w
|
||||
"
|
||||
sizes="(max-width: 450px) 200px,
|
||||
|
@ -21,7 +21,7 @@ schema: artist
|
|||
decoding="async"
|
||||
width="200"
|
||||
height="200"
|
||||
/>
|
||||
>
|
||||
<div class="media-meta">
|
||||
<h2 class="page-title"><?= htmlspecialchars($artist["name"]) ?></h2>
|
||||
<span class="sub-meta country">{% tablericon "map-pin" %} <?= htmlspecialchars(
|
||||
|
@ -111,13 +111,3 @@ schema: artist
|
|||
<?php renderMediaGrid($artist["albums"]); ?>
|
||||
<?php endif; ?>
|
||||
</article>
|
||||
<?php
|
||||
$html = ob_get_clean();
|
||||
$htmlMin = new HtmlMin();
|
||||
$htmlMin->doOptimizeAttributes(true);
|
||||
$htmlMin->doRemoveComments(true);
|
||||
$htmlMin->doSumUpWhitespace(true);
|
||||
$htmlMin->doRemoveWhitespaceAroundTags(true);
|
||||
$htmlMin->doOptimizeViaHtmlDomParser(false);
|
||||
echo $htmlMin->minify($html);
|
||||
?>
|
||||
|
|
|
@ -22,7 +22,7 @@ schema: book
|
|||
decoding="async"
|
||||
width="200"
|
||||
height="307"
|
||||
/>
|
||||
>
|
||||
<div class="media-meta">
|
||||
<h2 class="page-title"><?= htmlspecialchars($book["title"]) ?></h2>
|
||||
<?php if (!empty($book["tags"])): ?>
|
||||
|
@ -67,13 +67,3 @@ schema: book
|
|||
<?= parseMarkdown($book["description"]) ?>
|
||||
<?php endif; ?>
|
||||
</article>
|
||||
<?php
|
||||
$html = ob_get_clean();
|
||||
$htmlMin = new HtmlMin();
|
||||
$htmlMin->doOptimizeAttributes(true);
|
||||
$htmlMin->doRemoveComments(true);
|
||||
$htmlMin->doSumUpWhitespace(true);
|
||||
$htmlMin->doRemoveWhitespaceAroundTags(true);
|
||||
$htmlMin->doOptimizeViaHtmlDomParser(false);
|
||||
echo $htmlMin->minify($html);
|
||||
?>
|
||||
|
|
|
@ -45,13 +45,3 @@ schema: genre
|
|||
<button data-toggle-button>Show more</button>
|
||||
<?php endif; ?>
|
||||
</article>
|
||||
<?php
|
||||
$html = ob_get_clean();
|
||||
$htmlMin = new HtmlMin();
|
||||
$htmlMin->doOptimizeAttributes(true);
|
||||
$htmlMin->doRemoveComments(true);
|
||||
$htmlMin->doSumUpWhitespace(true);
|
||||
$htmlMin->doRemoveWhitespaceAroundTags(true);
|
||||
$htmlMin->doOptimizeViaHtmlDomParser(false);
|
||||
echo $htmlMin->minify($html);
|
||||
?>
|
||||
|
|
|
@ -20,7 +20,7 @@ schema: movie
|
|||
decoding="async"
|
||||
width="256"
|
||||
height="180"
|
||||
/>
|
||||
>
|
||||
<div class="media-meta">
|
||||
<h2 class="page-title"><?= htmlspecialchars($movie["title"]) ?> (<?= htmlspecialchars($movie["year"]) ?>)</h2>
|
||||
<?php if (!empty($movie["tags"])): ?>
|
||||
|
@ -63,13 +63,3 @@ schema: movie
|
|||
<?= parseMarkdown($movie["description"]) ?>
|
||||
<?php endif; ?>
|
||||
</article>
|
||||
<?php
|
||||
$html = ob_get_clean();
|
||||
$htmlMin = new HtmlMin();
|
||||
$htmlMin->doOptimizeAttributes(true);
|
||||
$htmlMin->doRemoveComments(true);
|
||||
$htmlMin->doSumUpWhitespace(true);
|
||||
$htmlMin->doRemoveWhitespaceAroundTags(true);
|
||||
$htmlMin->doOptimizeViaHtmlDomParser(false);
|
||||
echo $htmlMin->minify($html);
|
||||
?>
|
||||
|
|
|
@ -20,7 +20,7 @@ schema: show
|
|||
decoding="async"
|
||||
width="256"
|
||||
height="180"
|
||||
/>
|
||||
>
|
||||
<div class="media-meta">
|
||||
<h2 class="page-title"><?= htmlspecialchars($show["title"]) ?> (<?= htmlspecialchars($show["year"]) ?>)</h2>
|
||||
<?php if (!empty($show["tags"])): ?>
|
||||
|
@ -60,13 +60,3 @@ schema: show
|
|||
<?= parseMarkdown($show["description"]) ?>
|
||||
<?php endif; ?>
|
||||
</article>
|
||||
<?php
|
||||
$html = ob_get_clean();
|
||||
$htmlMin = new HtmlMin();
|
||||
$htmlMin->doOptimizeAttributes(true);
|
||||
$htmlMin->doRemoveComments(true);
|
||||
$htmlMin->doSumUpWhitespace(true);
|
||||
$htmlMin->doRemoveWhitespaceAroundTags(true);
|
||||
$htmlMin->doOptimizeViaHtmlDomParser(false);
|
||||
echo $htmlMin->minify($html);
|
||||
?>
|
||||
|
|
|
@ -38,13 +38,3 @@ schema: tags
|
|||
</article>
|
||||
<?php endforeach; ?>
|
||||
<?php renderPaginator($pagination, $totalPages); ?>
|
||||
<?php
|
||||
$html = ob_get_clean();
|
||||
$htmlMin = new HtmlMin();
|
||||
$htmlMin->doOptimizeAttributes(true);
|
||||
$htmlMin->doRemoveComments(true);
|
||||
$htmlMin->doSumUpWhitespace(true);
|
||||
$htmlMin->doRemoveWhitespaceAroundTags(true);
|
||||
$htmlMin->doOptimizeViaHtmlDomParser(false);
|
||||
echo $htmlMin->minify($html);
|
||||
?>
|
||||
|
|
|
@ -37,7 +37,7 @@ updated: "now"
|
|||
decoding="async"
|
||||
width="200"
|
||||
height="307"
|
||||
/>
|
||||
>
|
||||
</a>
|
||||
<div class="media-meta">
|
||||
<a href="{{ book.url }}">
|
||||
|
|
|
@ -40,7 +40,7 @@ schema: blog
|
|||
decoding="async"
|
||||
width="200"
|
||||
height="auto"
|
||||
/>
|
||||
>
|
||||
{%- endif -%}
|
||||
{{ post.content | markdown }}
|
||||
{% render "blocks/index.liquid",
|
||||
|
|
|
@ -23,7 +23,7 @@ excludeFromSitemap: true
|
|||
decoding="async"
|
||||
width="720"
|
||||
height="480"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<h2 style="text-align:center">403</h2>
|
||||
|
|
|
@ -23,7 +23,7 @@ excludeFromSitemap: true
|
|||
decoding="async"
|
||||
width="720"
|
||||
height="480"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
<h2 style="text-align:center">404</h2>
|
||||
<p style="text-align:center">What kind of idiots do you have working here?</p>
|
||||
|
|
|
@ -23,7 +23,7 @@ excludeFromSitemap: true
|
|||
decoding="async"
|
||||
width="720"
|
||||
height="480"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
<div style="text-align:center">
|
||||
<h2>429</h2>
|
||||
|
|
|
@ -23,7 +23,7 @@ excludeFromSitemap: true
|
|||
decoding="async"
|
||||
width="720"
|
||||
height="480"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
<div style="text-align:center">
|
||||
<h2>500</h2>
|
||||
|
|
|
@ -84,7 +84,8 @@ description: Search through posts and other content on my site.
|
|||
searchOptions: {
|
||||
fields: ["title", "tags"],
|
||||
prefix: true,
|
||||
fuzzy: 0.1,
|
||||
fuzzy: 0.3,
|
||||
combineWith: "OR",
|
||||
boost: { title: 5, tags: 2, description: 1 },
|
||||
},
|
||||
});
|
||||
|
@ -94,12 +95,11 @@ description: Search through posts and other content on my site.
|
|||
const $input = document.querySelector(".search__form--input");
|
||||
const $results = document.querySelector(".search__results");
|
||||
const $loadMoreButton = document.querySelector(".search__load-more");
|
||||
const $typeCheckboxes = document.querySelectorAll(
|
||||
'.search__form--type input[type="checkbox"]',
|
||||
);
|
||||
const $typeCheckboxes = document.querySelectorAll('.search__form--type input[type="checkbox"]');
|
||||
|
||||
$form.removeAttribute("action");
|
||||
$form.removeAttribute("method");
|
||||
|
||||
if ($fallback) $fallback.remove();
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
|
@ -107,7 +107,7 @@ description: Search through posts and other content on my site.
|
|||
let currentResults = [];
|
||||
let total = 0;
|
||||
let debounceTimeout;
|
||||
|
||||
let isLoading = false;
|
||||
const parseMarkdown = (markdown) =>
|
||||
markdown
|
||||
? markdown
|
||||
|
@ -117,7 +117,6 @@ description: Search through posts and other content on my site.
|
|||
.replace(/\n/g, "<br>")
|
||||
.replace(/[#*_~`]/g, "")
|
||||
: "";
|
||||
|
||||
const truncateDescription = (markdown, maxLength = 225) => {
|
||||
const plainText =
|
||||
new DOMParser().parseFromString(parseMarkdown(markdown), "text/html")
|
||||
|
@ -126,12 +125,29 @@ description: Search through posts and other content on my site.
|
|||
? `${plainText.substring(0, maxLength)}...`
|
||||
: plainText;
|
||||
};
|
||||
|
||||
const renderSearchResults = (results) => {
|
||||
const resultHTML = results
|
||||
.map(
|
||||
({ title, url, description, type, total_plays }) => `
|
||||
<li class="search__results--result">
|
||||
<li class="search__results--result">
|
||||
<h3>
|
||||
<a href="${url}">${title}</a>
|
||||
${type === "artist" && total_plays > 0 ? ` <mark>${total_plays} plays</mark>` : ""}
|
||||
</h3>
|
||||
<p>${truncateDescription(description)}</p>
|
||||
</li>
|
||||
`,
|
||||
)
|
||||
.join("");
|
||||
|
||||
$results.innerHTML = resultHTML || '<li class="search__results--no-results">No results found.</li>';
|
||||
$results.style.display = "block";
|
||||
};
|
||||
const appendSearchResults = (results) => {
|
||||
const newResultsHTML = results
|
||||
.map(
|
||||
({ title, url, description, type, total_plays }) => `
|
||||
<li class="search__results--result">
|
||||
<h3>
|
||||
<a href="${url}">${title}</a>
|
||||
${
|
||||
|
@ -140,45 +156,50 @@ description: Search through posts and other content on my site.
|
|||
: ""
|
||||
}
|
||||
</h3>
|
||||
<p>${truncateDescription(description)}</p>
|
||||
</li>
|
||||
`,
|
||||
<p>${truncateDescription(description)}</p>
|
||||
</li>
|
||||
`,
|
||||
)
|
||||
.join("");
|
||||
|
||||
$results.innerHTML =
|
||||
resultHTML ||
|
||||
'<li class="search__results--no-results">No results found.</li>';
|
||||
$results.style.display = "block";
|
||||
$results.insertAdjacentHTML("beforeend", newResultsHTML);
|
||||
};
|
||||
|
||||
const getSelectedTypes = () => Array.from($typeCheckboxes).filter((cb) => cb.checked).map((cb) => cb.value);
|
||||
const loadSearchIndex = async (query, types, page) => {
|
||||
isLoading = true;
|
||||
$loadMoreButton.disabled = true;
|
||||
$loadMoreButton.textContent = "Loading...";
|
||||
|
||||
try {
|
||||
const typeQuery = types.join(",");
|
||||
const response = await fetch(
|
||||
`https://www.coryd.dev/api/search.php?q=${query}&type=${typeQuery}&page=${page}&pageSize=${PAGE_SIZE}`,
|
||||
`https://www.coryd.dev/api/search.php?q=${encodeURIComponent(
|
||||
query,
|
||||
)}&type=${typeQuery}&page=${page}&pageSize=${PAGE_SIZE}`,
|
||||
);
|
||||
const data = await response.json();
|
||||
|
||||
total = data.total || 0;
|
||||
|
||||
const formattedResults = (data.results || []).map((item) => ({
|
||||
...item,
|
||||
id: item.result_id,
|
||||
}));
|
||||
|
||||
miniSearch.removeAll();
|
||||
miniSearch.addAll(formattedResults);
|
||||
|
||||
return formattedResults;
|
||||
} catch (error) {
|
||||
console.error("Error fetching search data:", error);
|
||||
|
||||
return [];
|
||||
} finally {
|
||||
isLoading = false;
|
||||
$loadMoreButton.disabled = false;
|
||||
$loadMoreButton.textContent = "Load More";
|
||||
}
|
||||
};
|
||||
|
||||
const getSelectedTypes = () =>
|
||||
Array.from($typeCheckboxes)
|
||||
.filter((cb) => cb.checked)
|
||||
.map((cb) => cb.value);
|
||||
|
||||
const updateSearchResults = (results) => {
|
||||
if (currentPage === 1) {
|
||||
renderSearchResults(results);
|
||||
|
@ -189,58 +210,45 @@ description: Search through posts and other content on my site.
|
|||
currentPage * PAGE_SIZE < total ? "block" : "none";
|
||||
};
|
||||
|
||||
const appendSearchResults = (results) => {
|
||||
const newResultsHTML = results
|
||||
.map(
|
||||
({ title, url, description, type, total_plays }) => `
|
||||
<li class="search__results--result">
|
||||
<h3>
|
||||
<a href="${url}">${title}</a>
|
||||
${
|
||||
type === "artist" && total_plays > 0
|
||||
? ` <mark>${total_plays} plays</mark>`
|
||||
: ""
|
||||
}
|
||||
</h3>
|
||||
<p>${truncateDescription(description)}</p>
|
||||
</li>
|
||||
`,
|
||||
)
|
||||
.join("");
|
||||
$results.insertAdjacentHTML("beforeend", newResultsHTML);
|
||||
};
|
||||
|
||||
const handleSearch = async () => {
|
||||
const query = $input.value.trim();
|
||||
|
||||
if (!query) {
|
||||
renderSearchResults([]);
|
||||
|
||||
$loadMoreButton.style.display = "none";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$results.innerHTML = '<li class="search__results--loading">Searching...</li>';
|
||||
$results.style.display = "block";
|
||||
$loadMoreButton.style.display = "none";
|
||||
|
||||
const results = await loadSearchIndex(query, getSelectedTypes(), 1);
|
||||
|
||||
currentResults = results;
|
||||
currentPage = 1;
|
||||
|
||||
updateSearchResults(results);
|
||||
};
|
||||
|
||||
$input.addEventListener("input", () => {
|
||||
clearTimeout(debounceTimeout);
|
||||
debounceTimeout = setTimeout(handleSearch, 150);
|
||||
debounceTimeout = setTimeout(handleSearch, 300);
|
||||
});
|
||||
|
||||
$typeCheckboxes.forEach((cb) =>
|
||||
cb.addEventListener("change", handleSearch),
|
||||
);
|
||||
$typeCheckboxes.forEach((cb) => cb.addEventListener("change", handleSearch));
|
||||
|
||||
$loadMoreButton.addEventListener("click", async () => {
|
||||
if (isLoading) return;
|
||||
|
||||
currentPage++;
|
||||
const nextResults = await loadSearchIndex(
|
||||
$input.value.trim(),
|
||||
getSelectedTypes(),
|
||||
currentPage,
|
||||
);
|
||||
|
||||
const nextResults = await loadSearchIndex($input.value.trim(), getSelectedTypes(), currentPage);
|
||||
|
||||
currentResults = [...currentResults, ...nextResults];
|
||||
|
||||
updateSearchResults(nextResults);
|
||||
});
|
||||
})();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue