Skip to content

Commit 9e06b36

Browse files
authored
Merge pull request #224 from honeylogic-io/add-htmx
feat: Add htmx
2 parents 3377c3f + 51fc7f5 commit 9e06b36

File tree

10 files changed

+139
-88
lines changed

10 files changed

+139
-88
lines changed

.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
DJANGO_SETTINGS_MODULE=config.settings.local
22
PYTHONBREAKPOINT=pudb.set_trace
3-
DATABASE_URL=psql://postgres:postgres@localhost:5432/django-wtf
3+
DATABASE_URL=psql://postgres:postgres@localhost:5432/django_wtf
44
REDIS_URL=redis://localhost:6379/
55
CELERY_BROKER_URL=$REDIS_URL
66
DJANGO_SETTINGS_MODULE=config.settings.local

config/settings/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
"django_json_ld",
9292
"django_custom_error_views",
9393
"django_admin_shellx",
94+
"django_htmx",
9495
"health_check",
9596
"meta",
9697
"modelcluster",
@@ -181,6 +182,7 @@
181182
"django_user_agents.middleware.UserAgentMiddleware",
182183
"django.middleware.common.BrokenLinkEmailsMiddleware",
183184
"django.middleware.clickjacking.XFrameOptionsMiddleware",
185+
"django_htmx.middleware.HtmxMiddleware",
184186
# TODO: What does this do?
185187
"watson.middleware.SearchContextMiddleware",
186188
"wagtail.contrib.redirects.middleware.RedirectMiddleware",

django_wtf/core/search_view.py

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

44
from django_wtf.core.models import Repository
5+
from django_wtf.core.views.index_view import categories_ordered_by_total_repositories
56

67

78
class SearchView(OriginalSearchView):
8-
template_name = "core/search.html"
99
paginate_by = 20
1010
models = (Repository,)
1111

12+
def get_template_names(self): # pyright: ignore [reportIncompatibleMethodOverride]
13+
if self.request.htmx:
14+
template_name = "core/search_table.html"
15+
else:
16+
template_name = "core/search.html"
17+
18+
return [template_name]
19+
1220
def get_queryset(self):
1321
repositories = Repository.valid.all()
14-
return watson.filter(repositories, self.query)
22+
23+
category = self.request.GET.get("category", None)
24+
if category and category != "All":
25+
repositories = repositories.filter(categories__name=category)
26+
27+
search = self.request.GET.get("q", None)
28+
if search:
29+
repositories = watson.filter(repositories, search)
30+
return repositories
1531

1632
def get_context_data(self, **kwargs):
1733
ctx = super().get_context_data(**kwargs)
34+
ctx["categories"] = categories_ordered_by_total_repositories()
1835
return ctx

django_wtf/core/views/index_view.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@
1010
)
1111

1212

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+
1325
class IndexView(MetadataMixin, TemplateView):
1426
template_name = "core/index.html"
1527
title = "Django.WTF: The Django package index"
@@ -35,7 +47,7 @@ class IndexView(MetadataMixin, TemplateView):
3547

3648
def get_context_data(self, **kwargs):
3749
context = super().get_context_data(**kwargs)
38-
context["categories"] = self.categories_ordered_by_total_repositories()
50+
context["categories"] = categories_ordered_by_total_repositories()
3951
context["trending_apps"] = trending_repositories(days_since=14)[0:5]
4052
context["trending_developers"] = trending_profiles()[0:5]
4153
context["social_news"] = SocialNews.objects.filter(
@@ -44,16 +56,5 @@ def get_context_data(self, **kwargs):
4456
context["top_apps"] = Repository.valid.order_by("-stars")[0:5]
4557
return context
4658

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

django_wtf/templates/core/base.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% load tailwind_tags %}
1+
{% load tailwind_tags django_htmx %}
22
<!DOCTYPE html>
33
<html lang="en-US">
44
<head>
@@ -40,5 +40,7 @@
4040
<script defer
4141
src="https://s.depode.com/ingress/7ca0f5ff-8ef2-45fb-9718-37d34cddfe79/script.js"></script>
4242
{% endif %}
43+
<script src="https://unpkg.com/[email protected]"></script>
44+
{% django_htmx_script %}
4345
</body>
4446
</html>

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>
Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,44 @@
11
{% extends "core/base.html" %}
22
{% block content %}
3-
<div class="mb-3">
4-
{% for object in object_list %}
5-
<div class="mb-1 rounded">
6-
<div class="shadow-xl card bg-base-100">
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>
3+
<div class="mb-5 w-full flex-col content-center self-center lg:mt-5 lg:flex lg:w-7/12">
4+
<form class="form flex justify-between">
5+
<label class="form-control">
6+
<div class="label">
7+
<span class="label-text">Search</span>
228
</div>
9+
<input type="text"
10+
name="q"
11+
value="{{ request.GET.q }}"
12+
hx-include="[name='category']"
13+
hx-get="{% url 'core:search' %}"
14+
hx-push-url="true"
15+
hx-target="#search_table"
16+
hx-trigger="keyup changed delay:0.5s"
17+
class="input input-bordered input-sm min-w-64" />
18+
</label>
19+
<div class="flex gap-4">
20+
<label class="form-control">
21+
<div class="label">
22+
<span class="label-text">Category</span>
23+
</div>
24+
<select name="category"
25+
class="select select-bordered"
26+
hx-trigger="change"
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 %}
38+
</select>
39+
</label>
2340
</div>
24-
{% endfor %}
41+
</form>
42+
<div id="search_table" class="table table-sm mt-7">{% include "core/search_table.html" %}</div>
2543
</div>
2644
{% 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)