diff --git a/static/src/scss/_404.scss b/static/src/scss/_404.scss
new file mode 100644
index 0000000..ffb880c
--- /dev/null
+++ b/static/src/scss/_404.scss
@@ -0,0 +1,43 @@
+body.page-404 {
+ main {
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ margin: 0;
+ color: $white;
+ }
+
+ .content-wrapper {
+ position: absolute;
+ text-align: center;
+ background-color: color.adjust($dark, $alpha: -0.2);
+ border-radius: $input-radius;
+ padding: 2rem;
+
+ h1 {
+ font-size: 5rem;
+ }
+
+ p {
+ font-size: 110%;
+ }
+
+ a:hover {
+ color: $grey-lighter;
+ }
+ }
+
+ marquee {
+ background-repeat: no-repeat;
+ background-size: cover;
+ background-position: center;
+ width: 100%;
+ height: 100%;
+
+ &.outer {
+ font-size: 5rem;
+ }
+ }
+}
diff --git a/static/src/scss/base.scss b/static/src/scss/base.scss
index 0c39012..06e07b2 100644
--- a/static/src/scss/base.scss
+++ b/static/src/scss/base.scss
@@ -16,6 +16,7 @@
@import "shareon";
@import "search";
@import "spotify";
+@import "404";
html,
body {
diff --git a/website/common/templates/404.html b/website/common/templates/404.html
index d31e54c..da9ae2a 100644
--- a/website/common/templates/404.html
+++ b/website/common/templates/404.html
@@ -1,11 +1,21 @@
{% extends "base.html" %}
+{% load static wagtailcore_tags wagtailimages_tags %}
+
+{% block body_class %}page-404{% endblock %}
+
{% block title %}Page not found{% endblock %}
-{% block body_class %}template-404{% endblock %}
+{% block main_content %}
+
-{% block content %}
-
+
There's nothing here!
+
The page you are looking for could not be found.
+
Go home
+
{% endblock %}
diff --git a/website/common/tests/test_views.py b/website/common/tests/test_views.py
new file mode 100644
index 0000000..ede6b6c
--- /dev/null
+++ b/website/common/tests/test_views.py
@@ -0,0 +1,14 @@
+from django.test import TestCase
+from django.urls import reverse
+
+
+class Error404PageTestCase(TestCase):
+ url = reverse("404")
+
+ def test_accessible(self) -> None:
+ response = self.client.get(self.url)
+ self.assertEqual(response.status_code, 404)
+
+ def test_queries(self) -> None:
+ with self.assertNumQueries(10):
+ self.client.get(self.url)
diff --git a/website/common/views.py b/website/common/views.py
new file mode 100644
index 0000000..9541896
--- /dev/null
+++ b/website/common/views.py
@@ -0,0 +1,23 @@
+from typing import Any
+
+from django.http.response import HttpResponse
+from django.views.defaults import ERROR_404_TEMPLATE_NAME
+from django.views.generic import TemplateView
+
+from website.home.models import HomePage
+
+
+class Error404View(TemplateView):
+ template_name = ERROR_404_TEMPLATE_NAME
+
+ def render_to_response(self, context: dict, **response_kwargs: Any) -> HttpResponse:
+ response_kwargs["status"] = 404
+ return super().render_to_response(context, **response_kwargs)
+
+ def get_context_data(self, **kwargs: dict) -> dict:
+ context = super().get_context_data(**kwargs)
+ context["homepage"] = HomePage.objects.live().get()
+ return context
+
+
+page_not_found = Error404View.as_view()
diff --git a/website/urls.py b/website/urls.py
index 89eeae5..bedf18b 100644
--- a/website/urls.py
+++ b/website/urls.py
@@ -6,6 +6,8 @@ from wagtail.contrib.sitemaps.views import sitemap
from wagtail.documents import urls as wagtaildocs_urls
from wagtail.images.views.serve import ServeView
+from website.common.views import page_not_found
+
urlpatterns = [
path("admin/", include(wagtailadmin_urls)),
path("documents/", include(wagtaildocs_urls)),
@@ -19,9 +21,14 @@ urlpatterns = [
name="wagtailimages_serve",
),
path("sitemap.xml", sitemap),
+ path("404/", page_not_found, name="404"),
]
+if not settings.DEBUG:
+ handler404 = "website.common.views.page_not_found"
+
+
if settings.DEBUG:
from django.conf.urls.static import static