Add infinity scrolling for /feeds

This commit is contained in:
Joakim Hellsén 2024-03-26 02:31:53 +01:00
commit d97f980b66
No known key found for this signature in database
GPG key ID: D196AE66FEBE1DC9
7 changed files with 67 additions and 33 deletions

View file

@ -65,6 +65,7 @@ INSTALLED_APPS: list[str] = [
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.sitemaps",
"django_htmx",
]
MIDDLEWARE: list[str] = [
@ -77,6 +78,7 @@ MIDDLEWARE: list[str] = [
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django_htmx.middleware.HtmxMiddleware",
]
# Use PostgreSQL as the default database

View file

@ -13,6 +13,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView, LogoutView, PasswordChangeView
from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import SuspiciousOperation
from django.core.paginator import EmptyPage, Paginator
from django.db.models.manager import BaseManager
from django.http import FileResponse, Http404, HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404, render
@ -20,7 +21,6 @@ from django.template import loader
from django.urls import reverse_lazy
from django.views import View
from django.views.generic.edit import CreateView
from django.views.generic.list import ListView
from feedvault.feeds import add_url
from feedvault.models import Domain, Entry, Feed, FeedAddResult, UserUploadedFile
@ -33,6 +33,10 @@ if TYPE_CHECKING:
logger: logging.Logger = logging.getLogger(__name__)
class HtmxHttpRequest(HttpRequest):
htmx: Any
class IndexView(View):
"""Index path."""
@ -74,24 +78,33 @@ class FeedView(View):
return render(request, "feed.html", context)
class FeedsView(ListView):
class FeedsView(View):
"""All feeds."""
model = Feed
paginate_by = 100
template_name = "feeds.html"
context_object_name = "feeds"
def get(self, request: HtmxHttpRequest) -> HttpResponse:
"""All feeds."""
feeds: BaseManager[Feed] = Feed.objects.only("id", "feed_url")
def get_context_data(self, **kwargs) -> dict: # noqa: ANN003
"""Get the context data."""
context = super().get_context_data(**kwargs)
feed_amount: int = Feed.objects.count() or 0
context["description"] = f"Archiving {feed_amount} feeds"
context["keywords"] = "feed, rss, atom, archive, rss list"
context["author"] = "TheLovinator"
context["canonical"] = "https://feedvault.se/feeds/"
context["title"] = "Feeds"
return context
paginator = Paginator(object_list=feeds, per_page=100)
page_number = int(request.GET.get("page", default=1))
try:
pages = paginator.get_page(page_number)
except EmptyPage:
return HttpResponse("")
context = {
"feeds": pages,
"description": "An archive of all feeds",
"keywords": "feed, rss, atom, archive, rss list",
"author": "TheLovinator",
"canonical": "https://feedvault.se/feeds/",
"title": "Feeds",
"page": page_number,
}
template_name = "partials/feeds.html" if request.htmx else "feeds.html"
return render(request, template_name, context)
class AddView(LoginRequiredMixin, View):

17
poetry.lock generated
View file

@ -463,6 +463,21 @@ files = [
django = ">=3.2.4"
sqlparse = ">=0.2"
[[package]]
name = "django-htmx"
version = "1.17.3"
description = "Extensions for using Django with htmx."
optional = false
python-versions = ">=3.8"
files = [
{file = "django-htmx-1.17.3.tar.gz", hash = "sha256:a2069219920d7ef0883ddbf5e8d931069db145a0d4a8a032a2708f840c7a68a6"},
{file = "django_htmx-1.17.3-py3-none-any.whl", hash = "sha256:0de964ca257eda2a4ebeeaa8181320119378fa5f95a2fc2f2bfbdd35034ed424"},
]
[package.dependencies]
asgiref = ">=3.6"
Django = ">=3.2"
[[package]]
name = "django-ninja"
version = "1.1.0"
@ -1299,4 +1314,4 @@ brotli = ["Brotli"]
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
content-hash = "67041176bd9ca4289c6900d794465da1df4a966ed81625367552fa238b7976f8"
content-hash = "e21c650c4ac009f1e6ba8939aa6236a63b8dc3a095b803fe7e13a529fc62b072"

View file

@ -7,7 +7,7 @@ readme = "README.md"
[tool.poetry.dependencies]
python = "^3.12"
django = {extras = ["argon2"], version = "^5.0.3"}
django = { extras = ["argon2"], version = "^5.0.3" }
python-dotenv = "^1.0.1"
feedparser = "^6.0.11"
gunicorn = "^21.2.0"
@ -15,9 +15,10 @@ dateparser = "^1.2.0"
discord-webhook = "^1.3.1"
django-ninja = "^1.1.0"
django-debug-toolbar = "^4.3.0"
whitenoise = {extras = ["brotli"], version = "^6.6.0"}
whitenoise = { extras = ["brotli"], version = "^6.6.0" }
rich = "^13.7.1"
psycopg = {extras = ["binary"], version = "^3.1.18"}
psycopg = { extras = ["binary"], version = "^3.1.18" }
django-htmx = "^1.17.3"
[tool.poetry.group.dev.dependencies]
ruff = "^0.3.0"
@ -25,9 +26,7 @@ djlint = "^1.34.1"
[build-system]
build-backend = "poetry.core.masonry.api"
requires = [
"poetry-core",
]
requires = ["poetry-core"]
[tool.ruff]
exclude = ["migrations"]

View file

@ -9,7 +9,7 @@
{% if author %}<meta name="author" content="{{ author }}" />{% endif %}
{% if canonical %}<link rel="canonical" href="{{ canonical }}" />{% endif %}
<title>{{ title|default:"FeedVault" }}</title>
<script src="{% static 'htmx.min.js' %}"></script>
<script src="{% static 'htmx.min.js' %}" defer></script>
<style>
html {
max-width: 88ch;

View file

@ -1,12 +1,5 @@
{% extends "base.html" %}
{% block content %}
<h2>Latest Feeds</h2>
{% if feeds %}
{% for feed in feeds %}
<a href="{% url 'feed' feed.id %}">{{ feed.feed_url|default:"Unknown Feed" }} →</a>
<br>
{% endfor %}
{% else %}
<p>No feeds yet. Time to add some!</p>
{% endif %}
{% include "partials/feeds.html" %}
{% endblock %}

View file

@ -0,0 +1,12 @@
{% if feeds %}
{% for feed in feeds %}
<a href="{% url 'feed' feed.id %}">{{ feed.feed_url|default:"Unknown Feed" }} →</a>
<br>
{% endfor %}
{% else %}
<p>No feeds yet. Time to add some!</p>
{% endif %}
<div hx-get="{% url 'feeds' %}?page={{ page|add:1 }}"
hx-trigger="revealed"
hx-target="this"
hx-swap="outerHTML">Loading...</div>