Switched from runtime file-based template loading (os.Stat + ParseGlob) to compile-time embedding (embed.FS + ParseFS). Templates are now bundled into the binary — no need to COPY them into Docker image. This fixes the fallback response issue where h.loaded was always false because templates weren't present in the container filesystem.
93 lines
2.8 KiB
Go
93 lines
2.8 KiB
Go
// package templates handles Go html/template rendering for the website.
|
|
package templates
|
|
|
|
import (
|
|
"embed"
|
|
"html/template"
|
|
"log"
|
|
"net/http"
|
|
|
|
"gitea.mrixs.me/Mrixs/MrixsCraft-server/internal/config"
|
|
"gitea.mrixs.me/Mrixs/MrixsCraft-server/internal/database"
|
|
)
|
|
|
|
//go:embed html/*.html
|
|
var templateFS embed.FS
|
|
|
|
// 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
|
|
}
|
|
|
|
// NewHandler creates a new templates handler and parses embedded 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
|
|
}
|
|
h.render(w, "index.html", pageData{Title: "Главная"})
|
|
}
|
|
|
|
func (h *Handler) loginPage(w http.ResponseWriter, r *http.Request) {
|
|
h.render(w, "login.html", pageData{Title: "Вход"})
|
|
}
|
|
|
|
func (h *Handler) registerPage(w http.ResponseWriter, r *http.Request) {
|
|
h.render(w, "register.html", pageData{Title: "Регистрация"})
|
|
}
|
|
|
|
func (h *Handler) profilePage(w http.ResponseWriter, r *http.Request) {
|
|
h.render(w, "profile.html", pageData{Title: "Профиль"})
|
|
}
|
|
|
|
// render executes the base layout template which calls {{template "content" .}}
|
|
// to inject the named page content.
|
|
func (h *Handler) render(w http.ResponseWriter, page string, data pageData) {
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
if h.tmpl == nil {
|
|
http.Error(w, "Templates not loaded", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if err := h.tmpl.ExecuteTemplate(w, "base.html", data); err != nil {
|
|
log.Printf("Template error (base.html → %s): %v", page, err)
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
// ── Template parsing ───────────────────────────────────────────
|
|
|
|
func (h *Handler) parseTemplates() {
|
|
tmpl, err := template.New("").Funcs(template.FuncMap{}).ParseFS(templateFS, "html/*.html")
|
|
if err != nil {
|
|
log.Printf("Template parse error: %v", err)
|
|
return
|
|
}
|
|
h.tmpl = tmpl
|
|
log.Println("Loaded embedded HTML templates")
|
|
}
|