diff --git a/umap/static/umap/favicons/apple-touch-icon.png b/umap/static/umap/favicons/apple-touch-icon.png
new file mode 100644
index 00000000..6bace25e
Binary files /dev/null and b/umap/static/umap/favicons/apple-touch-icon.png differ
diff --git a/umap/static/umap/favicons/favicon.ico b/umap/static/umap/favicons/favicon.ico
new file mode 100644
index 00000000..4deae7d7
Binary files /dev/null and b/umap/static/umap/favicons/favicon.ico differ
diff --git a/umap/static/umap/favicons/icon-192.png b/umap/static/umap/favicons/icon-192.png
new file mode 100644
index 00000000..d46f0a3b
Binary files /dev/null and b/umap/static/umap/favicons/icon-192.png differ
diff --git a/umap/static/umap/favicons/icon-512.png b/umap/static/umap/favicons/icon-512.png
new file mode 100644
index 00000000..5e44c836
Binary files /dev/null and b/umap/static/umap/favicons/icon-512.png differ
diff --git a/umap/static/umap/favicons/icon.svg b/umap/static/umap/favicons/icon.svg
new file mode 100644
index 00000000..9bb4774a
--- /dev/null
+++ b/umap/static/umap/favicons/icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/umap/static/umap/favicons/manifest.webmanifest b/umap/static/umap/favicons/manifest.webmanifest
new file mode 100644
index 00000000..a893e5b7
--- /dev/null
+++ b/umap/static/umap/favicons/manifest.webmanifest
@@ -0,0 +1,6 @@
+{
+ "icons": [
+ { "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
+ { "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" }
+ ]
+}
diff --git a/umap/templates/base.html b/umap/templates/base.html
index 4d93f5bd..9e5a8d34 100644
--- a/umap/templates/base.html
+++ b/umap/templates/base.html
@@ -15,6 +15,11 @@
{% endblock extra_head %}
+ {# See https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs #}
+
+
+
+
{% block header %}
diff --git a/umap/urls.py b/umap/urls.py
index 630ea45a..6f52c00f 100644
--- a/umap/urls.py
+++ b/umap/urls.py
@@ -183,7 +183,15 @@ urlpatterns += i18n_patterns(
re_path(r"^user/(?P.+)/$", views.user_maps, name="user_maps"),
re_path(r"", include(i18n_urls)),
)
-urlpatterns += (path("stats/", cache_page(60 * 60)(views.stats), name="stats"),)
+urlpatterns += (
+ path("stats/", cache_page(60 * 60)(views.stats), name="stats"),
+ path("favicon.ico", views.favicon_file),
+ path("icon.svg", views.favicon_file),
+ path("apple-touch-icon.png", views.favicon_file),
+ path("manifest.webmanifest", views.favicon_file),
+ path("icon-192.png", views.favicon_file),
+ path("icon-512.png", views.favicon_file),
+)
if settings.DEBUG and settings.MEDIA_ROOT:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
diff --git a/umap/views.py b/umap/views.py
index 0d341585..fc885589 100644
--- a/umap/views.py
+++ b/umap/views.py
@@ -21,6 +21,7 @@ from django.core.signing import BadSignature, Signer
from django.core.validators import URLValidator, ValidationError
from django.db.models import Q
from django.http import (
+ FileResponse,
HttpResponse,
HttpResponseBadRequest,
HttpResponseForbidden,
@@ -34,6 +35,8 @@ from django.utils.encoding import smart_bytes
from django.utils.http import http_date
from django.utils.translation import gettext as _
from django.utils.translation import to_locale
+from django.views.decorators.cache import cache_control
+from django.views.decorators.http import require_GET
from django.views.generic import DetailView, TemplateView, View
from django.views.generic.base import RedirectView
from django.views.generic.detail import BaseDetailView
@@ -469,9 +472,7 @@ class MapDetailMixin:
else:
map_statuses = AnonymousMapPermissionsForm.STATUS
datalayer_statuses = AnonymousDataLayerPermissionsForm.STATUS
- properties["edit_statuses"] = [
- (i, str(label)) for i, label in map_statuses
- ]
+ properties["edit_statuses"] = [(i, str(label)) for i, label in map_statuses]
properties["datalayer_edit_statuses"] = [
(i, str(label)) for i, label in datalayer_statuses
]
@@ -1016,6 +1017,17 @@ def stats(request):
)
+@require_GET
+@cache_control(max_age=60 * 60 * 24, immutable=True, public=True) # one day
+def favicon_file(request):
+ # See https://adamj.eu/tech/2022/01/18/how-to-add-a-favicon-to-your-django-site/
+ name = request.path.lstrip("/")
+ file = (Path(settings.PROJECT_DIR) / "static" / "umap" / "favicons" / name).open(
+ "rb"
+ )
+ return FileResponse(file)
+
+
def logout(request):
do_logout(request)
if is_ajax(request):