Skip to content

Commit 023ae0b

Browse files
authored
feat: custom 404 not found page for invalid routes (#140)
1 parent 22f3d2c commit 023ae0b

File tree

3 files changed

+236
-12
lines changed

3 files changed

+236
-12
lines changed

lib/algora_web/controllers/error_html.ex

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
11
defmodule AlgoraWeb.ErrorHTML do
22
use AlgoraWeb, :html
33

4-
# If you want to customize your error pages,
5-
# uncomment the embed_templates/1 call below
6-
# and add pages to the error directory:
7-
#
8-
# * lib/algora_web/controllers/error_html/404.html.heex
9-
# * lib/algora_web/controllers/error_html/500.html.heex
10-
#
11-
# embed_templates "error_html/*"
4+
embed_templates "error_html/*"
125

13-
# The default is to render a plain text page based on
14-
# the template name. For example, "404.html" becomes
15-
# "Not Found".
166
def render(template, _assigns) do
177
Phoenix.Controller.status_message_from_template(template)
188
end
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>404 - Page Not Found</title>
7+
<style>
8+
* {
9+
margin: 0;
10+
padding: 0;
11+
box-sizing: border-box;
12+
}
13+
14+
body {
15+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
16+
background: #000;
17+
color: #fff;
18+
min-height: 100vh;
19+
display: flex;
20+
align-items: center;
21+
justify-content: center;
22+
padding: 1rem;
23+
overflow: hidden;
24+
}
25+
26+
.container {
27+
text-align: center;
28+
max-width: 500px;
29+
position: relative;
30+
z-index: 2;
31+
}
32+
33+
.error-code {
34+
font-size: clamp(4rem, 12vw, 8rem);
35+
font-weight: 800;
36+
line-height: 0.9;
37+
margin-bottom: 1.5rem;
38+
background: linear-gradient(135deg, #fff 0%, #a0a0a0 100%);
39+
-webkit-background-clip: text;
40+
-webkit-text-fill-color: transparent;
41+
background-clip: text;
42+
letter-spacing: -0.05em;
43+
position: relative;
44+
}
45+
46+
.error-code::before {
47+
content: '404';
48+
position: absolute;
49+
top: 0;
50+
left: 0;
51+
right: 0;
52+
background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%);
53+
-webkit-background-clip: text;
54+
-webkit-text-fill-color: transparent;
55+
background-clip: text;
56+
filter: blur(2px);
57+
z-index: -1;
58+
}
59+
60+
.title {
61+
font-size: 1.5rem;
62+
font-weight: 600;
63+
margin-bottom: 0.75rem;
64+
color: #fff;
65+
letter-spacing: -0.025em;
66+
}
67+
68+
.description {
69+
font-size: 1rem;
70+
color: #888;
71+
margin-bottom: 2.5rem;
72+
line-height: 1.5;
73+
margin-left: auto;
74+
margin-right: auto;
75+
}
76+
77+
.home-button {
78+
display: inline-flex;
79+
align-items: center;
80+
gap: 0.5rem;
81+
padding: 0.75rem 1.5rem;
82+
background: #fff;
83+
color: #000;
84+
text-decoration: none;
85+
border-radius: 0.5rem;
86+
font-weight: 600;
87+
font-size: 0.875rem;
88+
transition: all 0.2s ease;
89+
border: 2px solid transparent;
90+
position: relative;
91+
overflow: hidden;
92+
}
93+
94+
.home-button::before {
95+
content: '';
96+
position: absolute;
97+
top: 0;
98+
left: -100%;
99+
width: 100%;
100+
height: 100%;
101+
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
102+
transition: left 0.6s ease;
103+
}
104+
105+
.home-button:hover {
106+
background: #f5f5f5;
107+
transform: translateY(-1px);
108+
box-shadow: 0 4px 12px rgba(255,255,255,0.1);
109+
}
110+
111+
.home-button:hover::before {
112+
left: 100%;
113+
}
114+
115+
.home-button:active {
116+
transform: translateY(0);
117+
}
118+
119+
.floating-elements {
120+
position: absolute;
121+
top: 0;
122+
left: 0;
123+
width: 100%;
124+
height: 100%;
125+
pointer-events: none;
126+
z-index: 1;
127+
}
128+
129+
.floating-dot {
130+
position: absolute;
131+
width: 4px;
132+
height: 4px;
133+
background: rgba(255,255,255,0.1);
134+
border-radius: 50%;
135+
animation: float 6s ease-in-out infinite;
136+
}
137+
138+
.floating-dot:nth-child(1) {
139+
top: 20%;
140+
left: 10%;
141+
animation-delay: 0s;
142+
}
143+
144+
.floating-dot:nth-child(2) {
145+
top: 60%;
146+
right: 15%;
147+
animation-delay: 1s;
148+
}
149+
150+
.floating-dot:nth-child(3) {
151+
bottom: 30%;
152+
left: 20%;
153+
animation-delay: 2s;
154+
}
155+
156+
.floating-dot:nth-child(4) {
157+
top: 40%;
158+
right: 30%;
159+
animation-delay: 3s;
160+
}
161+
162+
@keyframes float {
163+
0%, 100% {
164+
transform: translateY(0px) scale(1);
165+
opacity: 0;
166+
}
167+
50% {
168+
transform: translateY(-20px) scale(1.2);
169+
opacity: 1;
170+
}
171+
}
172+
173+
.glow {
174+
position: absolute;
175+
top: 50%;
176+
left: 50%;
177+
transform: translate(-50%, -50%);
178+
width: 300px;
179+
height: 300px;
180+
background: radial-gradient(circle, rgba(255,255,255,0.03) 0%, transparent 70%);
181+
border-radius: 50%;
182+
z-index: 1;
183+
}
184+
185+
@media (max-width: 640px) {
186+
.container {
187+
max-width: 90%;
188+
}
189+
190+
.title {
191+
font-size: 1.25rem;
192+
}
193+
194+
.description {
195+
font-size: 0.875rem;
196+
margin-bottom: 2rem;
197+
}
198+
}
199+
</style>
200+
</head>
201+
<body>
202+
<div class="floating-elements">
203+
<div class="floating-dot"></div>
204+
<div class="floating-dot"></div>
205+
<div class="floating-dot"></div>
206+
<div class="floating-dot"></div>
207+
<div class="glow"></div>
208+
</div>
209+
210+
<div class="container">
211+
<div class="error-code">404</div>
212+
<h1 class="title">This page could not be found</h1>
213+
<p class="description">
214+
Sorry, the page you're looking for doesn't exist or has been moved.
215+
</p>
216+
<.link navigate="/" class="home-button">
217+
<svg
218+
xmlns="http://www.w3.org/2000/svg"
219+
width="16"
220+
height="16"
221+
viewBox="0 0 24 24"
222+
fill="none"
223+
stroke="currentColor"
224+
stroke-width="2"
225+
stroke-linecap="round"
226+
stroke-linejoin="round"
227+
>
228+
<path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M5 12l14 0" /><path d="M5 12l6 6" /><path d="M5 12l6 -6" />
229+
</svg>
230+
Go back home
231+
</.link>
232+
</div>
233+
</body>
234+
</html>

test/algora_web/controllers/error_html_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ defmodule AlgoraWeb.ErrorHTMLTest do
55
import Phoenix.Template
66

77
test "renders 404.html" do
8-
assert render_to_string(AlgoraWeb.ErrorHTML, "404", "html", []) == "Not Found"
8+
assert render_to_string(AlgoraWeb.ErrorHTML, "404", "html", []) =~ "could not be found"
99
end
1010

1111
test "renders 500.html" do

0 commit comments

Comments
 (0)