A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go
80
fork

Configure Feed

Select the types of activity you want to include in your feed.

add 404 page

+122 -4
+32
pkg/appview/handlers/errors.go
··· 1 + package handlers 2 + 3 + import ( 4 + "html/template" 5 + "net/http" 6 + ) 7 + 8 + // NotFoundHandler handles 404 errors 9 + type NotFoundHandler struct { 10 + Templates *template.Template 11 + RegistryURL string 12 + } 13 + 14 + func (h *NotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 15 + RenderNotFound(w, r, h.Templates, h.RegistryURL) 16 + } 17 + 18 + // RenderNotFound renders the 404 page template. 19 + // Use this from other handlers when a resource is not found. 20 + func RenderNotFound(w http.ResponseWriter, r *http.Request, templates *template.Template, registryURL string) { 21 + w.WriteHeader(http.StatusNotFound) 22 + 23 + data := struct { 24 + PageData 25 + }{ 26 + PageData: NewPageData(r, registryURL), 27 + } 28 + 29 + if err := templates.ExecuteTemplate(w, "404", data); err != nil { 30 + http.Error(w, "Page not found", http.StatusNotFound) 31 + } 32 + }
+3 -3
pkg/appview/handlers/repository.go
··· 37 37 // Resolve identifier (handle or DID) to canonical DID and current handle 38 38 did, resolvedHandle, _, err := atproto.ResolveIdentity(r.Context(), identifier) 39 39 if err != nil { 40 - http.Error(w, "User not found", http.StatusNotFound) 40 + RenderNotFound(w, r, h.Templates, h.RegistryURL) 41 41 return 42 42 } 43 43 ··· 48 48 return 49 49 } 50 50 if owner == nil { 51 - http.Error(w, "User not found", http.StatusNotFound) 51 + RenderNotFound(w, r, h.Templates, h.RegistryURL) 52 52 return 53 53 } 54 54 ··· 136 136 } 137 137 138 138 if len(tagsWithPlatforms) == 0 && len(manifests) == 0 { 139 - http.Error(w, "Repository not found", http.StatusNotFound) 139 + RenderNotFound(w, r, h.Templates, h.RegistryURL) 140 140 return 141 141 } 142 142
+1 -1
pkg/appview/handlers/user.go
··· 23 23 // Resolve identifier (handle or DID) to canonical DID and current handle 24 24 did, resolvedHandle, pdsEndpoint, err := atproto.ResolveIdentity(r.Context(), identifier) 25 25 if err != nil { 26 - http.Error(w, "User not found", http.StatusNotFound) 26 + RenderNotFound(w, r, h.Templates, h.RegistryURL) 27 27 return 28 28 } 29 29
+8
pkg/appview/routes/routes.go
··· 224 224 } 225 225 router.Get("/auth/logout", logoutHandler.ServeHTTP) 226 226 router.Post("/auth/logout", logoutHandler.ServeHTTP) 227 + 228 + // Custom 404 handler 229 + router.NotFound(middleware.OptionalAuth(deps.SessionStore, deps.Database)( 230 + &uihandlers.NotFoundHandler{ 231 + Templates: deps.Templates, 232 + RegistryURL: registryURL, 233 + }, 234 + ).ServeHTTP) 227 235 } 228 236 229 237 // CORSMiddleware returns a middleware that sets CORS headers for API endpoints
+56
pkg/appview/static/css/style.css
··· 2373 2373 padding: 0.75rem; 2374 2374 } 2375 2375 } 2376 + 2377 + /* 404 Error Page */ 2378 + .error-page { 2379 + display: flex; 2380 + align-items: center; 2381 + justify-content: center; 2382 + min-height: calc(100vh - 60px); 2383 + text-align: center; 2384 + padding: 2rem; 2385 + } 2386 + 2387 + .error-content { 2388 + max-width: 480px; 2389 + } 2390 + 2391 + .error-icon { 2392 + width: 80px; 2393 + height: 80px; 2394 + color: var(--secondary); 2395 + margin-bottom: 1.5rem; 2396 + } 2397 + 2398 + .error-code { 2399 + font-size: 8rem; 2400 + font-weight: 700; 2401 + color: var(--primary); 2402 + line-height: 1; 2403 + margin-bottom: 0.5rem; 2404 + } 2405 + 2406 + .error-content h1 { 2407 + font-size: 2rem; 2408 + margin-bottom: 0.75rem; 2409 + color: var(--fg); 2410 + } 2411 + 2412 + .error-content p { 2413 + font-size: 1.125rem; 2414 + color: var(--secondary); 2415 + margin-bottom: 2rem; 2416 + } 2417 + 2418 + @media (max-width: 768px) { 2419 + .error-code { 2420 + font-size: 5rem; 2421 + } 2422 + 2423 + .error-icon { 2424 + width: 60px; 2425 + height: 60px; 2426 + } 2427 + 2428 + .error-content h1 { 2429 + font-size: 1.5rem; 2430 + } 2431 + }
+22
pkg/appview/templates/pages/404.html
··· 1 + {{ define "404" }} 2 + <!DOCTYPE html> 3 + <html lang="en"> 4 + <head> 5 + <title>404 - Lost at Sea | ATCR</title> 6 + {{ template "head" . }} 7 + </head> 8 + <body> 9 + {{ template "nav-simple" . }} 10 + <main class="error-page"> 11 + <div class="error-content"> 12 + <i data-lucide="anchor" class="error-icon"></i> 13 + <div class="error-code">404</div> 14 + <h1>Lost at Sea</h1> 15 + <p>The page you're looking for has drifted into uncharted waters.</p> 16 + <a href="/" class="btn btn-primary">Return to Port</a> 17 + </div> 18 + </main> 19 + <script>lucide.createIcons();</script> 20 + </body> 21 + </html> 22 + {{ end }}