diff --git a/umap/static/favicon.ico b/umap/static/favicon.ico
deleted file mode 100644
index 0aa459cc..00000000
Binary files a/umap/static/favicon.ico and /dev/null differ
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..0f2ff064
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..39affe5c
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..5a4175dd
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..3103a0c2
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..f7fbf130
--- /dev/null
+++ b/umap/static/umap/favicons/icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/umap/templates/base.html b/umap/templates/base.html
index 4d93f5bd..0a57fe35 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..cd32d406 100644
--- a/umap/urls.py
+++ b/umap/urls.py
@@ -5,9 +5,11 @@ from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.auth import views as auth_views
from django.contrib.auth.decorators import login_required
+from django.contrib.staticfiles.storage import staticfiles_storage
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.views.decorators.cache import cache_control, cache_page, never_cache
from django.views.decorators.csrf import ensure_csrf_cookie
+from django.views.generic.base import RedirectView
from . import views
from .decorators import (
@@ -183,7 +185,23 @@ 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",
+ cache_control(max_age=60 * 60 * 24, immutable=True, public=True)(
+ RedirectView.as_view(
+ url=staticfiles_storage.url("umap/favicons/favicon.ico")
+ )
+ ),
+ ),
+ path(
+ "manifest.webmanifest",
+ cache_control(max_age=60 * 60 * 24, immutable=True, public=True)(
+ views.webmanifest
+ ),
+ ),
+)
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..d9f8d647 100644
--- a/umap/views.py
+++ b/umap/views.py
@@ -15,6 +15,7 @@ from django.contrib.auth import logout as do_logout
from django.contrib.auth import get_user_model
from django.contrib.gis.measure import D
from django.contrib.postgres.search import SearchQuery, SearchVector
+from django.contrib.staticfiles.storage import staticfiles_storage
from django.core.mail import send_mail
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.core.signing import BadSignature, Signer
@@ -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,27 @@ def stats(request):
)
+@require_GET
+@cache_control(max_age=60 * 60 * 24, immutable=True, public=True) # One day.
+def webmanifest(request):
+ return simple_json_response(
+ **{
+ "icons": [
+ {
+ "src": staticfiles_storage.url("umap/favicons/icon-192.png"),
+ "type": "image/png",
+ "sizes": "192x192",
+ },
+ {
+ "src": staticfiles_storage.url("umap/favicons/icon-512.png"),
+ "type": "image/png",
+ "sizes": "512x512",
+ },
+ ]
+ }
+ )
+
+
def logout(request):
do_logout(request)
if is_ajax(request):