From 09f543ecb17b937f76c4c133de4590f07a416b7b Mon Sep 17 00:00:00 2001 From: antoliny0919 Date: Sat, 12 Jul 2025 14:56:43 +0900 Subject: [PATCH] Refactored convert pagination to django-components structure. --- .gitignore | 1 - base/components/components.py | 51 +++++++++++++++++ base/components/pagination.html | 30 ++++++++++ base/templatetags/components.py | 40 -------------- djangosnippets/settings/base.py | 21 ++++--- djangosnippets/settings/production.py | 14 +---- djangosnippets/settings/testing.py | 10 +++- djangosnippets/static/scss/main.scss | 55 ------------------- .../templates/base/components/pagination.html | 21 ------- .../templates/cab/language_list.html | 4 +- .../templates/cab/partials/language_list.html | 4 +- .../cab/partials/most_bookmarked.html | 4 +- .../templates/cab/partials/tag_list.html | 4 +- .../templates/cab/partials/top_rated.html | 4 +- .../templates/cab/snippet_list.html | 4 +- djangosnippets/templates/cab/tag_list.html | 4 +- .../templates/cab/user_bookmarks.html | 4 +- djangosnippets/templates/cab/user_detail.html | 4 +- theme/static_src/src/styles.css | 28 ++++++++++ 19 files changed, 149 insertions(+), 158 deletions(-) create mode 100644 base/components/components.py create mode 100644 base/components/pagination.html delete mode 100644 base/templatetags/components.py delete mode 100644 djangosnippets/templates/base/components/pagination.html create mode 100644 theme/static_src/src/styles.css diff --git a/.gitignore b/.gitignore index 59955fc3..c80a33c5 100644 --- a/.gitignore +++ b/.gitignore @@ -198,7 +198,6 @@ cython_debug/ # $GIT_DIR/info/exclude or the core.excludesFile configuration variable as # described in https://git-scm.com/docs/gitignore *.pyc -src *DS_Store *~ *.db diff --git a/base/components/components.py b/base/components/components.py new file mode 100644 index 00000000..7579bde0 --- /dev/null +++ b/base/components/components.py @@ -0,0 +1,51 @@ +from typing import Literal, Optional + +from django_components import Component, register +from pydantic import BaseModel + +from base.pagination import PAGE_VAR, Pagination +from base.templatetags.base_templatetags import querystring + + +class PaginationItem(BaseModel): + kind: Literal["current", "ellipsis", "number"] + text: Optional[str | int] = None + attrs: Optional[dict] = None + + +@register("pagination") +class PaginationComponent(Component): + template_file = "pagination.html" + + class Kwargs(BaseModel): + pagination_obj: Pagination + model_config = {"arbitrary_types_allowed": True} + + def pagination_number(self, pagination: Pagination, num: int) -> PaginationItem: + """ + Generates a list of `PaginatedItem`, each representing an individual page with + its associated properties in a pagination navigation list. + """ + if num == pagination.paginator.ELLIPSIS: + return PaginationItem(kind="ellipsis", text=pagination.paginator.ELLIPSIS) + elif num == pagination.page_num: + return PaginationItem(kind="current", text=num) + else: + link = querystring(None, {**pagination.params, PAGE_VAR: num}) + return PaginationItem( + kind="number", + text=num, + attrs={"href": link}, + ) + + def get_template_data(self, args, kwargs, slots, context): + pagination = kwargs.pagination_obj + page_elements = [self.pagination_number(pagination, page_num) for page_num in pagination.page_range] + previous_page_link = f"?{PAGE_VAR}={pagination.page_num - 1}" if pagination.page.has_previous() else "" + next_page_link = f"?{PAGE_VAR}={pagination.page_num + 1}" if pagination.page.has_next() else "" + return { + "pagination": pagination, + "previous_page_link": previous_page_link, + "next_page_link": next_page_link, + "page_elements": page_elements, + } diff --git a/base/components/pagination.html b/base/components/pagination.html new file mode 100644 index 00000000..e2899ec9 --- /dev/null +++ b/base/components/pagination.html @@ -0,0 +1,30 @@ +{% if pagination.multi_page %} + +{% endif %} diff --git a/base/templatetags/components.py b/base/templatetags/components.py deleted file mode 100644 index a271b7d0..00000000 --- a/base/templatetags/components.py +++ /dev/null @@ -1,40 +0,0 @@ -from django import template -from django.utils.html import format_html -from django.utils.safestring import mark_safe - -from base.pagination import PAGE_VAR - -from .base_templatetags import querystring - -register = template.Library() - - -@register.simple_tag -def pagination_number(pagination, i): - """ - Generate an individual page index link in a paginated list. - """ - if i == pagination.paginator.ELLIPSIS: - return format_html("{} ", pagination.paginator.ELLIPSIS) - elif i == pagination.page_num: - return format_html('{} ', i) - else: - link = querystring(None, pagination.params, {PAGE_VAR: i}) - return format_html( - '{} ', - link, - i, - mark_safe(' class="end"' if i == pagination.paginator.num_pages else ""), - i, - ) - - -@register.inclusion_tag("base/components/pagination.html", name="pagination") -def pagination_tag(pagination): - previous_page_link = f"?{PAGE_VAR}={pagination.page_num - 1}" - next_page_link = f"?{PAGE_VAR}={pagination.page_num + 1}" - return { - "pagination": pagination, - "previous_page_link": previous_page_link, - "next_page_link": next_page_link, - } diff --git a/djangosnippets/settings/base.py b/djangosnippets/settings/base.py index 76d884bd..ee45b4df 100644 --- a/djangosnippets/settings/base.py +++ b/djangosnippets/settings/base.py @@ -104,15 +104,18 @@ def user_url(user): "django.contrib.messages.context_processors.messages", "django.template.context_processors.request", ], - "loaders": [( - "django.template.loaders.cached.Loader", [ - "django.template.loaders.filesystem.Loader", - "django.template.loaders.app_directories.Loader", - "django_components.template_loader.Loader", - ] - )], - 'builtins': [ - 'django_components.templatetags.component_tags', + "loaders": [ + ( + "django.template.loaders.cached.Loader", + [ + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + "django_components.template_loader.Loader", + ], + ) + ], + "builtins": [ + "django_components.templatetags.component_tags", ], }, } diff --git a/djangosnippets/settings/production.py b/djangosnippets/settings/production.py index 1f011110..16462a13 100644 --- a/djangosnippets/settings/production.py +++ b/djangosnippets/settings/production.py @@ -7,7 +7,7 @@ import sentry_sdk from sentry_sdk.integrations.django import DjangoIntegration -from .base import * # noqa: F403 +from .base import * # noqa def env_to_bool(input): @@ -23,18 +23,6 @@ def env_to_bool(input): DEBUG = env_to_bool(os.environ.get("DEBUG", False)) -# Use the cached template loader. -del TEMPLATES[0]["APP_DIRS"] -TEMPLATES[0]["OPTIONS"]["loaders"] = ( - ( - "django.template.loaders.cached.Loader", - ( - "django.template.loaders.filesystem.Loader", - "django.template.loaders.app_directories.Loader", - ), - ), -) - AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "") AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "") AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME", "") diff --git a/djangosnippets/settings/testing.py b/djangosnippets/settings/testing.py index 10e26f65..b2081951 100644 --- a/djangosnippets/settings/testing.py +++ b/djangosnippets/settings/testing.py @@ -22,6 +22,7 @@ "django.contrib.sessions", "django.contrib.sites", "django.contrib.staticfiles", + "django_components", "allauth", "allauth.account", "allauth.socialaccount", @@ -53,13 +54,20 @@ os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, "cab", "tests", "templates"), SNIPPETS_TEMPLATES_DIR, ], - "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", "django.template.context_processors.request", ], + "loaders": [ + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + "django_components.template_loader.Loader", + ], + "builtins": [ + "django_components.templatetags.component_tags", + ], }, } ] diff --git a/djangosnippets/static/scss/main.scss b/djangosnippets/static/scss/main.scss index daf52980..aed047fc 100644 --- a/djangosnippets/static/scss/main.scss +++ b/djangosnippets/static/scss/main.scss @@ -359,61 +359,6 @@ body.simple { } } -nav.pagination { - display: flex; - justify-content: center; - text-align: center; - ul { - margin-left: 1rem; - margin-right: 1rem; - } - li { - display: inline-block; - a, em, span { - padding: 5px 10px; - line-height: 20px; - border: 1px solid transparent; - border-radius: 6px; - transition: border-color .2s cubic-bezier(0.3, 0, 0.5, 1); - cursor: pointer; - } - a:hover { - border-color: $secondary-color; - text-decoration: none; - } - em { - font-style: normal; - cursor: default; - } - .current-page { - font-weight: bold; - color: white; - background-color: $secondary-color; - } - .disabled { - color: gray; - cursor: default; - border-color: transparent; - } - } - .previous-page::before, .next-page::after { - display: inline-block; - width: 1rem; - height: 1rem; - vertical-align: text-bottom; - content: ""; - background-color: currentColor; - } - .previous-page::before { - clip-path: polygon(9.8px 12.8px, 8.7px 12.8px, 4.5px 8.5px, 4.5px 7.5px, 8.7px 3.2px, 9.8px 4.3px, 6.1px 8px, 9.8px 11.7px, 9.8px 12.8px); - margin-right: 4px; - } - .next-page::after { - clip-path: polygon(6.2px 3.2px, 7.3px 3.2px, 11.5px 7.5px, 11.5px 8.5px, 7.3px 12.8px, 6.2px 11.7px, 9.9px 8px, 6.2px 4.3px, 6.2px 3.2px); - margin-left: 4px; - } -} - footer { padding: 30px 0 30px 0; clear: both; diff --git a/djangosnippets/templates/base/components/pagination.html b/djangosnippets/templates/base/components/pagination.html deleted file mode 100644 index 4b44fc99..00000000 --- a/djangosnippets/templates/base/components/pagination.html +++ /dev/null @@ -1,21 +0,0 @@ -{% load components %} - -{% if pagination.multi_page %} - -{% endif %} diff --git a/djangosnippets/templates/cab/language_list.html b/djangosnippets/templates/cab/language_list.html index 949b5e2b..27f9b550 100644 --- a/djangosnippets/templates/cab/language_list.html +++ b/djangosnippets/templates/cab/language_list.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load core_tags components %} +{% load core_tags %} {% block head_title %}All languages{% endblock %} @@ -12,6 +12,6 @@ {% endfor %} - {% pagination pagination %} + {% component "pagination" pagination_obj=pagination / %} {% endblock %} diff --git a/djangosnippets/templates/cab/partials/language_list.html b/djangosnippets/templates/cab/partials/language_list.html index 3a4c5a3c..3cf478f3 100644 --- a/djangosnippets/templates/cab/partials/language_list.html +++ b/djangosnippets/templates/cab/partials/language_list.html @@ -1,4 +1,4 @@ -{% load static components %} +{% load static %} @@ -10,5 +10,5 @@

All languages

{% endfor %} - {% pagination pagination %} + {% component "pagination" pagination_obj=pagination / %} diff --git a/djangosnippets/templates/cab/partials/most_bookmarked.html b/djangosnippets/templates/cab/partials/most_bookmarked.html index 81445100..6054046b 100644 --- a/djangosnippets/templates/cab/partials/most_bookmarked.html +++ b/djangosnippets/templates/cab/partials/most_bookmarked.html @@ -1,5 +1,5 @@ -{% load core_tags components %} +{% load core_tags %} {% load static %}

Most bookmarked snippets{% if months %} last {{ months }} months{% endif %}

@@ -30,7 +30,7 @@

Most bookmarked snippets{% if months %} last {{ months }} months{% endif %}< {% endfor %} - {% pagination pagination %} + {% component "pagination" pagination_obj=pagination / %}

{{ hits }} snippet{{ hits|pluralize }} posted so far.

{% else %}

No snippets posted yet.

diff --git a/djangosnippets/templates/cab/partials/tag_list.html b/djangosnippets/templates/cab/partials/tag_list.html index 010e94fb..663ad053 100644 --- a/djangosnippets/templates/cab/partials/tag_list.html +++ b/djangosnippets/templates/cab/partials/tag_list.html @@ -1,5 +1,5 @@ -{% load core_tags components %} +{% load core_tags %}

All tags

{% if object_list %} @@ -9,7 +9,7 @@

All tags

{% endfor %} - {% pagination pagination %} + {% component "pagination" pagination_obj=pagination / %} {% else %}

No tags have been used yet.

{% endif %} diff --git a/djangosnippets/templates/cab/partials/top_rated.html b/djangosnippets/templates/cab/partials/top_rated.html index 0a48a82b..644f4329 100644 --- a/djangosnippets/templates/cab/partials/top_rated.html +++ b/djangosnippets/templates/cab/partials/top_rated.html @@ -1,6 +1,6 @@ {% load static %} -{% load core_tags components %} +{% load core_tags %}

Top-rated snippets{% if months %} last {{ months }} months{% endif %}

@@ -28,7 +28,7 @@

Top-rated snippets{% if months %} last {{ months }} months{% endif %}

{% endfor %} - {% pagination pagination %} + {% component "pagination" pagination_obj=pagination / %}

{{ hits }} snippet{{ hits|pluralize }} posted so far.

{% else %}

No snippets posted yet.

diff --git a/djangosnippets/templates/cab/snippet_list.html b/djangosnippets/templates/cab/snippet_list.html index 5fceeb60..e28fd62f 100644 --- a/djangosnippets/templates/cab/snippet_list.html +++ b/djangosnippets/templates/cab/snippet_list.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load core_tags components %} +{% load core_tags %} {% load static %} {% block bodyclass %}snippet-list{% endblock %} {% block head_title %}All snippets{% if months %} last {{ months }} months{% endif %}{% endblock %} @@ -30,7 +30,7 @@ {% endfor %} - {% pagination pagination %} + {% component "pagination" pagination_obj=pagination / %}

{{ hits }} snippet{{ hits|pluralize }} posted so far.

{% else %}

No snippets posted yet.

diff --git a/djangosnippets/templates/cab/tag_list.html b/djangosnippets/templates/cab/tag_list.html index 77114235..635ae1e1 100644 --- a/djangosnippets/templates/cab/tag_list.html +++ b/djangosnippets/templates/cab/tag_list.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load core_tags components %} +{% load core_tags %} {% block head_title %}All tags{% endblock %} {% block bodyclass %}tags-list{% endblock %} @@ -14,7 +14,7 @@ {% endfor %} - {% pagination pagination %} + {% component "pagination" pagination_obj=pagination / %} {% else %}

No tags have been used yet.

{% endif %} diff --git a/djangosnippets/templates/cab/user_bookmarks.html b/djangosnippets/templates/cab/user_bookmarks.html index 69be39c0..68063a2c 100644 --- a/djangosnippets/templates/cab/user_bookmarks.html +++ b/djangosnippets/templates/cab/user_bookmarks.html @@ -1,5 +1,5 @@ {% extends "base_user.html" %} -{% load core_tags components %} +{% load core_tags %} {% block bodyclass %}bookmarks{% endblock %} {% block head_title %}Your bookmarks{% endblock %} @@ -29,7 +29,7 @@ - {% pagination pagination %} + {% component "pagination" pagination_obj=pagination / %} {% else %}

You haven't bookmarked any snippets yet.

{% endif %} diff --git a/djangosnippets/templates/cab/user_detail.html b/djangosnippets/templates/cab/user_detail.html index 42915ebb..0e2043a3 100644 --- a/djangosnippets/templates/cab/user_detail.html +++ b/djangosnippets/templates/cab/user_detail.html @@ -1,5 +1,5 @@ {% extends "base_user.html" %} -{% load cache core_tags components %} +{% load cache core_tags %} {% block bodyclass %}user{% endblock %} {% load static %} @@ -35,7 +35,7 @@ {% 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 %} - {% pagination pagination %} + {% component "pagination" pagination_obj=pagination / %} {% else %}

No snippets posted yet.

{% endif %} diff --git a/theme/static_src/src/styles.css b/theme/static_src/src/styles.css new file mode 100644 index 00000000..7f4b903c --- /dev/null +++ b/theme/static_src/src/styles.css @@ -0,0 +1,28 @@ +@import "tailwindcss" important; + +@theme { + --color-base-orange-400: #ffc656; + --color-base-white-400: #fafafa; + --color-base-gray-400: #7a7a7a; +} + +@layer components { + .arrow-left::before { + @apply content-[''] w-4 h-4 bg-current mr-2; + clip-path: polygon(9.8px 12.8px, 8.7px 12.8px, 4.5px 8.5px, 4.5px 7.5px, 8.7px 3.2px, 9.8px 4.3px, 6.1px 8px, 9.8px 11.7px, 9.8px 12.8px); + } + + .arrow-right::after { + @apply content-[''] w-4 h-4 bg-current ml-2; + clip-path: polygon(6.2px 3.2px, 7.3px 3.2px, 11.5px 7.5px, 11.5px 8.5px, 7.3px 12.8px, 6.2px 11.7px, 9.9px 8px, 6.2px 4.3px, 6.2px 3.2px); + } +} + +/** + * A catch-all path to Django template files, JavaScript, and Python files + * that contain Tailwind CSS classes and will be scanned by Tailwind to generate the final CSS file. + * + * If your final CSS file is not being updated after code changes, you may want to broaden or narrow + * the scope of this path. + */ +@source "../../../**/*.{html,py,js}";