diff --git a/docs/404.rst b/docs/404.rst
new file mode 100644
index 0000000..569aeb6
--- /dev/null
+++ b/docs/404.rst
@@ -0,0 +1,7 @@
+:orphan:
+:layout: 404
+
+404
+===
+
+The requested URL was not found on this site.
diff --git a/docs/_public/404.html b/docs/_public/404.html
deleted file mode 100644
index 4da86ac..0000000
--- a/docs/_public/404.html
+++ /dev/null
@@ -1 +0,0 @@
-
404 | Not found
diff --git a/docs/customisation/layouts.rst b/docs/customisation/layouts.rst
index 3507dfe..4ab0f44 100644
--- a/docs/customisation/layouts.rst
+++ b/docs/customisation/layouts.rst
@@ -129,3 +129,6 @@ This template offers a special container for buttons:
`Docs `_
`GitHub `_
+
+404 layout
+~~~~~~~~~~
diff --git a/src/shibuya/__init__.py b/src/shibuya/__init__.py
index 10064ad..965f021 100644
--- a/src/shibuya/__init__.py
+++ b/src/shibuya/__init__.py
@@ -2,6 +2,7 @@
from pathlib import Path
from sphinx.application import Sphinx
from sphinx.builders.html import StandaloneHTMLBuilder
+from sphinx.builders.dirhtml import DirectoryHTMLBuilder
from .context import (
normalize_pageurl,
normalize_localtoc,
@@ -59,6 +60,16 @@ def _initialize_builder(app: Sphinx):
if isinstance(app.builder, StandaloneHTMLBuilder):
app.builder.highlighter.formatter = WrapLineFormatter
+ if isinstance(app.builder, DirectoryHTMLBuilder):
+ _get_outfilename = app.builder.get_outfilename
+
+ def get_outfilename(pagename: str) -> str:
+ if pagename == '404':
+ return (Path(app.builder.outdir) / '404.html').resolve()
+ return _get_outfilename(pagename)
+
+ app.builder.get_outfilename = get_outfilename
+
def setup(app: Sphinx):
"""Entry point for sphinx theming."""
diff --git a/src/shibuya/theme/shibuya/layout/404.html b/src/shibuya/theme/shibuya/layout/404.html
new file mode 100644
index 0000000..03c9658
--- /dev/null
+++ b/src/shibuya/theme/shibuya/layout/404.html
@@ -0,0 +1,28 @@
+{%- extends "layout.html" -%}
+
+{% block extrahead %}
+
+{% endblock %}
+
+{% block body %}
+
+{% endblock %}