- Redesigned base.html: dark Minecraft theme, sticky header, responsive grid, cards, server cards with status indicators, profile styles - index.html: hero section, server list grid, how-to-start steps, features section - login.html: centered card layout, client-side validation, fetch API - registration.html: password confirmation, pattern validation, error alerts - profile.html: new page — skin/cape upload & delete, launcher download links, auth-gated via localStorage token - templates.go: added /profile route, extended pageData with Username/UUID
124 lines
3.3 KiB
Go
124 lines
3.3 KiB
Go
// package templates handles Go html/template rendering for the website.
|
|
package templates
|
|
|
|
import (
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"gitea.mrixs.me/Mrixs/MrixsCraft-server/internal/config"
|
|
"gitea.mrixs.me/Mrixs/MrixsCraft-server/internal/database"
|
|
)
|
|
|
|
// pageData is passed to all templates.
|
|
type pageData struct {
|
|
Title string
|
|
Username string
|
|
UUID string
|
|
}
|
|
|
|
// Handler serves template-rendered pages.
|
|
type Handler struct {
|
|
db *database.DB
|
|
cfg *config.Config
|
|
tmpl *template.Template
|
|
loaded bool
|
|
}
|
|
|
|
// NewHandler creates a new templates handler and parses on-disk templates.
|
|
func NewHandler(db *database.DB, cfg *config.Config) *Handler {
|
|
h := &Handler{db: db, cfg: cfg}
|
|
h.parseTemplates()
|
|
return h
|
|
}
|
|
|
|
// RegisterRoutes mounts template-rendered pages.
|
|
func (h *Handler) RegisterRoutes(mux *http.ServeMux) {
|
|
mux.HandleFunc("GET /", h.index)
|
|
mux.HandleFunc("GET /login", h.loginPage)
|
|
mux.HandleFunc("GET /register", h.registerPage)
|
|
mux.HandleFunc("GET /profile", h.profilePage)
|
|
}
|
|
|
|
// ── Page handlers ──────────────────────────────────────────────
|
|
|
|
func (h *Handler) index(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/" {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
if !h.loaded {
|
|
fallback(w, "MrixsCraft")
|
|
return
|
|
}
|
|
h.render(w, "index.html", pageData{Title: "Главная"})
|
|
}
|
|
|
|
func (h *Handler) loginPage(w http.ResponseWriter, r *http.Request) {
|
|
if !h.loaded {
|
|
fallback(w, "Login")
|
|
return
|
|
}
|
|
h.render(w, "login.html", pageData{Title: "Вход"})
|
|
}
|
|
|
|
func (h *Handler) registerPage(w http.ResponseWriter, r *http.Request) {
|
|
if !h.loaded {
|
|
fallback(w, "Register")
|
|
return
|
|
}
|
|
h.render(w, "register.html", pageData{Title: "Регистрация"})
|
|
}
|
|
|
|
func (h *Handler) profilePage(w http.ResponseWriter, r *http.Request) {
|
|
if !h.loaded {
|
|
fallback(w, "Profile")
|
|
return
|
|
}
|
|
h.render(w, "profile.html", pageData{Title: "Профиль"})
|
|
}
|
|
|
|
// render executes the named template with data, writing to w.
|
|
func (h *Handler) render(w http.ResponseWriter, name string, data pageData) {
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
if err := h.tmpl.ExecuteTemplate(w, name, data); err != nil {
|
|
log.Printf("Template error (%s): %v", name, err)
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
// fallback writes a minimal placeholder when templates are missing.
|
|
func fallback(w http.ResponseWriter, title string) {
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("<h1>" + title + "</h1>"))
|
|
}
|
|
|
|
// ── Template parsing ───────────────────────────────────────────
|
|
|
|
func (h *Handler) parseTemplates() {
|
|
dirs := []string{
|
|
filepath.Join("internal", "templates", "html"),
|
|
"templates",
|
|
}
|
|
for _, dir := range dirs {
|
|
if _, err := os.Stat(dir); err != nil {
|
|
continue
|
|
}
|
|
pattern := filepath.Join(dir, "*.html")
|
|
tmpl, err := template.New("").Funcs(template.FuncMap{}).ParseGlob(pattern)
|
|
if err != nil {
|
|
log.Printf("Template parse error in %s: %v", dir, err)
|
|
continue
|
|
}
|
|
if tmpl != nil {
|
|
h.tmpl = tmpl
|
|
h.loaded = true
|
|
log.Printf("Loaded templates from %s", dir)
|
|
return
|
|
}
|
|
}
|
|
log.Println("No HTML templates found; using placeholder responses")
|
|
}
|