Skip to content

Added sorting tab to snippet list. #602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions base/components/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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,
}
8 changes: 8 additions & 0 deletions base/components/sorting_tabs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<nav aria-labelledby="sorting-tabs">
<h2 id="sorting-tabs" class="sr-only">Sorting Tabs</h2>
<ul class="m-0 inline-flex gap-2 p-2 border-2 border-base-green-400 rounded-lg font-common">
{% for tab in tabs %}
<li><a {% html_attrs tab.attrs %} class="inline-block px-4 py-2 rounded-md {% if tab.is_current %}bg-base-green-400 text-base-white-400 no-underline{% else %}underline duration-300 transition-colors hover:bg-base-green-400/30 hover:text-base-green-800{% endif %}">{{ tab.text }}</a></li>
{% endfor %}
</ul>
</nav>
30 changes: 26 additions & 4 deletions base/main.py
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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
10 changes: 10 additions & 0 deletions cab/main.py
Original file line number Diff line number Diff line change
@@ -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",),
}
5 changes: 3 additions & 2 deletions cab/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion djangosnippets/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/smoothness/jquery-ui.css" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Raleway:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Libertinus+Sans:ital,wght@0,400;0,700;1,400&family=Nunito:ital,wght@0,200..1000;1,200..1000&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Raleway:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
<link rel="alternate" href="{% url 'cab_feed_latest' %}" type="application/atom+xml" title="Feed of latest snippets" />
<link rel="stylesheet" href="{% static "css/main.css" %}" type="text/css" />
{% block feeds %}{% endblock %}
Expand Down Expand Up @@ -62,6 +62,7 @@

<div id="base-container">
<h1>{% block content_header %}{% endblock %}</h1>
{% block new_content_header %}{% endblock %}
{% with current_url_name=request.resolver_match.url_name %}
<div id="content" class="{% if current_url_name == 'home' %}w-1/2{% else %}w-full{% endif %}">
{% block content %}
Expand Down
15 changes: 10 additions & 5 deletions djangosnippets/templates/cab/snippet_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}
<header class="bg-transparent">
<h1 class="my-20 text-center float-none font-header text-8xl md:text-left">{{ hits }} snippet{{ hits|pluralize }}</h1>
<div class="my-4 flex justify-between px-4">
<div></div>
{% component 'sorting_tabs' object_list=object_list / %}
</div>
</header>
{% endblock %}

{% block content %}
{% if object_list %}
{% component 'snippet_list' snippet_list=object_list / %}
{% component 'pagination' pagination_obj=pagination / %}
<p class="count">{{ hits }} snippet{{ hits|pluralize }} posted so far.</p>
{% else %}
<p class="empty">No snippets posted yet.</p>
{% endif %}
{% endblock %}

Expand Down
11 changes: 9 additions & 2 deletions djangosnippets/templates/cab/user_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}
<header class="bg-transparent">
<h1 class="my-20 text-center float-none font-header text-8xl md:text-left">Snippet{{ hits|pluralize }} by {{ author.username }}</h1>
<div class="my-4 flex justify-between px-4">
<div></div>
{% component 'sorting_tabs' object_list=object_list / %}
</div>
</header>
{% endblock %}


{% block content %}
{% if object_list %}
{% component 'snippet_list' snippet_list=object_list / %}
{% cache 600 author_detail_sidebar author.username %}
<p class="count">{% if request.user.username == author.username %}You've{% else %}{{ author.username }} has{% endif %} posted {{ author.snippet_set.count }} snippet{{ author.snippet_set.count|pluralize }}.</p>
{% endcache %}
{% component "pagination" pagination_obj=pagination / %}
{% else %}
Expand Down
1 change: 1 addition & 0 deletions theme/static_src/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down