diff --git a/base/components/components.py b/base/components/components.py
index 9cc72c7d..7efce844 100644
--- a/base/components/components.py
+++ b/base/components/components.py
@@ -3,6 +3,7 @@
from django_components import Component, register
from pydantic import BaseModel
+from base.main import TAB_VAR, ObjectList
from base.pagination import PAGE_VAR, Pagination
from base.templatetags.base_templatetags import querystring
@@ -68,3 +69,35 @@ def get_template_data(self, args, kwargs, slots, context):
"next_page_link": next_page_link,
"page_elements": page_elements,
}
+
+
+class TabItem(BaseModel):
+ text: str
+ is_current: bool
+ attrs: Optional[dict]
+
+
+@register("sorting_tabs")
+class SortingTabs(Component):
+ template_file = "sorting_tabs.html"
+
+ class Kwargs(BaseModel):
+ object_list: ObjectList
+ model_config = {"arbitrary_types_allowed": True}
+
+ def create_tab(self, object_list, tab):
+ verbose_text = tab.replace("_", " ").capitalize()
+ is_current = tab == object_list.current_tab
+ link = querystring(None, {**object_list.params, TAB_VAR: tab})
+ attrs = {"href": link}
+ if is_current:
+ attrs["aria-selected"] = "true"
+ return TabItem(text=verbose_text, is_current=is_current, attrs=attrs)
+
+ def get_template_data(self, args, kwargs, slots, context):
+ object_list = kwargs.object_list
+ tabs = [self.create_tab(object_list, tab) for tab in object_list.sorting_tabs]
+ return {
+ "tabs": tabs,
+ "object_list": object_list,
+ }
diff --git a/base/components/sorting_tabs.html b/base/components/sorting_tabs.html
new file mode 100644
index 00000000..99a39c94
--- /dev/null
+++ b/base/components/sorting_tabs.html
@@ -0,0 +1,8 @@
+
diff --git a/base/main.py b/base/main.py
index ec29a514..0ce5f1cd 100644
--- a/base/main.py
+++ b/base/main.py
@@ -1,21 +1,42 @@
from .pagination import PAGE_VAR, Pagination
+TAB_VAR = "tab"
+
class ObjectList:
pagination_class = Pagination
+ base_ordering = ()
+ sorting_tabs = {}
def __init__(self, request, model, queryset, list_per_page):
self.model = model
+ self.opts = model._meta
self.queryset = queryset
self.list_per_page = list_per_page
- self.params = dict(request.GET.lists())
+ self.params = dict(request.GET.dict())
+ self.current_tab = self.params.get(TAB_VAR, None)
+ if self.opts.ordering:
+ self.base_ordering = self.opts.ordering
if PAGE_VAR in self.params:
del self.params[PAGE_VAR]
- self.result_objects = self.get_objects(request)
+ self.result_objects = self.get_objects(request, queryset)
def __iter__(self):
return iter(self.result_objects)
+ def tab_sort(self, queryset):
+ result_queryset = queryset
+ if self.current_tab:
+ sort_value = self.sorting_tabs[self.current_tab]
+ result_queryset = result_queryset.order_by(*sort_value, *self.base_ordering)
+ else:
+ for tab_name, tab_order in self.sorting_tabs.items():
+ if tab_order == self.base_ordering:
+ self.current_tab = tab_name
+ break
+
+ return result_queryset
+
def paginate(self, request, queryset):
pagination = self.pagination_class(
request,
@@ -26,6 +47,7 @@ def paginate(self, request, queryset):
self.pagination = pagination
return pagination.get_objects()
- def get_objects(self, request):
- paginate_result = self.paginate(request, self.queryset)
+ def get_objects(self, request, queryset):
+ tab_result = self.tab_sort(queryset)
+ paginate_result = self.paginate(request, tab_result)
return paginate_result
diff --git a/cab/main.py b/cab/main.py
new file mode 100644
index 00000000..79ac08e5
--- /dev/null
+++ b/cab/main.py
@@ -0,0 +1,10 @@
+from base.main import ObjectList
+
+
+class SnippetList(ObjectList):
+ sorting_tabs = {
+ "newest": ("-pub_date",),
+ "latest_updated": ("-updated_date",),
+ "highest_rated": ("-rating_score",),
+ "most_bookmarked": ("-bookmark_count",),
+ }
diff --git a/cab/utils.py b/cab/utils.py
index 34dafd87..48e93c54 100644
--- a/cab/utils.py
+++ b/cab/utils.py
@@ -7,9 +7,10 @@
from django.utils.safestring import mark_safe
from markdown import markdown as markdown_func
-from base.main import ObjectList
from base.pagination import Pagination
+from .main import SnippetList
+
def object_list(
request,
@@ -45,7 +46,7 @@ def object_list(
opts = model._meta
if paginate_by:
if queryset.model == Snippet:
- object_list = ObjectList(request, queryset.model, queryset, 15)
+ object_list = SnippetList(request, queryset.model, queryset, 15)
pagination = object_list.pagination
else:
pagination = Pagination(request, model, queryset, paginate_by)
diff --git a/djangosnippets/templates/base.html b/djangosnippets/templates/base.html
index 2441d9f7..d5eb8d8f 100644
--- a/djangosnippets/templates/base.html
+++ b/djangosnippets/templates/base.html
@@ -8,7 +8,7 @@
-
+
{% block feeds %}{% endblock %}
@@ -62,6 +62,7 @@
{% block content_header %}{% endblock %}
+ {% block new_content_header %}{% endblock %}
{% with current_url_name=request.resolver_match.url_name %}
{% block content %}
diff --git a/djangosnippets/templates/cab/snippet_list.html b/djangosnippets/templates/cab/snippet_list.html
index 1d8823c1..e3a5b914 100644
--- a/djangosnippets/templates/cab/snippet_list.html
+++ b/djangosnippets/templates/cab/snippet_list.html
@@ -2,17 +2,22 @@
{% load core_tags %}
{% load static %}
{% block bodyclass %}snippet-list{% endblock %}
-{% block head_title %}All snippets{% if months %} last {{ months }} months{% endif %}{% endblock %}
+{% block head_title %}Snippet list{% endblock %}
-{% block content_header %}All snippets{% if months %} last {{ months }} months{% endif %}{% endblock %}
+{% block new_content_header %}
+
+{% endblock %}
{% block content %}
{% if object_list %}
{% component 'snippet_list' snippet_list=object_list / %}
{% component 'pagination' pagination_obj=pagination / %}
-
{{ hits }} snippet{{ hits|pluralize }} posted so far.
- {% else %}
-
No snippets posted yet.
{% endif %}
{% endblock %}
diff --git a/djangosnippets/templates/cab/user_detail.html b/djangosnippets/templates/cab/user_detail.html
index 1c903bb3..310e9349 100644
--- a/djangosnippets/templates/cab/user_detail.html
+++ b/djangosnippets/templates/cab/user_detail.html
@@ -7,14 +7,21 @@
{% block head_title %}Snippets by {{ author.username }}{% if months %}, last {{ months }} months{% endif %}{% endblock %}
-{% block content_header %}Snippets by {{ author.username }}{% if months %}, last {{ months }} months{% endif %}{% endblock %}
+{% block new_content_header %}
+
+{% endblock %}
{% block content %}
{% if object_list %}
{% component 'snippet_list' snippet_list=object_list / %}
{% cache 600 author_detail_sidebar author.username %}
-
{% if request.user.username == author.username %}You've{% else %}{{ author.username }} has{% endif %} posted {{ author.snippet_set.count }} snippet{{ author.snippet_set.count|pluralize }}.
{% endcache %}
{% component "pagination" pagination_obj=pagination / %}
{% else %}
diff --git a/theme/static_src/src/styles.css b/theme/static_src/src/styles.css
index 910e1ee2..3e94d371 100644
--- a/theme/static_src/src/styles.css
+++ b/theme/static_src/src/styles.css
@@ -7,6 +7,7 @@
--color-base-gray-400: #7a7a7a;
--color-base-green-400: #256918;
--color-base-green-800: #12330c;
+ --font-header: "Libertinus Sans", sans-serif;
--font-title: "Playfair Display", sans-serif;
--font-text: "Nunito", sans-serif;
--font-common: "Raleway", sans-serif;