Add all the relevant search messages
This commit is contained in:
parent
bcc9a2c2f2
commit
996f7b9c2a
6 changed files with 40 additions and 15 deletions
|
@ -1,10 +1,15 @@
|
|||
window.addEventListener("load", () => {
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
const searchResults = document.getElementById("search-results");
|
||||
const resultsCount = document.getElementById("result-count");
|
||||
const resultsCountDisplay = document.getElementById("result-count");
|
||||
|
||||
function handleSearchResults(event) {
|
||||
resultsCount.textContent =
|
||||
event.target.querySelectorAll(".listing-item").length;
|
||||
const resultsCount = event.target.querySelectorAll(".listing-item").length;
|
||||
if (resultsCount) {
|
||||
resultsCountDisplay.textContent =
|
||||
`Found ${resultsCount} result` + (resultsCount > 1 ? "s" : "");
|
||||
} else {
|
||||
resultsCountDisplay.textContent = "";
|
||||
}
|
||||
}
|
||||
searchResults.addEventListener("htmx:after-swap", handleSearchResults);
|
||||
searchResults.addEventListener("htmx:afterSwap", handleSearchResults);
|
||||
});
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
body.page-searchpage {
|
||||
.search-controls {
|
||||
margin: 2rem auto;
|
||||
|
@ -15,4 +16,9 @@ body.page-searchpage {
|
|||
#search-indicator {
|
||||
animation: search-loading 1.5s linear infinite;
|
||||
}
|
||||
|
||||
#search-results > p {
|
||||
font-size: 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django.core.paginator import EmptyPage, Paginator
|
||||
from django.http.request import HttpRequest
|
||||
from django.http.response import HttpResponse, HttpResponseBadRequest
|
||||
from django.http.response import HttpResponse
|
||||
from django.shortcuts import render
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.functional import cached_property
|
||||
|
@ -24,9 +24,10 @@ class SearchPage(BaseContentMixin, RoutablePageMixin, BasePage): # type: ignore
|
|||
content_panels = BasePage.content_panels + BaseContentMixin.content_panels
|
||||
search_fields = BasePage.search_fields + BaseContentMixin.search_fields
|
||||
PAGE_SIZE = 15
|
||||
MIN_SEARCH_TERM = 3
|
||||
|
||||
class SearchParamsSerializer(serializers.Serializer):
|
||||
q = serializers.CharField()
|
||||
q = serializers.CharField(min_length=3)
|
||||
page = serializers.IntegerField(min_value=1, default=1)
|
||||
|
||||
@cached_property
|
||||
|
@ -44,18 +45,20 @@ class SearchPage(BaseContentMixin, RoutablePageMixin, BasePage): # type: ignore
|
|||
context = super().get_context(request)
|
||||
context["search_query"] = request.GET.get("q", "")
|
||||
context["search_url"] = self.reverse_subpage("results")
|
||||
context["MIN_SEARCH_TERM"] = self.MIN_SEARCH_TERM
|
||||
return context
|
||||
|
||||
@route(r"^results/$")
|
||||
@method_decorator(require_GET)
|
||||
def results(self, request: HttpRequest) -> HttpResponse:
|
||||
if not request.GET.get("q", None):
|
||||
return HttpResponse()
|
||||
|
||||
serializer = self.SearchParamsSerializer(data=request.GET)
|
||||
|
||||
if not serializer.is_valid():
|
||||
return HttpResponseBadRequest(serializer.errors)
|
||||
return render(
|
||||
request,
|
||||
"search/enter-search-term.html",
|
||||
{"MIN_SEARCH_TERM": self.MIN_SEARCH_TERM},
|
||||
)
|
||||
|
||||
search_query = serializer.validated_data["q"]
|
||||
page_num = serializer.validated_data["page"]
|
||||
|
|
1
website/search/templates/search/enter-search-term.html
Normal file
1
website/search/templates/search/enter-search-term.html
Normal file
|
@ -0,0 +1 @@
|
|||
<p>Enter a search term (of at least {{ MIN_SEARCH_TERM }} characters) to search</p>
|
|
@ -21,7 +21,7 @@
|
|||
name="q"
|
||||
placeholder="Search"
|
||||
hx-get="{{ search_url }}"
|
||||
hx-trigger="keyup changed delay:300ms, search{% if search_query %}, revealed{% endif %}"
|
||||
hx-trigger="keyup changed delay:300ms, search{% if search_query %}, load{% endif %}"
|
||||
hx-target="#search-results"
|
||||
autocomplete="off"
|
||||
value="{{ search_query }}"
|
||||
|
@ -35,11 +35,17 @@
|
|||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p>Showing <span id="result-count">0</span> results</p>
|
||||
</section>
|
||||
|
||||
<section class="container" id="search-results"></section>
|
||||
<section class="container" id="search-results-container">
|
||||
<p id="result-count"></p>
|
||||
|
||||
<div id="search-results">
|
||||
{% if not search_query %}
|
||||
{% include "search/enter-search-term.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
{% include "common/listing-item.html" %}
|
||||
{% endfor %}
|
||||
|
||||
{% if not results and page_num == 1 %}
|
||||
<p>No results found</p>
|
||||
{% endif %}
|
||||
|
||||
{% if results.has_next %}
|
||||
<span hx-get="{{ search_url }}{% querystring page=results.next_page_number %}" hx-trigger="revealed" hx-swap="outerHTML"></span>
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in a new issue