Add infinity scrolling for /feeds
This commit is contained in:
parent
07f7011a68
commit
d97f980b66
7 changed files with 67 additions and 33 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
17
poetry.lock
generated
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
|
|||
12
templates/partials/feeds.html
Normal file
12
templates/partials/feeds.html
Normal 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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue