django-scroll-to-top 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_scroll_to_top-0.1.0/LICENSE +21 -0
- django_scroll_to_top-0.1.0/PKG-INFO +632 -0
- django_scroll_to_top-0.1.0/README.md +590 -0
- django_scroll_to_top-0.1.0/pyproject.toml +111 -0
- django_scroll_to_top-0.1.0/setup.cfg +4 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/__init__.py +3 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/admin.py +1000 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/admin_preview.py +297 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/apps.py +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/checks.py +262 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/contrast.py +62 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/forms.py +867 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/__init__.py +1 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/recolor.py +119 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/registry.py +244 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/sanitizer.py +299 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/LICENSE.tabler.txt +21 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/__init__.py +1 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/filled/arrow-badge-up.svg +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/filled/arrow-big-up.svg +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/filled/caret-up.svg +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/filled/circle-arrow-up.svg +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/filled/circle-caret-up.svg +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/filled/circle-chevron-up.svg +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/filled/square-arrow-up.svg +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/filled/square-chevron-up.svg +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/filled/square-rounded-arrow-up.svg +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/filled/square-rounded-chevron-up.svg +13 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/manifest.json +144 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/arrow-badge-up.svg +19 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/arrow-big-up.svg +19 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/arrow-up.svg +21 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/caret-up.svg +19 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/chevron-up.svg +19 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/circle-arrow-up.svg +22 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/circle-caret-up.svg +20 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/circle-chevron-up.svg +20 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/square-arrow-up.svg +21 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/square-chevron-up.svg +20 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/square-rounded-arrow-up.svg +21 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/icons/tabler/outline/square-rounded-chevron-up.svg +20 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/locale/ru/LC_MESSAGES/django.mo +0 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/locale/ru/LC_MESSAGES/django.po +1517 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/management/__init__.py +0 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/management/commands/__init__.py +0 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/management/commands/scroll_to_top_check_contrast.py +55 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/management/commands/scroll_to_top_diagnose.py +58 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/migrations/0001_initial.py +171 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/migrations/__init__.py +1 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/models.py +1074 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/presentation.py +117 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/py.typed +1 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/renderer.py +294 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/services.py +143 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/settings.py +115 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/signals.py +20 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/site_config.py +200 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/static/django_scroll_to_top/admin-icon-picker.css +719 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/static/django_scroll_to_top/admin-icon-picker.js +882 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/static/django_scroll_to_top/obstacle-adapter.d.ts +41 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/static/django_scroll_to_top/obstacle-adapter.js +190 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/static/django_scroll_to_top/obstacle-adapter.min.js +1 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/static/django_scroll_to_top/scroll-to-top.css +446 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/static/django_scroll_to_top/scroll-to-top.d.ts +70 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/static/django_scroll_to_top/scroll-to-top.js +993 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/static/django_scroll_to_top/scroll-to-top.min.css +1 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/static/django_scroll_to_top/scroll-to-top.min.js +1 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/styles.py +139 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/templates/admin/base_site.html +11 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/templates/admin/django_scroll_to_top/scrolltoprevision/change_form.html +69 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/templates/django_scroll_to_top/admin_preview.html +84 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/templates/django_scroll_to_top/includes/scroll_to_top_tag.html +1 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/templates/django_scroll_to_top/scroll_to_top.html +62 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/templatetags/__init__.py +1 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/templatetags/scroll_to_top.py +74 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/urls.py +11 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top/views.py +26 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top.egg-info/PKG-INFO +632 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top.egg-info/SOURCES.txt +102 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top.egg-info/dependency_links.txt +1 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top.egg-info/requires.txt +12 -0
- django_scroll_to_top-0.1.0/src/django_scroll_to_top.egg-info/top_level.txt +1 -0
- django_scroll_to_top-0.1.0/tests/test_accessibility.py +80 -0
- django_scroll_to_top-0.1.0/tests/test_admin_integration.py +492 -0
- django_scroll_to_top-0.1.0/tests/test_admin_preview.py +262 -0
- django_scroll_to_top-0.1.0/tests/test_app.py +7 -0
- django_scroll_to_top-0.1.0/tests/test_base_fields.py +71 -0
- django_scroll_to_top-0.1.0/tests/test_collision_contract.py +264 -0
- django_scroll_to_top-0.1.0/tests/test_css_contract.py +71 -0
- django_scroll_to_top-0.1.0/tests/test_diagnostics.py +118 -0
- django_scroll_to_top-0.1.0/tests/test_dismissal.py +197 -0
- django_scroll_to_top-0.1.0/tests/test_hooks.py +100 -0
- django_scroll_to_top-0.1.0/tests/test_lifecycle.py +145 -0
- django_scroll_to_top-0.1.0/tests/test_localization.py +41 -0
- django_scroll_to_top-0.1.0/tests/test_obstacle_adapter.py +64 -0
- django_scroll_to_top-0.1.0/tests/test_registry.py +96 -0
- django_scroll_to_top-0.1.0/tests/test_renderer.py +195 -0
- django_scroll_to_top-0.1.0/tests/test_runtime_contract.py +61 -0
- django_scroll_to_top-0.1.0/tests/test_security.py +38 -0
- django_scroll_to_top-0.1.0/tests/test_site_config.py +303 -0
- django_scroll_to_top-0.1.0/tests/test_styling.py +272 -0
- django_scroll_to_top-0.1.0/tests/test_svg_sanitizer.py +157 -0
- django_scroll_to_top-0.1.0/tests/test_uploaded_icon_admin.py +257 -0
- django_scroll_to_top-0.1.0/tests/test_visibility_scroll.py +226 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kroxiksut
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-scroll-to-top
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Accessible and configurable scroll-to-top controls for Django sites and Django Admin
|
|
5
|
+
Author-email: kroxiksut <fmalkov91@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/kroxiksut/django-scroll-to-top
|
|
8
|
+
Project-URL: Source, https://github.com/kroxiksut/django-scroll-to-top
|
|
9
|
+
Project-URL: Documentation, https://github.com/kroxiksut/django-scroll-to-top/tree/main/docs
|
|
10
|
+
Project-URL: Changelog, https://github.com/kroxiksut/django-scroll-to-top/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Issues, https://github.com/kroxiksut/django-scroll-to-top/issues
|
|
12
|
+
Keywords: django,scroll-to-top,back-to-top,scroll,go-to-top,accessibility,a11y,wcag,django-admin,ui,frontend,csp
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Framework :: Django
|
|
15
|
+
Classifier: Framework :: Django :: 4.2
|
|
16
|
+
Classifier: Framework :: Django :: 5.0
|
|
17
|
+
Classifier: Framework :: Django :: 5.1
|
|
18
|
+
Classifier: Framework :: Django :: 5.2
|
|
19
|
+
Classifier: Framework :: Django :: 6.0
|
|
20
|
+
Classifier: Intended Audience :: Developers
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.10
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: Django<7,>=4.2
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: pytest<9,>=8; extra == "test"
|
|
34
|
+
Requires-Dist: pytest-django<5,>=4.8; extra == "test"
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: ruff<1,>=0.11; extra == "dev"
|
|
37
|
+
Requires-Dist: pyright<2,>=1.1.390; extra == "dev"
|
|
38
|
+
Requires-Dist: django-stubs<6,>=4.2; extra == "dev"
|
|
39
|
+
Requires-Dist: build<2,>=1.2; extra == "dev"
|
|
40
|
+
Requires-Dist: twine<7,>=5; extra == "dev"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
<p align="center">
|
|
44
|
+
<img src="https://raw.githubusercontent.com/kroxiksut/django-scroll-to-top/main/docs/assets/django-scroll-to-top-logo.png" alt="django-scroll-to-top logo" width="180">
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
<h1 align="center">django-scroll-to-top</h1>
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
Accessible, configurable scroll-to-top control for Django sites and the Django Admin.
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
<p align="center">
|
|
54
|
+
<a href="https://pypi.org/project/django-scroll-to-top/"><img src="https://img.shields.io/pypi/v/django-scroll-to-top.svg" alt="PyPI version"></a>
|
|
55
|
+
<a href="https://pypi.org/project/django-scroll-to-top/"><img src="https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue.svg" alt="Python versions"></a>
|
|
56
|
+
<a href="https://www.djangoproject.com/"><img src="https://img.shields.io/badge/Django-4.2%20LTS%20%7C%205.x%20%7C%206.0-092E20.svg?logo=django&logoColor=white" alt="Django versions"></a>
|
|
57
|
+
</p>
|
|
58
|
+
|
|
59
|
+
<p align="center">
|
|
60
|
+
<a href="https://github.com/kroxiksut/django-scroll-to-top/actions/workflows/ci.yml"><img src="https://github.com/kroxiksut/django-scroll-to-top/actions/workflows/ci.yml/badge.svg" alt="CI status"></a>
|
|
61
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
|
62
|
+
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Linted with Ruff"></a>
|
|
63
|
+
<a href="https://microsoft.github.io/pyright/"><img src="https://microsoft.github.io/pyright/img/pyright_badge.svg" alt="Checked with pyright"></a>
|
|
64
|
+
</p>
|
|
65
|
+
|
|
66
|
+
<p align="center">
|
|
67
|
+
<b>English</b> · <a href="README.ru.md">Русский</a>
|
|
68
|
+
</p>
|
|
69
|
+
|
|
70
|
+
> **Beta (`0.x`).** The package is feature-complete, tested, and builds clean
|
|
71
|
+
> distributions. While the version stays in the `0.x` series the public API may
|
|
72
|
+
> still change between minor releases before `1.0.0`.
|
|
73
|
+
|
|
74
|
+
`django-scroll-to-top` is a reusable Django application that adds an accessible,
|
|
75
|
+
configurable scroll-to-top control to application pages and the standard Django
|
|
76
|
+
Admin.
|
|
77
|
+
|
|
78
|
+
The developer experience is deliberately small:
|
|
79
|
+
|
|
80
|
+
1. Install the package and add its Django app.
|
|
81
|
+
2. Run migrations.
|
|
82
|
+
3. Add one template tag to the base site template.
|
|
83
|
+
4. Configure appearance and behavior through Django Admin.
|
|
84
|
+
|
|
85
|
+
No jQuery, external CDN, frontend framework, or mandatory frontend build step is
|
|
86
|
+
required.
|
|
87
|
+
|
|
88
|
+
## Why This Package
|
|
89
|
+
|
|
90
|
+
A basic scroll-to-top link is easy to write. A reusable production component
|
|
91
|
+
also needs to handle:
|
|
92
|
+
|
|
93
|
+
- separate desktop and mobile presentation;
|
|
94
|
+
- keyboard navigation, focus, contrast, and reduced motion;
|
|
95
|
+
- standard Django Admin integration;
|
|
96
|
+
- safe custom SVG icons;
|
|
97
|
+
- light and dark themes;
|
|
98
|
+
- cookie banners, chats, sticky navigation, and other fixed elements;
|
|
99
|
+
- user dismissal without breaking the primary scroll action;
|
|
100
|
+
- strict Content Security Policy deployments;
|
|
101
|
+
- caching, localization, packaging, and upgrade compatibility.
|
|
102
|
+
|
|
103
|
+
This package provides those behaviors while keeping page-template changes
|
|
104
|
+
minimal.
|
|
105
|
+
|
|
106
|
+
## Features
|
|
107
|
+
|
|
108
|
+
- One template tag for public site integration.
|
|
109
|
+
- Independent site and standard Django Admin configurations.
|
|
110
|
+
- Database-backed configuration managed through Django Admin.
|
|
111
|
+
- Draft, publish, rollback, and configuration-copy workflows.
|
|
112
|
+
- Explicit desktop values and per-field mobile inheritance/overrides.
|
|
113
|
+
- Top-left, top-right, bottom-left, and bottom-right placement.
|
|
114
|
+
- Circle, square, rounded-square, pill, and icon-with-label templates.
|
|
115
|
+
- Solid, outline, soft, ghost, glass, and controlled gradient variants.
|
|
116
|
+
- Configurable colors, borders, shadows, focus rings, spacing, and sizing.
|
|
117
|
+
- Built-in light/dark presets and theme inheritance.
|
|
118
|
+
- Live desktop/mobile preview using the production renderer.
|
|
119
|
+
- Built-in Tabler starter icons plus developer and administrator icon sources.
|
|
120
|
+
- Safe SVG upload, sanitization, preview, recoloring, and license metadata.
|
|
121
|
+
- Scroll thresholds, short-page detection, fixed-header offsets, and optional
|
|
122
|
+
target selectors.
|
|
123
|
+
- Native smooth scrolling with `prefers-reduced-motion` support.
|
|
124
|
+
- Collision avoidance for banners, launchers, chats, toast containers, sticky
|
|
125
|
+
navigation, and other floating controls.
|
|
126
|
+
- Local/session user dismissal with expiration, reset versions, and restore UX.
|
|
127
|
+
- Django i18n with English canonical strings and Russian as the first bundled
|
|
128
|
+
translation.
|
|
129
|
+
|
|
130
|
+
## Installation
|
|
131
|
+
|
|
132
|
+
```console
|
|
133
|
+
python -m pip install django-scroll-to-top
|
|
134
|
+
python manage.py migrate
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Add the application and enable the required integration scopes:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
INSTALLED_APPS = [
|
|
141
|
+
# ...
|
|
142
|
+
"django_scroll_to_top",
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
DJANGO_SCROLL_TO_TOP = {
|
|
146
|
+
"SITE_ENABLED": True,
|
|
147
|
+
"ADMIN_ENABLED": True,
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Include the package URLConf so the public template tag can load its versioned
|
|
152
|
+
same-origin stylesheet endpoint in strict-CSP deployments:
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from django.urls import include, path
|
|
156
|
+
|
|
157
|
+
urlpatterns = [
|
|
158
|
+
# ...
|
|
159
|
+
path(
|
|
160
|
+
"scroll-to-top/",
|
|
161
|
+
include(
|
|
162
|
+
("django_scroll_to_top.urls", "django_scroll_to_top"),
|
|
163
|
+
namespace="django_scroll_to_top",
|
|
164
|
+
),
|
|
165
|
+
),
|
|
166
|
+
]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The package supports and tests the standard Django Admin templates on the
|
|
170
|
+
documented Django compatibility matrix. The integration uses documented Django
|
|
171
|
+
extension points, preserves standard branding, and avoids monkeypatching private
|
|
172
|
+
Django APIs.
|
|
173
|
+
|
|
174
|
+
When `DJANGO_SCROLL_TO_TOP["ADMIN_ENABLED"]` is true, place
|
|
175
|
+
`"django_scroll_to_top"` before `"django.contrib.admin"` in `INSTALLED_APPS`
|
|
176
|
+
so the package's `admin/base_site.html` footer override is selected through the
|
|
177
|
+
normal Django template resolution rules.
|
|
178
|
+
|
|
179
|
+
Custom `AdminSite` instances, overridden base admin templates, and third-party
|
|
180
|
+
admin themes are best-effort integrations and are not yet covered by the
|
|
181
|
+
compatibility test matrix. Projects using them should verify the integration
|
|
182
|
+
locally and report incompatibilities so they can be investigated and fixed
|
|
183
|
+
collaboratively.
|
|
184
|
+
|
|
185
|
+
No separate admin-integration app is required for the current standard-admin
|
|
186
|
+
footer injection. If a future integration app becomes necessary, it should use
|
|
187
|
+
its own app label instead of overloading the main package label.
|
|
188
|
+
|
|
189
|
+
### Custom AdminSite Recipe
|
|
190
|
+
|
|
191
|
+
If a project overrides `admin/base_site.html` or uses a custom `AdminSite`
|
|
192
|
+
template tree, keep the normal branding blocks and add the package tag in the
|
|
193
|
+
footer block:
|
|
194
|
+
|
|
195
|
+
```django
|
|
196
|
+
{% extends "admin/base.html" %}
|
|
197
|
+
{% load i18n scroll_to_top %}
|
|
198
|
+
|
|
199
|
+
{% block branding %}
|
|
200
|
+
{{ block.super }}
|
|
201
|
+
{% endblock %}
|
|
202
|
+
|
|
203
|
+
{% block footer %}
|
|
204
|
+
{{ block.super }}
|
|
205
|
+
{% scroll_to_top scope="admin" %}
|
|
206
|
+
{% endblock %}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The default admin policy hides the control on anonymous auth pages such as the
|
|
210
|
+
login and password-reset screens. Set
|
|
211
|
+
`DJANGO_SCROLL_TO_TOP["ADMIN_SHOW_ON_AUTH_PAGES"] = True` to opt into showing it
|
|
212
|
+
there as well.
|
|
213
|
+
|
|
214
|
+
## Template Usage
|
|
215
|
+
|
|
216
|
+
Add one tag near the end of the shared base template:
|
|
217
|
+
|
|
218
|
+
```django
|
|
219
|
+
{% load scroll_to_top %}
|
|
220
|
+
|
|
221
|
+
<!-- Page content -->
|
|
222
|
+
|
|
223
|
+
{% scroll_to_top %}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The tag resolves the published site configuration, renders the selected safe
|
|
227
|
+
icon and controlled template variant, and loads package assets. Ordinary visual
|
|
228
|
+
options are not passed as template-tag arguments. Dynamic color and sizing
|
|
229
|
+
variables are delivered through a versioned same-origin stylesheet rather than
|
|
230
|
+
an inline `style` attribute, so the one-tag contract remains intact without
|
|
231
|
+
silently requiring `unsafe-inline`.
|
|
232
|
+
|
|
233
|
+
Projects can override documented package templates through standard Django
|
|
234
|
+
template loaders.
|
|
235
|
+
|
|
236
|
+
## Configuration Model
|
|
237
|
+
|
|
238
|
+
Django settings own installation and infrastructure choices only. Normal
|
|
239
|
+
appearance and behavior are stored in database-backed configuration and edited
|
|
240
|
+
through Django Admin.
|
|
241
|
+
|
|
242
|
+
Configuration scopes:
|
|
243
|
+
|
|
244
|
+
| Scope | Purpose |
|
|
245
|
+
| --- | --- |
|
|
246
|
+
| `site` | Public and application pages using the template tag |
|
|
247
|
+
| `admin` | Standard Django Admin pages |
|
|
248
|
+
|
|
249
|
+
Django Sites integration is included. When `django.contrib.sites` is installed,
|
|
250
|
+
the current Site may have a Site-specific profile with a global fallback. The
|
|
251
|
+
package also remains usable without the Sites Framework. Site and admin
|
|
252
|
+
configurations remain independent but can be copied explicitly.
|
|
253
|
+
|
|
254
|
+
Desktop values are primary. Each mobile-capable field explicitly inherits its
|
|
255
|
+
desktop value or stores an override. The admin form shows this relationship
|
|
256
|
+
instead of hiding inheritance behind empty values.
|
|
257
|
+
|
|
258
|
+
### Visibility and Scrolling
|
|
259
|
+
|
|
260
|
+
Each revision configures when the control appears and where it scrolls:
|
|
261
|
+
|
|
262
|
+
- visibility threshold mode (`pixels`, `viewport`, or `combined`) with
|
|
263
|
+
`show_after_px`, `show_after_viewports`, and a `min_document_height_px` floor
|
|
264
|
+
so short pages never show the control;
|
|
265
|
+
- show/hide delays and a visibility direction (`always`, `scroll_up_only`, or
|
|
266
|
+
`hide_on_scroll_down`);
|
|
267
|
+
- a page-level opt-out via a `data-scroll-top="disabled"` attribute on `<body>`;
|
|
268
|
+
- an optional scroll target selector with a vertical offset and an optional
|
|
269
|
+
fixed-header selector whose height is subtracted, falling back to the top of
|
|
270
|
+
the document when empty or not found;
|
|
271
|
+
- `smooth` or `instant` scrolling (reduced-motion users always get an instant
|
|
272
|
+
jump), using native `window.scrollTo` without a custom animation loop.
|
|
273
|
+
|
|
274
|
+
### Visual Templates and Styling
|
|
275
|
+
|
|
276
|
+
Appearance is built from controlled package CSS classes, never arbitrary
|
|
277
|
+
templates stored in the database:
|
|
278
|
+
|
|
279
|
+
- shapes: `circle`, `square`, `rounded-square`, and `pill`;
|
|
280
|
+
- fill variants: `solid`, `outline`, `soft`, `ghost`, `glass` (translucent with
|
|
281
|
+
a backdrop-blur fallback), and `gradient` (two configured colors and an angle);
|
|
282
|
+
- shadow presets (`none`/`small`/`medium`/`large`), opacity, border width,
|
|
283
|
+
focus-ring width/offset, and a backdrop-blur amount for the glass variant.
|
|
284
|
+
|
|
285
|
+
The six fill variants, shown on the default circle shape:
|
|
286
|
+
|
|
287
|
+
| Fill | Preview | Description |
|
|
288
|
+
| --- | :---: | --- |
|
|
289
|
+
| `solid` | <img src="https://raw.githubusercontent.com/kroxiksut/django-scroll-to-top/main/docs/assets/shared/7.2-fill-solid.png" alt="Solid fill" width="96"> | Opaque background |
|
|
290
|
+
| `outline` | <img src="https://raw.githubusercontent.com/kroxiksut/django-scroll-to-top/main/docs/assets/shared/7.2-fill-outline.png" alt="Outline fill" width="96"> | Border only, no fill |
|
|
291
|
+
| `soft` | <img src="https://raw.githubusercontent.com/kroxiksut/django-scroll-to-top/main/docs/assets/shared/7.2-fill-soft.png" alt="Soft fill" width="96"> | Soft translucent background |
|
|
292
|
+
| `ghost` | <img src="https://raw.githubusercontent.com/kroxiksut/django-scroll-to-top/main/docs/assets/shared/7.2-fill-ghost.png" alt="Ghost fill" width="96"> | Transparent; background appears on hover |
|
|
293
|
+
| `glass` | <img src="https://raw.githubusercontent.com/kroxiksut/django-scroll-to-top/main/docs/assets/shared/7.2-fill-glass.png" alt="Glass fill" width="96"> | Glassy: translucent with a backdrop blur |
|
|
294
|
+
| `gradient` | <img src="https://raw.githubusercontent.com/kroxiksut/django-scroll-to-top/main/docs/assets/shared/7.2-fill-gradient.png" alt="Gradient fill" width="96"> | Gradient between two configured colors |
|
|
295
|
+
|
|
296
|
+
Unknown shapes, fills, or shadows fall back to safe defaults, forced-colors mode
|
|
297
|
+
neutralizes every variant, and projects can still override the package template
|
|
298
|
+
through standard Django template resolution.
|
|
299
|
+
|
|
300
|
+
## Placement and Floating-Element Collisions
|
|
301
|
+
|
|
302
|
+
Both desktop and mobile modes support all four viewport corners, independent
|
|
303
|
+
offsets, safe-area insets, bounded `z-index`, obstacle spacing, and
|
|
304
|
+
fallback-corner order.
|
|
305
|
+
|
|
306
|
+
Host elements can declare themselves as obstacles:
|
|
307
|
+
|
|
308
|
+
```html
|
|
309
|
+
<div data-scroll-top-obstacle>
|
|
310
|
+
<!-- Cookie banner, chat launcher, sticky action, and so on -->
|
|
311
|
+
</div>
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Administrators may also configure validated CSS selectors. The browser runtime
|
|
315
|
+
measures visible rectangles and applies one of these policies:
|
|
316
|
+
|
|
317
|
+
- ignore obstacles;
|
|
318
|
+
- shift along the selected edge;
|
|
319
|
+
- try configured fallback corners;
|
|
320
|
+
- hide the control when no safe placement exists.
|
|
321
|
+
|
|
322
|
+
Cookie and chat packages remain optional. They do not become dependencies of
|
|
323
|
+
`django-scroll-to-top`.
|
|
324
|
+
|
|
325
|
+
### Optional Obstacle Adapter
|
|
326
|
+
|
|
327
|
+
For cookie banners and other floating widgets that are not easy to target with a
|
|
328
|
+
single static selector, an optional adapter ships at
|
|
329
|
+
`django_scroll_to_top/obstacle-adapter.js`. It is never loaded by the
|
|
330
|
+
`{% scroll_to_top %}` tag; include it only where you need it:
|
|
331
|
+
|
|
332
|
+
```html
|
|
333
|
+
<script src="{% static 'django_scroll_to_top/obstacle-adapter.min.js' %}" defer></script>
|
|
334
|
+
<script>
|
|
335
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
336
|
+
// Generic registration: tag selectors and recalculate on widget events.
|
|
337
|
+
window.djsttObstacleAdapter.register({
|
|
338
|
+
selectors: [".chat-widget", ".sticky-bottom-nav", ".toast-stack"],
|
|
339
|
+
gap: 12,
|
|
340
|
+
priority: 5,
|
|
341
|
+
events: ["my-widget:open", "my-widget:close"]
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Or reuse the bundled django-cookies-152fz preset (panel + launcher).
|
|
345
|
+
window.djsttObstacleAdapter.register(
|
|
346
|
+
window.djsttObstacleAdapter.presets.djangoCookies152fz
|
|
347
|
+
);
|
|
348
|
+
});
|
|
349
|
+
</script>
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
The adapter tags matching markup with `data-scroll-top-obstacle` (including
|
|
353
|
+
elements inserted later, such as a compact launcher that appears after the
|
|
354
|
+
banner closes), and bridges the configured open/close/collapse events to
|
|
355
|
+
`window.djstt.refresh()`. The cookie banner panel and its compact launcher are
|
|
356
|
+
listed as separate selectors so each is measured on its own bounding rectangle
|
|
357
|
+
while visible. Cross-origin iframe contents are never inspected; tagging an
|
|
358
|
+
`<iframe>` makes the engine treat the iframe rectangle itself as an obstacle.
|
|
359
|
+
|
|
360
|
+
Collision avoidance and theme-aware enhancements are progressive enhancement
|
|
361
|
+
behaviors. The no-JavaScript baseline remains a plain top-of-document link in
|
|
362
|
+
the configured corner with the conservative built-in preset.
|
|
363
|
+
|
|
364
|
+
## Icons
|
|
365
|
+
|
|
366
|
+
The unified icon catalog has three sources:
|
|
367
|
+
|
|
368
|
+
- `builtin`: vendored Tabler starter icons;
|
|
369
|
+
- `developer`: icons registered by trusted project code;
|
|
370
|
+
- `uploaded`: SVG files uploaded and approved through Django Admin.
|
|
371
|
+
|
|
372
|
+
Built-in examples include suitable arrow, chevron, caret, circle, badge,
|
|
373
|
+
bar, and square variants from [Tabler Icons](https://tabler.io/icons).
|
|
374
|
+
|
|
375
|
+
### Icon Color Requirements
|
|
376
|
+
|
|
377
|
+
The button reads its colors from the database configuration. For an icon to pick
|
|
378
|
+
up the configured color, its SVG must paint with `currentColor` rather than a
|
|
379
|
+
hard-coded color — that is, use `fill="currentColor"` (filled icons) or
|
|
380
|
+
`stroke="currentColor"` (outline icons). The control then applies, in priority
|
|
381
|
+
order:
|
|
382
|
+
|
|
383
|
+
1. **Icon color override** (`icon_color` / `dark_icon_color`) when set;
|
|
384
|
+
2. otherwise the **foreground color** (`foreground_color`), which is also the
|
|
385
|
+
label color.
|
|
386
|
+
|
|
387
|
+
Multicolor/original uploaded icons keep their own colors and ignore these
|
|
388
|
+
fields (they do not use `currentColor`). Built-in Tabler icons already use
|
|
389
|
+
`currentColor`, so they recolor automatically.
|
|
390
|
+
|
|
391
|
+
Tabler Icons are distributed under the
|
|
392
|
+
[MIT License](https://github.com/tabler/tabler-icons/blob/main/LICENSE). That
|
|
393
|
+
license permits broad use, modification, and redistribution, including
|
|
394
|
+
commercial use, while requiring preservation of its copyright and license
|
|
395
|
+
notice. Release artifacts include the required notice and source/version
|
|
396
|
+
metadata.
|
|
397
|
+
|
|
398
|
+
### Uploaded SVG Safety
|
|
399
|
+
|
|
400
|
+
Administrator-uploaded SVG is not rendered directly. The pipeline:
|
|
401
|
+
|
|
402
|
+
- parses SVG as XML;
|
|
403
|
+
- rejects DTD, entities, scripts, event handlers, external resources, embedded
|
|
404
|
+
documents, unsafe namespaces, and excessive complexity;
|
|
405
|
+
- allows only documented graphical elements and attributes;
|
|
406
|
+
- normalizes geometry and `viewBox` data;
|
|
407
|
+
- stores and renders only a sanitized payload;
|
|
408
|
+
- supports `currentColor` recoloring for compatible icons;
|
|
409
|
+
- preserves safe original colors only in an explicit multicolor mode.
|
|
410
|
+
|
|
411
|
+
Technical sanitization does not grant a right to use an icon. Uploaded icons
|
|
412
|
+
carry author, source, license, copyright, and attribution metadata, plus an
|
|
413
|
+
administrator confirmation that the project may use and distribute the file.
|
|
414
|
+
|
|
415
|
+
The package does not treat an uploaded SVG as free or open content merely
|
|
416
|
+
because the file was accepted by the sanitizer. The site operator remains
|
|
417
|
+
responsible for confirming usage and redistribution rights, keeping attribution
|
|
418
|
+
data accurate, and exporting icon-attribution records when the deployment needs
|
|
419
|
+
them.
|
|
420
|
+
|
|
421
|
+
## Themes and Colors
|
|
422
|
+
|
|
423
|
+
Administrator-configured colors are delivered through a versioned same-origin
|
|
424
|
+
stylesheet generated by the package, without storing arbitrary CSS or requiring
|
|
425
|
+
`unsafe-inline`. The stylesheet uses the same resolved Site/profile
|
|
426
|
+
configuration as the component renderer and remains effective without
|
|
427
|
+
JavaScript.
|
|
428
|
+
|
|
429
|
+
Manual and inherited color modes are supported. Standard Django Admin
|
|
430
|
+
configuration can inherit supported admin theme variables and react to
|
|
431
|
+
light/dark changes with safe fallbacks. The built-in `inherit_admin_theme`
|
|
432
|
+
mode prefers publicly observable Django Admin variables, falls back to a neutral
|
|
433
|
+
preset when they are absent, and also exposes namespaced `--dstt-admin-*`
|
|
434
|
+
adapter hooks for third-party admin themes.
|
|
435
|
+
|
|
436
|
+
Colors are otherwise configured manually per revision. (The earlier
|
|
437
|
+
browser-based page color analysis workflow was removed as unnecessary.)
|
|
438
|
+
|
|
439
|
+
## User Dismissal
|
|
440
|
+
|
|
441
|
+
Persistent user dismissal is separate from temporary runtime visibility and from
|
|
442
|
+
the administrative enable flag. Each revision configures dismissal:
|
|
443
|
+
|
|
444
|
+
- `allow_user_dismissal` renders a visible close control;
|
|
445
|
+
- the storage mechanism is `local`, `session`, a functional `cookie`, or `none`
|
|
446
|
+
(in-memory only). The default `local` mode stores nothing until the visitor
|
|
447
|
+
actually dismisses the control;
|
|
448
|
+
- the duration is either `persistent` (kept until the revision's configuration
|
|
449
|
+
token or `dismissal_version` changes) or day-based via `dismissal_days`, which
|
|
450
|
+
self-clears once it lapses;
|
|
451
|
+
- `dismissal_requires_confirmation` asks the visitor to confirm before hiding;
|
|
452
|
+
- `dismissal_version` is an explicit knob to intentionally re-show the control.
|
|
453
|
+
|
|
454
|
+
Storage keys are namespaced by scope, site, configuration token, and dismissal
|
|
455
|
+
version, and all storage access tolerates denied or unavailable storage without
|
|
456
|
+
breaking the scroll action. The control can be restored programmatically with
|
|
457
|
+
`window.djstt.restore()`. Triple-click dismissal remains experimental because
|
|
458
|
+
the first normal click starts scrolling and may hide the control immediately; it
|
|
459
|
+
is not enabled by default.
|
|
460
|
+
|
|
461
|
+
## Accessibility
|
|
462
|
+
|
|
463
|
+
The component targets WCAG 2.2 AA within its scope:
|
|
464
|
+
|
|
465
|
+
- accessible name independent of icon or tooltip;
|
|
466
|
+
- keyboard operation and visible focus;
|
|
467
|
+
- appropriate pointer target size;
|
|
468
|
+
- contrast validation for normal, hover, active, and focus states;
|
|
469
|
+
- `prefers-reduced-motion` support;
|
|
470
|
+
- forced-colors/high-contrast behavior;
|
|
471
|
+
- zoom and RTL support;
|
|
472
|
+
- no keyboard trap or unexpected focus movement;
|
|
473
|
+
- decorative SVG hidden from accessibility APIs.
|
|
474
|
+
|
|
475
|
+
The structural contract above is implemented and covered by tests: a translatable
|
|
476
|
+
accessible name on both the control and the close control, a minimum 24x24 CSS px
|
|
477
|
+
target floor, a no-JavaScript link fallback, no positive tabindex, visible
|
|
478
|
+
focus-visible outlines, forced-colors and reduced-motion handling, and RTL-safe
|
|
479
|
+
logical properties. A full WCAG 2.2 AA audit and zoom (200%/400%) verification in
|
|
480
|
+
real browsers are tracked as later stabilization steps (see [Roadmap](#roadmap)).
|
|
481
|
+
|
|
482
|
+
## Security, Privacy, and CSP
|
|
483
|
+
|
|
484
|
+
- No arbitrary HTML, JavaScript, or CSS is stored through admin forms.
|
|
485
|
+
- Production never renders an unsanitized original SVG upload.
|
|
486
|
+
- No telemetry or external network calls are enabled by default.
|
|
487
|
+
- Strict CSP support does not silently require `unsafe-inline`.
|
|
488
|
+
- Browser storage failures degrade safely.
|
|
489
|
+
- Cookie-based or authenticated database dismissal is optional and documented
|
|
490
|
+
separately if enabled.
|
|
491
|
+
|
|
492
|
+
See [SECURITY.md](SECURITY.md) for the supported versions and how to report a
|
|
493
|
+
vulnerability.
|
|
494
|
+
|
|
495
|
+
### Minimal CSP Configuration
|
|
496
|
+
|
|
497
|
+
The default `DJANGO_SCROLL_TO_TOP["CSP_MODE"]` is `"external"`. In that mode,
|
|
498
|
+
the component uses same-origin `<link>` and `<script>` tags and works with a
|
|
499
|
+
policy such as:
|
|
500
|
+
|
|
501
|
+
```text
|
|
502
|
+
Content-Security-Policy:
|
|
503
|
+
default-src 'self';
|
|
504
|
+
style-src 'self';
|
|
505
|
+
script-src 'self';
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
If the host project uses nonce-based script delivery, set
|
|
509
|
+
`DJANGO_SCROLL_TO_TOP["CSP_MODE"] = "nonce"` and provide `csp_nonce` in the
|
|
510
|
+
template context or `request.csp_nonce`. The package adds that nonce to its
|
|
511
|
+
external script tag while keeping style delivery on the same-origin stylesheet
|
|
512
|
+
endpoint.
|
|
513
|
+
|
|
514
|
+
## Runtime Events
|
|
515
|
+
|
|
516
|
+
The browser runtime uses one documented global entrypoint, `window.djstt`, with
|
|
517
|
+
`init(root?)`, `refresh(root?)`, and `destroy(root?)` helpers for progressive
|
|
518
|
+
enhancement and partial-navigation integrations.
|
|
519
|
+
|
|
520
|
+
The runtime dispatches these namespaced DOM events from each component root:
|
|
521
|
+
|
|
522
|
+
- `djstt:show`
|
|
523
|
+
- `djstt:hide`
|
|
524
|
+
- `djstt:scroll-start`
|
|
525
|
+
- `djstt:scroll-end`
|
|
526
|
+
- `djstt:dismiss`
|
|
527
|
+
|
|
528
|
+
HTMX-like fragment replacement may call `window.djstt.init(fragmentRoot)`. Turbo
|
|
529
|
+
and similar full-page navigation layers may call `window.djstt.refresh()`.
|
|
530
|
+
|
|
531
|
+
## Extension Points
|
|
532
|
+
|
|
533
|
+
Optional hooks are configured in `DJANGO_SCROLL_TO_TOP` as a dotted path or a
|
|
534
|
+
callable, and a faulty hook never breaks rendering:
|
|
535
|
+
|
|
536
|
+
- `SITE_ID_RESOLVER(request) -> int | None` — resolve the current Site id without
|
|
537
|
+
depending on `django.contrib.sites`;
|
|
538
|
+
- `PROFILE_RESOLVER(scope, site_id) -> ScrollTopProfile | None` — override
|
|
539
|
+
profile/revision selection; return `None` to fall back to built-in resolution;
|
|
540
|
+
- `OBSTACLE_SELECTORS() -> list[str]` — merge extra obstacle selectors into every
|
|
541
|
+
rendered control.
|
|
542
|
+
|
|
543
|
+
Developer icons are registered through `register_developer_icon(...)`. The
|
|
544
|
+
stable public surface is `window.djstt` (`init`/`refresh`/`destroy`, `version`,
|
|
545
|
+
`dismiss`/`restore`/`debug`), the namespaced `djstt:*` DOM events, the
|
|
546
|
+
`data-dstt-*` attributes on the control wrapper, the `data-scroll-top-obstacle`
|
|
547
|
+
marker, and the `django_scroll_to_top/scroll_to_top.html` template. Internal
|
|
548
|
+
service and model APIs are not part of the public contract.
|
|
549
|
+
|
|
550
|
+
## Diagnostics
|
|
551
|
+
|
|
552
|
+
System checks report common misconfigurations with stable ids and actionable
|
|
553
|
+
hints:
|
|
554
|
+
|
|
555
|
+
- `dstt.W001`/`W002`: migrations cannot be inspected, or are unapplied.
|
|
556
|
+
- `dstt.W003`: unsupported `CSP_MODE`.
|
|
557
|
+
- `dstt.W004`: package URLConf is missing while site rendering is enabled.
|
|
558
|
+
- `dstt.W005`: `django_scroll_to_top` is ordered after `django.contrib.admin`.
|
|
559
|
+
- `dstt.W006`: unsupported `DEFAULT_COLLISION_POLICY`.
|
|
560
|
+
- `dstt.W007`: `DJANGO_SCROLL_TO_TOP` is not a dict or has unknown keys.
|
|
561
|
+
- `dstt.W008`: `ADMIN_ENABLED` is set but `django.contrib.admin` is not installed.
|
|
562
|
+
- `dstt.W009`: `SITES_FRAMEWORK_ENABLED` is set but `django.contrib.sites` is not
|
|
563
|
+
installed.
|
|
564
|
+
- `dstt.W010`: packaged templates or minified static assets are missing.
|
|
565
|
+
|
|
566
|
+
Two management commands help diagnose a deployment:
|
|
567
|
+
|
|
568
|
+
```console
|
|
569
|
+
python manage.py scroll_to_top_diagnose # resolved config per scope, no secrets
|
|
570
|
+
python manage.py scroll_to_top_check_contrast # non-zero exit if a published revision fails
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
## Asset Build
|
|
574
|
+
|
|
575
|
+
Release assets are minified reproducibly with:
|
|
576
|
+
|
|
577
|
+
```console
|
|
578
|
+
python tools/minify_assets.py
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
## Compatibility
|
|
582
|
+
|
|
583
|
+
The support matrix covers Django 4.2 LTS, 5.x, and 6.x with the Python versions
|
|
584
|
+
supported by each selected Django release. Django 4 support is scoped to 4.2 LTS
|
|
585
|
+
rather than the entire 4.x line. The matrix is defined in `pyproject.toml` and
|
|
586
|
+
verified in CI (`tox.ini` mirrors it).
|
|
587
|
+
|
|
588
|
+
The base runtime dependency set is limited to Django.
|
|
589
|
+
|
|
590
|
+
## Feedback
|
|
591
|
+
|
|
592
|
+
This is an early (`0.x` beta) release, and real-world reports are especially
|
|
593
|
+
valuable. Bug reports and feedback are welcome via
|
|
594
|
+
[GitHub issues](https://github.com/kroxiksut/django-scroll-to-top/issues),
|
|
595
|
+
particularly on:
|
|
596
|
+
|
|
597
|
+
- **Admin integration** — the package is tested against the standard Django
|
|
598
|
+
Admin templates. Custom `AdminSite` instances, overridden base admin
|
|
599
|
+
templates, and third-party admin themes are best-effort and not yet in the
|
|
600
|
+
compatibility test matrix; please report what works and what does not.
|
|
601
|
+
- **Frontend behavior** — collision avoidance with real cookie banners, chat
|
|
602
|
+
launchers, sticky navigation, and toast stacks; placement across viewport
|
|
603
|
+
sizes and safe-area insets; behavior under strict CSP; theme inheritance with
|
|
604
|
+
custom admin themes; and partial-navigation layers such as HTMX and Turbo.
|
|
605
|
+
- **Accessibility in real browsers** — keyboard, focus, contrast, forced-colors,
|
|
606
|
+
reduced motion, RTL, and zoom (200%/400%); see the [Roadmap](#roadmap) for the
|
|
607
|
+
audits still in progress.
|
|
608
|
+
|
|
609
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for how to file an effective report.
|
|
610
|
+
|
|
611
|
+
## Roadmap
|
|
612
|
+
|
|
613
|
+
Tracked for after the initial release:
|
|
614
|
+
|
|
615
|
+
- Full WCAG 2.2 AA audit and zoom (200%/400%) verification in real browsers.
|
|
616
|
+
- Optional authenticated database-backed dismissal endpoint.
|
|
617
|
+
|
|
618
|
+
## Project Documentation
|
|
619
|
+
|
|
620
|
+
- [Changelog](CHANGELOG.md)
|
|
621
|
+
- [Architecture](ARCHITECTURE.md)
|
|
622
|
+
- [Contributor guide](CONTRIBUTING.md)
|
|
623
|
+
- [Security policy](SECURITY.md)
|
|
624
|
+
- [Code of conduct](CODE_OF_CONDUCT.md)
|
|
625
|
+
- [Repository structure](STRUCTURE.md)
|
|
626
|
+
|
|
627
|
+
## License
|
|
628
|
+
|
|
629
|
+
The package is licensed under MIT. See [LICENSE](LICENSE).
|
|
630
|
+
|
|
631
|
+
Third-party assets retain their own licenses. The vendored Tabler subset and
|
|
632
|
+
its upstream MIT notice are documented in [THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md).
|