From 09d2fd3a880013686c6f3eaa4aed71a731e946c8 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Sun, 12 Apr 2026 14:58:08 +0200 Subject: [PATCH] ui: add custom centered 404 page --- internal/features/anime/handler.go | 12 ++++++---- internal/templates/not_found.templ | 12 ++++++++++ static/css/style.css | 35 ++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 internal/templates/not_found.templ diff --git a/internal/features/anime/handler.go b/internal/features/anime/handler.go index 8ef34dd..b785ff4 100644 --- a/internal/features/anime/handler.go +++ b/internal/features/anime/handler.go @@ -53,7 +53,8 @@ func NewHandler(svc *Service) *Handler { func (h *Handler) HandleCatalog(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { - http.NotFound(w, r) + w.WriteHeader(http.StatusNotFound) + templates.NotFoundPage().Render(r.Context(), w) return } templates.Catalog().Render(r.Context(), w) @@ -122,7 +123,8 @@ func (h *Handler) HandleAnimeDetails(w http.ResponseWriter, r *http.Request) { idStr := r.URL.Path[len("/anime/"):] id, err := strconv.Atoi(idStr) if err != nil || id <= 0 { - http.NotFound(w, r) + w.WriteHeader(http.StatusNotFound) + templates.NotFoundPage().Render(r.Context(), w) return } @@ -136,7 +138,8 @@ func (h *Handler) HandleAnimeDetails(w http.ResponseWriter, r *http.Request) { } if jikan.IsNotFoundError(err) { - http.NotFound(w, r) + w.WriteHeader(http.StatusNotFound) + templates.NotFoundPage().Render(r.Context(), w) return } @@ -210,7 +213,8 @@ func (h *Handler) HandleAPIAnime(w http.ResponseWriter, r *http.Request) { } templates.AnimeRecommendations(recs).Render(r.Context(), w) default: - http.Error(w, "not found", http.StatusNotFound) + w.WriteHeader(http.StatusNotFound) + templates.NotFoundPage().Render(r.Context(), w) } } diff --git a/internal/templates/not_found.templ b/internal/templates/not_found.templ new file mode 100644 index 0000000..f318b22 --- /dev/null +++ b/internal/templates/not_found.templ @@ -0,0 +1,12 @@ +package templates + +templ NotFoundPage() { + @Layout("mal - not found", false) { +
+

404

+

Page not found

+

The page you requested does not exist, or it was moved.

+

Back to catalog

+
+ } +} diff --git a/static/css/style.css b/static/css/style.css index 486589b..0151dcf 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -466,6 +466,41 @@ main { font-size: 0.9rem; } +.not-found-page { + width: min(780px, calc(100vw - (var(--space-6) * 2))); + min-height: 72vh; + margin: 0 auto; + padding: var(--space-8) var(--space-7); + display: grid; + align-content: center; + justify-items: center; + gap: var(--space-3); + text-align: center; +} + +.not-found-code { + margin: 0; + color: var(--text-muted); + font-size: clamp(4rem, 15vw, 10rem); + letter-spacing: 0.04em; + line-height: 0.9; +} + +.not-found-page h1 { + margin: 0; + font-size: clamp(2rem, 4vw, 3rem); +} + +.not-found-link { + color: var(--accent); + text-decoration: none; + font-size: 1.05rem; +} + +.not-found-link:hover { + text-decoration: underline; +} + .auth-shell { width: min(560px, 100%); }