Skip to content

Commit 38af4ab

Browse files
committed
feat: Add htmx/reactivity to search page
1 parent 0a852a5 commit 38af4ab

File tree

5 files changed

+74
-62
lines changed

5 files changed

+74
-62
lines changed

django_wtf/core/search_view.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from watson.views import SearchView as OriginalSearchView
33

44
from django_wtf.core.models import Repository
5-
from django_wtf.core.models.category_model import Category
5+
from django_wtf.core.views.index_view import categories_ordered_by_total_repositories
66

77

88
class SearchView(OriginalSearchView):
@@ -29,18 +29,7 @@ def get_queryset(self):
2929
repositories = watson.filter(repositories, search)
3030
return repositories
3131

32-
def categories_ordered_by_total_repositories(self):
33-
categories = []
34-
for c in Category.objects.all():
35-
count_matching_repositories = Repository.objects.filter(
36-
categories__in=[c]
37-
).count()
38-
if count_matching_repositories:
39-
setattr(c, "total_repositories", count_matching_repositories)
40-
categories.append(c)
41-
return sorted(categories, key=lambda c: c.total_repositories, reverse=True)
42-
4332
def get_context_data(self, **kwargs):
4433
ctx = super().get_context_data(**kwargs)
45-
ctx["categories"] = self.categories_ordered_by_total_repositories()
34+
ctx["categories"] = categories_ordered_by_total_repositories()
4635
return ctx

django_wtf/core/views/index_view.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from django.templatetags.static import static
22
from django.views.generic.base import TemplateView
33
from meta.views import MetadataMixin
4-
from watson import search as watson
54

65
from django_wtf.core.models import Category, Repository, SocialNews
76
from django_wtf.core.queries import (
@@ -11,6 +10,18 @@
1110
)
1211

1312

13+
def categories_ordered_by_total_repositories():
14+
categories = []
15+
for c in Category.objects.all():
16+
count_matching_repositories = Repository.objects.filter(
17+
categories__in=[c]
18+
).count()
19+
if count_matching_repositories:
20+
setattr(c, "total_repositories", count_matching_repositories)
21+
categories.append(c)
22+
return sorted(categories, key=lambda c: c.total_repositories, reverse=True)
23+
24+
1425
class IndexView(MetadataMixin, TemplateView):
1526
template_name = "core/index.html"
1627
title = "Django.WTF: The Django package index"
@@ -36,7 +47,7 @@ class IndexView(MetadataMixin, TemplateView):
3647

3748
def get_context_data(self, **kwargs):
3849
context = super().get_context_data(**kwargs)
39-
context["categories"] = self.categories_ordered_by_total_repositories()
50+
context["categories"] = categories_ordered_by_total_repositories()
4051
context["trending_apps"] = trending_repositories(days_since=14)[0:5]
4152
context["trending_developers"] = trending_profiles()[0:5]
4253
context["social_news"] = SocialNews.objects.filter(
@@ -45,16 +56,5 @@ def get_context_data(self, **kwargs):
4556
context["top_apps"] = Repository.valid.order_by("-stars")[0:5]
4657
return context
4758

48-
def categories_ordered_by_total_repositories(self):
49-
categories = []
50-
for c in Category.objects.all():
51-
count_matching_repositories = Repository.objects.filter(
52-
categories__in=[c]
53-
).count()
54-
if count_matching_repositories:
55-
setattr(c, "total_repositories", count_matching_repositories)
56-
categories.append(c)
57-
return sorted(categories, key=lambda c: c.total_repositories, reverse=True)
58-
5959
def get_meta_image(self, context=None):
6060
return static("images/logo.png")

django_wtf/templates/core/components/_navbar.html

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,45 +37,38 @@
3737
<a class="w-32 lg:ml-6" href="/">
3838
<img src="{% static 'images/logo.png' %}" alt="Django.wtf">
3939
</a>
40-
<div class="hidden ml-12 lg:flex form-control">
41-
<form id="search-form" action="{% url 'core:search' %}">
42-
<input type="text"
43-
name="q"
44-
value="{{ request.GET.q }}"
45-
placeholder="Search"
46-
class="input input-bordered">
47-
</form>
48-
<script>
49-
const form = document.querySelector("#search-form");
50-
const input = form.querySelector("input");
51-
input.addEventListener("keydown", (e) => {
52-
if (e.key === "Enter") {
53-
form.submit();
54-
}
55-
});
56-
</script>
57-
</div>
58-
<div class="hidden ml-10 lg:flex">
59-
<ul class="p-0 text-white uppercase menu menu-horizontal">
40+
<div class="hidden lg:flex gap-6">
41+
<div class="hidden ml-16 lg:flex form-control">
42+
{% if request.path != "/search/" %}
43+
<form id="search-form" action="{% url 'core:search' %}">
44+
<input type="text"
45+
name="q"
46+
value="{{ request.GET.q }}"
47+
placeholder="Search"
48+
class="input input-bordered text-sm">
49+
</form>
50+
{% endif %}
51+
</div>
52+
<ul class="text-white uppercase menu menu-horizontal menu-xs gap-4">
6053
{% flag "newsletter" %}
6154
<li class="btn btn-outline btn-accent">
62-
<a href="{% url 'core:subscriber-landing' %}">Newsletter</a>
55+
<a class="text-sm" href="{% url 'core:subscriber-landing' %}">Newsletter</a>
6356
</li>
6457
{% endflag %}
6558
<li>
66-
<a href="{% url 'core:top-repositories' %}">Best apps</a>
59+
<a class="text-sm" href="{% url 'core:top-repositories' %}">Best apps</a>
6760
</li>
6861
<li>
69-
<a href="{% url 'core:trending-repositories' %}">Trending apps</a>
62+
<a class="text-sm" href="{% url 'core:trending-repositories' %}">Trending apps</a>
7063
</li>
7164
<li>
72-
<a href="{% url 'core:top-profiles' %}">Best profiles</a>
65+
<a class="text-sm" href="{% url 'core:top-profiles' %}">Best profiles</a>
7366
</li>
7467
<li>
75-
<a href="{% url 'core:trending-profiles' %}">Trending profiles</a>
68+
<a class="text-sm" href="{% url 'core:trending-profiles' %}">Trending profiles</a>
7669
</li>
7770
<li>
78-
<a href="{% url 'core:social-media-news' %}">Social media news</a>
71+
<a class="text-sm" href="{% url 'core:social-media-news' %}">Social media news</a>
7972
</li>
8073
</ul>
8174
</div>

django_wtf/templates/core/search.html

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
<input type="text"
1010
name="q"
1111
value="{{ request.GET.q }}"
12-
class="input input-bordered input-sm min-w-64"
12+
hx-include="[name='category']"
1313
hx-get="{% url 'core:search' %}"
14+
hx-push-url="true"
1415
hx-target="#search_table"
1516
hx-trigger="keyup changed delay:1s"
16-
hx-push-url="true" />
17+
class="input input-bordered input-sm min-w-64" />
1718
</label>
1819
<div class="flex gap-4">
1920
<label class="form-control">
@@ -22,18 +23,22 @@
2223
</div>
2324
<select name="category"
2425
class="select select-bordered"
25-
hx-get="{% url 'core:search' %}"
26-
hx-target="#search_table"
2726
hx-trigger="change"
28-
hx-push-url="true">
29-
<option selected>All</option>
30-
{% for category in categories %}<option value="{{ category.name }}">{{ category.name }}</option>{% endfor %}
27+
hx-include="[name='q']"
28+
hx-get="{% url 'core:search' %}"
29+
hx-push-url="true"
30+
hx-target="#search_table">
31+
<option>All</option>
32+
{% for category in categories %}
33+
<option value="{{ category.name }}"
34+
{% if category.name == request.GET.category %}selected{% endif %}>
35+
{{ category.name }}
36+
</option>
37+
{% endfor %}
3138
</select>
3239
</label>
3340
</div>
3441
</form>
35-
<table id="search_table" class="table table-sm mt-7">
36-
{% include "core/search_table.html" %}
37-
</table>
42+
<div id="search_table" class="table table-sm mt-7">{% include "core/search_table.html" %}</div>
3843
</div>
3944
{% endblock content %}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{% load admin_urls static %}
2+
3+
{% if object_list %}
4+
{% for object in object_list %}
5+
<div class="my-4 rounded">
6+
<div class="shadow-xl card bg-base-200">
7+
<div class="pb-2 card-body">
8+
<a target="_blank" href="{{ object.github_url }}">
9+
<h2 class="flex justify-between card-title">
10+
<span>{{ object.full_name }}</span>
11+
<span class="text-sm">⭐ {{ object.stars }}</span>
12+
</h2>
13+
</a>
14+
<p>
15+
{% for topic in object.topics|slice:"0:5" %}
16+
<a class="p-3 mr-1 text-xs badge badge-outline hover:brightness-125"
17+
href="{% url 'core:search' %}?q={{ topic }}">{{ topic|truncatechars:30 }}</a>
18+
{% endfor %}
19+
</p>
20+
<p class="mt-2">{{ object.description }}</p>
21+
</div>
22+
</div>
23+
</div>
24+
{% endfor %}
25+
{% endif %}

0 commit comments

Comments
 (0)