add 404 page

This commit is contained in:
Evan Jarrett
2025-12-22 12:43:18 -06:00
parent d11356cd18
commit 8d0cff63fb
6 changed files with 122 additions and 4 deletions
+32
View File
@@ -0,0 +1,32 @@
package handlers
import (
"html/template"
"net/http"
)
// NotFoundHandler handles 404 errors
type NotFoundHandler struct {
Templates *template.Template
RegistryURL string
}
func (h *NotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
RenderNotFound(w, r, h.Templates, h.RegistryURL)
}
// RenderNotFound renders the 404 page template.
// Use this from other handlers when a resource is not found.
func RenderNotFound(w http.ResponseWriter, r *http.Request, templates *template.Template, registryURL string) {
w.WriteHeader(http.StatusNotFound)
data := struct {
PageData
}{
PageData: NewPageData(r, registryURL),
}
if err := templates.ExecuteTemplate(w, "404", data); err != nil {
http.Error(w, "Page not found", http.StatusNotFound)
}
}
+3 -3
View File
@@ -37,7 +37,7 @@ func (h *RepositoryPageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
// Resolve identifier (handle or DID) to canonical DID and current handle
did, resolvedHandle, _, err := atproto.ResolveIdentity(r.Context(), identifier)
if err != nil {
http.Error(w, "User not found", http.StatusNotFound)
RenderNotFound(w, r, h.Templates, h.RegistryURL)
return
}
@@ -48,7 +48,7 @@ func (h *RepositoryPageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
return
}
if owner == nil {
http.Error(w, "User not found", http.StatusNotFound)
RenderNotFound(w, r, h.Templates, h.RegistryURL)
return
}
@@ -136,7 +136,7 @@ func (h *RepositoryPageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
}
if len(tagsWithPlatforms) == 0 && len(manifests) == 0 {
http.Error(w, "Repository not found", http.StatusNotFound)
RenderNotFound(w, r, h.Templates, h.RegistryURL)
return
}
+1 -1
View File
@@ -23,7 +23,7 @@ func (h *UserPageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Resolve identifier (handle or DID) to canonical DID and current handle
did, resolvedHandle, pdsEndpoint, err := atproto.ResolveIdentity(r.Context(), identifier)
if err != nil {
http.Error(w, "User not found", http.StatusNotFound)
RenderNotFound(w, r, h.Templates, h.RegistryURL)
return
}
+8
View File
@@ -224,6 +224,14 @@ func RegisterUIRoutes(router chi.Router, deps UIDependencies) {
}
router.Get("/auth/logout", logoutHandler.ServeHTTP)
router.Post("/auth/logout", logoutHandler.ServeHTTP)
// Custom 404 handler
router.NotFound(middleware.OptionalAuth(deps.SessionStore, deps.Database)(
&uihandlers.NotFoundHandler{
Templates: deps.Templates,
RegistryURL: registryURL,
},
).ServeHTTP)
}
// CORSMiddleware returns a middleware that sets CORS headers for API endpoints
+56
View File
@@ -2373,3 +2373,59 @@ a.license-badge:hover {
padding: 0.75rem;
}
}
/* 404 Error Page */
.error-page {
display: flex;
align-items: center;
justify-content: center;
min-height: calc(100vh - 60px);
text-align: center;
padding: 2rem;
}
.error-content {
max-width: 480px;
}
.error-icon {
width: 80px;
height: 80px;
color: var(--secondary);
margin-bottom: 1.5rem;
}
.error-code {
font-size: 8rem;
font-weight: 700;
color: var(--primary);
line-height: 1;
margin-bottom: 0.5rem;
}
.error-content h1 {
font-size: 2rem;
margin-bottom: 0.75rem;
color: var(--fg);
}
.error-content p {
font-size: 1.125rem;
color: var(--secondary);
margin-bottom: 2rem;
}
@media (max-width: 768px) {
.error-code {
font-size: 5rem;
}
.error-icon {
width: 60px;
height: 60px;
}
.error-content h1 {
font-size: 1.5rem;
}
}
+22
View File
@@ -0,0 +1,22 @@
{{ define "404" }}
<!DOCTYPE html>
<html lang="en">
<head>
<title>404 - Lost at Sea | ATCR</title>
{{ template "head" . }}
</head>
<body>
{{ template "nav-simple" . }}
<main class="error-page">
<div class="error-content">
<i data-lucide="anchor" class="error-icon"></i>
<div class="error-code">404</div>
<h1>Lost at Sea</h1>
<p>The page you're looking for has drifted into uncharted waters.</p>
<a href="/" class="btn btn-primary">Return to Port</a>
</div>
</main>
<script>lucide.createIcons();</script>
</body>
</html>
{{ end }}