Skip to content

Commit be01023

Browse files
committed
feat(server/web): error display pages
1 parent 979efce commit be01023

File tree

4 files changed

+123
-1
lines changed

4 files changed

+123
-1
lines changed

internal/server/fetch.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (s *Server) StaticDocument(w http.ResponseWriter, r *http.Request) {
5757
// Validate document ID
5858
if len(id) != s.Config.IDLength && !slices.Contains(s.Config.Documents, id) {
5959
err := fmt.Errorf("id is of length %d, should be %d", len(id), s.Config.IDLength)
60-
util.WriteError(w, http.StatusBadRequest, err)
60+
util.RenderError(&resources, w, http.StatusBadRequest, err)
6161
return
6262
}
6363

internal/server/web/error.html

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
9+
<title>Spacebin</title>
10+
11+
<meta property="og:title" content="Spacebin: Text sharing for the final frontier" />
12+
<meta property="og:url" content="spaceb.in" />
13+
<meta property="og:type" content="website" />
14+
<meta property="og:description"
15+
content="A highly-reliable pastebin server, built in Go, that's capable of serving notes, code, or any other documents." />
16+
<meta name="description"
17+
content="Spacebin is a highly-reliable pastebin server, built with Go, that's capable of serving notes, code, or any other documents." />
18+
<meta property="og:color" content="#e34b4a" />
19+
20+
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
21+
<link rel="stylesheet" type="text/css" href="/static/normalize.css">
22+
<link rel="stylesheet" type="text/css" href="/static/global.css">
23+
</head>
24+
25+
<body>
26+
<header>
27+
<img src="/static/logo.svg" alt="Spacebin Logo" />
28+
29+
<a id="home" href="/" aria-label="Spacebin Home Page">
30+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"
31+
class="main-grid-item-icon" fill="none" stroke="currentColor" stroke-linecap="round"
32+
stroke-linejoin="round" stroke-width="2">
33+
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
34+
<polyline points="9 22 9 12 15 12 15 22" />
35+
</svg>
36+
</a>
37+
38+
39+
<a id="github" href="https://github.com/orca-group/spirit" aria-label="Spacebin Github">
40+
<svg fill="none" height="24" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
41+
stroke-width="2" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
42+
<path
43+
d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" />
44+
</svg>
45+
</a>
46+
47+
<a id="wiki" href="https://github.com/orca-group/spirit/blob/main/README.md/#-spirit"
48+
aria-label="Spacebin Documentation">
49+
<svg fill="none" height="24" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
50+
stroke-width="2" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
51+
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" />
52+
<path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" />
53+
</svg>
54+
</a>
55+
56+
<p id="donate" aria-label="Spacebin Donation Page">
57+
Keep Spacebin free of ads by <a href="https://github.com/sponsors/lukewhrit">donating</a>. ❤️
58+
</p>
59+
</header>
60+
61+
<main>
62+
<h1 id="error">
63+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="28" height="28" id="warning" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
64+
<circle cx="12" cy="12" r="10" />
65+
<line x1="12" x2="12" y1="8" y2="12" />
66+
<line x1="12" x2="12.01" y1="16" y2="16" />
67+
</svg>
68+
{{.Status}}
69+
</h1>
70+
<p>{{.Error}}</p>
71+
</main>
72+
73+
<script src="/static/app.js"></script>
74+
</body>
75+
76+
</html>

internal/server/web/static/global.css

+22
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ textarea {
4444
display: inline;
4545
}
4646

47+
textarea:hover, textarea:focus {
48+
outline: none;
49+
border: none;
50+
}
51+
4752
header {
4853
padding: 3px 9px;
4954
margin: 0;
@@ -100,3 +105,20 @@ img {
100105
max-width: 24px;
101106
height: auto;
102107
}
108+
109+
h1 {
110+
font-size: 1.25rem; /* 20px */
111+
line-height: 1.75rem; /* 28px */
112+
margin-bottom: 5px;
113+
padding: 0;
114+
}
115+
116+
#error {
117+
display: inline-flex;
118+
align-items: center;
119+
gap: 10px;
120+
}
121+
122+
#warning {
123+
color: #F97583;
124+
}

internal/util/helpers.go

+24
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package util
1818

1919
import (
20+
"embed"
2021
"encoding/json"
2122
"fmt"
2223
"html/template"
@@ -105,3 +106,26 @@ func WriteError(w http.ResponseWriter, status int, e error) error {
105106

106107
return nil
107108
}
109+
110+
// RenderError renders errors to the client using an HTML template.
111+
func RenderError(r *embed.FS, w http.ResponseWriter, status int, err error) error {
112+
tmpl := template.Must(template.ParseFS(r, "web/error.html"))
113+
114+
w.Header().Set("Content-Type", "text/html")
115+
w.WriteHeader(status)
116+
117+
data := struct {
118+
Status string
119+
Error string
120+
}{
121+
Status: strings.Join([]string{fmt.Sprintf("%d", status), http.StatusText(status)}, " "),
122+
Error: err.Error(),
123+
}
124+
125+
err = tmpl.Execute(w, data)
126+
if err != nil {
127+
return err
128+
}
129+
130+
return nil
131+
}

0 commit comments

Comments
 (0)