Redirect favicon.ico and dynamic webmanifest
Before Width: | Height: | Size: 638 B |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 7.3 KiB |
|
@ -1,5 +1,5 @@
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||||
<rect x="0.25" y="0.25" width="15.5" height="15.5" rx="7.75" fill="#F2F2F2" stroke="#F2F2F2" stroke-width="0.5"/>
|
<rect x=".3" y=".3" width="15.5" height="15.5" rx="7.8" fill="#F2F2F2" stroke="#F2F2F2" stroke-width=".5"/>
|
||||||
<path d="M5.85165 3.48438C4.82662 3.97171 3.99789 4.79329 3.50169 5.81407C3.00549 6.83484 2.87134 7.99406 3.12131 9.10118C3.37127 10.2083 3.99047 11.1974 4.87712 11.906C5.76377 12.6145 6.8651 13.0004 8.00009 13C4.1329 9.39063 3.24228 4.9375 5.85165 3.48438ZM8.00009 13C9.13508 13.0004 10.2364 12.6145 11.1231 11.906C12.0097 11.1974 12.6289 10.2083 12.8789 9.10118C13.1288 7.99406 12.9947 6.83484 12.4985 5.81407C12.0023 4.79329 11.1736 3.97171 10.1485 3.48438C12.7579 4.9375 11.8673 9.39063 8.00009 13Z" fill="#323E56"/>
|
<path d="M5.9 3.5A5 5 0 0 0 8 13C4.1 9.4 3.2 5 5.9 3.5ZM8 13a5 5 0 0 0 2.1-9.5C12.8 4.9 12 9.4 8 13Z" fill="#323E56"/>
|
||||||
<path d="M9.85156 5.64062C9.85156 5.88378 9.80367 6.12455 9.71062 6.34919C9.61757 6.57383 9.48119 6.77794 9.30925 6.94988C9.13732 7.12181 8.9332 7.2582 8.70856 7.35125C8.48392 7.4443 8.24315 7.49219 8 7.49219C7.75685 7.49219 7.51608 7.4443 7.29144 7.35125C7.0668 7.2582 6.86268 7.12181 6.69075 6.94988C6.51881 6.77794 6.38243 6.57383 6.28938 6.34919C6.19633 6.12455 6.14844 5.88378 6.14844 5.64062C6.14844 5.14956 6.34351 4.67861 6.69075 4.33137C7.03798 3.98414 7.50894 3.78906 8 3.78906C8.49107 3.78906 8.96202 3.98414 9.30925 4.33137C9.65649 4.67861 9.85156 5.14956 9.85156 5.64062Z" fill="#323E56"/>
|
<path d="M9.9 5.6a1.9 1.9 0 1 1-3.8 0 1.9 1.9 0 0 1 3.8 0Z" fill="#323E56"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 390 B |
|
@ -16,9 +16,9 @@
|
||||||
<meta name="viewport"
|
<meta name="viewport"
|
||||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
{# See https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs #}
|
{# See https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs #}
|
||||||
<link rel="icon" href="/favicon.ico" sizes="32x32">
|
<link rel="icon" href="{{ STATIC_URL }}umap/favicons/favicon.ico" sizes="32x32">
|
||||||
<link rel="icon" href="/icon.svg" type="image/svg+xml">
|
<link rel="icon" href="{{ STATIC_URL }}umap/favicons/icon.svg" type="image/svg+xml">
|
||||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png"><!-- 180×180 -->
|
<link rel="apple-touch-icon" href="{{ STATIC_URL }}umap/favicons/apple-touch-icon.png"><!-- 180×180 -->
|
||||||
<link rel="manifest" href="/manifest.webmanifest">
|
<link rel="manifest" href="/manifest.webmanifest">
|
||||||
</head>
|
</head>
|
||||||
<body class="{% block body_class %}{% endblock body_class %}">
|
<body class="{% block body_class %}{% endblock body_class %}">
|
||||||
|
|
22
umap/urls.py
|
@ -5,9 +5,11 @@ from django.conf.urls.static import static
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth import views as auth_views
|
from django.contrib.auth import views as auth_views
|
||||||
from django.contrib.auth.decorators import login_required
|
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.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||||
from django.views.decorators.cache import cache_control, cache_page, never_cache
|
from django.views.decorators.cache import cache_control, cache_page, never_cache
|
||||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||||
|
from django.views.generic.base import RedirectView
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
from .decorators import (
|
from .decorators import (
|
||||||
|
@ -185,12 +187,20 @@ urlpatterns += i18n_patterns(
|
||||||
)
|
)
|
||||||
urlpatterns += (
|
urlpatterns += (
|
||||||
path("stats/", cache_page(60 * 60)(views.stats), name="stats"),
|
path("stats/", cache_page(60 * 60)(views.stats), name="stats"),
|
||||||
path("favicon.ico", views.favicon_file),
|
path(
|
||||||
path("icon.svg", views.favicon_file),
|
"favicon.ico",
|
||||||
path("apple-touch-icon.png", views.favicon_file),
|
cache_control(max_age=60 * 60 * 24, immutable=True, public=True)(
|
||||||
path("manifest.webmanifest", views.favicon_file),
|
RedirectView.as_view(
|
||||||
path("icon-192.png", views.favicon_file),
|
url=staticfiles_storage.url("umap/favicons/favicon.ico")
|
||||||
path("icon-512.png", views.favicon_file),
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"manifest.webmanifest",
|
||||||
|
cache_control(max_age=60 * 60 * 24, immutable=True, public=True)(
|
||||||
|
views.webmanifest
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if settings.DEBUG and settings.MEDIA_ROOT:
|
if settings.DEBUG and settings.MEDIA_ROOT:
|
||||||
|
|
|
@ -15,13 +15,13 @@ from django.contrib.auth import logout as do_logout
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.gis.measure import D
|
from django.contrib.gis.measure import D
|
||||||
from django.contrib.postgres.search import SearchQuery, SearchVector
|
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.mail import send_mail
|
||||||
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
||||||
from django.core.signing import BadSignature, Signer
|
from django.core.signing import BadSignature, Signer
|
||||||
from django.core.validators import URLValidator, ValidationError
|
from django.core.validators import URLValidator, ValidationError
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import (
|
from django.http import (
|
||||||
FileResponse,
|
|
||||||
HttpResponse,
|
HttpResponse,
|
||||||
HttpResponseBadRequest,
|
HttpResponseBadRequest,
|
||||||
HttpResponseForbidden,
|
HttpResponseForbidden,
|
||||||
|
@ -1018,14 +1018,24 @@ def stats(request):
|
||||||
|
|
||||||
|
|
||||||
@require_GET
|
@require_GET
|
||||||
@cache_control(max_age=60 * 60 * 24, immutable=True, public=True) # one day
|
@cache_control(max_age=60 * 60 * 24, immutable=True, public=True) # One day.
|
||||||
def favicon_file(request):
|
def webmanifest(request):
|
||||||
# See https://adamj.eu/tech/2022/01/18/how-to-add-a-favicon-to-your-django-site/
|
return simple_json_response(
|
||||||
name = request.path.lstrip("/")
|
**{
|
||||||
file = (Path(settings.PROJECT_DIR) / "static" / "umap" / "favicons" / name).open(
|
"icons": [
|
||||||
"rb"
|
{
|
||||||
|
"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",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
)
|
)
|
||||||
return FileResponse(file)
|
|
||||||
|
|
||||||
|
|
||||||
def logout(request):
|
def logout(request):
|
||||||
|
|