Skip to content

Commit 7a5b9cd

Browse files
committed
feat: custom error pages and --config arg
1 parent 133bc82 commit 7a5b9cd

File tree

12 files changed

+530
-26
lines changed

12 files changed

+530
-26
lines changed

internal/assets/custom_pages.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package assets
2+
3+
import (
4+
"embed"
5+
"html/template"
6+
"net/http"
7+
)
8+
9+
//go:embed templates/*
10+
var templatesFS embed.FS
11+
12+
var (
13+
ErrorTemplate *template.Template
14+
WelcomeTemplate *template.Template
15+
GlobalStyles template.HTML
16+
)
17+
18+
func init() {
19+
var err error
20+
21+
// Read embedded CSS
22+
cssContent, err := templatesFS.ReadFile("templates/style.css")
23+
if err != nil {
24+
panic(err)
25+
}
26+
// Wrap in style tags to avoid formatter issues in HTML templates
27+
GlobalStyles = template.HTML("<style>" + string(cssContent) + "</style>")
28+
29+
ErrorTemplate, err = template.ParseFS(templatesFS, "templates/error.html")
30+
if err != nil {
31+
panic(err)
32+
}
33+
WelcomeTemplate, err = template.ParseFS(templatesFS, "templates/welcome.html")
34+
if err != nil {
35+
panic(err)
36+
}
37+
}
38+
39+
// ErrorPageData holds data for the error page template
40+
type ErrorPageData struct {
41+
Code int
42+
Title string
43+
Description string
44+
FooterLink string
45+
Styles template.HTML
46+
}
47+
48+
// RenderErrorPage renders the error page to the response writer
49+
func RenderErrorPage(w http.ResponseWriter, code int, title, description string) {
50+
w.WriteHeader(code)
51+
w.Header().Set("Content-Type", "text/html")
52+
53+
data := ErrorPageData{
54+
Code: code,
55+
Title: title,
56+
Description: description,
57+
FooterLink: "https://github.com/tryGoUp",
58+
Styles: GlobalStyles,
59+
}
60+
61+
if err := ErrorTemplate.Execute(w, data); err != nil {
62+
// Fallback if template fails
63+
http.Error(w, description, code)
64+
}
65+
}
66+
67+
// RenderWelcomePage renders the welcome page
68+
func RenderWelcomePage(w http.ResponseWriter) {
69+
w.WriteHeader(http.StatusOK)
70+
w.Header().Set("Content-Type", "text/html")
71+
72+
data := struct {
73+
FooterLink string
74+
Styles template.HTML
75+
}{
76+
FooterLink: "https://github.com/tryGoUp",
77+
Styles: GlobalStyles,
78+
}
79+
80+
if err := WelcomeTemplate.Execute(w, data); err != nil {
81+
http.Error(w, "Welcome to GoUp!", http.StatusOK)
82+
}
83+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>GoUp - {{ .Title }}</title>
8+
{{ .Styles }}
9+
</head>
10+
11+
<body>
12+
<div class="main-container">
13+
<div class="logo-wrapper">
14+
<svg class="logo-svg" width="156" height="151" viewBox="0 0 156 151" fill="none"
15+
xmlns="http://www.w3.org/2000/svg">
16+
<path d="M124.463 14L127.714 102.007H151.286L154.537 14H124.463Z" fill="#F6F8EA" />
17+
<path
18+
d="M151.448 144.223C148.305 147.408 144.296 149 139.419 149C134.65 149 130.749 147.408 127.714 144.223C124.571 140.916 123 136.874 123 132.097C123 127.197 124.571 123.094 127.714 119.787C130.749 116.48 134.65 114.826 139.419 114.826C144.296 114.826 148.305 116.48 151.448 119.787C154.483 123.094 156 127.197 156 132.097C156 136.874 154.483 140.916 151.448 144.223Z"
19+
fill="#2ABFC4" />
20+
<path
21+
d="M91.3172 63C86.3218 63 81.8138 61.9431 77.7931 59.8293C73.8333 57.7155 70.696 54.6957 68.381 50.77C66.127 46.8444 65 42.2544 65 37C65 31.806 66.1575 27.2462 68.4724 23.3206C70.7874 19.3345 73.9552 16.2846 77.9759 14.1707C81.9966 12.0569 86.5046 11 91.5 11C96.4954 11 101.003 12.0569 105.024 14.1707C109.045 16.2846 112.213 19.3345 114.528 23.3206C116.843 27.2462 118 31.806 118 37C118 42.194 116.812 46.784 114.436 50.77C112.121 54.6957 108.923 57.7155 104.841 59.8293C100.821 61.9431 96.3126 63 91.3172 63ZM91.3172 49.5923C94.3023 49.5923 96.8305 48.5052 98.9017 46.331C101.034 44.1568 102.1 41.0465 102.1 37C102.1 32.9535 101.064 29.8432 98.9931 27.669C96.9828 25.4948 94.4851 24.4077 91.5 24.4077C88.454 24.4077 85.9259 25.4948 83.9155 27.669C81.9052 29.7828 80.9 32.8932 80.9 37C80.9 41.0465 81.8747 44.1568 83.8241 46.331C85.8345 48.5052 88.3322 49.5923 91.3172 49.5923Z"
22+
fill="#2ABFC4" />
23+
<path
24+
d="M43.3836 20.2657C42.2735 18.2098 40.6667 16.6531 38.5632 15.5958C36.5182 14.4797 34.0934 13.9217 31.2888 13.9217C26.4392 13.9217 22.5536 15.5371 19.6322 18.7678C16.7107 21.9399 15.25 26.1986 15.25 31.5441C15.25 37.242 16.7692 41.7063 19.8075 44.9371C22.9042 48.1091 27.1403 49.6951 32.5158 49.6951C36.1968 49.6951 39.2936 48.7552 41.806 46.8755C44.3769 44.9958 46.2466 42.2937 47.4152 38.7692H28.3966V27.6671H61V41.6769C59.8898 45.4364 57.9909 48.9315 55.3032 52.1622C52.6738 55.393 49.3142 58.007 45.2241 60.0042C41.1341 62.0014 36.5182 63 31.3764 63C25.2998 63 19.8659 61.6783 15.0747 59.035C10.342 56.3329 6.6317 52.6028 3.94397 47.8448C1.31466 43.0867 0 37.6531 0 31.5441C0 25.435 1.31466 20.0014 3.94397 15.2434C6.6317 10.4266 10.342 6.6965 15.0747 4.05315C19.8075 1.35105 25.2122 0 31.2888 0C38.6509 0 44.8443 1.79161 49.8693 5.37482C54.9526 8.95804 58.3123 13.9217 59.9483 20.2657H43.3836Z"
25+
fill="#2ABFC4" />
26+
<path
27+
d="M58 71V125.415H41.0845V118.004C39.3699 120.409 37.0288 122.359 34.0612 123.855C31.1595 125.285 27.9281 126 24.3669 126C20.1463 126 16.4203 125.09 13.1888 123.27C9.95743 121.384 7.45144 118.686 5.67086 115.176C3.89029 111.665 3 107.537 3 102.791V71H19.8165V100.548C19.8165 104.189 20.7728 107.017 22.6853 109.032C24.5977 111.047 27.1697 112.055 30.4011 112.055C33.6984 112.055 36.3034 111.047 38.2158 109.032C40.1283 107.017 41.0845 104.189 41.0845 100.548V71H58Z"
28+
fill="#F6F8EA" />
29+
<path
30+
d="M76.8387 78.47C78.4799 75.9387 80.7448 73.8942 83.6333 72.3365C86.5218 70.7788 89.9027 70 93.7759 70C98.3056 70 102.409 71.1358 106.085 73.4075C109.761 75.6791 112.65 78.9243 114.75 83.143C116.917 87.3618 118 92.262 118 97.8438C118 103.425 116.917 108.358 114.75 112.642C112.65 116.861 109.761 120.138 106.085 122.475C102.409 124.746 98.3056 125.882 93.7759 125.882C89.9683 125.882 86.5874 125.103 83.6333 123.546C80.7448 121.988 78.4799 119.976 76.8387 117.51V151H60V70.7788H76.8387V78.47ZM100.866 97.8438C100.866 93.6899 99.6842 90.4447 97.3209 88.1082C95.0232 85.7067 92.1675 84.506 88.7538 84.506C85.4058 84.506 82.5501 85.7067 80.1868 88.1082C77.8891 90.5096 76.7402 93.7873 76.7402 97.9411C76.7402 102.095 77.8891 105.373 80.1868 107.774C82.5501 110.175 85.4058 111.376 88.7538 111.376C92.1019 111.376 94.9576 110.175 97.3209 107.774C99.6842 105.308 100.866 101.998 100.866 97.8438Z"
31+
fill="#F6F8EA" />
32+
</svg>
33+
</div>
34+
<div class="status-code">{{ .Code }}</div>
35+
<h2 class="title">{{ .Title }}</h2>
36+
<p class="description">{{ .Description }}</p>
37+
38+
<a href="/" class="btn-home">Back to Home</a>
39+
40+
<br>
41+
<a href="{{ .FooterLink }}" target="_blank" class="footer-link">GoUp Project on GitHub</a>
42+
</div>
43+
</body>
44+
45+
</html>
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
2+
3+
:root {
4+
--color-bg: #1D1719;
5+
--color-accent: #2ABFC4;
6+
--color-text: #F6F8EA;
7+
--color-text-muted: rgba(246, 248, 234, 0.6);
8+
9+
--font-primary: 'Poppins', sans-serif;
10+
11+
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
12+
}
13+
14+
* {
15+
box-sizing: border-box;
16+
margin: 0;
17+
padding: 0;
18+
}
19+
20+
body {
21+
background-color: var(--color-bg);
22+
color: var(--color-text);
23+
font-family: var(--font-primary);
24+
min-height: 100vh;
25+
display: flex;
26+
flex-direction: column;
27+
align-items: center;
28+
justify-content: center;
29+
overflow: hidden;
30+
position: relative;
31+
-webkit-font-smoothing: antialiased;
32+
-moz-osx-font-smoothing: grayscale;
33+
}
34+
35+
/* Background Ambient Glow */
36+
body::before {
37+
content: '';
38+
position: absolute;
39+
width: 60vw;
40+
height: 60vw;
41+
background: radial-gradient(circle, rgba(42, 191, 196, 0.08) 0%, transparent 70%);
42+
top: -20%;
43+
left: 50%;
44+
transform: translateX(-50%);
45+
z-index: -1;
46+
pointer-events: none;
47+
}
48+
49+
.main-container {
50+
text-align: center;
51+
z-index: 10;
52+
padding: 2rem;
53+
max-width: 600px;
54+
width: 100%;
55+
animation: fadeUp 1s var(--ease-out-expo) forwards;
56+
opacity: 0;
57+
transform: translateY(20px);
58+
}
59+
60+
.logo-wrapper {
61+
margin-bottom: 2.5rem;
62+
display: inline-block;
63+
transition: transform 0.3s var(--ease-out-expo);
64+
}
65+
66+
.logo-wrapper:hover {
67+
transform: scale(1.05);
68+
}
69+
70+
.logo-svg {
71+
width: 80px;
72+
height: auto;
73+
}
74+
75+
/* Error Code Styling */
76+
.status-code {
77+
font-size: 8rem;
78+
font-weight: 700;
79+
line-height: 1;
80+
margin-bottom: 0.5rem;
81+
color: var(--color-accent);
82+
letter-spacing: -0.04em;
83+
background: linear-gradient(135deg, var(--color-accent) 0%, rgba(42, 191, 196, 0.6) 100%);
84+
-webkit-background-clip: text;
85+
-webkit-text-fill-color: transparent;
86+
opacity: 0.9;
87+
}
88+
89+
.title {
90+
font-size: 2rem;
91+
font-weight: 600;
92+
margin-bottom: 1rem;
93+
color: var(--color-text);
94+
}
95+
96+
.description {
97+
font-size: 1.125rem;
98+
line-height: 1.6;
99+
color: var(--color-text-muted);
100+
font-weight: 300;
101+
margin-bottom: 3rem;
102+
max-width: 480px;
103+
margin-left: auto;
104+
margin-right: auto;
105+
}
106+
107+
/* Primary Action Button */
108+
.btn-home {
109+
display: inline-flex;
110+
align-items: center;
111+
justify-content: center;
112+
padding: 0.75rem 2rem;
113+
font-size: 1rem;
114+
font-weight: 600;
115+
color: var(--color-bg);
116+
background-color: var(--color-accent);
117+
border: none;
118+
border-radius: 50px;
119+
text-decoration: none;
120+
transition: all 0.2s ease;
121+
box-shadow: 0 4px 20px rgba(42, 191, 196, 0.25);
122+
}
123+
124+
.btn-home:hover {
125+
background-color: #fff;
126+
color: var(--color-bg);
127+
transform: translateY(-2px);
128+
box-shadow: 0 8px 30px rgba(42, 191, 196, 0.4);
129+
}
130+
131+
.btn-home:active {
132+
transform: translateY(0);
133+
}
134+
135+
/* Footer styling */
136+
.footer-link {
137+
margin-top: 4rem;
138+
font-size: 0.875rem;
139+
color: var(--color-text-muted);
140+
text-decoration: none;
141+
transition: color 0.2s ease;
142+
display: inline-block;
143+
opacity: 0.6;
144+
}
145+
146+
.footer-link:hover {
147+
color: var(--color-accent);
148+
opacity: 1;
149+
}
150+
151+
/* Animations */
152+
@keyframes fadeUp {
153+
to {
154+
opacity: 1;
155+
transform: translateY(0);
156+
}
157+
}
158+
159+
/* Responsive adjustments */
160+
@media (max-width: 768px) {
161+
.status-code {
162+
font-size: 6rem;
163+
}
164+
165+
.title {
166+
font-size: 1.75rem;
167+
}
168+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>Welcome to GoUp</title>
8+
{{ .Styles }}
9+
</head>
10+
11+
<body>
12+
<div class="main-container">
13+
<div class="logo-wrapper">
14+
<svg class="logo-svg" width="156" height="151" viewBox="0 0 156 151" fill="none"
15+
xmlns="http://www.w3.org/2000/svg">
16+
<path d="M124.463 14L127.714 102.007H151.286L154.537 14H124.463Z" fill="#F6F8EA" />
17+
<path
18+
d="M151.448 144.223C148.305 147.408 144.296 149 139.419 149C134.65 149 130.749 147.408 127.714 144.223C124.571 140.916 123 136.874 123 132.097C123 127.197 124.571 123.094 127.714 119.787C130.749 116.48 134.65 114.826 139.419 114.826C144.296 114.826 148.305 116.48 151.448 119.787C154.483 123.094 156 127.197 156 132.097C156 136.874 154.483 140.916 151.448 144.223Z"
19+
fill="#2ABFC4" />
20+
<path
21+
d="M91.3172 63C86.3218 63 81.8138 61.9431 77.7931 59.8293C73.8333 57.7155 70.696 54.6957 68.381 50.77C66.127 46.8444 65 42.2544 65 37C65 31.806 66.1575 27.2462 68.4724 23.3206C70.7874 19.3345 73.9552 16.2846 77.9759 14.1707C81.9966 12.0569 86.5046 11 91.5 11C96.4954 11 101.003 12.0569 105.024 14.1707C109.045 16.2846 112.213 19.3345 114.528 23.3206C116.843 27.2462 118 31.806 118 37C118 42.194 116.812 46.784 114.436 50.77C112.121 54.6957 108.923 57.7155 104.841 59.8293C100.821 61.9431 96.3126 63 91.3172 63ZM91.3172 49.5923C94.3023 49.5923 96.8305 48.5052 98.9017 46.331C101.034 44.1568 102.1 41.0465 102.1 37C102.1 32.9535 101.064 29.8432 98.9931 27.669C96.9828 25.4948 94.4851 24.4077 91.5 24.4077C88.454 24.4077 85.9259 25.4948 83.9155 27.669C81.9052 29.7828 80.9 32.8932 80.9 37C80.9 41.0465 81.8747 44.1568 83.8241 46.331C85.8345 48.5052 88.3322 49.5923 91.3172 49.5923Z"
22+
fill="#2ABFC4" />
23+
<path
24+
d="M43.3836 20.2657C42.2735 18.2098 40.6667 16.6531 38.5632 15.5958C36.5182 14.4797 34.0934 13.9217 31.2888 13.9217C26.4392 13.9217 22.5536 15.5371 19.6322 18.7678C16.7107 21.9399 15.25 26.1986 15.25 31.5441C15.25 37.242 16.7692 41.7063 19.8075 44.9371C22.9042 48.1091 27.1403 49.6951 32.5158 49.6951C36.1968 49.6951 39.2936 48.7552 41.806 46.8755C44.3769 44.9958 46.2466 42.2937 47.4152 38.7692H28.3966V27.6671H61V41.6769C59.8898 45.4364 57.9909 48.9315 55.3032 52.1622C52.6738 55.393 49.3142 58.007 45.2241 60.0042C41.1341 62.0014 36.5182 63 31.3764 63C25.2998 63 19.8659 61.6783 15.0747 59.035C10.342 56.3329 6.6317 52.6028 3.94397 47.8448C1.31466 43.0867 0 37.6531 0 31.5441C0 25.435 1.31466 20.0014 3.94397 15.2434C6.6317 10.4266 10.342 6.6965 15.0747 4.05315C19.8075 1.35105 25.2122 0 31.2888 0C38.6509 0 44.8443 1.79161 49.8693 5.37482C54.9526 8.95804 58.3123 13.9217 59.9483 20.2657H43.3836Z"
25+
fill="#2ABFC4" />
26+
<path
27+
d="M58 71V125.415H41.0845V118.004C39.3699 120.409 37.0288 122.359 34.0612 123.855C31.1595 125.285 27.9281 126 24.3669 126C20.1463 126 16.4203 125.09 13.1888 123.27C9.95743 121.384 7.45144 118.686 5.67086 115.176C3.89029 111.665 3 107.537 3 102.791V71H19.8165V100.548C19.8165 104.189 20.7728 107.017 22.6853 109.032C24.5977 111.047 27.1697 112.055 30.4011 112.055C33.6984 112.055 36.3034 111.047 38.2158 109.032C40.1283 107.017 41.0845 104.189 41.0845 100.548V71H58Z"
28+
fill="#F6F8EA" />
29+
<path
30+
d="M76.8387 78.47C78.4799 75.9387 80.7448 73.8942 83.6333 72.3365C86.5218 70.7788 89.9027 70 93.7759 70C98.3056 70 102.409 71.1358 106.085 73.4075C109.761 75.6791 112.65 78.9243 114.75 83.143C116.917 87.3618 118 92.262 118 97.8438C118 103.425 116.917 108.358 114.75 112.642C112.65 116.861 109.761 120.138 106.085 122.475C102.409 124.746 98.3056 125.882 93.7759 125.882C89.9683 125.882 86.5874 125.103 83.6333 123.546C80.7448 121.988 78.4799 119.976 76.8387 117.51V151H60V70.7788H76.8387V78.47ZM100.866 97.8438C100.866 93.6899 99.6842 90.4447 97.3209 88.1082C95.0232 85.7067 92.1675 84.506 88.7538 84.506C85.4058 84.506 82.5501 85.7067 80.1868 88.1082C77.8891 90.5096 76.7402 93.7873 76.7402 97.9411C76.7402 102.095 77.8891 105.373 80.1868 107.774C82.5501 110.175 85.4058 111.376 88.7538 111.376C92.1019 111.376 94.9576 110.175 97.3209 107.774C99.6842 105.308 100.866 101.998 100.866 97.8438Z"
31+
fill="#F6F8EA" />
32+
</svg>
33+
</div>
34+
<h2 class="title">Welcome!</h2>
35+
<p class="description">Your GoUp server is up and running. Upload your files to the root directory to get
36+
started.</p>
37+
38+
<a href="https://github.com/tryGoUp" target="_blank" class="btn-home">Read Documentation</a>
39+
40+
<br>
41+
<a href="{{ .FooterLink }}" target="_blank" class="footer-link">GoUp Project on GitHub</a>
42+
</div>
43+
</body>
44+
45+
</html>

internal/cli/cli.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
var tuiMode bool
1616
var benchMode bool
17+
var configPath string
1718

1819
// rootCmd represents the base command when called without any subcommands.
1920
var rootCmd = &cobra.Command{
@@ -39,6 +40,7 @@ func init() {
3940

4041
startCmd.Flags().BoolVarP(&tuiMode, "tui", "t", false, "Enable TUI mode")
4142
startCmd.Flags().BoolVarP(&benchMode, "bench", "b", false, "Enable benchmark mode")
43+
startCmd.Flags().StringVarP(&configPath, "config", "c", "", "Path to specific configuration file")
4244
}
4345

4446
var generateCmd = &cobra.Command{
@@ -148,14 +150,29 @@ var startCmd = &cobra.Command{
148150
}
149151

150152
func start(cmd *cobra.Command, args []string) {
151-
configs, err := config.LoadAllConfigs()
152-
if err != nil {
153-
fmt.Printf("Error loading configurations: %v\n", err)
154-
os.Exit(1)
153+
var configs []config.SiteConfig
154+
var err error
155+
156+
if configPath != "" {
157+
configs, err = config.LoadConfigsFromFile(configPath)
158+
if err != nil {
159+
fmt.Printf("Error loading config from %s: %v\n", configPath, err)
160+
os.Exit(1)
161+
}
162+
} else {
163+
configs, err = config.LoadAllConfigs()
164+
if err != nil {
165+
fmt.Printf("Error loading configurations: %v\n", err)
166+
os.Exit(1)
167+
}
155168
}
156169

157170
if len(configs) == 0 {
158-
fmt.Printf("No configurations found in %s\n", config.GetConfigDir())
171+
if configPath != "" {
172+
fmt.Printf("No valid configurations found in %s\n", configPath)
173+
} else {
174+
fmt.Printf("No configurations found in %s\n", config.GetConfigDir())
175+
}
159176
os.Exit(1)
160177
}
161178

0 commit comments

Comments
 (0)