Merge pull request 'chore: extract settings template to HTML file' (#129) from feature/extract-settings-template-126 into master
This commit was merged in pull request #129.
This commit is contained in:
@@ -2,6 +2,7 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -9,89 +10,7 @@ import (
|
|||||||
"gitea.leeworks.dev/0xwheatyz/gitea-mobile/internal/middleware"
|
"gitea.leeworks.dev/0xwheatyz/gitea-mobile/internal/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
var settingsTemplate = template.Must(template.New("settings").Parse(`<!DOCTYPE html>
|
const settingsTemplatePath = "internal/templates/settings.html"
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
||||||
<title>Settings — Gitea Mobile</title>
|
|
||||||
<style>
|
|
||||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
||||||
body {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
||||||
background: #0d1117; color: #e6edf3;
|
|
||||||
padding: 1rem;
|
|
||||||
padding-top: max(1rem, env(safe-area-inset-top));
|
|
||||||
}
|
|
||||||
h1 { font-size: 1.5rem; margin-bottom: 1rem; }
|
|
||||||
.card {
|
|
||||||
background: #161b22; border: 1px solid #30363d; border-radius: 8px;
|
|
||||||
padding: 1rem; margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
label { display: block; font-size: 0.875rem; color: #8b949e; margin-bottom: 0.5rem; }
|
|
||||||
input[type="text"], input[type="password"] {
|
|
||||||
width: 100%; padding: 0.5rem; font-size: 1rem;
|
|
||||||
background: #0d1117; border: 1px solid #30363d; border-radius: 6px;
|
|
||||||
color: #e6edf3; margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
input:focus { outline: none; border-color: #58a6ff; }
|
|
||||||
button {
|
|
||||||
width: 100%; padding: 0.75rem; font-size: 1rem; font-weight: 600;
|
|
||||||
background: #238636; color: #fff; border: none; border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
button:active { background: #2ea043; }
|
|
||||||
.message {
|
|
||||||
padding: 0.75rem; border-radius: 6px; margin-bottom: 1rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
}
|
|
||||||
.message.success { background: #0d2818; border: 1px solid #238636; color: #3fb950; }
|
|
||||||
.message.error { background: #2d1117; border: 1px solid #da3633; color: #f85149; }
|
|
||||||
.message.info { background: #0c1d2e; border: 1px solid #1f6feb; color: #58a6ff; }
|
|
||||||
.hint { font-size: 0.75rem; color: #8b949e; margin-top: 0.25rem; margin-bottom: 1rem; }
|
|
||||||
.status { font-size: 0.875rem; color: #8b949e; }
|
|
||||||
.status .connected { color: #3fb950; }
|
|
||||||
.logout-btn {
|
|
||||||
background: #21262d; border: 1px solid #30363d; margin-top: 0.5rem;
|
|
||||||
}
|
|
||||||
.logout-btn:active { background: #30363d; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Settings</h1>
|
|
||||||
|
|
||||||
{{if .Message}}
|
|
||||||
<div class="message {{.MessageType}}">{{.Message}}</div>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if .HasToken}}
|
|
||||||
<div class="card">
|
|
||||||
<p class="status">Status: <span class="connected">Connected</span></p>
|
|
||||||
<p class="hint">A Gitea API token is configured.</p>
|
|
||||||
<form method="POST" action="/settings">
|
|
||||||
<input type="hidden" name="action" value="logout">
|
|
||||||
<button type="submit" class="logout-btn">Remove Token</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<form method="POST" action="/settings">
|
|
||||||
<input type="hidden" name="action" value="save">
|
|
||||||
<label for="token">Gitea API Token</label>
|
|
||||||
<input type="password" id="token" name="token" placeholder="Enter your Gitea API token" required>
|
|
||||||
<p class="hint">Generate a token at your Gitea instance under Settings → Applications.</p>
|
|
||||||
<button type="submit">{{if .HasToken}}Update Token{{else}}Save Token{{end}}</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{if .HasToken}}
|
|
||||||
<p style="text-align:center; margin-top:1rem;">
|
|
||||||
<a href="/" style="color:#58a6ff; text-decoration:none;">Back to Dashboard</a>
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
</body>
|
|
||||||
</html>`))
|
|
||||||
|
|
||||||
// SettingsHandler handles GET and POST requests for the settings page.
|
// SettingsHandler handles GET and POST requests for the settings page.
|
||||||
type SettingsHandler struct {
|
type SettingsHandler struct {
|
||||||
@@ -126,8 +45,7 @@ func (h *SettingsHandler) handleGet(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data := settingsData{HasToken: hasToken}
|
data := settingsData{HasToken: hasToken}
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
h.renderSettings(w, data)
|
||||||
settingsTemplate.Execute(w, data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SettingsHandler) handlePost(w http.ResponseWriter, r *http.Request) {
|
func (h *SettingsHandler) handlePost(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -172,6 +90,18 @@ func (h *SettingsHandler) renderWithMessage(w http.ResponseWriter, r *http.Reque
|
|||||||
Message: msg,
|
Message: msg,
|
||||||
MessageType: msgType,
|
MessageType: msgType,
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
h.renderSettings(w, data)
|
||||||
settingsTemplate.Execute(w, data)
|
}
|
||||||
|
|
||||||
|
func (h *SettingsHandler) renderSettings(w http.ResponseWriter, data settingsData) {
|
||||||
|
tmpl, err := template.ParseFiles(settingsTemplatePath)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to parse settings template", "error", err)
|
||||||
|
http.Error(w, "template error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
if err := tmpl.Execute(w, data); err != nil {
|
||||||
|
slog.Error("failed to execute settings template", "error", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||||
|
<title>Settings — Gitea Mobile</title>
|
||||||
|
<style>
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||||
|
background: #0d1117; color: #e6edf3;
|
||||||
|
padding: 1rem;
|
||||||
|
padding-top: max(1rem, env(safe-area-inset-top));
|
||||||
|
}
|
||||||
|
h1 { font-size: 1.5rem; margin-bottom: 1rem; }
|
||||||
|
.card {
|
||||||
|
background: #161b22; border: 1px solid #30363d; border-radius: 8px;
|
||||||
|
padding: 1rem; margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
label { display: block; font-size: 0.875rem; color: #8b949e; margin-bottom: 0.5rem; }
|
||||||
|
input[type="text"], input[type="password"] {
|
||||||
|
width: 100%; padding: 0.5rem; font-size: 1rem;
|
||||||
|
background: #0d1117; border: 1px solid #30363d; border-radius: 6px;
|
||||||
|
color: #e6edf3; margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
input:focus { outline: none; border-color: #58a6ff; }
|
||||||
|
button {
|
||||||
|
width: 100%; padding: 0.75rem; font-size: 1rem; font-weight: 600;
|
||||||
|
background: #238636; color: #fff; border: none; border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
button:active { background: #2ea043; }
|
||||||
|
.message {
|
||||||
|
padding: 0.75rem; border-radius: 6px; margin-bottom: 1rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
.message.success { background: #0d2818; border: 1px solid #238636; color: #3fb950; }
|
||||||
|
.message.error { background: #2d1117; border: 1px solid #da3633; color: #f85149; }
|
||||||
|
.message.info { background: #0c1d2e; border: 1px solid #1f6feb; color: #58a6ff; }
|
||||||
|
.hint { font-size: 0.75rem; color: #8b949e; margin-top: 0.25rem; margin-bottom: 1rem; }
|
||||||
|
.status { font-size: 0.875rem; color: #8b949e; }
|
||||||
|
.status .connected { color: #3fb950; }
|
||||||
|
.logout-btn {
|
||||||
|
background: #21262d; border: 1px solid #30363d; margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
.logout-btn:active { background: #30363d; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Settings</h1>
|
||||||
|
|
||||||
|
{{if .Message}}
|
||||||
|
<div class="message {{.MessageType}}">{{.Message}}</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .HasToken}}
|
||||||
|
<div class="card">
|
||||||
|
<p class="status">Status: <span class="connected">Connected</span></p>
|
||||||
|
<p class="hint">A Gitea API token is configured.</p>
|
||||||
|
<form method="POST" action="/settings">
|
||||||
|
<input type="hidden" name="action" value="logout">
|
||||||
|
<button type="submit" class="logout-btn">Remove Token</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<form method="POST" action="/settings">
|
||||||
|
<input type="hidden" name="action" value="save">
|
||||||
|
<label for="token">Gitea API Token</label>
|
||||||
|
<input type="password" id="token" name="token" placeholder="Enter your Gitea API token" required>
|
||||||
|
<p class="hint">Generate a token at your Gitea instance under Settings → Applications.</p>
|
||||||
|
<button type="submit">{{if .HasToken}}Update Token{{else}}Save Token{{end}}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{if .HasToken}}
|
||||||
|
<p style="text-align:center; margin-top:1rem;">
|
||||||
|
<a href="/" style="color:#58a6ff; text-decoration:none;">Back to Dashboard</a>
|
||||||
|
</p>
|
||||||
|
{{end}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user